Communitygithub.com

chartreel

Turn a CSV or user-provided data into accurate data-animation videos (bar chart race, line race, counter, share/waffle) exported as MP4, GIF, and cover PNG in various aspect ratios for social media and video platforms.

What is chartreel?

chartreel is a CLI tool that lets AI agents and developers create honest, data-driven animated chart videos from CSV files or user-provided numbers. It supports four templates: bar chart races (`race`), line chart races (`line`), big-number counters (`counter`), and share/waffle shifts (`share`). The tool enforces strict accuracy—every on-screen number comes directly from the CSV or linear interpolation between adjacent rows, never from memory or inference. Users can customize style presets (classic, cinematic, news, editorial, arcade, retro, glass, bold) for different social platforms like TikTok, YouTube Shorts, Bilibili, Xiaohongshu, and X. The output includes MP4, GIF, and a cover PNG, with options for aspect ratios (9:16, 16:9, 1:1, 4:5, 3:4). chartreel validates data integrity, checks for missing values, and allows AI agents to write data stories with hooks, key moments, takeaways, and source citations. It's ideal for automated data journalism, social media content creation, or educational visualizations where fidelity to source data is paramount.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Xkongai/chartreel/tree/HEAD/skills/chartreel

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

What does chartreel do?

Make short, honest data-animation videos with the chartreel CLI. You pick the chart, shape the data, write the story, render, and check the result. The renderer only ever shows values from the CSV or straight-line interpolations between two adjacent rows.

0. Tools

chartreel doctor          # checks ffmpeg, Chromium and fonts

If chartreel is missing:

pip install "git+https://github.com/Xkongai/chartreel"   # or: uv tool install git+https://github.com/Xkongai/chartreel
python -m playwright install chromium                      # skip if Chrome/Chromium is already installed
# ffmpeg: macOS `brew install ffmpeg` · Ubuntu `sudo apt install ffmpeg` · Windows `winget install Gyan.FFmpeg`
# Chinese/Japanese/Korean text on Linux: `sudo apt install fonts-noto-cjk fonts-noto-color-emoji`

1. Get real data — never invent numbers

  • Use the user's file when they give one. Keep it unchanged; reshape into a new CSV.
  • Otherwise fetch from a primary, citable source and save the raw response next to the CSV. See references/data-sources.md (World Bank API, Our World in Data, FRED, Eurostat, national statistics offices).
  • If the user types numbers in chat, use exactly those and cite them as "user-provided".
  • Never fill gaps from memory. Blank cells are allowed: interior gaps are interpolated and chartreel validate reports how many; leading/trailing blanks mean the series is absent.
  • Record the source name, indicator code or URL, and license; they go into --source.

2. Choose the template

StoryTemplateData shape
Who is #1 over time, overtakes ("GDP ranking 1990–2024")raceperiod × series (5–40 series)
How a few things grew or crossed ("China vs India population")lineperiod × series (2–8 series)
One jaw-dropping number, then "×N" comparisons ("from $191B to $18.7T")counterlabel,value[,note] (2–5 rows)
How a whole is split and shifts ("world population by region")shareperiod × parts (2–10 parts, non-negative)

3. Shape the CSV

year,China,India,United States        # wide: first column = period, one column per series
1990,361560229446,320979026420,5963144000000

year,name,value                       # long: also accepted, pivoted automatically
1990,China,361560229446

label,value,note                      # counter
1980年,191487500000,改革开放初期

Rules: periods ascending; plain numbers (commas, $, % are stripped); UTF-8 (BOM ok). For long ranges, keep yearly rows — more rows give smoother, more truthful motion.

4. Write the data story

  1. Hook (title): the question or the surprise, ≤ 2 short lines. "The world's largest economies, 1990–2024", "中印人口之争".
  2. Context (subtitle): units and scope — "GDP, current US$".
  3. Key moments (--note "PERIOD: text"): 1–3 events. Each must be visible in the data at that period (check the CSV before writing "X passes Y").
  4. Takeaway (--takeaway): one sentence computed from the CSV. Do the arithmetic in code, e.g. python -c "print(18729668435848/361560229446)" → 51.8 → "China's GDP grew 52× in 34 years". Round honestly.
  5. Source (--source): always. Example: World Bank WDI (NY.GDP.MKTP.CD), CC BY 4.0.

Put it all in a JSON config so the render is reproducible (references/options.md lists every key):

