Communitygithub.com

yazzang-homelab/motion-studio

Write a six-part XML state spec for a one-shape UI morph film (inputs, direction, structure, build, gotchas, start): states on downbeats, cursor-driven changes, seamless loop, approval gate. Use for 'UI morph', 'state list'.

Qu'est-ce que motion-studio ?

motion-studio is a Claude Code agent skill that write a six-part XML state spec for a one-shape UI morph film (inputs, direction, structure, build, gotchas, start): states on downbeats, cursor-driven changes, seamless loop, approval gate. Use for 'UI morph', 'state list'.

Compatible avec✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/yazzang-homelab/motion-studio/tree/HEAD/skills/ui-morph-spec

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

UI morph spec (course step 06, level L3)

Write the state list, not the vibe. The most-bookmarked prompt of the Opus 5.5 launch week was not a one-liner: @twoclipping's UI morph loop and @verbove's MakerMap film both used an XML spec with inputs to ask for, a direction, a beat-by-beat state list, build rules and gotchas. The idea behind them: one shape that never cuts. A single element changes size, radius and color from state to state (button, loader, player, chart, command palette), a cursor causes each change with a real click, and the last frame equals the first so the film loops.

Request arguments (may be empty), shown once:

Credit: the six-section layout follows @twoclipping's public template (https://x.com/twoclipping/status/2103273003555402193; the XML is in the main post, not in a thread reply as the course says) and @verbove's MakerMap spec (https://x.com/verbove/status/2103483957266268381). The template in this skill is written in motion-studio's own words: assets/spec-template.xml.

1. Ask for the inputs

Ask in one AskUserQuestion round (subagents cannot ask; you do):

InputDefaultRule
Product + URLrequiredcapture real UI and copy with /motion-studio:product-reel stage 3 when there is a URL
8 to 12 states in story orderlogo, CTA, email field, loader, check, card, chart, command paletteone per downbeat
Real data per stateasklabels, numbers, names from the product; no placeholders
Brand colors, fonts, one accentfrom capture or studio.jsonone accent
Tracksynthesize minimal at 120 BPMa supplied track must allow this use and start on a downbeat
Formats9x16, 1x1, 16x9same timeline, reframed
Loopyesthe last state morphs back into the first

2. Fill the spec

Copy the template into the project as docs/spec.xml and fill every [...] with the answers. Keep all six sections: <inputs>, <direction>, <structure>, <build>, <gotchas>, <start>. The motion-director subagent (motion-studio:motion-director) can draft it from your brief; it writes only under docs/.

3. Put the states on the beat grid

  1. Project: scaffold with --loop if needed (node "${CLAUDE_PLUGIN_ROOT}/skills/studio-init/scripts/init.mjs" <dir> --title "<Product> morph" --loop --duration <S> --install; in a skills-only install use node "${CLAUDE_SKILL_DIR}/../studio-init/scripts/init.mjs" ... with the same flags, or invoke the studio-init skill).

  2. Grid: node tools/score.mjs --style minimal --bpm 120 --dur <S>, or measure the supplied track with node tools/beats.mjs audio/<track>.

  3. State list with exact downbeat times, loop checks and warnings:

    node "${CLAUDE_SKILL_DIR}/scripts/statelist.mjs" --states "logo,CTA button,email field,loader,check,card,chart,palette" --out docs/statelist.md
    
    FlagUse
    --states "a,b:2,c" or --file list.txtstates in order; :2 holds a state for two bars
    --beats audio/beats.jsonmeasured grid (default when the file exists); --beats none ignores it
    --bpm N, --beats-per-bar Noverride the grid
    --no-loopa film that ends instead of looping
    --jsonone JSON line with every state's start, end and content timing

    It warns when the loop length differs from studio.json duration, when the first state is not at 0 s (a pickup in the track), or when a state holds under 1 s. Fix the duration or trim the track before continuing.

  4. Fill the cursor action, data and sound columns of docs/statelist.md, and copy the table into docs/shotlist.md.

4. The gate

Show the state list on the beat grid and wait for the user's OK before writing any film code (the <start> section says so, and so does the course). A rejected list is rewritten, not coded around. Record the decision on the Status: line of docs/shotlist.md.

5. Build from the verified example

Copy assets/morph-loop.film.js to film/film.js and adapt it: it is a working 16 s, 8-state loop at 120 BPM that renders in every format. Replace STATES (sizes in 1080 px units, fill token), COPY and the content painters with the approved list and the real data; keep the mechanics:

MechanicAPIRule
state timesgrid.bar(i)never typed seconds
container size, radius, color channels, camera zoomloopTrack(t, keys, dur, spring)keys in [0, duration]; the seam change once, as a key at the first downbeat (this example) or at t = duration
content in and outswapAlpha(t, start, nextStart)in after the morph starts, out before the next
cursorloopTrack on x and y, cursor(g, x, y, { pressed })clicks the current element on the downbeat
tabs and list highlightsindicator(t, stops, { width })edges on different springs
soundscues from grid.bar and grid.beatclick on presses, swoosh under morphs
grain and other frame-indexed noisegrain(g, W, H, c.frame % LOOP_FRAMES, ...) with LOOP_FRAMES = Math.round(dur * fps)the critique compares hash(0) with hash(duration, { wrap: false }); noise seeded by the raw frame index makes the end differ from frame 0 and fails the loop check

Every pattern with its reasoning: references/morph-recipes.md. Set studio.json "loop": true and duration to the loop length, then npm run lint.

6. Critique and deliver

Run the critique loop from /motion-studio:motion-reel (at least 3 rounds, all axes >= 8, no open P0; each round builds the mixed render and both evidence passes first, see its pipeline runbook). For morph loops also check out/review/<fmt>/loop.png (live pass only; the video/ pass has no loop pane) and the "loop seam" metric (hash(0) equals hash(duration, { wrap: false }), continuity ratio <= 1.5; the |end - first| pane must be black, which frame-indexed grain breaks unless its index wraps), labels during every swap in strip.png, and the cursor position at each downbeat in contact.png. A seam jump is a P0. Then npm run build.

Rules for morph films

  • One container, never cut. States differ by size, radius, fill and content only.
  • A cursor causes every change; no state changes by itself.
  • Something moves on every beat: a press, typing, a counter, a line drawing, a highlight step.
  • Real product data only. Springs with at most a hint of overshoot; none on type.
  • Banned: bouncy easing, glows, gradients on UI chrome, particle bursts, dead beats.
  • Never will-change (or any rasterizing trick) on anything the camera scales.

Next: /motion-studio:springs to tune the feel; /motion-studio:ship-formats for per-format reframing and delivery.

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

yazzang-homelab/motion-studio

Make Claude watch its own frames: critique.mjs evidence, harsh 7-axis scores, timestamped P0/P1/P2 problems in docs/review_log.md, fix the 3 worst, re-check, pass the gate. Use for 'critique it', 'review the frames', 'is it good'.

yazzang-homelab/motion-studio

Plan long-form or overnight films: director's brief (PLAN FIRST or GO, budget, definition of done), ANIMATION_GUIDE + STORYBOARD, chapter subagents, gates, chunked render. Use for 'overnight film', 'music video', '2-minute film'.

yazzang-homelab/motion-studio

Make a launch video, app or product reel, explainer or motion ad from code, end to end: brand assets from a URL, beat-grid shot list, synced sound, critique loop, all formats. Default for new video requests; not footage edits.

yazzang-homelab/motion-studio

Brand-asset stage of a product film (motion-reel runs the whole film): capture real screenshots, logo, colors and fonts from a URL, never redraw UI; brand story beats; voice + mascot. Use to grab or fix a brand's assets.

yazzang-homelab/motion-studio

Turn a reference (a frame, a video or an image library) into docs/style_guide.md and a beat-grid shot list: measure cuts, palette and pace, take grammar not content, wait for OK. Use when the user supplies or names a look.

yazzang-homelab/motion-studio

Build, debug or speed up the seek(t) render engine: render contract, canvas vs page capture, workers/subframes/chunks, determinism fixes, Remotion or HyperFrames handoff. Use for 'render is slow', 'frames differ', 'use Remotion'.

yazzang-homelab/motion-studio

Ship every format from one timeline, then package it: layout() reframing (never crop), render all formats, per-format checks, deliver.mjs, a brand skill, a service offer. Use for 'export 9:16 and 16:9', 'deliver', 'make a skill'.

yazzang-homelab/motion-studio

The viral one-line 'showreel for a résumé' prompt: why it works (anatomy), the credited quote, and seeded variants that avoid look-alike reels; runs it as an engine test. Use for that prompt, its variations, or a showreel.

yazzang-homelab/motion-studio

Score a film to its beat grid: measure a track (beats.mjs) or synthesize one (score.mjs), cue SFX from the film, add voice, mix to -14 LUFS / -1 dBTP at exact length. Use for 'add music', 'sync to the beat', 'SFX', 'loudness'.

yazzang-homelab/motion-studio

Make motion feel physical with closed-form springs from lib/motion.js: presets, springFromFeel, track() for multi-target values, loopTrack loops, indicators, text swaps. Use for 'feels linear', 'add bounce', 'easing to springs'.

yazzang-homelab/motion-studio

Scaffold a motion-studio film project (seek(t) renderer, springs, beat grid, synthesized sound, critique tools), install it, set up the browser, run doctor. Use for 'set up the motion studio', 'new film project', 'init studio'.

Skills associés