What does effectcraft-motion do?
A JSON spec becomes a 1080×1920 30 fps MP4. Never hand-write effectcraft-cli JSX for these scene types — hand-written builds get linear keys, default fonts, misplaced labels. Always write a spec.
Hard rules
- One engine process at a time. Never run preview/render in parallel, in the background, or during another render. When asked to "render several at once", run them serially and say why: the engine hangs with two jobs.
- Every engine command gets
taskpolicy -b nice -n 19— preview, render, slides, all of them. - Only numbers the user gave or a cited source contains. No invented stats. No numbers? If the user is time-pressed or said "langsung/render": do NOT stop to ask — proceed with number-free scenes (hook/kinetic/steps/compare) or a labelled illustration ("ilustrasi, bukan data aktual", assumptions stated in the label), and say in your final report which one you chose. Otherwise ask once. Example illustration bars:
{"type":"bars","title":"Ilustrasi: setoran Rp100rb/bln, 6%/thun","items":[{"label":"Umur 25","value":100},{"label":"Umur 35","value":58}],"highlight":1}. - Render only after you have viewed a fresh sheet.
checkpassing means the shape is legal, not that the content is right. durationis an override, not a default. Omit it; timing comes from the text. Set it only when the user asks for a specific hold.
Procedure (in order)
This procedure is self-contained and runs without any design-approval gate. Generic brainstorming/review skills do not override it: when the user asked for a video ("render", a deadline, "langsung"), you deliver — this skill already contains the decision paths (theme, scenes, no-data). Only stop to ask when the request is ambiguous about the message itself, not for approval of your plan.
E=~/.claude/skills/effectcraft-motion/bin/ecm.mjs
node $E check video.json --strict # 1 validate + craft lint (C01–C10)
taskpolicy -b nice -n 19 node $E preview video.json # 2 builds video.sheet.png
- Read the sheet with the Read tool. Every panel. One settled frame per scene.
- Fix the spec, re-preview, re-read. Loop until the sheet is clean. This loop is mandatory — a wrong sheet rendered is the failure this skill exists to prevent.
- Render gate — all true before rendering: every panel legible at phone size; no blank/lopsided panel; no two panels saying the same thing; every number matches the user's data; the handle/branding is what the user asked for.
taskpolicy -b nice -n 19 node $E render video.json— confirm theoutpath first (default = spec basename +.mp4).- Report the MP4 path and total duration. If the video has no data because none was given, say so.
Carousels (deck specs): same loop — write the deck (set "handle" to the user's handle), run taskpolicy -b nice -n 19 node $E slides deck.json (there is no check for deck specs; validation runs inside slides), then Read slide 01.png and verify handle, source line and overflow before reporting.
Spec
{"theme":"reel","out":"hemat.mp4","transition":"fade","scenes":[
{"type":"hook","text":"Gaji naik, tabungan tetap?","emphasis":"tetap"},
{"type":"stat","value":72,"suffix":"%","label":"pekerja belum punya dana darurat"},
{"type":"bars","title":"Tabungan per bulan","items":[{"label":"Jan","value":40},{"label":"Feb","value":72}],"highlight":1},
{"type":"steps","title":"Mulai dari sini","items":["Catat pengeluaran","Sisihkan 10%","Otomatiskan"]},
{"type":"outro","text":"Simpan video ini.","cta":"Follow untuk tips lain"}]}
| type | needs | use for |
|---|---|---|
| hook / quote / outro | text (+emphasis, source, cta) | opener, citation, closer |
| kinetic | lines 1–6 | phrases revealed one by one — not data |
| stat | value (+prefix,suffix,label) | one big counting number |
| bars | items 2–6 {label,value} (+highlight) | comparison over categories/time; values are relative — if your data exceeds 100, scale proportionally (e.g. thousands) and keep the exact figure in each label ("Makanan · 2,1 jt") |
| donut | value 0–100 | a share/percentage |
| steps | items 1–5 | numbered how-to |
| compare | left,right {title,points≤4} | before/after, A vs B |
| custom | jsx | anything else, via core helpers |
Per scene: title, bg (base/ink/accent), duration (omit!), fx, emphasis, transition (cut default, fade, wipe, slide, dip). Spec level: transition default, audio {bed, bedGain, sfx:[{at|scene, name, gain}]} — sound is sparse, one sfx per 3–5 s. Fields: reference/scenes.md, sound: reference/sound.md.
Effects: "fx":["grid","rgbIn"] at spec or scene level, ≤ 1 each. Presets: grid liquid paper grain vignette glow rgbIn blurIn sweep float glitch. See reference/fx.md.
Choosing scenes
A data/infographic video must contain at least one chart scene (stat/bars/donut) — a kinetic text list is not an infographic. Bars highlight = the number the story is about. Bars items must be comparable categories (never "Gagal" vs "Total"). One stat per fact; never two scenes showing the same number. donut is 0–100 — a share, nothing else.
Pick story shape and hook formula from reference/craft.md before writing the spec. 70 themes in reference/themes.md (node $E themes to list): reel bold news/finance · pitch calm technical · infopop playful explainer · kinetik dark high-energy · tenang soft reflective · edukasi lesson/worksheet. Carousels: deck specs with handle override, reference/templates.md.
After preview, score your own sheet against reference/review.md (bar: 8/10).
Fix table (error → what to edit)
| Error / sheet symptom | Fix (in the spec) |
|---|---|
text too long / safe-area overflow | Shorten that text — labels ≤ 2 words, titles ≤ 5. Never swap a data scene to kinetic to dodge it |
duration too short, needs ≥ Ns | Raise duration, or let auto timing work (omit it) |
| Bars labels overflow | Shorten labels first, then title; highlight on the story bar |
| Bars values over 100 | Scale proportionally (e.g. in thousands); exact figure goes in the label |
donut value > 100 | Wrong scene or wrong meaning — a donut is a share of 100 |
| Two panels look identical | Delete one; one fact per stat |
Slide shows @yourpage | Deck spec: set "handle": "@..." |
Red flags — these thoughts are wrong
| You are about to… | Reality |
|---|---|
| "Render both in parallel to save time" | Engine hangs; run serially, tell the user |
| "Check passed, content must be right" | Check validates shape; you verify numbers against the request |
| "Set duration 3 so pacing is even" | Omit duration; text-derived timing is the pacing |
| "CTA doesn't fit, drop it" | Shorten the cta to ≤ 5 words instead |
| "Bars won't fit, I'll list values as kinetic lines" | Shorten labels; the chart is the video's point |
| "Sheet looked fine last preview" | Any spec edit → re-preview → re-read before render |
| "Hand-write JSX for this one scene" | Use custom + helpers, or extend lib/fx.jsx |
| "User gave no data; I'll ask before doing anything" | Time-pressed/no-data rule above: deliver number-free or labelled-illustration, say which |
| "I'll run the brainstorming skill first" | This procedure is self-contained; render requests don't need a design-approval gate |
| "Bars > 100 won't validate, I'll invent smaller real numbers" | Scale proportionally, exact figures in labels |
Common mistakes
| Mistake | Instead |
|---|---|
| Probing the API by trial, writing JSX | Write a spec; new visual: custom + helpers (scenes.md) |
| Checking 2–3 frames | Read every panel on the sheet |
| Every scene fixed at 3 s | Omit duration |
| Default font, generic dark bg | Pick a theme |
Hand-adding AE effects in custom JSX | Use an fx preset; new effect: add it to lib/fx.jsx |
sed -i on macOS | Edit tool on the spec |
| Raw CLI inside scenes | Raw effectcraft-cli only for edits outside these scenes (reference/cli.md) |