
chart-animation
This skill should be used when the user asks to "make a bar chart race", "turn a CSV into a video", "build an animated data visualization", "create an animated statistics video", "animate a chart/graph", "make a number counter/ticker", "animate a ranking over time", or "batch-render one chart template across many datasets". Covers data-driven keyframing, value interpolation, rank transitions, counters, pacing, annotation, and template×data batch output.
- Installs
- 1.3K
- Last 24h
- +36
- Trending rank
- #4075
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/iart-ai/data-animation-skills --skill chart-animation- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads chart-animation automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Data Video
Turn a dataset into a chart that moves with intent: a bar chart race, a growing line, a count-up stat. The craft is mapping numbers to pixels every frame, easing the value (not just the opacity), and pacing the data so a viewer can actually read it.
When to use
- Bar chart race / ranking-over-time (the headline use case).
- Animated line/area reveal, animated counters and number tickers.
- One chart design rendered across many datasets (template × CSV → N videos).
The one rule that prevents 90% of bugs
Drive every value from the current frame — never from wall-clock time or a library's internal animation loop. A video frame is rendered deterministically; if a bar's height comes from a CSS transition or a D3/GSAP/Chart.js animation, it flickers or desyncs because the renderer and the animation clock disagree. Compute the displayed value as a pure function of frame.
import { useCurrentFrame, interpolate } from "remotion";
const frame = useCurrentFrame();
const value = interpolate(frame, [0, 60], [0, 1287], { extrapolateRight: "clamp" });
In Remotion, disable all third-party chart animations (animation: false in Chart.js, no D3 .transition()) and let useCurrentFrame() be the only clock. D3 is still great for scales and shapes (scaleLinear, scaleBand, line()) — just not its timers.
Map data → pixels
A chart is two functions: a value scale and a frame interpolator. Keep them separate.
| Layer | Tool | Job |
|---|---|---|
| Value scale | scaleLinear / scaleBand | data units → px (height, x-position) |
| Frame interpolation | interpolate / spring | frame → eased progress 0→1 |
| Display value | round + Intl.NumberFormat | progress → the number a human reads |
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" }));
Easing value changes
Ease the value the same way you'd ease motion. For a count-up or a bar growing in, easeOutCubic reads as "settling on a number." For rank changes, prefer spring so a bar that overtakes another has a little weight.
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;
Never linearly interpolate a value the viewer is reading unless it's a steady time axis (a clock, a year counter) — linear motion on a headline number feels robotic.
Counters / number tickers
Interpolate the underlying number, then format on render. Two musts: round before formatting (no 1287.4013), and fix the digit box so the layout doesn't jump as digits change.
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
For currency/percent use Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }). Tabular figures keep each digit the same width so the number doesn't wiggle.
Bar chart race — rank transitions
The signature move. Real datasets are sparse (yearly/monthly rows); a smooth race needs interpolated keyframes between data rows plus bars that slide to new ranks. The y-position comes from a rank that is itself interpolated, so an overtake animates as a glide, not a jump.
// 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
Render with stable keys per item (so React tracks each bar across reorders), animate y and width off the per-frame value, and show a moving year/date label. See references/bar-chart-race.md for a complete, runnable Remotion component.
Pacing data over time
Animation that's too fast is unreadable. Budget time per data event, not per second of polish.
| Beat | Budget | Why |
|---|---|---|
| Intro / first frame | hold 1–1.5s | let the viewer read axes + units before motion |
| Per data row (race) | 0.3–0.6s | fast enough to feel alive, slow enough to track the leader |
| A highlighted moment | +0.5–1s slow-down | dwell on the crossover / record / inflection |
| Final state | hold 2–3s | the takeaway needs to land and be screenshot-able |
Reveal progressively — one series, then the next — instead of all data at once; viewers can only track one moving thing at a time.
Labeling & annotation
Numbers without context are noise. Always render: an always-visible value label on each bar/point (it animates with the value), a time indicator (year/date), and axis units once. Add a callout only at the moment it matters (a crossover, a peak) — annotate the inflection, then let it fade.
Template × data — batch output
The payoff of code-driven charts: one design, many datasets. Make the dataset an input prop, never a hardcoded constant, then render once per file.
// 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
Keep colors/fonts/layout in a single theme object so 50 videos stay brand-consistent and only the numbers change. See references/data-pipeline.md for CSV→props parsing, validation, and the full batch script.
Output checklist
- Every animated value is a pure function of
useCurrentFrame(); no library timers. - Numbers are rounded and formatted (
Intl.NumberFormat), digits usetabular-nums. - Race bars carry stable keys; rank changes glide via interpolated rank.
- Axes/units labeled once; value labels animate with their value.
- Intro hold, readable per-row pace, final hold ≥2s.
- Dataset is an input prop — one template renders every CSV in the folder.
Deliver & verify (rendered stills → MP4)
Packaged helper (
scripts/): tile your stills withscripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png, then assert the encode withscripts/probe-mp4.sh out.mp4 [WxH] [fps]. Seescripts/README.md.
Remotion is frame-deterministic — every bar height, counter value, and rank is a pure function of useCurrentFrame(), so you can render any exact frame headlessly with no seek harness. The deliverable is an MP4 carrying exact numbers, so still-inspection is non-negotiable here: a one-pixel layout bug is forgivable, a wrong digit is not.
Output contract:
- A Remotion project with the chart registered (
<Composition>+ zodschema+defaultProps), all motion frame-driven (no timers /Date.now()/Math.random(), no Chart.js/D3.transition()clocks). - Deliverable = the rendered
out/*.mp4(plus the project, so the user can re-render with new datasets). - Data-dependent duration (N rows × frames/row)? compute it in
calculateMetadata, not by hand.
Verify loop — render stills → inspect → encode. Render single frames first (cheap, no video encode), then encode only once the numbers and layout are right.
# 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":[...]}'
- Use
npx remotion compositionsto read each chart'sdurationInFrames/fpsand pick the end frame. - Data-driven / batch (the headline case): verify ONE representative dataset via stills before batch-rendering all N files — a height-scale or column-mapping bug caught once beats finding it in 50 MP4s.
- README demo GIF for free:
npx remotion render Race out/demo.gif --codec=gif.
Before you finish:
npx remotion stillrenders cleanly at frame 0, mid, and last — no errors, no missing fonts/assets.- Every number is exact (rounded,
Intl.NumberFormat,tabular-nums) and inside the safe area at each frame. - Frame-driven only — no
Date.now()/Math.random()/ library timers (determinism holds in CI). - The shipped dataset props render correctly (not just
defaultProps) — right column mapped, right scale. - Full MP4 encoded and plays; (optional) GIF rendered for the README.
Reference files
references/bar-chart-race.md— a complete runnable Remotion bar-chart-race component: sparse-row keyframe interpolation, per-frame ranking, gliding y-positions, animated value labels, and a D3-scale axis. Plus a vanilla canvas variant.references/data-pipeline.md— CSV/JSON → typed props parsing and validation, the theme object pattern, animated counters/line-reveal recipes, and the template×data batch render script for N videos.
FAQ
What does the chart-animation skill do?
This skill should be used when the user asks to "make a bar chart race", "turn a CSV into a video", "build an animated data visualization", "create an animated statistics video", "animate a chart/graph", "make a number counter/ticker", "animate a ranking over time", or "batch-render one chart template across many datasets". Covers data-driven keyframing, value interpolation, rank transitions, counters, pacing, annotation, and template×data batch output.
How do I install chart-animation?
Run npx skills add https://github.com/iart-ai/data-animation-skills --skill chart-animation in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/chart-animation/ (personal) or .claude/skills/chart-animation/ (project).
Which AI agents can use chart-animation?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is chart-animation safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains chart-animation?
It is published by iart-ai in iart-ai/data-animation-skills. It has 1,323 recorded installs.
More from iart-ai/data-animation-skills
animated-infographic
iart-ai/data-animation-skills
This skill should be used when the user asks to "make an animated infographic", "create an infographic video", "build an infographic animation", "animate an explainer infographic", "do a sequenced reveal of icons and stats", "animate icons with key numbers and connectors", or "lay out a designed infographic that animates in sequence". Covers infographic layout & visual hierarchy, staggered element reveals, animating icons/pictograms, key-number counters, connectors/flow, and section pacing. For heavy charting (bar chart race, charts from a CSV) use the chart-animation skill instead.
presentation-video
iart-ai/data-animation-skills
This skill should be used when the user asks to "make an animated presentation", "turn a pitch deck into a video", "convert slides/a deck to video", "make a presentation video", "build a deck video", "narrate a slide deck as a video", or "auto-advance slides synced to a voiceover". Covers rebuilding slides as motion graphics with staggered build reveals, slide-to-slide transitions, and timing locked to per-slide narration.
Popular frontend & design skills
setup-matt-pocock-skills
mattpocock/skills
Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.
frontend-design
anthropics/skills
Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.
hyperframes-animation
heygen-com/hyperframes
All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.
prototype
mattpocock/skills
Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.
hyperframes-core
heygen-com/hyperframes
The HyperFrames composition contract — build one renderable project. Use for composition structure, the data- timing attributes, class="clip", tracks, sub-compositions, variables, framework-owned media playback, deterministic-render rules, and validation. Read before writing composition HTML.
vercel-react-best-practices
vercel-labs/agent-skills
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.