图像与设计
需要给 SVG 图标、插画、Logo 做描边绘制、路径变形…
适用于用 CSS、SMIL 或 GSAP/Flubber 给 SVG 做轻量矢量动画,并交付可独立打开 HTML 进行冻结截图验证的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
需要给 SVG 图标、插画、Logo 做通用
解决思路
- 按任务选择 SVG 动画驱动:CSS 适合声明式、简单的绘制/淡入淡出;SMIL 适合自包含、无 JS bundle 的 SVG;JS(GSAP/Web Animations)适合需要协调、可 scrub、可 morph 的动画。
- 做 stroke draw-on 时,把 stroke-dasharray 设为与路径等长,把 stroke-dashoffset 设为同长度(完全偏移、不可见),再把 stroke-dashoffset 动画到 0。
- 使用 CSS draw-on 骨架:`.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 长度,无需测量。
- 做反向擦除时,把 stroke-dashoffset 从 0 动画回 `len`。
- 多条路径错峰出现时,用 `animation-delay` 做 stagger。
- 控制绘制方向:绘制方向遵循路径点顺序;如果画反了,在编辑器中反转路径,或把 offset 符号取反。
- 做朴素 path morph 时,先确保两个 `d` 属性的命令数量和类型完全一致,因为路径会逐点插值。
- 路径点数不匹配时用 GSAP MorphSVG(GSAP 3.12 起免费):`gsap.registerPlugin(MorphSVGPlugin); gsap.to('#start', { morphSVG: '#end', duration: 0.8, ease: 'power2.inOut' });`。
- 用 MorphSVG 把任意形状转成可 morph 路径:`MorphSVGPlugin.convertToPath('circle, rect, ellipse, line, polygon');`。
- 不依赖 GSAP 时用 Flubber 生成插值器,适合 React/Framer Motion:`import { interpolate } from 'flubber'; const interpolator = interpolate(pathA, pathB, { maxSegmentLength: 2 });`,把 t 喂给 tween。
- 手工 morph(如 icon toggle)时,保持两条路径命令结构一致,直接用 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] } });`。
- 在 MotionPath 中用 `autoRotate: true` 让对象朝向路径切线;用 `align` 让坐标相对于路径元素。
- 无 JS 时用 SMIL `animateMotion`,配合 `rotate='auto'` 和 `<mpath href='#track'/>`。
- 用 CSS `offset-path` 实现现代声明式沿路径运动:`offset-path: path('M10,80 C...'); animation: move 3s linear infinite;`,配 `@keyframes move { to { offset-distance: 100%; } }`,并设 `offset-rotate: auto;`。
- 动画渐变:动画 `gradientTransform` 或 stop offsets。
- 做 sheen 扫光:用 `<linearGradient id='sheen'>` 配三个 stop(0% 透明、50% 白色 0.8、100% 透明),再用 `<animateTransform attributeName='gradientTransform' type='translate' from='-1 0' to='1 0' dur='2s' repeatCount='indefinite'/>`。
- 动画滤镜:用 `feDisplacementMap` 的 `scale` 做 gooey/wobble,用 `feGaussianBlur` 的 `stdDeviation` 做 focus pull,用 `feColorMatrix`/`feFlood` 做 glow。
- 滤镜是 paint-heavy 的,动画要少用;能用 `transform`/`opacity` 的地方优先用它们。
- 按需求快速选实现:单个声明式 draw/fade 用 CSS。
- 按需求快速选实现:自包含、无 JS bundle 用 SMIL(SVG 内 `<animate*>`)。
- 按需求快速选实现:需要协调、可 scrub、绑定滚动的动画用 GSAP。
- 按需求快速选实现:点数不匹配的 morph 用 GSAP MorphSVG 或 Flubber。
- 按需求快速选实现:需要沿路径跟随并旋转用 GSAP MotionPath / CSS offset-path。
- 注意 SMIL caveat:IE/旧 Edge 不支持,历史上被标记废弃;要最大覆盖或滚动同步优先 CSS/JS;常青浏览器中自包含图标资产仍可用 SMIL。
- 用 SVGO 构建/清理:保留 `viewBox`,去掉编辑器元数据,但禁用 `cleanupIds`/`removeViewBox` 以及任何会重命名 CSS/JS/SMIL 所引用 ID 的插件。
- 如果动画单个子路径或形状,禁用 `mergePaths` 和 `convertShapeToPath`。
- 把 SVG inline 到 DOM(不要 `<img src>`),这样 CSS/JS 能访问其内部;`<img>` 内嵌 SVG 只能通过内部 SMIL/CSS 自动画。
- 设置显式 `viewBox`,避免固定 `width`/`height`,让资产流式缩放。
- 做 draw-on 时确保路径是实际描边(`fill:none; stroke:...`),不是填充轮廓;dashoffset 只影响 stroke。
- 尊重 `prefers-reduced-motion`:限制循环/大幅运动,保留静态最终状态。
- 使用 packaged helper:`scripts/seek-shot.sh anim.html 0 1.5 3` 冻结 `?t=N` harness 并逐帧截图;`scripts/contact-sheet.sh sheet.png frame-*.png` 平铺成 contact sheet 一眼审查;见 `scripts/README.md`。
- 对自包含 icon/logo/draw-on,交付一个可直接在浏览器打开的 HTML 文件:在 markup 中 inline SVG,用一个驱动机制驱动动画,无构建步骤;一个文件是矢量资产的正确层级,不要上 bundler。
- 输出契约:一个 `.html` 文件,inline `<svg>` 加 CSS `@keyframes` / 带 CDN GSAP 的 `<script>` / SMIL `<animate*>`,三选一驱动。
- 为该驱动加入 seek harness,使任意时刻都可被冻结截图。
- seek harness 用 `?t=N` seek 并暂停,让截图落在静止帧;用与 SVG 动画驱动匹配的机制。
- SMIL seek 机制:`const svg = document.querySelector('svg'); svg.pauseAnimations(); svg.setCurrentTime(N);`。
- CSS `@keyframes` draw-on seek 机制:`el.style.animationDelay=(-N)+'s'; el.style.animationPlayState='paused';`。
- GSAP timeline seek 机制:`tl.pause(); tl.seek(N);`。
- seek harness 骨架:`const t = new URLSearchParams(location.search).get('t'); if (t !== null) { const N = parseFloat(t); /* 按驱动 seek */ } window.__ready = true;`。
- 验证循环:按 start/mid/end 打开文件(`?t=0`、`?t=<dur/2>`、`?t=<dur>`),各截图,检查保真度(描边方向正确、morph 端点干净)和伪影(路径被 `viewBox` 裁剪、陈旧 dashoffset 导致描边消失、FOUC、morph 接缝卡顿)。
- 用任意 headless 工具截图,例如 `npx playwright screenshot --wait-for-timeout=500 "file://$PWD/icon.html?t=0.7" frame-mid.png`。
- 完成前检查 1:独立打开无 console 错误,inline SVG 可达,CDN(如有)加载。
- 完成前检查 2:你的驱动的 seek 机制能冻结确定性帧。
- 完成前检查 3:start/mid/end 已截图,符合 brief,无裁剪或超出 `viewBox` 的描边。
- 完成前检查 4:尊重 `prefers-reduced-motion`,循环/大幅运动被限制,静态最终状态保留。
- 完成前检查 5:easing 是有意的,选用 `ease`/GSAP ease,不要意外用 `linear` 做 draw-on。
- 查阅 `references/svg-techniques.md`:包含完整 dashoffset 数学与 `getTotalLength` 坑、`pathLength='1'` 归一化、GSAP MorphSVG vs Flubber 决策指南与代码、icon-toggle morph(hamburger↔close)、MotionPath/offset-path 细节、SMIL-vs-CSS-vs-JS 权衡、以及为动画调优的 SVGO 配置。
适用边界 · 注意事项
- 需要兼容 IE/旧 Edge 或做滚动同步时,不要只靠 SMIL;改用 CSS 或 JS。
- 路径是填充轮廓、没有实际 stroke 时,不要用 stroke-dashoffset 做 draw-on;改成真实描边路径或换动画机制。
- 两个路径的命令数量/类型不一致且不使用 GSAP MorphSVG/Flubber 时,不要做朴素 path morph;否则插值会失败或形状跳变。