{
  "template": "race", "theme": "dark", "aspect": "9:16", "duration": 15,
  "title": "The world's largest economies, 1990–2024", "subtitle": "GDP, current US$",
  "source": "World Bank WDI (NY.GDP.MKTP.CD), CC BY 4.0",
  "takeaway": "China's GDP grew 52× in 34 years", "prefix": "$", "top": 10,
  "notes": ["2010: China passes Japan"],
  "series": {"China": {"emoji": "🇨🇳", "color": "#FF6B6B"}}
}

Chinese videos: add "locale": "zh" (numbers as 万/亿/万亿) and write title/notes in Chinese.

4b. Pick a style preset (optional, recommended for social video)

--style bundles a theme, a hook card, a year counter, the #1 decoration and effects. Every preset keeps the numbers exact: the hook only covers the first ~1.5 s, before the data starts moving, and nothing is drawn over the takeaway or (for races) between bars.

--styleLookGood for
classic (default)clean, no hookdocs, slides, X
cinematicgold-on-teal, letterbox hook, vignette, rolling year, crown on #1, punch-inYouTube Shorts, Bilibili
newsTV straps: "DATA" hook strap, rank numbers, red year badge, source strapserious topics, Weibo/X
editorialpaper, typewriter hook, grey bars + --highlight "A,B", big serif yearXiaohongshu, newsletters
arcadeneon, confetti + punch when a bar reaches the top 3, rank-up ▲, speed streaksDouyin/TikTok, gaming
retroVHS: scanlines, chromatic text, PLAY stamp, typewriter hooknostalgic topics
glassdrifting colour blobs, frosted chart panel, top progress bartech/product topics
boldDouyin big-text: giant highlighted hook words, huge year, rank numbersDouyin/Kuaishou

Story options that go with presets:

  • --hook "Who has the world's biggest economy?": the first-second question (defaults to the title; --no-hook turns it off). It must be answerable from the data.
  • --cta "Follow for more data stories": a small line under the takeaway.
  • Fine-tune: --fx bg,vignette,letterbox,scanlines,punch,confetti,trails,arrows,glass replaces the preset's effects, --no-fx confetti drops one; --year-style watermark|roll|row|badge, --progress timeline|top|both|none, --highlight leader|"A,B", --leader/--no-leader, --ranks, --safe-zone/--no-safe-zone (presets keep clear of the Douyin/Shorts buttons and caption area). chartreel styles lists everything.
  • --audio music.mp3 [--audio-fade 1.0] puts a track the user owns or licensed under the MP4 (trimmed, faded in/out). Never download copyrighted music; chartreel ships none.

A config file's "theme" is ignored when you pass --style on the command line (pass --theme to override).

5. Validate, render, check

chartreel validate data.csv -c story.json          # schema + option check, clear row/column errors
chartreel render   data.csv -c story.json -o out/  # out/data.mp4, out/data.gif, out/data-cover.png
chartreel preview  data.csv -c story.json -o out/  # optional: self-contained HTML player to scrub

Platform presets: Douyin/TikTok/Shorts/Reels -a 9:16 -d 15 (10–30 s) · Xiaohongshu -a 3:4 or 9:16 · Bilibili/YouTube/X -a 16:9 · X/Instagram feed -a 1:1 or 4:5. Pace: about 0.3–0.6 s per period for a race. Quick drafts: --size 540 --fps 15. --jobs N sets parallel workers. A 12 s 1080×1920 race renders in about 10–30 s depending on CPU.

Then look at the output before you hand it over:

ffmpeg -v error -i out/data.mp4 -vf "fps=1,scale=360:-1,tile=4x3" -frames:v 1 out/contact.png

Open the cover and the contact sheet. Check: title not cut, labels readable, no CJK tofu boxes (□), the takeaway matches the numbers, the source is visible, the hook (first second) reads in one glance. Fix and re-render if needed.

6. Hand over

Report the MP4, GIF and cover paths, the source and license, and how the takeaway was computed. Say plainly if any cells were interpolated (validate prints it). Do not claim a trend the data does not show.

Accuracy rules (non-negotiable)

  • On-screen values = CSV values at each period, linear interpolation in between. The counter template counts up to each value and then holds the exact number; say so if asked.
  • Derived numbers (ratios, growth, "passes") must be computed from the CSV, not recalled.
  • Never mix units or currencies in one chart; never compare nominal and real values silently.
  • Always show the source. Keep the raw download so the user can audit it.

Related Skills