Communitygithub.com

li-code-animation

用代码做初中数学知识短视频(函数图像、几何作图、公式推导、概念辨析),16:9 MP4,画面由 HTML/CSS/SVG 写死坐标、GSAP 编排动作、无头 Chromium 逐帧截图、FFmpeg 编码,默认无旁白只画面加字幕、默认深夜光轨深色风、六镜结构、交付前必过六道自检。当用户要做数学微课/知识动画/讲解短片,要改已有代码动画工程的某一镜或某一秒,要换主题重做同款,要复渲、要加码率、要打工程包时使用。不用于数字人口播、实拍剪辑、纯配音课、只要一张图或一份课件。

li-code-animation 是什么?

li-code-animation is a Claude Code agent skill that 用代码做初中数学知识短视频(函数图像、几何作图、公式推导、概念辨析),16:9 MP4,画面由 HTML/CSS/SVG 写死坐标、GSAP 编排动作、无头 Chromium 逐帧截图、FFmpeg 编码,默认无旁白只画面加字幕、默认深夜光轨深色风、六镜结构、交付前必过六道自检。当用户要做数学微课/知识动画/讲解短片,要改已有代码动画工程的某一镜或某一秒,要换主题重做同款,要复渲、要加码率、要打工程包时使用。不用于数字人口播、实拍剪辑、纯配音课、只要一张图或一份课件。.

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/MathLiLiLi/li-code-animation/tree/main

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Li's Code Animation Skill

One-Liner: Turn a "hard to explain" point from a math lesson into a 90-second code-animated video that students can pause and rewatch, with formulas perfectly aligned every time.

The core tech stack is fixed to four steps, with no AI-generated visuals: HTML/CSS/SVG for scenes → GSAP for timelines → Headless Chromium for frame-by-frame capture → FFmpeg for H.264 MP4 encoding. HyperFrames only handles the project contract and scheduling; it does not generate a single frame — it's a printing press; you have to write the manuscript yourself.

