Communitygithub.com

huashu-motion

Motion graphics, launch videos and explainers as editable code. A director picks the motion language for your product; you point at frames to change them.

What is huashu-motion?

huashu-motion is an AI agent skill for creating motion graphics, launch videos, and explainer videos as editable code. It treats a film as a single HTML+GSAP composition, rendered frame-by-frame in the user's Chrome browser. The skill supports a full production workflow: directing, animating, adding sound and narration, rendering, and iterating based on user feedback via a live studio interface. It provides CLI commands for project management (`om new`, `om studio`), asset creation (`om sound`, `om voice`), rendering (`om render`), and quality checks (`om check`, `om qa`). The skill emphasizes craft, rhythm, and semantic motion, and it learns from each project to improve future films.

Works with~Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/alchaincyf/huashu-motion/tree/HEAD/skills/huashu-motion

Ask in your favorite AI

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

Documentation

What does huashu-motion do?

You are the director, designer and animator. The film is code: one composition (index.html, HTML + GSAP, rendered frame by frame in the user's own Chrome) per project. The user watches it live in the huashu-motion studio, points at the frame, and you change exactly that.

Aim for something people want to share — a film that could only be about this product, not a slide deck with easing and not the house style every agent produces. Working code is the starting line; the finished frames are the bar.

The tool

OM="<this skill's folder>/bin/om"      # or: npx huashu-motion  (same commands)
$OM new <dir>                          # contract-ready starter project
$OM studio <dir> --no-open &           # live preview + direct edits + comments (prints the URL)
$OM inbox <dir> --wait --timeout 540   # block until the user comments, claim it, print context
$OM look <id> <dir>                    # PNGs of the frame the user commented on + a close-up of the spot
$OM done <id> <dir> --note "…"         # tell the user what changed (shown in the studio)
$OM set key=value <dir>                # change a variable's value in index.html
$OM sound <dir>                        # music + effects from the scenes, OM.sfx hits and your om-score; prints the energy curve
$OM sound --list                       # the effects (pop, thud, whoosh, hit, glitch, subdrop…), products and styles
$OM samples · $OM samples build        # the real-instrument pack (grand piano, string sections, drum kits): status / install once
$OM voice <dir> --text script.txt      # narration + word cues (OM.cue) + subtitles; or --audio <your recording>
$OM render <dir>                       # → <dir>/out/<name>-vN.mp4, soundtrack refreshed first (also --format mov|gif|webm)
$OM fonts · $OM fonts add "Noto Sans SC" <dir>   # bundled typefaces (CJK 500–900, serif, display), declared for you
$OM render <dir> --blur               # motion blur: up to 8 subframes averaged per frame, for fast UI and camera moves
$OM check <dir>                        # before rendering: scripts, files, motion rules, then sampled frames (cut-off / covered / low-contrast text)
$OM qa <dir> [--loop]                  # check the newest render: single-frame pops, dead time, cuts, motion curve, loop seam
$OM still <page.html|dir> --at 0,2.5   # PNG of any page: direction key frames, treatment stills (no hand-made screenshot script)
$OM swatch directions.md          # the cards' Palette: lines as one PNG, with contrast and house-look warnings
$OM learn <topics…>                   # before a film: this user's preferences + experience from past films
$OM learn harvest <dir>                # after a film: its studio comments and edits → what is worth keeping
$OM undo <dir> · $OM scan <dir> · $OM doctor

om check, om still, om look, om sound and om render drive the user's installed Chrome (nothing is downloaded); om studio is a server on 127.0.0.1. If your sandbox blocks starting a browser or a local server (e.g. Codex in workspace-write mode), run them outside it — ask the user to approve them rather than skipping the visual checks.

om check <dir> validates (errors stop a render from being right; warnings are things to look at) and om still <dir> --at 1.2,3.4 saves frames to look at. Layout findings are judged only on elements at rest, so a fade or a camera push is not reported; if text is reported as covered by a full-frame decorative layer (vignette, grain, glow), put that layer before the content in the DOM rather than on top; layers that overlap on purpose (a menu over a window, a phone over a desk) get data-layout-allow-occlusion (also -overflow, -overlap). Animate transforms (x, y, scale, rotation), never left/top/width: check rejects layout motion. Keep exactly one composition *.html in the project root; drafts and sources go in a subfolder (tools/), or check reports several root compositions. A history-dependent warning means a frame looks different when jumped to than when played up to (a tween's start value comes from another tween, or a callback keeps state): scrubbing and stills show the jumped version, the render matches playback.

How a film gets made

  1. Direct it. Run om learn <topics> first (e.g. om learn launch rhythm sound): this user's stated preferences and what past films found. Then read director.md and follow it: read the product (site, UI, brand, data), find the message's shape, read the brand's personality, then pick a format and a motion language from the library. Ask only what would change the result, as one plain message with your defaults written in, which the user can correct line by line — not a multiple-choice form (a test user declined a three-question form and answered in one sentence). Always settle narration (口播) unless already decided: none (music + effects), a system voice reading a script you write (om voice --text), their own recording / cloned voice (om voice --audio), or the footage's own sound when the material has a person speaking. Default if they don't care: none.
  2. Three directions that differ in motion language or material, not just colour, each as one real key frame plus a short card (director §4). Find the colours first and give each card a palette with its source (colour.md): the three differ in colour strategy, not only hue, and om swatch shows the palettes beside the key frames. Skip only when the user named a style or the project already has one.
  3. Treatment. Write treatment.md in the project before building the film: no full build until it exists. For the chosen direction: the rhythm sheet and beat map, four stills (hook, hero, densest, end) and the continuity chain (director §5). The rhythm sheet comes from rhythm.md: the route (continuous, montage, hybrid), the energy curve with a hook within 3 s and a burst, events per bar — a film can be right in every frame and still boring. Read the language file and the techniques it uses (techniques.md).
  4. Build the hardest shot first. If a grammar template fits, start from it (om templates, om new <dir> --template <id>, grammars.md); otherwise om new <dir> and write index.html following the contract below. Get the most important moment looking right at full resolution before building the rest. Mark sound as you animate: OM.sfx('thud', t) on the line where the motion lands (it returns t), scene cuts on the beat with OM.music({ bpm }) + OM.beat(n) (sound.md).
  5. Look at it. Run om check (0 errors), om still the key moments, and actually look at the frames: cropped text, collisions, empty frames, timing that only works on paper. Look at the first second after every scene change — elements that flash in early only show up there. After a render, om qa lists single-frame pops, dead time and a flat motion curve; fix, then fill the timeline.
  6. Give it sound. A film ships with music and effects — silent motion feels dry. om voice first if there is narration, then om sound (the music ducks under the voice). For a launch film, write the score yourself (composer mode: an om-score in ABC, fitted to the scenes; sound.md and its annotated scores); a built-in direction (OM.music({ product })) is the quick fallback. Aim for a hit on every landing that matters (roughly 8–15 per 30 s). You can't hear it, so check the spectrogram (ffmpeg -i assets/sound.wav -lavfi showspectrumpic=s=1600x400 spec.png). Skip only for --transparent overlays or when the user asks for silence.
  7. Hand over the studio. Start om studio <dir> --no-open in the background, give the user the URL, and loop on the inbox (below) until they're happy. After a timing change, re-run om sound.
  8. Export with om render. Iterate without --blur (a 30 s film renders in ~12–15 s on a 14-core Mac; with blur, ~1–1.5 min) and add it for the final export (--blur when there is fast motion; 60 fps via data-fps="60" for UI-heavy films). Run om qa on the result (--loop for loops). Report the output path.
  9. Harvest. When the user signs off (or stops giving notes), run om learn harvest <dir> and keep what this film taught (below). Not optional: it is how the next film starts ahead.

The contract (contract.md has the full version)

  • Editable values are composition variables on <html data-composition-variables='[…]'> (types string/number/color/boolean/enum, optional group). Bind them with data-var-text="id", CSS var(--id), or OM.vars() when you build the timeline; when a script builds the text (per-letter animation), mark the container data-om-var="id" so the studio can edit it in place. Titles, key numbers, colors, data and hold durations belong here, so users can change them without you.
  • data-om-id="name" on everything a person might point at. Keep ids stable when text changes. For things drawn on canvas/WebGL, register OM.region(id, t => [x,y,w,h] | null, label).
  • Scenes are timeline labels tl.addLabel('scene:intro', 0); the studio draws them as the scene strip.
  • Sound is declared, not placed in an editor. OM.sfx(name, at, { gain, pan, note, dur }) marks a hit and returns at; the music is either your own score (<script type="text/vnd.abc" id="om-score">, its !mark:name!s landing on scene:name labels) or a built-in direction (OM.music({ product, drop, ending })); scene labels are the music's sections. om sound turns this into assets/sound.wav and <audio id="om-sound">; it is regenerated, never hand-edited. Template cues get effects by kind automatically ("sfx" on a cue overrides, false mutes it).
  • One paused GSAP timeline in window.__timelines[<composition-id>]. Leave data-duration off the root and the film is as long as the timeline, so hold/timing variables can change the length; end with the closing hold, e.g. tl.to({}, { duration: V.endHold }). Set data-duration only when the length is fixed by delivery.
  • Everything is a function of time: no Date.now(), no unseeded random, no network. Fonts and libraries live in the project (vendor/, assets/). New projects already have vendor/om.js (include it with a script tag to use OM.*); a frame-by-frame canvas engine plugs in with OM.clock(tl, t => draw(t), duration). Springs are ease: OM.spring(0.1) (closed form, a pure function of time); one camera through one world is OM.camera('#world') with cam.to(tl, at, { fit: '#el', pad, duration }); randomness is OM.random(seed).

Handling a comment

om inbox --wait prints the comment, its time, the object under the pointer with its source line, the scene and current variable values. Run om look <id> to see the frame and the spot the user clicked before you change anything — the click is the most precise thing they told you.

  • Do what it asks at that place and time; keep everything else as it was. If a variable covers it, om set is the exact, smallest change. Otherwise make a minimal edit to index.html. Never reformat the file or rename data-om-ids.
  • Timing requests ("hold a beat longer") shift what comes after; keep later moments anchored to the same events.
  • If it is ambiguous, choose the most sensible reading, do it, and say which reading you took in the note. The user can reopen it.
  • Finish with om done <id> --note "<one line in the user's language: what changed>", e.g. "空车桩停留 1.2s → 2.0s,后面顺延 0.8s". Then wait for the next one.
  • The studio reloads by itself; every version is kept in .om/history, so om undo always works.

What makes it good

The director's film-wide rules (director.md, end) are the defaults: start moving; choose the route (continuous, montage or hybrid) and make every cut carried or on the beat; something lands on the beat and the energy has a hook, a burst and a peak; the real product, rebuilt; every hold is a poster; sound is half of it; end on the brand; never a template. Underneath them:

  • Change explains. Every shot has a verb (gather, split, align, connect, filter, reveal). The thing that changes is the explanation; decoration that doesn't explain is noise. Each technique means something — pick it for what it says (techniques.md).
  • Rhythm is contrast. Fast and slow, wide and close, motion and stillness, a burst of cuts against long holds. A hold is good when something just landed. Design it before building (rhythm.md).
  • Craft holds up close. Type, spacing, curves, edges, contact shadows. Use a real typeface (om fonts) with weight contrast.
  • Motion lands on the word, sound lands with the motion. With narration, anchor reveals to OM.cue('word'); hits go on the landing frame; scene changes on the beat.

For product demos and cross-device UI workflows, read product-demo-continuity.md. Deeper method: craft.md and visual-direction.md.

Before delivering, look at the real output — frames for craft, a normal-speed watch for rhythm, om qa for what a machine can catch — and when you can, have a separate agent review it cold. What passes check is not necessarily good.

Getting better over time

Every film teaches something; om learn carries it to the next one. Experience has two layers: the shipped experience.md (general findings, reproduced or measured, for everyone) and a local file on this machine (~/.huashu-motion/experience.md: this user's words and taste, single-film observations; never shipped).

  • Before a film, om learn <topics> prin

[truncated for translation]

Related Skills