关于 chart-animation
chart-animation 是使用 Remotion 制作数据动画图表和视频的技能,适用于图表创作者。它强调按帧确定动画数值、安排可读节奏,并支持模板复用于不同数据集。
主要功能
- 01按帧驱动的确定性动画
- 02条形图竞赛与排名过渡
- 03折线、面积图和计数器动画
- 04模板复用于多个数据集
- 05通过静帧和视频进行验证
适用场景
- 01根据时间序列数据制作条形图竞赛
- 02为多个数据集渲染相同图表设计
- 03制作计数器或折线揭示动画
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ iart-ai/ data-animation-skills --skill chart-animation安装后在 Claude Code 中输入/chart-animation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/bar-chart-race.mddata-pipeline.md详细介绍
数据视频
将数据集转化为随数据变化的图表:条形图竞赛、不断增长的折线、递增统计数字。关键在于逐帧将数字映射为像素,对数值(而不只是透明度)进行缓动,并合理安排数据节奏,让观众看得清楚。
适用场景
- 条形图竞赛/随时间变化的排名(核心用例)。
- 动画折线/面积图渐显、动画计数器和数字滚动效果。
- 将同一种图表设计用于多个数据集(模板 × CSV → N 个视频)。
避免 90% 错误的一条规则
所有数值都必须由当前帧驱动,绝不能依赖墙上时钟或库内部的动画循环。 视频帧是确定性渲染的;如果条形图高度来自 CSS 过渡或 D3/GSAP/Chart.js 动画,就会闪烁或不同步,因为渲染器和动画时钟并不一致。将显示数值计算为帧的纯函数。
import { useCurrentFrame, interpolate } from "remotion";
const frame = useCurrentFrame();
const value = interpolate(frame, [0, 60], [0, 1287], { extrapolateRight: "clamp" });
在 Remotion 中,禁用所有第三方图表动画(Chart.js 中设置 animation: false,不使用 D3 的 .transition()),并让 useCurrentFrame() 成为唯一时钟。D3 仍然非常适合用于比例尺和形状(scaleLinear、scaleBand、line()),但不要用它的计时器。
将数据映射为像素
图表由两个函数构成:数值比例尺和帧插值器。将它们分开处理。
| 层 | 工具 | 用途 |
|---|---|---|
| 数值比例尺 | scaleLinear / scaleBand | 数据单位 → px(高度、x 坐标) |
| 帧插值 | interpolate / spring | 帧 → 缓动进度 0→1 |
| 显示数值 | round + Intl.NumberFormat | 进度 → 人类可读的数字 |
import { scaleLinear } from "d3-scale";
const yScale = scaleLinear().domain([0, maxValue]).range([0, chartHeight]);
const barHeight = yScale(interpolate(frame, [0, 45], [0, datum.value], { extrapolateRight: "clamp" }));
缓动数值变化
像缓动运动一样缓动数值。对于递增计数或增长的条形图,easeOutCubic 看起来像“数值逐渐稳定下来”。对于排名变化,优先使用 spring,这样超过其他条形图时会显得更有分量。
const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
const t = easeOutCubic(interpolate(frame, [start, end], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }));
const shown = from + (to - from) * t;
除非是稳定的时间轴(时钟、年份计数器),否则不要对观众正在读取的数值做线性插值——标题数字的线性变化会显得很机械。
计数器/数字滚动效果
先对底层数值进行插值,再在渲染时格式化。必须做到两点:格式化前先取整(避免出现 1287.4013),并且固定数字框宽度,避免数字变化时布局跳动。
const n = Math.round(interpolate(frame, [0, 50], [0, 1287], { extrapolateRight: "clamp" }));
const label = new Intl.NumberFormat("en-US").format(n); // "1,287"
// CSS: font-variant-numeric: tabular-nums; line-height: 1; → no width jitter, no clipping
货币/百分比格式可使用 Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })。表格数字能让每个数字保持相同宽度,避免数字抖动。
条形图竞赛——排名过渡
这是标志性效果。真实数据集通常是稀疏的(按年/月记录);流畅的竞赛需要在数据行之间进行关键帧插值,并让条形图滑动到新的排名位置。y 坐标由经过插值的排名决定,因此超越效果是平滑滑动,而非突然跳跃。
// frame → continuous time between sparse rows, then rank each item by its interpolated value
const t = frame / fps; // seconds
const i = Math.min(Math.floor(t), rows.length - 2);
const f = easeInOut(t - i); // 0→1 within the current row pair
const vals = items.map((it) => ({
it,
v: rows[i][it] + (rows[i + 1][it] - rows[i][it]) * f, // interpolated value
}));
vals.sort((a, b) => b.v - a.v); // rank this frame
vals.forEach((d, rank) => { d.y = rank * (barH + gap); }); // y from interpolated rank
为每个项目使用稳定的键进行渲染(以便 React 在顺序变化时跟踪每个条形图),根据每帧的数值为 y 和 width 添加动画,并显示动态年份/日期标签。完整且可运行的 Remotion 组件请参见 references/bar-chart-race.md。
安排数据随时间变化的节奏
动画太快会让人看不清。应为每个数据事件安排时长,而不是只顾着把每一秒都做得精致。
| 节拍 | 时长 | 原因 |
|---|---|---|
| 开场/第一帧 | 停留 1–1.5s | 在动画开始前,让观众读懂坐标轴和单位 |
| 每行数据(竞赛) | 0.3–0.6s | 速度足以营造动感,同时又能看清领先者 |
| 强调时刻 | +0.5–1s 慢放 | 聚焦于交叉、纪录或拐点 |
| 最终状态 | 停留 2–3s | 留出时间让观众理解重点并截图 |
逐步展示数据——先展示一个系列,再展示下一个——而不是一次性展示全部数据;观众一次只能跟踪一个移动对象。
标签与注释
没有上下文的数字只是噪声。始终渲染:每个条形/数据点上始终可见的数值标签(随数值变化)、时间指示器(年份/日期),以及轴单位。只在关键时刻(交叉、峰值)添加说明标注——指出拐点,然后让标注淡出。
模板 × 数据 — 批量输出
代码驱动图表的优势:一个设计,多组数据。将数据集设为输入属性,而不是硬编码常量,然后为每个文件渲染一次。
// Remotion: data is a prop; same composition, different CSV → different video
export const Race = ({ data }) => { /* …reads `data`, hardcodes nothing… */ };
# render the same template for every dataset in /data
for f in data/*.json; do
name=$(basename "$f" .json)
npx remotion render Race "out/$name.mp4" --props="$f"
done
将颜色、字体和布局集中在单个主题对象中,让 50 个视频保持品牌一致,只改变数字。CSV→属性的解析、验证和完整批处理脚本,请参阅 references/data-pipeline.md。
输出检查清单
- 每个动画值都是
useCurrentFrame()的纯函数;不使用库计时器。 - 数字经过舍入和格式化(
Intl.NumberFormat),数字使用tabular-nums。 - 排名变化条带使用稳定的键;排名通过插值实现平滑过渡。
- 坐标轴/单位只标注一次;数值标签随数值变化而动画。
- 开场停留时间充足、每行节奏清晰易读、结尾停留 ≥2s。
- 数据集是输入属性 — 一个模板即可渲染文件夹中的每个 CSV。
交付与验证(渲染静帧 → MP4)
已打包的辅助脚本(
scripts/):使用scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png拼接静帧,然后使用scripts/probe-mp4.sh out.mp4 [WxH] [fps]验证编码结果。请参阅scripts/README.md。
Remotion 的帧是确定性的 — 每个条形高度、计数器数值和排名都是 useCurrentFrame() 的纯函数,因此可以在无头模式下渲染任意指定帧,无需定位帧的测试工具。交付物是包含准确数字的 MP4,因此检查静帧必不可少:一像素的布局错误可以接受,但数字错误不行。
输出约定:
- 一个已注册图表的 Remotion 项目(
<Composition>+ zodschema+defaultProps),所有动画均由帧驱动(不使用计时器/Date.now()/Math.random(),不使用 Chart.js/D3.transition()时钟)。 - 交付物 = 渲染后的
out/*.mp4(以及项目,以便用户使用新数据集重新渲染)。 - 时长取决于数据(N 行 × 每行帧数)?在
calculateMetadata中计算,不要手动填写。
验证流程 — 渲染静帧 → 检查 → 编码。 先渲染单帧(成本低,无需视频编码),确认数字和布局正确后,再进行一次编码。
# 1. Frame-exact stills at start / mid / end (PNG, headless, fast) — with the SHIPPED props
npx remotion still Race out/f-start.png --frame=0 --props='{"data":[...]}'
npx remotion still Race out/f-mid.png --frame=90 --props='{"data":[...]}'
npx remotion still Race out/f-end.png --frame=149 --props='{"data":[...]}' # last = durationInFrames - 1
# 2. Inspect each PNG — FIDELITY (axis labels, value labels, year/date, ranks, units all EXACT —
# round + tabular-nums working, no 1287.4013) AND artifacts (bar overflow, off-canvas label,
# clipped safe-area, missing font, wrong data binding / wrong column mapped).
# 3. Only after the stills check out, encode:
npx remotion render Race out/race.mp4 --props='{"data":[...]}'
- 使用
npx remotion compositions查看每个图表的durationInFrames/fps,并选择结束帧。 - 数据驱动/批量处理(核心场景):批量渲染全部 N 个文件之前,先通过静帧验证一个有代表性的数据集 — 一次发现高度比例或列映射错误,胜过在 50 个 MP4 中逐个排查。
- 轻松生成 README 演示 GIF:
npx remotion render Race out/demo.gif --codec=gif。
完成前:
npx remotion still在第 0 帧、中间帧和最后一帧均可正常渲染 — 无错误,无缺失字体/资源。- 每个数字都准确无误(已舍入,使用
Intl.NumberFormat和tabular-nums),且每帧都位于安全区域内。 - 仅由帧驱动 — 不使用
Date.now()/Math.random()/库计时器(确保在 CI 中保持确定性)。 - 已随项目交付的数据集属性能够正确渲染(不仅是
defaultProps)— 列映射正确,比例正确。 - 完整 MP4 已编码且可播放;(可选)为 README 渲染 GIF。
参考文件
references/bar-chart-race.md— 完整且可运行的 Remotion 条形图竞赛组件:稀疏行关键帧插值、逐帧排名、平滑过渡的 y 轴位置、动画数值标签,以及 D3 比例尺坐标轴。另附原生 Canvas 版本。references/data-pipeline.md— CSV/JSON → 类型化属性的解析与验证、主题对象模式、动画计数器/线条显现方案,以及用于生成 N 个视频的模板 × 数据批量渲染脚本。