IconFlux 是一个专注于「SVG 描边图标之间平滑形变(Morph)」的轻量引擎。你只需要给它两段任意的 SVG path d 数据——无论它们的点数是否相同、命令类型是否一致、子路径数量是否匹配——它都能自动算出最优对应关系,并在任意时间点吐出一段新的路径数据,从而实现菜单变关闭、播放变暂停、太阳变月亮、星星变爱心这类「一镜到底」的图标动画。
它解决的是前端动画里一个非常具体、又长期被低估的痛点:
- 🥴 直接对坐标做线性插值会「缩、扭、穿帮」:两个图标的路径点数量不一样时甚至无法逐点对应;
- 🧮 手工对齐关键帧极其繁琐:每一对图标都要人工数点、调旋转组,无法规模化;
- 🪶 现有方案往往绑定框架:React/Vue 换一套就要换一套绑定,原生 HTML、小程序、Canvas 场景用不了。
| 维度 | IconFlux 的做法 |
|---|---|
| 算法路线 | 不走「刚体 Procrustes 对齐 + 极坐标插值」,而是 弧长等比重采样 → 环形最优对应(自动寻找最佳起点偏移与顺/逆时针方向)→ 对齐帧内线性插值,对点数、命令类型完全不敏感 |
| 多子路径 | 内置 形状签名匹配,放大镜(圆环+手柄)、设置(齿轮+辐条)这类多路径图标也能自动配对,多出来的子路径自动淡入/淡出 |
| 平滑无自交 | 采用**向心 Catmull-Rom(α=0.5)**重建三次贝塞尔,锐角五角星也不会打结 |
| 框架无关 | 同一份引擎同时提供 ESM / CJS / IIFE / 自定义元素 <icon-morph> / 命令行 五种用法,React、Vue、Svelte、原生 JS、Node 构建脚本都能直接用 |
| 零运行时依赖 | 整个引擎没有任何 dependencies,gzip 后不到 10 KB,可离线运行 |
| 离线烘焙 | 自带 CLI,可在构建期把形变关键帧烤成 JSON / 表格 / SVG,不占用任何运行时性能 |
💡 灵感来源:近期社区出现的图标形变方案(如 morphicons、bloub)验证了「任意两图标互变」这一需求的热度。IconFlux 参考了它们验证过的产品目标与使用场景,但全部代码与核心算法均为独立自研,采用了一条不同的技术路线(弧长重采样 + 环形对应),并补齐了多子路径匹配、多状态序列、离线 CLI、无框架自定义元素等能力。
- 🔀 任意两图标互变:自动归一化
M/L/H/V/C/S/Q/T/A/Z全部命令,椭圆弧(A)按 SVG 规范展开为三次贝塞尔,点数不一致也能变。 - 📏 弧长等比重采样:每个子路径统一重采样为 N 个等弧长点,从数学上保证形变过程均匀、不卡顿。
- 🧭 最优环形对应:穷举环形起点偏移 × 顺/逆时针两种绕向,选取总位移最小的对应方案,旋转「自然涌现」,无需手工声明。
- 🧩 多子路径自动配对:基于尺度/旋转不敏感的径向形状签名做最优二分匹配,未匹配子路径平滑淡入淡出。
- 〰️ 两种重建风格:
smooth(向心 Catmull-Rom,默认,杜绝锐角自交)与polygon(折线,端点近零误差)。 - 🎞️ 动画控制器 + 多状态序列:
animateMorph支持 7 种内置缓动、延迟、取消;morphSequence支持 A→B→C 循环、驻留时间。 - 🧱
<icon-morph>自定义元素:Shadow DOM 隔离、路径对象池复用,一行标签即可用,不依赖任何框架。 - 🖥️ 零依赖 CLI:
iconflux keyframes烘焙关键帧(json/table/svg),iconflux inspect体检路径。 - 🪶 真零依赖 + 全格式产物:ESM、CJS、IIFE 单文件产物 + 完整 TypeScript 类型声明,gzip < 10 KB。
- 🧪 32 个测试用例全绿:解析、几何、对应算法、形变端点保真、动画时序、CLI 全链路覆盖。
- ♿ 可离线、可 SSR:无 DOM 环境下引擎照常工作,自定义元素仅在浏览器中注册。
- 运行时:任意现代浏览器,或 Node.js ≥ 16(开发测试推荐 18/20/22)
- 依赖:无,不需要
npm install任何第三方包
<svg viewBox="0 0 24 24" width="32" height="32" fill="none" stroke="currentColor" stroke-width="2">
<path id="icon" d="M3 6h18M3 12h18M3 18h18" />
</svg>
<script src="https://cdn.jsdelivr.net/gh/gitstq/iconflux@v1.0.0/dist/iconflux.iife.js"></script>
<script>
const close = 'M6 6l12 12M18 6L6 18';
document.querySelector('#icon').onclick = (e) => {
const start = e.target.getAttribute('d');
const { animateMorph } = IconFlux;
animateMorph(start, close, ({ d }) => e.target.setAttribute('d', d), {
duration: 420,
easing: 'easeInOutCubic',
});
};
</script><script type="module" src="https://cdn.jsdelivr.net/gh/gitstq/iconflux@v1.0.0/dist/iconflux.esm.js"></script>
<icon-morph id="btn" size="28" stroke-width="2" duration="420"></icon-morph>
<script type="module">
const el = document.querySelector('#btn');
el.setInstant('M3 6h18M3 12h18M3 18h18'); // 初始:菜单
el.morphTo('M6 6l12 12M18 6L6 18'); // 点击后:关闭
</script># 直接从 Git 安装(无需 npm registry)
npm install git+https://github.com/gitstq/iconflux.git
# 或克隆后本地 link// ESM(Vite / webpack / Rollup / Node ESM)
import { compileMorph, animateMorph } from 'iconflux';
// CJS
const { compileMorph } = require('iconflux');npx iconflux keyframes menu.svg close.svg --steps 8 --format json
node bin/iconflux.js inspect icon.svggit clone https://github.com/gitstq/iconflux.git
cd iconflux
npm test # 运行 32 个测试
node examples/node-keyframes.mjs # 终端查看 5 帧关键帧
# 浏览器直接打开 demo/index.html(无需起服务)返回一个函数 t => { d, groups },t ∈ [0,1]:
import { compileMorph } from 'iconflux';
const morph = compileMorph(menuD, closeD, {
samples: 96, // 每个子路径重采样点数,越大越细腻,默认 96
output: 'smooth', // 'smooth'(默认)| 'polygon'
});
morph(0).d; // 等于菜单
morph(0.5).d; // 中间帧
morph(1).d; // 等于关闭groups 是子路径级结果数组 [{ d, opacity, closed }],多子路径淡入淡出时可分别设置透明度。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
samples |
number |
96 |
每子路径弧长采样点数,范围 ≥ 8 |
output |
'smooth' | 'polygon' |
'smooth' |
路径重建风格;polygon 为折线、端点近零误差 |
duration |
number |
450 |
animateMorph 动画时长(毫秒) |
delay |
number |
0 |
动画延迟(毫秒) |
easing |
string | fn |
'easeInOutCubic' |
线性/三次/回弹/橡皮筋等 7 种,或自定义 t=>number |
可用缓动:linear、easeInOutCubic、easeOutCubic、easeInOutQuad、easeOutBack、easeInOutSine、easeOutElastic。
const ctrl = animateMorph(a, b, ({ d, groups, t, eased }) => {
path.setAttribute('d', d);
}, { duration: 500, easing: 'easeOutBack' });
await ctrl.finished; // 结束 Promise
ctrl.cancel(); // 随时取消(Promise reject)import { morphSequence } from 'iconflux';
const seq = morphSequence([menu, close, search, heart, star], (frame) => {
path.setAttribute('d', frame.d);
}, { loop: true, each: 600, hold: 200, easing: 'easeInOutCubic' });
seq.cancel();| 成员 | 说明 |
|---|---|
el.setInstant(d) |
无动画直接设置 |
el.morphTo(d, opts?) |
形变到新图标,返回结束 Promise;中途再次调用会从当前视觉状态续接 |
el.playSequence(list, opts?) |
播放多状态序列,loop:true 循环 |
el.stopSequence() |
停止序列 |
el.value |
当前路径数据 |
| 属性 | size、stroke-width、color、duration、easing、states(配合 autoplay 自动循环) |
<!-- 纯 HTML 自动循环:states 之间用两个分号 ;; 分隔 -->
<icon-morph states="M3 6h18..;;M6 6l12..;;M12 3l2.6.." autoplay size="32"></icon-morph># 输出 12 帧 JSON(含 t、d、子路径数)
iconflux keyframes a.svg b.svg --steps 12 --samples 96 --output smooth --format json
# 表格:step<TAB>t<TAB>d
iconflux keyframes a.svg b.svg --steps 8 --format table
# 直接输出横向排列的 SVG 条带
iconflux keyframes a.svg b.svg --steps 6 --format svg > strip.svg
# 体检:子路径数、闭合数、命令数、包围盒
iconflux inspect icon.svg输入既可以是 .svg/.txt 文件,也可以直接传 d 字符串,或用 - 从标准输入读取。
- 🎛️ 开关类按钮:菜单/关闭、播放/暂停、展开/收起、锁/解锁
- 🌗 模式切换:亮色/暗色(太阳/月亮)、列表/网格
- ❤️ 状态反馈:收藏(星星↔爱心)、点赞、勾选
- 🎞️ 品牌加载动画:Logo 多状态无缝循环
- 🛠️ 构建期产物:CLI 烘焙关键帧给设计交付、Lottie/SMIL/CSS 变量使用
下图是 10 对原创图标、每对 7 个时间点的真实形变接触表(由引擎直接生成):
交互式演示页(demo/index.html)实拍:
图标形变的本质难点是两条路径的点之间不存在天然一一对应。IconFlux 的流水线:
原始 d
└─ 解析归一化:全部命令 → 绝对坐标的 M/L/C/Z(椭圆弧按 SVG 规范展开)
└─ 细分扁平化:曲线按步长细分为稠密折线
└─ 弧长重采样:每个子路径 → N 个等弧长点(闭合/开放分别处理)
└─ 最优对应:穷举环形偏移 × 两种绕向,取总位移最小方案
└─ 多子路径配对:径向形状签名 + 质心距离的贪心最优匹配
└─ 对齐帧插值:逐点线性插值 + 缓动
└─ 重建输出:向心 Catmull-Rom 平滑曲线 / 折线
- 选型理由 1:弧长参数化比「按索引等分」更符合视觉匀速,避免长线段挤点、短线段飞点。
- 选型理由 2:环形穷举的复杂度仅 O(N²),N=96 时约 9k 次距离运算,毫秒级,却能让「箭头右转下」这类旋转自动发生。
- 选型理由 3:向心 Catmull-Rom(α=0.5)是唯一能在锐角五角星上不产生自交环的实用选择,且无需引入任何样条库。
- 零依赖哲学:图标库应当能被任何项目无痛引入,一个依赖都可能成为升级阻力,因此从解析器到 CLI 全部手写。
- v1.1:
viewBox差异自动归一、stroke-width 形变、子路径整体旋转插值选项 - v1.2:Web Worker 离线程烘焙、SMIL/CSS keyframes 代码导出器
- v1.3:React/Vue/Svelte 官方薄绑定(核心仍零依赖,绑定作为可选子路径导出)
- v1.4:与 Lucide/Tabler/Heroicons 图标数据包的适配示例与在线 Playground
- v2.0:填充图标(fill morph)与描边图标的混合形变
性能基准(大点数压力测试)、更多缓动曲线、图标数据集适配、无障碍(prefers-reduced-motion)策略、各框架示例仓库,欢迎在 Issue 区讨论。
IconFlux 属于工具库 / 组件类项目,无需安装可执行程序;以下是完整的集成与发布说明。
npm run build # 零依赖构建脚本,产出 dist/:
# iconflux.esm.js — ESM 单文件(打包器/现代浏览器)
# iconflux.cjs — CommonJS(require)
# iconflux.iife.js — 浏览器全局 window.IconFlux
# iconflux.d.ts — TypeScript 类型声明构建过程不依赖 esbuild/rollup/tsc,仅用 Node 标准库拼装,保证可复现。
| 环境 | 推荐产物 | 要点 |
|---|---|---|
| 原生 HTML / CDN | iconflux.iife.js |
一个 <script> 即用,支持 file:// 直接双击 |
| Vite/webpack/Rollup | iconflux.esm.js |
package.json 的 exports.import 已配置 Tree-shaking 友好 |
| Node CJS 脚本 | iconflux.cjs |
const { compileMorph } = require('iconflux') |
| TypeScript | 自动加载 iconflux.d.ts |
全部公共 API 均有类型 |
| 构建期离线烘焙 | bin/iconflux.js |
可接入 CI/Gulp/自定义流水线 |
- 遵循语义化版本(SemVer),当前 v1.0.0。
- 每个 Release 附带三份构建产物与
SHA256SUMS.txt校验文件。 - 校验下载产物:
sha256sum -c SHA256SUMS.txt- 浏览器:支持 Custom Elements v1 / ES2020 的现代浏览器(Chrome/Edge/Firefox/Safari 近年版本均可);引擎核心在更老浏览器中也可通过 IIFE 使用。
- Node:≥ 16(测试覆盖 18/20/22)。
- 图标坐标系:建议统一在 24×24
viewBox下使用;不同尺寸会按坐标直接插值,建议先归一化。
我们欢迎 Issue、PR 与图标示例!提交前请阅读完整的 CONTRIBUTING.md,核心约定:
- 提交信息遵循 Angular 规范:
feat:/fix:/docs:/test:/refactor:/chore:。 - 保持零运行时依赖:新增依赖默认不接受。
- 新功能必须附带
node --test测试,并同步更新三语文档与类型声明。 - Issue 请附上两段
d数据、复现步骤、浏览器/Node 版本。
行为准则:保持友善、就事论事,欢迎所有水平的贡献者。
本项目基于 MIT License 开源,可自由用于个人与商业项目,保留版权声明即可。
演示目录中的 18 枚示例图标路径数据同样为项目原创、随 MIT 协议发布。
如果这个项目帮你省下了手工对齐关键帧的时间,欢迎点一个 ⭐ 支持!
⬇ 下载最新 Release | 问题反馈 | 在线演示