optimize-web-animations について
フロントエンドのアニメーション性能を調査・改善するコーディングスキルです。ブラウザーで測定し、画面外の動きを止めながら、表示中のアニメーションと長期リソースの解放を確認します。
主な機能
- 01変更前後のアニメーション測定
- 02画面外の CSS アニメーション停止
- 03Canvas と WebGL のループ制御
- 04タイマー、リスナー、描画リソースの解放
- 05表示状態とルート切替の安定性確認
活用シーン
- 01画面外アニメーションの CPU・GPU 負荷軽減
- 02動きによるスクロールのカクつき調査
- 03RAF ループとリソースリークの点検
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ akillness/ jeo-skills --skill optimize-web-animationsインストール後、Claude Code で/optimize-web-animationsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
SKILL.toonagents/openai.yamlreferences/browser-profiling.md詳細
Web アニメーションの最適化
このスキルを使用する場面
- ユーザーが、アニメーションのパフォーマンス改善、画面外のアニメーションの一時停止、または React/Vite/Next/フロントエンドのページで「表示中のみ再生」する最適化の適用を求めている場合。
- メモリーリーク、長時間の利用でコンピューターの動作が遅くなるページが報告された場合、または長期間存続するリソース(RAF ループ、リスナー、オブザーバー、タイマー、GSAP トゥイーン、WebGL オブジェクト)の監査と解放を希望している場合。
- CSS アニメーション、canvas/WebGL の
requestAnimationFrameループ、マーキー/ティッカー、スケルトンローダー、GSAP/Three/Matter のエフェクトによるスクロールのカクつきの修正や、CPU/GPU 使用量の削減を希望している場合。 - ブラウザーで計測してから修正するサイクル(Codex Browser を推奨)が必要で、
IntersectionObserver/is-offscreenクラスで動きを制御し、スクリーンショットだけでなくoffscreenRunningCount、DOM/canvas 数、ルートサイクルの安定性で検証する場合。 - ソースレベルでのクリーンアップが必要な場合。アンマウント時にタイマーのクリア、RAF のキャンセル、オブザーバーの切断、リスナーの削除、Three/WebGL/GSAP リソースの破棄を行います。
- 一般的なパフォーマンス問題の調査(トレース、クエリプラン、負荷テストの結果、または CWV/Lighthouse レポートの解釈や、レイテンシ/スループット/メモリー/バンドルサイズにわたる最初の最適化対象の判断)には使用しません。その場合は
performance-optimizationに振り分けてください。このスキルを使用するのは、対象がすでにアニメーション/モーション関連のフロントエンド作業だと判明している場合に限ります。
基本ルール
編集前に実際のページを計測してください。目標はモーションをなくすことではなく、画面外では処理を停止し、表示時にはモーションを正しく再開し、ルート遷移/アンマウント時には長期間存続するリソースを解放することです。
利用できる場合は、特に localhost のページでは Codex Browser を使用してください。ユーザーから明示的な依頼がない限り、Chrome は使用しないでください。
ワークフロー
-
リポジトリのコンテキストを確認します。
AGENTS.mdまたはローカルの指示を読みます。- 早い段階で
git status --shortを実行します。 - ページコンポーネント、アニメーションフック、CSS キーフレーム、
requestAnimationFrame、setInterval、setTimeout、canvas/WebGL/物理コンポーネント、メディア要素、GSAP のタイムライン/トゥイーン、既存の可視性ユーティリティを探します。 - エフェクトのクリーンアップ処理を調べ、イベントリスナー、オブザーバー、RAF ループ、インターバル、タイマー、外部スクリプト、メディアストリーム、WebGL テクスチャ/マテリアル/ジオメトリ/レンダラー、アンマウント後に完了する可能性のある非同期処理を確認します。
- 作業ツリーに変更がある場合は、最初から対象を絞ってステージングする計画を立てます。
-
ブラウザーでベースラインを取得します。
- ユーザーが指定した正確なルートを開きます。
- レイアウトに差が出る可能性がある場合は、ページ上部、中ほど、フッター/下部コンテンツ、およびモバイルのビューポートでプロファイルします。
- 計算後の
animationName、animationPlayState、可視性を使って CSS アニメーションを数えます。::beforeと::afterも含めます。 - canvas/WebGL 要素は別途調べます。CSS のプロファイリングだけでは RAF ループが停止したことを証明できません。
- 画面外で実行中のアニメーション名と、それを所有する DOM 要素を記録します。
- メモリー/リークに関する依頼では、要素/canvas/image/iframe の数、取得できる場合は公開されている JS ヒープ指標、10~30 秒後のアイドル時サンプル、短いルートサイクルのサンプルも記録します。ヒープ API が
nullを返す場合や、Browser サンドボックスがモンキーパッチをブロックする場合は、その旨を伝え、安定した観測可能な数値とソース監査に基づいて判断します。 - ストレステストは範囲を限定してください。プロファイリング中に Browser のタブがクラッシュした場合は過負荷の証拠になりますが、最小限のテストで再現できない限り、原因を断定しすぎないでください。
- 再利用可能な Codex Browser 評価ツールについては、
references/browser-profiling.mdを参照してください。
-
モーションを制御する最小の所有元にパッチを適用します。
- アプリに既存のページ表示/可視性フックがある場合は、優先して使用します。
- ない場合は、
IntersectionObserverを追加し、セクションとアニメーション対象の子要素にis-offscreenなどの安定したクラスを付け外しします。 - 対象を絞ったルールで CSS アニメーションを一時停止します。
main > section.is-offscreen .expensive-animation,
.expensive-animation.is-offscreen {
animation-play-state: paused !important;
}
- カードやプレースホルダーが繰り返される場合は、ドキュメント全体ではなく、カードの外枠とアニメーションする子孫要素を監視します。
- マーキー/ティッカーのトラックは、そのセクションが画面外にあるときに一時停止します。
- スケルトンローダーや疑似要素のグリマーには、必要に応じて
::beforeと::afterの一時停止セレクターを含めます。 - Canvas/WebGL/物理演算のループでは、RAF ループを直接制御します。
- Canvas/コンテナーが交差したときに開始します。
- 画面外になったら
requestAnimationFrameをキャンセルします。 - 再び画面内に入ったら再開します。
- クリーンアップ時にオブザーバーを切断し、フレームをキャンセルします。
- ブラウザーでの検証に役立つ場合は、
data-animation-activeなど、視覚に影響しないデバッグマーカーを追加します。
- コンポーネントがすでに
prefers-reduced-motionに対応している場合は、その動作を尊重し、スクロール/アニメーション状態のために React のレンダーループを導入しないでください。 - リーク対策を強化します。
- エフェクトで作成したタイムアウト/インターバルをすべてクリアします。
- アンマウント前とループ再開前に RAF をキャンセルします。
IntersectionObserver、ResizeObserver、MutationObserver、カスタムサブスクリプションを切断します。- 同じハンドラー参照を使って、グローバル/window/document のリスナーを削除します。
- Three/WebGL のテクスチャ、マテリアル、ジオメトリ、レンダラーを破棄し、レンダラーの DOM ノードを削除します。
- DOM ノードやシェーダーのユニフォームなどの可変オブジェクトに対する GSAP のトゥイーン/タイムラインを停止します。
- メディアストリームを停止し、切り離された動画/音声ソースを一時停止します。
- 非同期ローダーを
isDisposedフラグで保護し、アンマウント後に読み込みが完了した場合は、読み込まれたリソースを破棄します。 - React のクリーンアップで、ref が変更される可能性があるという lint の警告が出た場合は、クリーンアップを返す前にエフェクト内で
ref.currentの値を取得します。 - 表示状態から復帰した後に遅延フレームで過大な更新が実行されないよう、物理演算またはシミュレーションのフレームデルタに上限を設けます。
-
ビルドだけでなく、動作も検証します。
- ルートを再読み込みし、同じトップ/中間/フッター/モバイルのプロファイルを再実行します。
- 目標結果:テスト対象のページセクションで
offscreenRunningCount: 0になること。 - 画面内にスクロールしたときに、表示中のアニメーションが動作または再開することを確認します。
- RAF/Canvas ループが画面外では非アクティブ、画面内ではアクティブと報告されることを確認します。あるいは、ソース/ランタイムの状態からキャンセルを証明します。
- リーク監査では、ルート遷移前後とアイドル時のサンプルを比較します。繰り返しナビゲーションした後、DOM/Canvas/画像の数が同じ基準値に戻ることを確認します。ただし、想定される非同期コンテンツの小さな変動は許容します。
- 検索/フィルター/ナビゲーションなど、通常のページ操作を実行し、オブザーバーが動的コンテンツを妨げないことを確認します。
- 新しいタブでコンソールの警告/エラーを確認します。
-
ローカルチェックを実行します。
- リポジトリ標準のチェックを使用します。React/Vite アプリでは、次のようなものが一般的です。
git diff --check
npm run lint
npm run build
- 既知の致命的でない警告は、失敗とは分けて記載します。
- リポジトリ/ユーザーの指示で求められた場合は、変更範囲を絞ってコミットします。
- 無関係な未コミット変更がある場合は、分離したインデックスを使用します。
rm -f /tmp/<task>-index
GIT_INDEX_FILE=/tmp/<task>-index git read-tree HEAD
# Apply only the intended hunks to the temporary index.
GIT_INDEX_FILE=/tmp/<task>-index git diff --cached --check
GIT_INDEX_FILE=/tmp/<task>-index git commit -m "Pause offscreen <page> animations"
git restore --staged <files> 2>/dev/null || true
- 作業ツリーが汚れている場合、すべてのハンクが作業対象に属していない限り、広範なファイルをステージしないでください。
- 根拠を添えて報告します。
- 判明した内容を最初に示します。まだ動作していたもの、リークの懸念があったもの、計測できなかったものを記載します。
- ソース監査上のリスクと、実ブラウザーでの計測結果を分けて記載します。
- 正確にサンプリングしたルート、画面外のアニメーション数、DOM/Canvas 数の安定性、ルート遷移の結果、ローカルチェックを含めます。
- 特に、ヒープカウンターが利用できない場合や、ブラウザーの計測が妨げられた場合は、制約を明確に記載します。
適切な修正パターン
- 長いセクションでは、セクションレベルと要素レベルの両方に
is-offscreenを適用します。これにより、画面下にある子要素のアニメーションも実行されないようにできます。 - ルートごとに共有の表示判定セレクター定数を用意します。例:
COURSES_PAGE_ANIMATION_VISIBILITY_SELECTOR。 - アニメーションの実行可否を判定する
IntersectionObserverのしきい値には、0.01前後を使用します。 - WebGL/canvas エフェクトには、RAF ループを直接制御します。CSS の
animation-play-stateでは、JavaScript のレンダリングループを一時停止できません。 - 一時停止後やフレーム遅延後に再開する物理演算ループでは、フレームデルタに上限を設けます。
- GSAP/WebGL エフェクトで使用する React の ref は、クリーンアップ対象のノードを保持します。
- アンマウント後に解決する可能性がある画像/動画/テクスチャ/データのローダーには、
isDisposedガードを設けます。 - 短時間のアイドル状態とルート切り替えを確認し、DOM ノード、canvas、iframe の蓄積や、メディアの解放漏れを検出します。
避けること
- プロファイルの基準を満たすために、すべてのアニメーションを削除すること。
- 祖先要素のセレクターの範囲が広すぎるために、表示中のヒーローアニメーションまで一時停止すること。
animation-play-stateが疑似要素や JavaScript の RAF ループにも適用されると思い込むこと。- 長いページで、ページ先頭の測定だけを信頼すること。
- ヒープカウンターを利用できないことを、メモリリークがない証拠とみなすこと。
- Browser で上限のないストレステストを実行すること。上限付きのサイクルを使い、クラッシュを記録し、因果関係を誇張しないでください。
- スクリーンショットだけをパフォーマンスの証拠とすること。
- 無関係なローカルの変更をコミットに含めること。
参考資料
- 上流ソース:https://github.com/MengTo/Skills/tree/main/agent-skills/codex/optimize-web-animations
- references/browser-profiling.md — オフスクリーン/アニメーションのプロファイリングに再利用できる Codex Browser 評価ツール
- agents/openai.yaml — 同梱のエージェント設定
コメント
Markdown 対応