svg-animation について
SVGアイコン、イラスト、ロゴ、データマークのアニメーションを扱うスキルです。CSS、SMIL、JavaScriptによる線の描画、パスの変形、パス上の移動に加え、最適化と動きを減らす設定への対応を説明します。
主な機能
- 01線を描くアニメーション
- 02SVGパスの変形
- 03パスに沿った移動
- 04グラデーションとフィルターのアニメーション
- 05SVGの最適化とアクセシビリティ
活用シーン
- 01アイコンの状態切り替えアニメーション
- 02署名や地図を描くアニメーション
- 03ロゴやデータマークへの動きの追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ iart-ai/ web-animation-skills --skill svg-animationインストール後、Claude Code で/svg-animationを入力して読み込まれたか確認します。
同梱ファイルREADME.mdreferences/svg-techniques.md
詳細
SVG アニメーション
鮮明で軽量、無限に拡大・縮小できるベクターの動きです。アイコン、イラスト、ロゴ、データマークに最適です。SVG は CSS(宣言的でシンプル)、SMIL(SVG 内の <animate>)、JS(制御やモーフィング向けの GSAP/Web Animations)の 3 通りでアニメーションできます。タスクに応じて選択してください。以下の手法には、それぞれの適用先が記載されています。
使用する場面
- アイコン、イラスト、署名、地図のストロークを描き出すアニメーション
- 図形やパスのモーフィング、アイコンの状態変化のアニメーション(メニュー ↔ 閉じる、再生 ↔ 一時停止)
- パスに沿った要素の移動(モーションパス)
- アニメーション付きグラデーション、フィルター(グロー、変位)、アニメーションロゴ
基本的な手法
ストロークを描き出す(定番)
ダッシュ配列をパスと同じ長さにし、オフセットを最大にして完全に非表示にしてから、オフセットを 0 までアニメーションさせます。
.path {
stroke-dasharray: var(--len);
stroke-dashoffset: var(--len);
animation: draw 1.4s ease forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
長さの取得方法:
- JS(最も確実):
const len = path.getTotalLength(); path.style.setProperty("--len", len); - JS を使わない方法:
<path>にpathLength="1"を設定し、stroke-dasharray: 1; stroke-dashoffset: 1;として、アニメーションで0にします。これにより、長さを測定せずにどのパスも 0~1 の長さに正規化できます。
オフセットを 0 から len にアニメーションさせると、逆向きに消去できます。複数のパスには animation-delay を設定して順番に開始します。描画方向はパスの点の順序に従います。逆向きに描画される場合は、エディターで順序を反転するか、オフセットの符号を反転してください。
あるパスから別のパスへのモーフィング
パスは点ごとに補間されるため、単純なモーフィングでは、両方の d 属性に同じ数と種類のコマンドが必要です。信頼性の高い方法は 2 つあります。
- GSAP MorphSVG(GSAP 3.12 以降は無料)— 異なる点の数を自動的に処理し、適切な対応付けを行います。
gsap.registerPlugin(MorphSVGPlugin);
gsap.to("#start", { morphSVG: "#end", duration: 0.8, ease: "power2.inOut" });
// Convert any shape to a morph-able path:
MorphSVGPlugin.convertToPath("circle, rect, ellipse, line, polygon");
- Flubber(小規模な単体ライブラリ)— GSAP を使わずに補間関数を生成できます。React/Framer Motion との併用に適しています。
import { interpolate } from "flubber";
const interpolator = interpolate(pathA, pathB, { maxSegmentLength: 2 });
// interpolator(0) === pathA, interpolator(1) === pathB; feed t into a tween.
手作業で作成するモーフィング(アイコンの切り替えなど)では、両方のパスのコマンド構造を同じにし、Web Animations または CSS で d を直接アニメーションさせます(最新のブラウザーでは、path("...") を使って d をアニメーションできます)。
パスに沿った移動
- GSAP MotionPath(推奨 — 制御、位置合わせ、スクラブに対応):
gsap.registerPlugin(MotionPathPlugin);
gsap.to("#rocket", {
duration: 4, repeat: -1, ease: "none",
motionPath: { path: "#track", align: "#track", autoRotate: true, alignOrigin: [0.5, 0.5] },
});
autoRotate: true はオブジェクトの向きをパスの接線に合わせます。align を指定すると、座標がパス要素を基準にします。
- SMIL(JS 不要):
<path id="track" d="M10,80 C40,10 120,10 150,80" fill="none"/>
<circle r="6" fill="#3b82f6">
<animateMotion dur="3s" repeatCount="indefinite" rotate="auto">
<mpath href="#track"/>
</animateMotion>
</circle>
- CSS の offset-path(最新の宣言的な方法):
offset-path: path("M10,80 C..."); animation: move 3s linear infinite;と@keyframes move { to { offset-distance: 100%; } }、さらにoffset-rotate: autoを指定します。
アニメーション付きグラデーションとフィルター
グラデーション:gradientTransform またはストップ位置をアニメーションさせます。光沢を走らせる例:
<linearGradient id="sheen">
<stop offset="0%" stop-color="#fff" stop-opacity="0"/>
<stop offset="50%" stop-color="#fff" stop-opacity=".8"/>
<stop offset="100%" stop-color="#fff" stop-opacity="0"/>
<animateTransform attributeName="gradientTransform" type="translate"
from="-1 0" to="1 0" dur="2s" repeatCount="indefinite"/>
</linearGradient>
フィルター:feDisplacementMap の scale をアニメーションさせて粘性や揺れを表現したり、feGaussianBlur の stdDeviation でフォーカスを移動したり、feColorMatrix/feFlood でグローを表現したりできます。フィルターは描画負荷が高いため、アニメーションは控えめにし、可能な場合は transform/opacity を優先してください。
実装方法の選択(すばやく選ぶ)
| 必要な機能 | 使用するもの |
|---|---|
| 単一の宣言的な描画/フェード | CSS |
| 自己完結型で、JS バンドル不要 | SMIL(SVG 内の <animate*>) |
| 同期制御、スクラブ、スクロール連動 | GSAP |
| 点の数が異なるモーフィング | GSAP MorphSVG または Flubber |
| 回転を伴うパス追従 | GSAP MotionPath/CSS offset-path |
SMIL の注意点:IE/旧 Edge ではサポートされておらず、以前は非推奨化のフラグが設定されていました。幅広いブラウザーへの対応やスクロール同期が必要な場合は、CSS または JS を優先してください。最新ブラウザーで使う自己完結型のアイコンアセットには、引き続き SMIL が適しています。
作成と最適化
- SVGO でビルド/クリーンアップします。
viewBoxは保持し、エディターのメタデータは削除します。ただし、cleanupIds/removeViewBoxと、CSS/JS/SMIL から参照している ID の名前を変更するプラグインは無効にします。個々のサブパスやシェイプをアニメーションさせる場合は、mergePathsとconvertShapeToPathも無効にします。 - CSS/JS から内部要素にアクセスできるよう、SVG を DOM にインラインで埋め込みます(
<img src>は使用しません)。<img>に埋め込んだ SVG は、内部の SMIL/CSS によるアニメーションのみ実行できます。 - 明示的な
viewBoxを設定し、アセットが柔軟に拡大縮小できるよう、固定のwidth/heightは避けます。 - 描画アニメーションでは、パスが塗りつぶされたアウトラインではなく、実際のストローク(
fill:none; stroke:...)であることを確認します。dashoffsetが作用するのはストロークのみです。 prefers-reduced-motionに対応します。ループや大きな動きは制限し、静止した最終状態を維持します。
提供と検証(スタンドアロン HTML)
同梱ヘルパー(
scripts/):scripts/seek-shot.sh anim.html 0 1.5 3は?t=Nハーネスでアニメーションを停止し、各時点のスクリーンショットを撮影します。scripts/contact-sheet.sh sheet.png frame-*.pngはそれらをタイル状に並べ、一目で確認できるようにします。scripts/README.mdを参照してください。
自己完結型のアイコン/ロゴ/描画アニメーションを提供する場合、成果物はブラウザーで直接開ける 1 つの HTML ファイルです。SVG をマークアップにインラインで埋め込み、アニメーションを 1 つの仕組みで制御し、ビルド工程は設けません。ベクターアセットには 1 ファイルが適切です。バンドラーは使わないでください。
出力要件:
.htmlファイルを 1 つ用意します。インラインの<svg>に加え、CSS の@keyframes/CDN から読み込む GSAP を使った<script>/SMIL の<animate*>のいずれかを含めます。制御方法は 1 つだけ選んでください。- スクリーンショット用に任意の時点でアニメーションを停止できるよう、選んだ制御方法に対応するシークハーネスを含めます。
シークハーネス — 正確な時点で停止する。 ?t=N で指定の時点へ移動して一時停止し、スクリーンショットで静止フレームを撮影できるようにします。SVG のアニメーション方法に合った仕組みを使用してください。
<script>
const t = new URLSearchParams(location.search).get("t");
if (t !== null) {
const N = parseFloat(t);
// SMIL: pause the SVG's own clock and scrub it
const svg = document.querySelector("svg");
svg.pauseAnimations(); svg.setCurrentTime(N);
// CSS @keyframes draw-on: el.style.animationDelay=(-N)+"s"; el.style.animationPlayState="paused";
// GSAP timeline: tl.pause(); tl.seek(N);
}
window.__ready = true;
</script>
検証ループ — レンダリング → 停止 → スクリーンショット → 確認: ファイルを開始/中間/終了時点(?t=0、?t=<dur/2>、?t=<dur>)で開き、それぞれスクリーンショットを撮影して、忠実度(ストロークが正しい方向に描画されるか、モーフィングの端点がきれいか)とアーティファクト(パスが viewBox でクリップされていないか、古い dashoffset によってストロークが消えていないか、FOUC、モーフィングの継ぎ目でのカクつき)を確認します。ヘッドレスツールはどれでも使用できます。
npx playwright screenshot --wait-for-timeout=500 "file://$PWD/icon.html?t=0.7" frame-mid.png
完了前の確認事項:
- スタンドアロンで開けること。コンソールエラーがなく、インライン SVG にアクセスでき、CDN(使用している場合)が読み込まれること。
- 選んだ制御方法のシーク機能で、決定論的なフレームを停止できること。
- 開始/中間/終了時点のスクリーンショットを撮影し、要件に合致していること。クリッピングや
viewBox外へのストロークがないこと。 prefers-reduced-motionに対応していること。ループや大きな動きが制限され、静止した最終状態が維持されること。- イージングが意図的に選ばれていること。
ease/GSAP のイージングを目的に沿って選び、意図しないlinearの描画アニメーションがないこと。
参考ファイル
references/svg-techniques.md—dashoffsetの計算方法とgetTotalLengthの注意点、pathLength="1"による正規化、GSAP MorphSVG と Flubber の選択ガイド(コード付き)、アイコン切り替えのモーフィング(ハンバーガー ↔ 閉じる)、MotionPath/offset-path の詳細、SMIL・CSS・JS の比較、およびアニメーション向けに調整した SVGO 設定をまとめています。