Prerequisites (Check Before Starting; Don't Proceed if Missing)

Run npx -y [email protected] doctor in the project root. Proceed only if all four items below are green.

SoftwareVersionPurposeWhat Happens if MissingHow to Fix (Linux/Cloud PC)
Node.js≥22Run CLI and scriptsThe whole pipeline failsnvm install 22
FFmpeg and ffprobe4.xEncoding, frame extraction, parameter checksIf only ffmpeg is present without ffprobe, both export and checks will failapt install ffmpeg (includes ffprobe). Do not use third-party package managers, as they often install only half.
Chromium / Chrome (headless)Recent 2 yearsFrame captureNo frames can be generatedapt install chromium. On cloud PCs, it's usually at /usr/local/bin/chromium.
GSAP3.x Local fileTimelines and tweensUsing CDN will silently produce a black screen with no errorsCopy assets/gsap.min.js from this skill into your project's assets/ folder.

The self-check also requires three optional tools (self-check is less thorough without them, but video production is unaffected):

ToolPurposeWhat to Do if Missing
playwright-coreAutomatic screenshot of 6 scenesnpm i playwright-core
ffmpeg's scale filterScreenshot brightness diagnosisAutomatically degrades to DOM diagnosis only
zipPackage source codeUse tar.gz instead and mention it in the delivery notes

Five Pitfalls to Avoid

  1. Both ffmpeg and ffprobe must be present; many systems only install the former.
  2. Do not mix installs from winget or portable packages; PATH versions may conflict.
  3. GSAP must always be a local file, never CDN; a broken CDN causes a silent black screen for the entire video.
  4. The browser runs in software rendering mode (seeing BeginFrame did not run in logs is normal); no need to configure your GPU.
  5. The default rendering bitrate is about 500 kbps; for 1080p, a normal range is 3–8 Mbps. Without explicitly specifying the bitrate, dark fine lines will blur. See Section 6.

Route Selection: Default to A; Use B Only for Narration or Complex Scenes

A Track · Pure Graphics (Default)B Track · Narration/Complex Scenes
Suitable ForFunction graphs, geometry, formula derivations, concept analysisNeeds narration, hands/characters/maps/3D, background music
ScenesThis skill's six-scene HTML+SVG, hardcoded coordinatesCalls the code2video skill: film.json script + component library
AudioNo narration by default; captions are on-screen text. User adds BGM later.TTS narration + music + loudness alignment
Commandnpx [email protected] rendernode $C/tools/make.mjs <movie directory> film
When to SwitchUser explicitly asks for "voiceover/audio/narration" or needs human actions, maps, charactersUser only wants visuals and text

The B track's capabilities are inherited, not duplicated: the code2video engine/kits/presets are not copied into this skill (about 20MB, and would cause version drift after updates). Instead, it calls the already installed copy. Bridging details are in references/two-tracks.md. The storyboard script is shared by both tracks; an A track storyboard can be converted to a B track film.json (via scripts/story-to-filmjson.mjs).

Workflow Upon Receiving a Task

0 · Environment Self-Check

npx -y [email protected] doctor
ls assets/gsap.min.js

If anything is missing, provide the installation command and pause, waiting for the user to install it. Do not pretend things will work.

1 · Clarify and Fill in Details (Users Usually Give Only One Sentence)

Teachers often start with just twenty words: "Use code to make a video about imaginary numbers: does x exist such that x² = -4?" You must fill in the remaining specifications. Ask only four questions, each with suggested options:

QuestionWhy It's EssentialSuggested Default
Where to stop the explanation?Determines the mathematical conclusion; the only part that can be "wrong."Stop at the step before a new concept is needed.
Duration and segments?Determines how many scenes to cut.90 seconds, six scenes.
Who decides the storyboard?The user might already have a sequence.You write it; show it to them first.
Target audience grade?Determines depth and vocabulary.Based on the topic's school level.

Don't ask about the style: Default is the dark "light trail" theme (user already chose it). Only ask if the user specifies a white background.

When the user says "you decide," summarize the defaults in one sentence ("Making it in dark style, 90 seconds, six scenes, stopping at this step. Tell me if it's wrong"), and wait for their nod.

2 · Create a Six-Scene Storyboard; Wait for User Approval

Following the structure in Section 3, create a storyboard table: scene number, duration, visual elements, caption text, and the question each scene solves. Provide only the storyboard; do not write code. Wait for the user to say "OK" before proceeding to step 3. This step has the lowest rework cost; always wait for confirmation.

3 · Create the Project

node <skill directory>/scripts/init-project.mjs --name <project folder> --title "<video title>" --scenes 6

The script copies the six-scene skeleton and index.html from assets/project-template/, copies GSAP, and generates a skeleton verify-seeks.json. Do not manually run npx hyperframes init; the template is already compliant.

The template contains the complete six-scene example "The Geometric Meaning of k in Inverse Proportion" (dark version). It can be rendered directly to produce the exact same video; to create a new video, keep its coordinate system, timeline, and styles; only change the text and k-value. This is much faster than writing from scratch.

4 · Write Each Scene's Visuals

  • Each of the six scenes gets its own file: compositions/scene-1-hook.html … scene-6-outro.html; index.html is only for mounting. Do not put all content into one giant HTML file.
  • All coordinates are hardcoded, not dependent on flow layout: first define the origin and scale (e.g., OX=460, OY=620, S=96, 1 unit = 96 pixels); all points are calculated from these.
  • Curves are generated by sampling the function to create a path; do not approximate by hand.
  • For formulas and colors, refer to references/visuals.md; for mathematical presentation, see references/math-rules.md.

5 · Lint

npx -y [email protected] lint

Must have 0 errors and 0 warnings. Fix any errors and rerun.

6 · Screenshot Each Scene (Self-Checks 1–3)

node <skill directory>/scripts/verify.mjs --browser=/usr/local/bin/chromium

For each scene, seek to the second with the most information, capture a screenshot to verify-shots/, and diagnose whether GSAP loaded, timelines are registered, elements overflow, and if there are any JavaScript errors. Review each screenshot yourself; don't just run the script and move on.

7 · Frame Extraction Verification (Self-Check 4)

Extract 16 frames from the previous video version and create a mosaic to confirm that each key element actually appears at its claimed time. See references/qa.md for the procedure.

8 · Render the Full Video (Must Explicitly Set Bitrate)

npx -y [email protected] render --output <name>.mp4 --quality delivery --video-bitrate 3M

--video-bitrate and --crf are mutually exclusive; use one or the other. A normal 90-second 1080p video is 15–25 MB; anything under 10 MB means it's over-compressed.

9 · Verify Final Video Parameters (Self-Check 6)

node <skill directory>/scripts/inspect-video.mjs <name>.mp4 --expect-duration 90

Checks resolution, frame rate, total frames, duration, bitrate, and file size. If any check fails, return to step 8 and re-render.

10 · Delivery

zip -qr <name>-project.zip <project folder> \
  -x "<project folder>/node_modules/*" -x "<project folder>/verify-shots/*" \
  -x "<project folder>/.verify-tmp/*" -x "<project folder>/*.mp4"

Deliver three things: the final mp4 file, the pure source code archive (excluding mp4), and three notes (what the video is about, what decisions were made for the user, and which parts the teacher should review). Simply sending the file is not enough.

3. Six-Scene Skeleton (90-Second Baseline)

The duration can be scaled on request, but the structure and order must not change: Hook first, then push forward, then generalize, then derive conclusion, then correct mistakes, finally wrap up.

#Scene IDStart/DurationScene's TaskMust Include
1s1-hook0 / 10Present a real problem that makes the viewer want to continue.Main graphic frozen + three-line question on the right + bottom caption.
2s2-q110 / 20Calculate the key quantity in the simplest case.Coordinate axes, curve, moving point, rectangle/triangle, line-by-line captions.
3s3-other30 / 18Verify the same conclusion in a different quadrant.Four curves lit sequentially + conclusion card.
4s4-triangle48 / 15Break the conclusion in half, providing the major premise.Geometric block + right-angle marker + three-line deduction.
5s5-table63 / 12Correct the most common error.Thin-line table + error card (with strikethrough) + correct card + key phrase.
6s6-outro75 / 15Restate the conclusion on a different coordinate scale, wrap up.Reduced version of the same diagram + centered three lines + pulsing emphasis.

index.html mounting points: body background must be hardcoded (dark #050a14), the six scenes' track-index 0–5 are continuous, start/duration align with the table above, and the full video's title is "Topic|Icon Name."

4. Math Presentation Quick Reference (Getting it Wrong is a Teaching Error)

Hard constraints; each one must appear in the visuals. The full list and counterexamples are in references/math-rules.md.

  1. Use symbols only, no specific numbers. For inverse proportion, go only up to |k| and ½|k|; the number "4" should never appear in the video. Apply the same logic to general conclusions.
  2. Fractions must use a horizontal fraction bar, never a slash or a/b notation.
  3. Triangle symbol is a subscript of S, not on the same line.
  4. Use "common points" instead of "intersection points."
  5. Fixed wording for negative cases: "When k<0, the same holds for quadrants II and IV."
  6. Use a single term for the same concept throughout the entire video; don't switch wording. Caption language should match the textbook.
  7. Before a conclusion appears, the visual evidence must already be drawn; never show the conclusion first and add the evidence later.

5. Visual Quick Reference (Default Dark Light-Trail Theme)

Full color values and implementation are in references/visuals.md. Remember three ironclad rules for dark backgrounds; everything else can be adjusted:

  1. Reduce area fills to 18% and add an outline — a 40% fill on a dark background becomes a blurry fog.
  2. Use "amber outline + very pale blue fill" for triangles/geometric blocks — gold solid fill on a dark blue background turns into a dirty olive color.
  3. Don't use background colors for tables; use thin lines for separation — a white-background table will look like three continuous rows when copied over.

Increase font size by 4 points compared to the white-background version. The top-left corner icon is fixed as Vibe Knowledge Awards | Scene Subtitle, 26px, letter-spacing 5px, left 84 / top 70.

**Font Ironclad Rule: Three font roles — Noto Sans CJK SC for Chinese, Inter for Latin labels and numbers, TeX Gyre Termes serif italic for math symbols (same family as Times, matches textbook letter shapes). @font-face must be written inside the <template>'s <style> (putting it in <head> will cause it to be discarded by the frame capture harness, and the font will silently not load). Details and four common pitfalls are in references/visuals.md, Section 0.

6. Rendering and Bitrate

ParameterValueDescription
--qualitydeliveryHigh-quality preset; the default preset will reduce bitrate.
--video-bitrate3MMust be explicitly set; mutually exclusive with --crf.
--resolutionDefault landscape (1920×1080)Use 4K only if explicitly requested.
--resumeResume after interruptionAlready rendered frames are not re-created.

Criteria: 90 seconds → file size 15–25MB, bitrate 1.5Mbps or higher, 2700 frames, duration 90.000000s. If numbers don't match, re-render; do not deliver.

When Clarity is Insufficient (Tested: --video-bitrate Doesn't Work)

Tested 2026-11: Using --video-bitrate 30M still results in 1.8Mbps; --quality delivery does the same. In other words, the built-in encoder's bitrate parameters are largely ignored. For delivery-grade clarity, you must take over the encoding yourself. If the user says it's "blurry," follow this path instead of repeatedly adjusting --video-bitrate:

# 1) Render frames only, no encoding (2700 frames / ~2.4GB / ~16 minutes)
npx -y [email protected] render --format png-sequence --output pngseq

# 2) Encode yourself. For static content and fine text, use CBR, not CRF (CRF only gives ~0.5Mbps, which will blur after platform re-encoding).
ffmpeg -v error -framerate 30 -i pngseq/frame_%06d.png \
  -c:v libx264 -b:v 4M -minrate 4M -maxrate 4M -bufsize 8M \
  -preset slow -tune animation \
  -x264-params "nal-hrd=cbr:aq-mode=3:chroma-qp-offset=-2" \
  -pix_fmt yuv420p -movflags +faststart -y out.mp4

chroma-qp-offset=-2 is for colored fine lines: cyan and amber text can lose color at the edges with 4:2:0 chroma subsampling; this parameter gives chroma a little more bitrate than luma.

Encoding takes about 2 minutes, yielding 90s / 43MB / 4Mbps. The 40MB mark is the sweet spot for "playable in class and still clear after platform re-encoding"; files under 10MB will look soft on mobile devices. For platforms (WeChat Video / Douyin), create a master version with -b:v 8M (about 85MB) so that it retains detail after platform re-encoding.

Don't rely on 4K supersampling: with software rendering, 2700 frames can take over an hour (tested: only 8% done after 20 minutes), which is unsustainable for a single project's timeline.

After encoding, you must zoom in to 1:1 on a single frame (using crop=760:300) to check for blockiness or ringing on text edges; a full-thumbnail view won't show the blur.

Sound Effects (Point Effects, Not BGM)

If the user says "add some audio" or "it's too quiet" but doesn't ask for BGM, only add point sound effects: each action on screen triggers a sound once, then goes silent. Background music in a math explainer video can reduce the sense of reflection and might also cover the teacher's own narration.

# 1) Write a timeline of action points (in absolute seconds). See assets/sfx-events.example.json for a sample.
python3 <skill directory>/scripts/make-sfx.py events.json -o sfx.wav --duration 90

# 2) Copy the video stream; only mix the audio track (don't change a single pixel of the video).
ffmpeg -v error -i in.mp4 -i sfx.wav -c:v copy -c:a aac -b:a 128k -shortest \
  -movflags +faststart -y out.mp4

Six types of sound effects, each for one purpose: brush for curve/line growth, slide for a moving point sliding uniformly, tick for a line of text appearing, ding for cards/titles/questions, thump for the most critical quantity, chime for ✓/key phrases/end credits.

Three rules:

  1. Don't sound for every line of text — only for "visual actions." About 30 points for a 90-second video is enough; more becomes noisy.
  2. Keep the peak below -16dBFS. tick at around -29dB, thump/ding at around -24dB. At this level, it's "audible but not distracting."
  3. After mixing, randomly check with ffmpeg -ss <t> -t 0.6 -af volumedetect: at sound effect points, it should be -24 to -30dB; in silent sections, it should be -91dB (true silence). If any sound effect point is above -18dB, reduce the volume.

7. Six Self-Checks (Must Pass All Before Delivery)

#What to CheckCommandPass Criteria
1Structural compliancenpx -y [email protected] lint0/0
2All six scenes have visualsscripts/verify.mjsAll six scenes produce images; no black screens, no JS errors.
3No element overflowSame as above; review diagnostic reportNo overflow entries; captions at least 80px from bottom.
4Timing is correctFrame extraction mosaic (see qa.md)Each segment's elements appear at their claimed time; no empty segments.
5Correct mathematical presentationCompare captions with math-rules.md scene by sceneAll seven rules pass.
6Final video parametersscripts/inspect-video.mjsAll checks (resolution, frames, duration, bitrate, size) pass.

Checks 1, 2, 3, 4, and 6 are machine-judged and human-reviewed; Check 5 can only be done by a human — it's the only thing that can prevent a teaching error.

8. Rules for Making Changes

User feedback must be received as a "three-part request": which scene / which second / what to change to. For vague requests like "this doesn't seem right," ask for clarification; don't redo the entire section.

After changes, rerun the relevant checks: changes to coordinates or font size → 1+2+3; changes to text → 5; changes to multiple scenes → all six checks.

It's faster to batch several changes together than to make many small, repeated edits, but major cross-scene changes require a new storyboard for confirmation.

See references/revisions.md for real revision logs (ten examples).

9. Prohibited Actions

  • Missing assets/gsap.min.js or using CDN instead.
  • Using scaleX/scaleY + transformOrigin for SVG line growth (only grows from one end).
  • Using onUpdate to drive SVG properties (onUpdate is not triggered during seek, leading to wrong screenshots).
  • Tweening properties that trigger reflow, such as letterSpacing or width.
  • Calling getTotalLength() when d="" (must first provide a sentinel d).
  • Rendering without specifying bitrate.
  • Putting all content into a single HTML file.
  • Using a slash to represent fractions in formulas.
  • Delivering only the mp4 without explaining what was changed.
  • Including <sup> inside SVG <text> (HTML tags inside SVG will misalign the entire text; use ² for superscripts).
  • Applying a scale pulse on a full-width (1920) container (a 4% increase will hit the border; Check 3 will flag an overflow. Instead, apply the scale to an inline-block container inside).
  • Placing an absolutely positioned strikethrough as a sibling of the target text (it will span across the entire column; place it inside a relative-positioned container within the text itself).
  • Using repeat: -1 for a looping pulse (the lint will throw an error if a sub-composition has no data-duration; instead, use a finite number of repetitions).
  • Leaving any temporary .html file in the project root (the lint will report "can only have one index.html").
  • When drawing a curve with two paths (a bright line + a glow), only setting dasharray/dashoffset on the bright line (the glow will appear entirely before it should, looking like "a dark shadow before the line is drawn"; both must be set and tweened at the same time).
  • Using --video-bitrate to achieve clarity (tested and ineffective; see Section 6).
  • Encoding only with CRF without checking the file size (CRF for static content only gives ~0.5Mbps, which will blur after platform re-encoding).
  • Using the system default font for Latin letters and numbers (system-ui in headless Chromium renders as DejaVu Sans, which is dull for letters and numbers; always use "Inter", sans-serif).
  • Writing Chinese font names in font-family (e.g., "Noto Sans SC"; if not installed, the linter will output font_family_without_font_face).
  • Drawing coordinate axes as just two straight lines without adding directional arrows at the endpoints (textbook standard: x to the right, y upward, each with a solid arrow; see the "Coordinate Axes" section in references/visuals.md).

9.5. Adding Fonts to an Old Project

For an old project (where the font is still system-ui), you don't need to rebuild; run one command to upgrade to the three-font system:

node scripts/apply-fonts.mjs --project <project folder>

It does five things: copies fonts to assets/fonts/, merges @font-face into the <template>'s <style> (anything in <head> will be discarded by the frame capture harness), locks .row/.cap/.tag containers to Inter, wraps each bare variable x/y/k/S in the text body with <i> (pure CSS selectors can't target bare text, so this is the most common reason "the font changed but nothing looks different"), and changes SVG's font-family to 'Termes', serif and italicizes x/y/k. Math symbols uniformly get calc(1em + 2px) to compensate for the visual shrinkage of serif vs. sans-serif. It is idempotent; running it multiple times won't duplicate anything.

Proceed as usual: lint → verify → render. The video must be re-rendered; these font changes won't affect the old output file.

10. Reference Files

FileWhen to Read
references/pipeline.mdFirst project, or when explaining the four-step pipeline to someone.
references/math-rules.mdBefore writing any formula or conclusion.
references/visuals.mdWhen defining colors, font sizes, cards, and formula layouts.
references/prompts.mdFor clarifying questions, writing storyboards, or teaching someone how to start.
references/revisions.mdWhen the user gives feedback, or to explain to a curriculum group "what it's like to revise something ten times."
references/qa.mdFor every self-check round, and to determine if a video is ready for delivery.
references/two-tracks.mdWhen narration/music/hands/maps/characters are needed; switching to B track.
assets/project-template/Copied by init-project.mjs when creating a project; do not edit manually.
assets/gsap.min.jsCopied into the project's assets/ folder when creating a project.

相关技能