# MOTIONHOUSE rulebook · kit 2.0.0 This kit is a complete motion graphics studio that runs on the person's computer: its own frame-by-frame engine, eight looks, 2D and 3D scenes, characters that act, a free voice, music and sound effects. You (Claude) fill in `brand.json` and `video.json` from the brief, the engine draws every frame, the person reviews it in **MotionHouse Preview**, and you render the final file. The brief is in the prompt the person pasted (made on frameland.io/motionhouse). Where this rulebook and the brief differ, the brief wins. Everything here is called **MotionHouse**. Keep your messages short and plain: the person may not be technical. Use only the npm scripts below. ## Commands | Command | What it does | | --- | --- | | `npm install` | Installs the engine (once). | | `npm run doctor` | Checks Node, the browser, ffmpeg, 3D support and the free voice. Run it first. | | `npm run fonts` | Gets the fonts for the look and brand (runs by itself when needed). | | `npm run voice` | Makes the voice-over with the free voice, or times the person's recording. Writes `build/voice.wav` + word timings. | | `npm run audio` | Builds the soundtrack: voice + music + sound effects → `build/mix.wav`. Run after every change to timing, voice or music. | | `npm run check` | Checks `video.json` and `brand.json` and names every problem. Fix them all. | | `npm run stills` | One still per scene → `out/storyboard//`. | | `npm run sheet` | A contact sheet, one frame every 0.5 s with the time on each → `out/sheet-.jpg`. | | `npm run preview` | MotionHouse Preview, live in the browser (only when your commands run on the person's own computer). | | `npm run preview:file` | Writes `MotionHouse Preview.html` (video + sound in one file) for the person to double-click. | | `npm run render` | Renders every format to `out/`. Options: `-- --format=9:16`, `-- --draft` (fast, lower quality), `-- --from=2 --to=6` (seconds). | | `npm run selftest` | Doctor + check + stills + a 2-second draft. Run once on a new computer. | Add `-- --q=0.6` to `stills`, `sheet` or `render` for faster 3D drafts on computers without a graphics card (`doctor` says "software"); leave it off for the final render. ## 1. Brand (`brand.json`) - `name`; `colors.accent` (buttons, pills; white or black text is picked for contrast); `colors.accent2` (the highlight: key words, numbers). Optional `colors.background` and `colors.text` are used only when `video.json` has `"background": "brand"`. - `fonts.heading` / `fonts.body`: `null` uses the look's fonts (best by default). A Google font name exactly as on fonts.google.com, or a file path like `"fonts/Brand-Bold.woff2"` (file in `public/fonts/`). - `logo`: a path in `public/` (SVG, or PNG with transparency), or `null` for the brand name in text. - `radius`: optional corner rounding in px; leave it out to use the look's. - Brief says "pick colours from my website and logo": read the site, look at the logo, choose `accent` and `accent2`, say what you chose in one line. ## 2. The person's files Copy (never move) the files the brief lists from the person's folder: logo → `public/brand/`, product photos and screenshots → `public/images/`, voice-over and music → `public/audio/`, font files → `public/fonts/`. Short lowercase names without spaces. If a file the brief mentions isn't there, ask once, then carry on without it. ## 3. Voice-over (`video.json` → `voice`) `"voice": { "mode": "none" | "free" | "file", "voice": "af_heart", "speed": 1, "file": "audio/voiceover.mp3", "lines": [ { "text": "…", "caps": "…", "gap": 0.3 } ] }` - **Lines are cuts, not sentences.** Split each sentence at natural pauses (commas, "and", "but") into 1-3 lines so the picture can change every 1.5-3.5 s while the voice keeps flowing. The free voice speaks each whole sentence in one breath, so it still sounds natural. Write numbers as they're said ("eighty-seven percent"). Keep the brief's script word for word; if the brief has no script but wants a voice, write one the way a person talks to a friend and show it to the person before making the voice. - `caps` (optional) sets the on-screen captions for a line: `"What *happens | if you *hold | your *breath?"` (`|` splits chunks, `*` marks the highlighted word). Without it, captions are split automatically, 1-3 words with one highlighted word. - **mode "free"** (no account, no cost): run `npm run voice`. The first run downloads the voice engine (about 120 MB, once). Voices: `af_heart` (US female, warm, best overall), `af_bella` (US female, bright), `af_nicole` (US female, soft), `af_sarah` (US female, clear), `am_michael` (US male, steady explainer), `am_fenrir` (US male, deeper), `am_puck` (US male, playful), `bf_emma` (UK female, calm), `bm_george` (UK male, documentary), `bm_fable` (UK male, storyteller). Use the brief's choice; otherwise pick one that fits and say which. `speed` 0.9-1.15. English only. - **mode "file"** (the person's recording, or one made with Higgsfield): copy it to `public/audio/voiceover.`, put the script in `lines` (exactly what is said), set `"file"`, run `npm run voice`. MotionHouse lines the script up with the recording (it uses the free voice as a guide when installed). Check the captions in the contact sheet. - **Recording with Higgsfield** (when the brief asks): check the Higgsfield connector's tools are there (`list_voices`, `generate_audio`). If not, tell the person: it needs a paid Higgsfield plan; in Claude open Settings → Connectors → Add custom connector, paste `https://mcp.higgsfield.ai/mcp`, sign in; offer the free voice instead. Otherwise: `list_voices`, offer 3 library voices that fit (never clone, imitate or name a real person's voice) in one multiple-choice question; say it uses their Higgsfield credits (with the cost if shown); `generate_audio` with an ElevenLabs model, script word for word, never sped up; `jobs_wait`; download to `public/audio/voiceover.mp3` (if the network blocks it, open the link in the browser on the person's computer and copy it from Downloads); offer one re-take; then mode "file" as above. - With any voice-over, the video's length follows the voice (see Timing), not the length in the brief. ## 4. `video.json` | Field | Meaning | | --- | --- | | `project`, `version` | Name (used in file names) and version (start at 1, +1 every feedback round). | | `fps` | 30. | | `formats` | Any of `"9:16"`, `"1:1"`, `"4:5"`, `"16:9"`. Every scene adapts to each. | | `look` | One of the eight looks (section 5). | | `pace` | `"fast"`, `"medium"`, `"calm"`: reading time for scenes without a voice. | | `background` | `"look"` (default), `"dark"`, `"light"` or `"brand"`. | | `overlay` | `true` for titles over the person's own footage: transparent ProRes 4444 MOV, use only `lowerThird` and `caption` scenes. | | `captions` | `true` shows the spoken words (needs a voice-over). | | `voice` | Section 3. | | `audio` | `{ "music": "auto" | "none" | mood | "audio/track.mp3", "musicVolume": 0.5, "sfx": true, "sfxVolume": 0.6 }`. Section 9. | | `cast` | Characters for 3D story scenes (section 8). | | `scenes` | The scenes, in order (sections 6-8). | Look at `examples/` for complete projects: `ad-punch` (text ad, no voice), `explainer-voice` (free voice, captions, steps, chart), `story-clay` (characters acting, narrated), `product-cinema` (3D title, product, logo), `overlay-titles` (transparent titles). Start from the closest one; replace everything in it. ## 5. The eight looks | Look | id | Kind | Use for | | --- | --- | --- | --- | | Punch | `punch` | 2D | Creator-style ads and hooks: huge condensed capitals slam in, marker swipe on the key word, grain. | | Studio | `studio` | 2D | Products, apps, SaaS: bright, soft white cards, dot grid, rising words. | | Ledger | `ledger` | 2D | Data, finance, news, explainers with numbers: serif headlines, mono numbers, self-drawing charts. | | Neon | `neon` | 2D | Tech, gaming, nightlife: glowing type that flickers on, haze, light streaks. | | Paper | `paper` | 2D | Handmade, food, kids, history: cut paper, torn edges, stop-motion steps. | | Sketch | `sketch` | 2D | Teaching and how-tos: marker on a whiteboard, words write themselves, doodles. | | Clay 3D | `clay` | 3D | Stories with characters, playful brands: soft clay world, rounded 3D type. | | Cinema 3D | `cinema` | 3D | Premium launches: metal 3D titles, products on a dark glossy stage, bloom. | Any scene type works in any look; 3D scenes take the look's style (clay, cinema, or flat cartoon in the 2D looks). Use the brief's look; if it says "pick for me", choose by the table and say why in one line. ## 6. Scene types Every scene takes `type`, plus either `duration` (seconds) or `lines` ([first, last] voice line index, see Timing), and optionally `transition` (`whip`, `slide`, `wipe`, `streak`, `sheet`, `erase`, `iris`, `flash`, `fade`, `cut`; default is the look's), `captions: false`, `sfx` (section 9) and `note` (what the scene is for). | type | fields | use for | | --- | --- | --- | | `title` | `title`, `kicker`, `subtitle` | the hook or opening line | | `kinetic` | `text` (`*accent*` words) | punchy statements, 3-8 words | | `words` | `lines` | the spoken words appear exactly as they're said (big type); captions are hidden on it | | `bullets` | `items` (2-4), `title` | benefits | | `steps` | `items` (2-4), `title` | numbered how-to steps | | `stat` | `value`, `label`, `prefix`, `suffix`, `decimals`, `source` | a number that counts up (`suffix: "%"` draws a ring) | | `chart` | `kind` (`bar`, `line`, `donut`, `compare`), `data` [{label, value}], `title`, `unit`, `prefix`, `highlight` (index), `source` | real data only, source on screen | | `quote` | `text`, `by` | testimonials the person gave you (never invent one) | | `image` | `src`, `caption`, `price`, `fit` (`contain` products / `cover` photos) | products, screenshots, photos | | `split` | `src`, `title`, `text`, `fit` | picture + words side by side | | `compare` | `left` {title, items}, `right` {title, items}, `title` | before/after, us vs them | | `cta` | `title`, `button`, `url` | the ending (logo shows if brand.json has one) | | `logo` | `tagline` | logo reveal / end card | | `lowerThird` | `name`, `role` | overlay: a name over footage | | `caption` | `text` | overlay: one subtitle line | | `title3d` | `title`, `kicker`, `subtitle`, `move` | 3D type that lands word by word | | `logo3d` | `tagline` | the logo on a 3D card turning in (or the name in 3D type) | | `product3d` | `src`, `shape` (`card`, `box`, `can`, `phone`), `caption`, `price`, `move` | the person's product on a turntable: `card` = their cut-out photo, `box` = packaging with the photo on the front, `can` = the image wrapped round a can, `phone` = an app screenshot on a phone | | `story3d` | section 8 | characters acting | ### From the brief to scenes - **Animated text ad:** `title`/`kinetic` hook, 2-4 `kinetic`/`stat`/`bullets`, `cta`. Mostly words, big and fast. - **Explainer:** `title`, one scene per point (`steps`, `chart`, `stat`, `image`, `split`), `cta` or `logo`. With a voice-over, one scene per sentence or two. - **Product promo:** hook, `image` or `product3d` with caption and price, `bullets`, `cta`. Every product shot uses the person's real photo. - **Story with characters:** `story3d` scenes (one per beat of the story, 2-4 s each), narrated or with characters speaking, ending on `logo3d` or `cta`. - **Titles and overlays:** `"overlay": true`, only `lowerThird` and `caption`. - The brief's words on screen are the words on screen: keep the wording, only split long lines and fix obvious typos. End with the call to action, price and URL (a `cta`), except overlays. ## 7. Timing - **With a voice-over:** give every scene `lines: [a, b]` and no `duration`. Each scene starts just before its first line is spoken and lasts until the next scene; the video ends 0.8 s after the last word. Run `npm run voice` before `stills`, and `npm run audio` after any change. - **Without a voice:** `duration` per scene = words × pace (fast 0.3 s, medium 0.4, calm 0.5 per word) + 1 s, never under 1.5 s (3D scenes at least 3 s). Fit the total to the brief's length: cut or merge scenes rather than rushing. The hook lands within 1.5 s. - **Beats** (story3d actions, sound cues) are timed with `"at": 1.2` (seconds into the scene), `"at": "60%"`, or `"word": "money"` (the moment that word is spoken in the scene's lines; add `"n": 2` for the second time it's said). ## 8. 3D characters and stories Define characters once in `video.json`: ```json "cast": { "sam": { "skin": "#E8B48C", "hair": "short", "hairColor": "#2B1D14", "top": "#3E7CC9", "bottom": "#2B2D42", "shoes": "#1E1E24", "sleeves": "short", "build": "adult", "extras": ["glasses"] } } ``` `hair`: short, long, bob, bun, ponytail, curly, spiky, bald, buzz · `build`: adult, kid, tall, round · `extras`: glasses, hat, cap, beanie, tie, scarf, backpack, beard, earrings. Give each character a distinct silhouette and colour; use the brand colours for their clothes when it fits. Describe a person's look only from the brief; never make a character look like a real, named person. A `story3d` scene: ```json { "type": "story3d", "lines": [2, 3], "set": "kitchen", "time": "day", "cast": [ { "id": "sam", "at": [-0.6, 0], "turn": 15 }, { "id": "ana", "at": [0.6, 0], "turn": -15 } ], "camera": { "shot": "full", "on": "sam", "move": "push" }, "props": [ { "id": "sign", "at": [1.4, -0.8], "text": "SALE" } ], "beats": [ { "at": 0, "who": "sam", "do": "wave", "face": "happy", "look": "camera" }, { "word": "but", "who": "ana", "do": "shrug", "face": "confused", "say": "Wait, really?" }, { "at": 2.2, "who": "sam", "do": "walk", "to": [0.2, 0.4], "for": 1.5 } ], "speaker": "sam", "text": "optional words at the top" } ``` - `set`: studio, office, room, kitchen, street, park, stage, void · `time`: day, sunset, night. `at` is [x, z] in metres (x left/right, z towards camera); `turn` is degrees (0 faces the camera). - `do` (actions): idle, stand, wave, waveBoth, point, pointLeft, pointRight, pointUp, present, presentBoth, shrug, think, celebrate, cheer, facepalm, armsCrossed, handsHips, clap, talk, explain, thumbsUp, scared, shock, bow, nod, shake, lookAround, dance, walk, run, jump, fall, sit, type, phone, hold, holdUp, give, sleep, sad, angry, peek, stretch. `walk`/`run` with `to` moves the character there (`for` = seconds). Other actions last until the next beat for that character, or `for` seconds. - `face` (emotions): neutral, happy, laugh, smile, sad, cry, angry, surprised, shock, scared, worried, thinking, confused, smug, proud, sleepy, wink, determined, love, embarrassed, bored. Actions pick a fitting face when you don't set one. Characters blink by themselves. - `look`: camera, left, right, up, down, or another character's id. - `say`: a speech bubble over the character for a moment (their mouth moves). `speaker`: the character whose mouth follows the voice-over (lip-sync) in this scene; leave it out for a narrator. - `hold`: a prop in the character's hand (`null` to put it down). Props: phone, laptop, coffee, box, bag, sign (`text`), product (`src`), money, bulb, heart, star, question, exclamation, chart, trophy, book, plant. Props in `props` stand in the scene. - `camera.shot`: wide, full, medium, close, face · `move`: drift, push, pull, orbit, pan, crane, dolly, handheld, static · `on`: follow one character · `angle`: degrees around. - **Acting well:** one clear action per beat, 1.5-3 s apart; react with the face on the key word; vary shots between scenes (full → close → two-shot); keep characters inside the frame in tall formats (x between -0.8 and 0.8 for two people); start each scene already in action. Check every story still. ## 9. Sound - Music: `"auto"` makes a track for the look (moods: punch→drive, studio→bright, ledger→pulse, neon→synth, paper→folk, sketch→lofi, clay→bounce, cinema→epic), fitted to the exact length with an ending on the last chord. Use `"mood"` names to pick another, `"audio/track.mp3"` for the person's own track, `"none"` for silence. Music ducks under the voice by itself. `musicVolume` 0.2-0.8. - Sound effects are added automatically on cuts, words landing, counts, bars and actions. Add your own with `"sfx": [ { "type": "pop", "at": 0.4 } ]` or `{ "type": "boing", "word": "jump" }`. Types: whoosh, swish, zap, paper, rustle, boom, impact, thump, thud, tap, tick, blip, pop, pluck, chime, shimmer, sparkle, riser, swell, marker, boing, clap, step. `"sfx": false` in `audio` turns the automatic ones off. - Everything is generated by MotionHouse, so it is free to use. ## 10. Check your work before showing anything 1. `npm run check` until it reports no problems. 2. `npm run voice` (if any) and `npm run audio`. 3. `npm run stills` and `npm run sheet`, then look at **every** image yourself. For each frame: text fits (2-3 lines, nothing touching the edges), contrast is clear, tall formats keep the top 12% and bottom 20% free of key content, captions don't cover key text (set `captions: false` on scenes whose words match the voice), characters are inside the frame and facing sensibly, the picture matches what's being said at that moment, nothing appears before its cause. 4. Fix and repeat. Tell the person in one line what you caught and fixed, and that the storyboard is ready. ## 11. MotionHouse Preview - Commands on the person's own computer: `npm run preview` (opens in the browser, updates live; leave it running). - Commands in a sandbox with their folder connected: `npm run preview:file`, then tell them to double-click `MotionHouse Preview.html` in the project folder. Rebuild after every change and ask them to reopen it. Tell the person: press play (it has sound), press **Approve** or **Change** on each scene, add notes, then **Copy feedback** and paste it here. ## 12. Feedback rounds When the person pastes a block starting `MOTIONHOUSE FEEDBACK` (or describes changes): change only the scenes marked "change" plus anything under "Overall"; raise `version` by 1; re-run voice/audio if the script or timing changed; check the changed scenes in stills; rebuild or refresh the preview; tell them what changed in one or two lines. Repeat until everything is approved or they ask for the final video. ## 13. Render and deliver `npm run render` → `out/-v-.mp4` (H.264 + AAC, ready for Meta, TikTok, YouTube) or `.mov` (ProRes 4444 with transparency) for overlays. 2D renders take about 5-10 s per second of video; 3D takes longer without a graphics card (tell the person the time up front; use `-- --draft` for a quick look). If `ffprobe` is available, confirm the duration. Copy the finished files into the folder the prompt names and tell the person their names. Offer one round of precise changes. ## 14. Going beyond the scene types Add a component in `src/scenes/two.tsx` (2D) or `src/three/scenes3d.tsx` (3D), register it in `SCENES_2D` / `SCENES_3D`, and add it to `src/core/catalog.js`. Rules, or frames will flicker or differ between preview and render: - Every value is a pure function of time: read `useScene().t` (seconds into the scene) and `useFrame()`. No CSS transitions or animations, no timers, no `Math.random()` (use `rand('seed')` from `src/core/anim.ts`). - Use the look's pieces from `src/looks/kit.tsx` (`Words`, `Enter`, `Card`, `Doodle`) and colours from `src/core/theme.ts`, sizes × `useFrame().u`. - Images through `asset('images/x.png')` and ``; 3D inside `` with everything posed in `draw(t)`. - Run `npm run check` (types and video.json), then `npm run stills`. ## Craft rules - One idea per scene. Kinetic: 3-8 words. Bullets/steps: 2-4 items under 6 words. - Brand colours and fonts only; `accent2` for highlighted words and numbers, `accent` for buttons. - Product photos must be the real product; never redraw a product or logo. - Never invent prices, numbers, reviews, quotes, results or claims. Respect the brief's "don't say" list. Health topics: accurate, calm, no gore. - Original writing only: take a format you like, never another creator's script, shots or characters. ## Troubleshooting | Problem | Fix | | --- | --- | | `npm run doctor` says browser missing | MotionHouse downloads Chrome Headless Shell on first render; if that's blocked, install Google Chrome or set `MOTIONHOUSE_BROWSER` to a Chrome/Edge/Chromium path. | | 3D is slow or says "software" | No graphics card in reach (normal in sandboxes): use `--q=0.6` for stills/sheets and `-- --draft` for test renders; final renders still work, just slower. On a Mac, `MOTIONHOUSE_GL=metal` is the default. | | A font doesn't load | Spelling as on fonts.google.com, or a `.woff2` in `public/fonts/` with its path in brand.json. | | The voice download fails | Open the link `npm run voice` prints in a browser, put the file in the folder it names, run it again. Or use the person's recording (mode "file"). | | Captions are off by a beat (own recording) | Make `voice.lines` match the recording word for word; re-run `npm run voice`. | | Render fails at the end | Check disk space; run `npm run render -- --format=9:16` one format at a time. | | `npm install` fails | The network may block npm. Tell the person in one sentence. |