cinetic — скилл для Claude Code: кинематографичная моушн-графика
Скилл для съёмки коротких промо-роликов кодом: раскадровка, тайминг, звук и рендер в Remotion или HyperFrames.
npx skills add Leonxlnx/cinetic --skill cinetic -a claude-codeЧто делает cinetic
cinetic превращает агента в режиссёра короткого фильма. Вы описываете продукт, а скилл ведёт проект от концепции и текста на экране до готового рендера: собирает таймлайн, привязанный к битам, синхронизирует с ним картинку и звуковую дорожку, которую тоже делает кодом. Подходит для launch-роликов, демо функций, зацикленных анимаций для лендингов и соцсетей, логотипных стингов, UI-проходок и кинетической типографики.
Внутри — скрипты для сборки проекта, рендера и финальной обработки, плюс набор проверок: линтер ищет запрещённые приёмы вроде эмодзи, неона и фиолетовых градиентов, а критики разбирают контактные листы и готовые кадры. Работает на Remotion 4 (React) или HyperFrames (HTML и GSAP), поэтому движок можно выбрать под свой стек.
Для работы нужен Node 22+, ffmpeg 6+ с libx264, Python 3.11+ с numpy, scipy, soundfile, pyloudnorm, opencv-python и librosa, а также Chromium или Chrome Headless Shell для рендера. Звуковой набор рендерит earshot 0.3+ в отдельном virtualenv — без него дорожку не собрать. Если у вас уже есть бренд с фирменным шрифтом или цветом из запрещённых, скилл не будет их перекрашивать: бренд важнее умолчаний, но их придётся отметить в BRIEF.md, иначе линтер выдаст ошибку.
Какие задачи решает
- собрать launch-ролик продукта из кода без монтажной программы
- сделать зацикленную анимацию функции для лендинга
- нарезать вертикальные и квадратные версии одного ролика
- свести картинку со звуковой дорожкой по битам
- проверить готовый рендер на бандинг и рассинхрон
Примеры запросов агенту
- сделай 30-секундный launch-фильм про наш новый экспорт в PDF, бренд — тёмно-синий и белый
- анимируй эту фичу для лендинга, зацикли на 8 секунд
- собери тизер к релизу и нарежь версии 9:16 и 1:1
Как установить cinetic
1Через Skills CLI (Vercel)
npx skills add Leonxlnx/cinetic --skill cinetic -a claude-code2Вручную: положить файлы
~/.claude/skills/cinetic/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/cinetic/
1Через Skills CLI (Vercel)
npx skills add Leonxlnx/cinetic --skill cinetic -a codex2Вручную: положить файлы
.agents/skills/cinetic/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add Leonxlnx/cinetic --skill cinetic -a cursor2Вручную: положить файлы
.cursor/skills/cinetic/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install Leonxlnx/cinetic cinetic2Вручную: положить файлы
.github/skills/cinetic/SKILL.md1Через Skills CLI (Vercel)
npx skills add Leonxlnx/cinetic --skill cinetic -a gemini-cli2Командой платформы
gemini skills install https://github.com/Leonxlnx/cinetic --path skills/cineticВручную: положить файлы
.devin/skills/cinetic/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add Leonxlnx/cinetic --skill cinetic -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о cinetic
Как установить cinetic в Claude?
Выполните npx skills add Leonxlnx/cinetic --skill cinetic -a claude-code. Скилл встанет в ~/.claude/skills/cinetic/SKILL.md.
Что делает cinetic?
Ведёт производство короткого ролика от идеи до рендера: раскадровка, тайминг по битам, текст на экране, звук кодом и финальная обработка кадра.
Что нужно для работы cinetic?
Node 22+, ffmpeg 6+ с libx264, Python 3.11+ с numpy, scipy, soundfile, pyloudnorm, opencv-python и librosa, Chromium или Chrome Headless Shell. Звук рендерит earshot 0.3+ в отдельном virtualenv.
Исходный текст
SKILL.md · MIT
---
name: cinetic
description: Direct, build and render premium cinematic motion design from code — launch films, product and feature videos, looping feature animations for landing pages and social, logo stings and reveals, UI walkthroughs, app demos, kinetic type, teasers, trailers, intros and promo clips. Use this whenever the user wants any video, animation, motion graphic or animated demo made with Remotion, HyperFrames, HTML/GSAP or React, or asks to storyboard, time, score, render, polish or critique one — even if they only say "make a video about X", "animate this feature" or "we need a launch clip". It supplies concept and copy discipline, type and colour taste that defers to a supplied brand, a beat-locked timeline that drives both picture and a code-made soundtrack, choreography and transition craft, real product UI in motion, film-grade finishing (true motion blur, no banding, BT.709, sync-checked mux) and a measured self-critique loop on contact sheets and renders.
license: MIT
compatibility: Needs Node 22+, ffmpeg 6+ with libx264, Python 3.11+ with numpy, scipy, soundfile, pyloudnorm, opencv-python and librosa (fonttools, brotli and uharfbuzz for outlined logos; pillow for gradient PNGs), and Chromium or Chrome Headless Shell for rendering; earshot 0.3+ (optional, in its own virtualenv) renders the sound kit and listens to the soundtrack. Works with Remotion 4 (React) or HyperFrames (HTML and GSAP).
---
# cinetic
You are directing a short film, not animating a web page. Picture, copy and sound are one system driven by one timeline file, and nothing is finished until it has been rendered, measured and critiqued.
- **Engines.** Remotion 4.0.529 (React, frame-driven) is the default. HyperFrames 0.8.79 (HTML plus a paused GSAP timeline) is the alternative. The craft is engine-independent; §7 lists the rules that differ per engine.
- **Numbers.** Every number here is a proven default from shipped work: a starting point that you can move away from when you have a stated reason. It is not a law of nature.
- **Brand.** When the user supplies a brand (colours, fonts, logo, footage, tone), the brand wins. The taste defaults cover the parts you have to invent.
- **Paths.** Paths such as `scripts/render.sh` work from the skill root and also inside a film project, because `scripts/new-film.sh` copies every script into the project. Every script except the internal helpers `brand-svg.ts` (which `brand-kit.sh` calls) and `hf-preflight.cjs` (which `hf-finish.sh` runs) prints `--help`.
- **Worked example.** `references/worked-example.md` walks through Tessel, a 33 s launch film at 1920×1080 and 60 fps, and shows each rule below in use, including the mistakes. Read it once before your first film.
## The bar
The target is a film people watch twice: one idea the product owns, told in pictures, where every frame looks chosen and nothing is there to fill space.
- **Substance before polish.** Show the specific, clever thing this product does, the thing a simpler product wouldn't. Flawless motion around a generic claim still loses to a rough film that makes the viewer think "oh, that's smart".
- **Its own look.** Every brand gets a visual language derived from its name, its product and its personality, inside the Hard bans below. Restraint means no decoration; it does not mean one minimal house style for everything.
- **Ultra clean and smooth.** Clean, modern frames, with creative ideas and choreography. Every move is eased, weighted and smooth at 60 fps: no jitter, no pops and no effects standing in for ideas.
- **Visual, not narrated.** The idea reads with the sound off; the words confirm what the picture already said.
- **Weight and stillness.** Motion has mass, arrives on the beat and then rests, so the fast moments land.
- **Sound that makes the picture feel better:** every hit is caused by something you can see.
- **Restraint over decoration.** When in doubt, remove.
- **Proof, not impression.** The process below exists because none of this can be judged in the editor or the Studio: you only know once you have watched the actual render and measured it.
## Hard bans
When you invent the look, none of these appear, ever. They are the fastest tells of generated work, and this skill exists to make films that don't look generated. `lint-film.mjs` checks the tokens and styles for them, and the critics check the frames.
- **Words:**
- eyebrow or kicker labels above a headline;
- stacked taglines, and "Introducing…";
- full sentences dumped at once: copy arrives as short fragments, one after another, with picture between them (§4, "Text flow");
- text walls, and random filler text: decorative mono captions, fake metrics, labels nobody needs, lorem ipsum.
Every word on screen earns its place.
- **Type:** serif typefaces, and italic or oblique styles, including a skew that fakes one. Use one clean, modern sans, plus a mono for code or numbers if the product needs one.
- **Colour:**
- orange, amber, beige, cream, tan or sand, as an accent, a paper or a glow;
- neon: very bright, saturated accents, glows, bloom and halos;
- purple, violet or indigo, and purple-to-blue or any multi-hue gradient;
- glassmorphism.
- **Decoration:**
- emoji and stock icons;
- sparkles standing for "AI", particles, confetti, lens flares and code rain;
- bouncy overshoot on anything that isn't landing, and any overshoot or per-letter trick on copy (only the one hero word may move letter by letter).
What remains is plenty: ink and paper (light or dark, neutral or cool), one accent with a meaning from any hue family outside the banned ones (red, green, teal, blue, yellow), one sans, and motion that is ultra clean and smooth, eased, weighted, motion-blurred and free of jitter. The creativity goes into the idea, the device and the choreography, not into effects.
If the user supplies a brand that includes one of these (their serif wordmark, their orange), the brand wins, because it is their identity rather than a default. Record it in `BRIEF.md` so the critics don't flag it, and mark the lines that set it with `// cinetic:brand-supplied <what>` so the lint accepts them.
## 1. Formats and defaults
Choose a row first. It sets the length, the density and the list of files to deliver. The recipe for each format is in `references/formats.md`. The numbers are the calm pace, the default; a brief that asks for energy (a teaser, a drop, a hype cut) opts into the crisp profile (§5), which is faster and allows a little more text (fragments up to 5 words, up to 10 visible) but still never a sentence dumped at once.
| Format | Length | fps | Grid (BPM) | Story beats | Words: total · new per fragment · visible at once | Sound | Deliverables |
|---|---|---|---|---|---|---|---|
| Launch film / teaser | 20–45 s | 60 | 100 (crisp 120) | 6–8 per 30 s (crisp 8–10) | 15–25, cap 30 · ≤ 4 · ≤ 8 (≤ 5 in replace mode) | full score + SFX | 16:9 master, 9:16 and 1:1 re-layouts, poster, brand kit if invented |
| Product / feature video, update film | 8–30 s | 60 | 100 | 1 capability per 8–10 s | ≤ 12 · ≤ 4 · ≤ 8 | UI SFX; calm: effects only at −18 LUFS (a light bed only when the brief wants a groove) | master, poster |
| Feature loop | 4–15 s, whole bars | 60 (GIF 25) | any; whole bars | 3–5 | ≤ 6, reads muted · ≤ 4 · ≤ 4 | optional | MP4, WebM, GIF, seamless seam |
| Logo sting | 3–8 s | 60 | 100–120 | 2–4 | name + ≤ 3 · ≤ 3 · name + 3 | one tuned hit + tail | MP4, ProRes 4444 alphas (held and cleared), poster, brand kit if invented |
| UI walkthrough | 20–90 s | 60 | 90–100 | 1 chapter per 2–4 bars | ≤ 5 per caption · ≤ 4 · one caption | bed + UI SFX | master, SRT captions |
Use 60 fps whenever UI, text or the camera moves. At 30 fps slow drifts visibly step and fast moves strobe, and 24 fps is never right for UI. A GIF is the one exception: export it at 25 fps (or 50) from the 60 fps master, because GIF frame delays are whole hundredths of a second and 30 fps plays 11% fast.
## 2. The five laws
1. **One idea, specific to this product.** You can say the film in one sentence, and the proof shows what this product does that the obvious or simpler version wouldn't. Restraint applies to decoration and copy, never to the product's intelligence: if the feature is smart, the film shows the smart part. *Why:* a viewer carries away one thing, and a film that would be equally true of a competitor, or of a dumber feature, gives them nothing to carry.
2. **One story device.** An object, shape or colour travels through every shot and never blinks out at a cut. In a launch film it ideally resolves into the mark at the end; in a feature loop or product video it is the unit the product acts on (the card, the row, the file). Find the object this product owns. A bare dot, line or block is the lazy default, and it is also the look of this skill's own examples. *Why:* it makes the film continuous, it lets the film read with the sound off, and an owned object is what makes the film unmistakably this brand's.
3. **One accent with one meaning.** The accent is a single token that means one thing, such as "now", "new" or "yours". Use it sparingly (about ≤ 8% of pixels) and let it flood the frame at most once. *Why:* a colour that means something is read without words, and a colour used everywhere means nothing.
4. **One house motion system.** Use a few named curves and springs, each for a stated reason, and take every frame number from `timeline.ts`. *Why:* consistent motion *is* brand motion, and ad-hoc eases read as generated.
5. **Verify by measurement.** A film is done only when the rendered pixels and the decoded audio pass the scripts and one round of critique. *Why:* Studio playback hides pops, ghost frames, sync slips and colour shifts that the encoded file will show.
## 3. Workflow
Every step writes a file, and every gate is a check you actually run. Work inline. Subagents are for critique only (§8), because building frames in parallel costs more time than it saves.
### Step 0: Intake → `BRIEF.md`
- If the brief already states the product, the message and the length, infer everything else and write your assumptions down.
- If it doesn't, ask at most 3 questions: the product in one line, the format and length, and where the film will be shown. Take everything else from §1.
- Choose the engine: Remotion by default; HyperFrames if the user already has a HyperFrames project, wants HTML/GSAP, or needs `--batch` renders driven by variables.
- Copy the hard bans (above) into `BRIEF.md`, plus any brand-supplied exceptions. Critics are later prompted with this file word for word, so it doubles as the QA contract.
- Choose the pace: calm (the default) unless the brief asks for energy; write it into the spec line. Crisp is an explicit opt-in (§5).
- Scaffold the project: `bash <skill>/scripts/new-film.sh films/<name> --fps 60 --size 1920x1080 [--engine hyperframes]`. It keeps the starter's own tempo (Remotion 100 BPM, HyperFrames 120) and the calm pace; add `--pace crisp` for a crisp film (120 BPM and the crisp pace), or `--bpm N` for another tempo. Pass `--link-modules <dir>/node_modules` to reuse an existing install instead of running `npm install` (a junction on Windows).
- **Gate:** `BRIEF.md` has a spec line, for example `1920x1080@60, 30s, 100BPM, pace: calm, audio: earshot kit (calm), no music`.
### Step 1: Concept → `TREATMENT.md`
Read `references/concept-and-story.md` now.
- Start from specifics, not from style. Write down:
- what the name means or evokes (it often hands you the mark and the device);
- the feature's non-obvious behaviour, finishing the sentence "unlike the obvious version, it…";
- the product's own objects (its rows, cards, readings and states).
- Write 3 concepts, each through a different lens:
- (a) the product's own verb or metaphor made literal;
- (b) the viewer's pain made visible;
- (c) a formal device: a relay object, a bookend, one unbroken camera move, or a container that becomes the product.
- Throw out any concept whose props could appear in another product's film. It isn't yours.
- **Draw the techniques; don't choose them.** Run `python3 scripts/pick.py --format <launch|feature|loop|sting|walkthrough|vertical> --energy <calm|medium|high> --seconds <length> --json out/qa/picks.json`, with `--energy calm` unless the brief asks for energy. It draws about one technique per 3.5 s of film when calm and per 2.5 s otherwise (9 or 12 for a 30 s launch, at least 4 for a short piece) from the measured library in `assets/library/techniques.json`, in the order the format needs them, weighted toward proven moves and the film's energy, and prints each recipe with default timing. Choosing by hand converges on the same fade-up, push-in and end card in every film; the draw is how two films stop looking alike. Build the picks the concept can carry, retold in its objects and device; the story, product truth and one consistent UI language come first, and a film that crams in every move reads as a showreel. Reroll a pick that fights the concept at most twice (`--category <cat> --exclude <id>`), or drop it, with a written reason; never add a technique the draw did not give you (draw one with `--category`), and pass `--brand-supplied <look>` when the brand owns a banned look. Read a drawn entry in full with `pick.py --show <id>`; `references/technique-library.md` lists every entry (search it, don't read it whole). Measured pacing, easing and text-timing norms are in `references/craft-rules.md`.
- Fill in `assets/TREATMENT.md` for the concept you chose:
- a logline;
- the arc: hook (inside the problem, felt by 1 s) → turn → proof (1–2 capabilities) → promise → lockup;
- the drawn techniques with the seed line, each placed in a beat (§3b of the template);
- the device path, shot by shot;
- a beat sheet with the columns bar | time | picture | copy (fragment, mode) | picture beat | sound: every thought of more than 4 words written as a chain of fragments, each with the picture beat it hands over to;
- the full copy with its word count;
- the final frame.
- Run the deletion test. Remove the demo beats, and the value should still read. Remove the value beats; if the film still "works", it was a feature tour.
- Run the specificity test. Would the film be just as true of a simpler product, for example an even split instead of an itemised one, or a plain list instead of a ranked one? If yes, the proof undersells the product; show the part that is hard.
- Run the feature-word test. Watching muted, would a stranger use the brief's word for the feature ("streak", "split")? If a clever device makes it read as something else, keep the feature's familiar form and let the device dress it.
- **Gate:**
- the logline is ≤ 15 words;
- the specificity test passes, with its answer written down;
- the word count is inside the §1 budget;
- every fragment is 1–4 words; no beat shows more than 8 words of copy (5 in replace mode); every thought of more than 4 words is a chain with a picture beat of 30–90 f between its fragments, and none arrives as one block (a crisp film allows 5 words per fragment and 10 on screen);
- copy is planned on at most about 65% of the runtime (80% in crisp), with a text-free picture stretch of at least 1.5 s in every 10 s;
- the device appears in every beat row, and every drawn technique is placed in a beat or dropped with a reason.
### Step 2: Brand and style frames → `src/brand/`
Read `references/brand-and-color.md` and the type section of `references/copy-and-type.md`.
- The starter's palette, fonts, mark and demo name are stand-ins marked `// cinetic:placeholder`, and `lint-film.mjs` reports an error until every marker is gone. Apply the user's brand, or invent one for this film, then delete the markers. A film that keeps the starter's look looks like every other film made from it.
- **Personality first.** Write three adjectives for the brand, then derive the choices from them. This mapping is in `references/brand-and-color.md` §2:
- the typeface: pick the sans for this brand from `@fontsource-variable/*` and vendor it with `node scripts/add-font.mjs <name>` (safe with a shared `node_modules`); Geist is only the starter's stand-in;
- weight and case;
- the stage (light or dark: a dev tool or a fire-named brand often wants dark), neutral or cool, and the accent's hue from the allowed families;
- the motion character, from crisp to unhurried.
A calm notes app and a fast CI tool should not share a look.
- Write `src/brand/tokens.ts` (`python3 scripts/palette.py --accent '#…' --stage dark` builds the neutrals, checks contrast and refuses a banned hue):
- colours: an ink, a paper, 2–4 neutrals, and one accent with its meaning in a comment;
- type: one family at 2 weights, plus a mono if you need one;
- a type scale;
- one tracking value per role.
- **Explore the mark before you commit to one.**
- Sketch 6–10 directions, each from a different source: the name's meaning, a letterform, the product's own object, the idea's metaphor, and a pure geometric construction.
- Render them together on one sheet and look at it (the `MarkSheet` still in `references/brand-and-color.md` §4).
- Reject any direction that could belong to ten other startups, including the "geometric block + accent dot" family, which is this skill's own example vocabulary.
- Run the misread test. Show the mark at 64 px for half a second. If it reads first as a common symbol (a minus, an emoticon, a menu or hamburger icon, a padlock, a play button, a plus), reject it or change it until it doesn't.
- Build the winner in `src/brand/Mark.tsx` on a 100-unit grid, with gaps of at least 8 units so it survives being scaled down.
- **A palette with character, inside the bans.** Derive it from the world of the name and the product (a hillside gives pine, moss and slate; a foundry gives charcoal, soot and a glowing red), not from framework defaults. When the name's world is heat or fire, orange is banned, so go red-hot (a deep red glowing on a true charcoal) or white-hot, never generic dev-tool blue: the colour must carry the name. A blue-grey near-black stage is the stock dev-tool dark theme (`palette.py` notes it), and in a dev tool red UI tags read as errors; spend the red on the brand's own thing.
- Framework blues (the `#3B82F6` / `#2563EB` family) and flat pure greys read as "default".
- Tint the neutrals toward the world, with a cool green-grey or a blue slate; a dark stage can be pine-black or ink-navy rather than `#000`.
- `references/brand-and-color.md` §8–10 has worked palettes.
- **Set the lockup like a typographer.** Render three settings side by side (mark-to-cap ratio, gap, weight, tracking) and pick the one where the mark and the word read as one object. A carelessly set wordmark costs more than any animation gains.
- Render 2–4 one-frame style stills from the `Stills` folder and look at them: the mark at 16 px and at full size, one statement frame, and one product frame. `npm run stills` renders the mark stills; add your own with `npx remotion still <StillId> out/stills/<name>.png`.
- **Gate:**
- the stills pass §4;
- the mark sheet and the chosen direction's reason are in `TREATMENT.md`;
- `node scripts/lint-film.mjs src` reports no placeholder and no colour or font that is not a token.
### Step 3: Timeline → `src/timeline.ts`
Read `references/timing-grid.md` now.
- Choose BPM and fps so that a beat is a whole number of frames (see §5).
- Map the beat sheet onto bars:
- `ACT` holds contiguous, bar-aligned acts;
- `CUE` holds named frames that sit on the grid;
- `COPY` holds one `{id, text, in, resolved, out}` entry per fragment: `line(id, text, in)` for a single fragment, `chain(id, 'build' | 'replace', [[text, inFrame], …])` for a thought in several (it adds `chain` and `mode` and times each fragment from the pace);
- `TOTAL` includes a tail of at least 60 f.
- Give each bar one motion peak, and let text and the hero action take turns on the grid.
- **Gate:** `npx tsx scripts/grid-check.ts src/timeline.ts` passes (`npm run check` runs it together with `tsc` and the lint). It checks the grid (every cue on the 16th grid or carrying an `offgrid:` reason), the reading holds, the event gap (no stretch past 72 f without an event or a reading hold; 48 f in crisp), the word budget, and the text flow, all against the film's `PACE_NAME` (`--pace` overrides it): `fragment` (words per entry), `copy-concurrent` (words visible on any frame, a leaving fragment counted until its exit is over), `read-first` (two separate lines never arrive together), `reveal-rate`, `chain-gap` (each fragment read before the next, with 30–90 f of picture between), `chain-beat` (a cue really happens in that picture beat), `read-quiet` (no cue starts inside a read), `word-rate` and `text-share`. In a calm film a missing or short picture beat, two lines arriving together and copy on more than 75% of the body are errors, not warnings. A HyperFrames project runs it on its `timeline.js`: `node scripts/grid-check.ts timeline.js`.
### Step 4: Build, act by act → `src/acts/`
Before you write motion, read `references/motion-tokens.md`, `references/camera.md`, `references/transitions.md`, and `references/product-ui.md` if the product appears. Keep `references/chromium-rendering.md` open while you debug.
- Make each act a pure function of `useCurrentFrame()`. Mount one `<Sequence>` per act in `Film.tsx`, and register each act as its own composition in the `Acts` folder so you can iterate on it alone.
- Take all motion from the tokens in `src/lib/anim.ts` (§6). A raw bezier inside an act is a lint error, because that is how a house style decays.
- Build the product UI from real components fed by one `data.ts` module with asserts on dates, weekdays, counts, plurals and sums. The data must agree with the story too: the person who paid doesn't owe, a "sorted" list is actually sorted, a stated ratio matches its numbers, and no number appears twice in one frame. That holds in every frame, in-between states included: a copy headed "owes Maya" over the whole bill's total is a wrong number on screen for as long as it shows. Frame the UI large enough to read on a phone: push in 2–5× on every interaction that carries the story, and hold a wide shot of readable UI for at most about 1.7 s. Every bar, segment, chart or bare number that carries meaning shows its value, label or unit: a row of "18 24 12 31" under M–S reads as dates, not pages. A screenshot never carries the hero shot.
- Make the product and the feature identifiable. Name the feature once, as a UI label, the one line of copy or the end card, and show enough real app chrome that a stranger knows this is software. "No feature name as a headline" never means "never name it". A feature label is not a payoff: land the value with one short line that makes it human ("Sam had the salad."), even in a muted loop.
- Frame only the meaningful part of the product. No half-empty grids, no tables cropped at the frame edge, no rows of blank cells: they read as a spreadsheet, not a product.
- Text that must be read stays readable in motion. Text being read (between its `resolved` and `out` frames) moves at most about 3 px/f, and at least 0.3 px/f of drift or a slow creep keeps it alive; a camera cruise under it runs 1.5–3 px/f. Keep labelled chips and numbers under about 20 px/f while they travel, or fly them with the text faded and let it resolve on landing, because motion blur on small text reads as a double image.
- Words reach the screen through `COPY` only: render statements with `src/fx/Chain.tsx` or `Words` from `copy(id)`, never a string literal in an act (`lint-film.mjs` flags `copy-literal`, `text-spring`, `text-pace`, `typing-rate` and `per-letter`).
- Moving elements never cover text they pass over: plan the paths and the z-order, and check the densest frames at full size.
- A progressive text reveal (letter by letter or with a sweep) must never spell a different word partway through ("tarn" briefly reading "tar"), and never shows part of a glyph: a soft wipe through an "n" reads as an "r" ("halder"). Step the mask from glyph edge to glyph edge on whole frames, or reveal whole words, and check the intermediate frames.
- Export from its act every frame the sound needs, as a named constant (for example `LANDINGS` or `SNAP`), so the cue export can import it.
- Wrap everything in `<FontGate>`.
- Iterate each act in this loop:
1. Render stills at each cue −2, 0 and +2.
2. Make an act contact sheet: `python3 scripts/sheet.py --comp Act2 --every 2 --out out/qa/act2.png` renders the act and tiles it with frame and time labels. Use `--every 2` for fast sections.
3. Run `bash scripts/layout-audit.sh Act2 --cues`.
- **Gate:**
- `lint-film.mjs` is clean;
- `layout-audit` reports 0 safe-area, overlap or `words` violations (no frame with more readable film words than the pace allows; product strings carry `data-ui` and count apart) and no readable text faster than 20 px/f; on the act sheets, text being read moves at most about 3 px/f;
- every act sheet has written review notes.
### Step 5: Sound → `public/audio/soundtrack.wav`
Read `references/sound.md` now.
- Run `npx tsx scripts/export-cues.ts`, which writes `out/cues.json`. Sync points are computed from the picture code (spring contact frames, 50% pop frames, velocity peaks, 97% settles, a fragment's resolve frame) and never typed by hand. Typed sync points landed 8–11 f off in practice.
- Pick the sound's personality row in `references/sound.md` §5.5a first, and with it the kit preset: `calm` (the starters' default) for calm brands and text-led films, `crisp` for fast and raw ones, `minimal` for precise, expensive ones (`python3 scripts/audio/kit.py init --preset crisp --force`). Drops onto silence and sub booms are for energetic launch films only.
- **The effects come from the earshot kit** (`audio/kit.json`, §1 of `sound.md`): one bank sound per role, rendered into `audio/kit/` with measured sync points. Run `python3 scripts/audio/kit.py render` (`npm run kit`, cached) and `kit.py check`; `kit.py tune` moves the tonal roles to `score.json`'s key after the key changes. Without earshot, `score.py` plays the takes already rendered in `audio/kit/`, and with none it falls back to its synth voices with a loud warning: install earshot (`docs/setup.md`) rather than ship on them.
- **Text gets one soft sound per fragment** (a `text` cue on the frame it resolves), never one per word, and what was just said is read in near-silence (§5.7). **The lockup is a stop-down and ONE clean element:** nothing in the 0.2–0.7 s before it, one `hit` on the frame the wordmark becomes readable (its `settleOf`), no whoosh into it and no snap, bell or motif on top. `score.py`'s stack guard warns on anything else within ±3 f.
- **Music only when the film wants a groove.** A calm, text-led film keeps `"music": "none"` (effects only, mastered at −18 LUFS); otherwise make the music drive the picture, whatever the personality:
- A motif that follows the story's progress, for example one tuned note per step climbing the scale (`progress` in `score.json`; under the calm kit give the steps `"kind": "bell"`, its tuned voice: the calm pop, tick, click and light landing are untuned taps and cannot climb).
- Section changes and the hero reveal land with the music's own event (drop, stop, re-entry). Designed effects go on discrete state changes only, about 5 per 10 s, clustered where the music is sparse; continuous motion and most cuts get none.
- The drop on the hero reveal, 30–60% in, is the loudest moment, and `payoff` points there. The lockup is the most resolved moment, not the loudest: the music stops on a bar line or filters down as the logo forms, then the one element and a 0.5–2.5 s tail. A sting is all lockup: its hit is its loudest moment.
- The sound enters with intent on frame 0 (a drone or a 150–450 ms entry at most), without a click, and runs 5–12 LU under the body for the first 2–3 s. That assumes frame 0 moves: a drone at full level over a still frame (an empty page, a blinking caret) reads as a mistake, so move the picture, not the sound.
- Fill in `audio/score.json`: key, `music`, and with music one chord per bar, sections (with a breakdown or stop about 5 LU down at 40–80% of the runtime), drops and silences (or a `bed`: a real track). Keep `"typing": "auto"` unless the brand asks otherwise.
- Run `python3 scripts/audio/score.py --cues out/cues.json --score audio/score.json --out public/audio/soundtrack.wav --stems out/stems --json out/qa/score.json` (`npm run audio`). The stems let `av-audit.py` check each sound against its cue; the master chain lives in `scripts/audio/master.py`.
- With earshot, run `python3 scripts/audio/listen.py` (`npm run listen`): earshot's timeline, sound sheet and critique in one process, into `out/qa/listen.json` and `out/qa/sound_sheet.png` (§9.1). Read the cue sync first and open the sheet.
- **Gate:**
- the WAV measures its target ±0.5 LUFS integrated (`master.lufs` in `audio/score.json`; without it −14 with music and −18 for an effects-only film; −16 only for a sting with music that plays at the head of other videos), with true peak ≤ −1.5 dBTP before encoding and the limiter under 1.5 dB at the payoff;
- the report's `sfx` line names the earshot kit (not `synth (fallback)`), `kit.py check` is clean, and no `stacked`, `rising` or `has no take on` warning is left;
- a film with music of 20 s or more has contrast: LRA 5–8 LU, and the payoff 2–3 LU above the median momentary loudness (`score.py` warns);
- every sound has something visible that causes it, at a loudness that matches that cause (a caret blink whispers; the hero reveal drops); not every picture event gets a sound, but once a class of action is sounded every instance is, at one level.
### Step 6: Render and finish → `out/film.mp4`
Read `references/finishing.md`...
© Leonxlnx · MIT · Leonxlnx/cinetic