creator-editing-studio 1.0.20260930 → 1.0.20261002
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/CLAUDE.md +233 -226
- package/template/STYLE.md +179 -165
- package/template/templates/STYLE.md +179 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "creator-editing-studio",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20261002",
|
|
4
4
|
"description": "Scaffolds a Creator Editing OS studio — components, scripts and rules for editing video from a plain-English brief.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
package/template/CLAUDE.md
CHANGED
|
@@ -48,250 +48,257 @@ Everything else in `src/design/` is the system and should be left alone. If a vi
|
|
|
48
48
|
a colour or a size that is not in tokens.ts, the answer is to add it to tokens.ts, never to
|
|
49
49
|
type it into a component.
|
|
50
50
|
|
|
51
|
-
## Non-negotiables
|
|
52
|
-
|
|
53
|
-
1. **No magic numbers.** Durations, curves, springs, staggers, blur come from `src/design/motion.ts`.
|
|
54
|
-
Colours, fonts, sizes, spacing come from `src/design/tokens.ts`. If a needed token does not
|
|
55
|
-
exist, add it to the token file (with a comment) instead of inlining a value.
|
|
56
|
-
2. **Timing derives from the spine.** Animation start frames come from word timestamps, beats,
|
|
57
|
-
or other elements' timings via helpers — never hand-typed frame numbers.
|
|
58
|
-
3. **`npm run check` and `motion-check --scale=2` must pass** before any render is shown to the user.
|
|
59
|
-
4. **Verify visually before claiming done** (see Verification). Never say something "looks good"
|
|
60
|
-
without having rendered and viewed the frames.
|
|
61
|
-
|
|
51
|
+
## Non-negotiables
|
|
52
|
+
|
|
53
|
+
1. **No magic numbers.** Durations, curves, springs, staggers, blur come from `src/design/motion.ts`.
|
|
54
|
+
Colours, fonts, sizes, spacing come from `src/design/tokens.ts`. If a needed token does not
|
|
55
|
+
exist, add it to the token file (with a comment) instead of inlining a value.
|
|
56
|
+
2. **Timing derives from the spine.** Animation start frames come from word timestamps, beats,
|
|
57
|
+
or other elements' timings via helpers — never hand-typed frame numbers.
|
|
58
|
+
3. **`npm run check` and `motion-check --scale=2` must pass** before any render is shown to the user.
|
|
59
|
+
4. **Verify visually before claiming done** (see Verification). Never say something "looks good"
|
|
60
|
+
without having rendered and viewed the frames.
|
|
61
|
+
|
|
62
62
|
---
|
|
63
63
|
|
|
64
|
-
## The 12 motion laws
|
|
65
|
-
|
|
66
|
-
1. **No linear easing** — except constant-velocity loops/scrolls (mark with `// motion-ok`).
|
|
67
|
-
2. **Entrances ease-out (`EASE.out`), exits ease-in (`EASE.in`), on-screen A-to-B moves ease-in-out (`EASE.inOut`).**
|
|
68
|
-
3. **Exits are faster than entrances** — `EXIT_RATIO` (0.65). Use `exitFrames()`.
|
|
69
|
-
4. **Max 2–3 animated properties per element.** No fade + scale + rotate + blur together.
|
|
70
|
-
5. **Never opacity alone.** Pair with 8–24px travel or scale >= 0.94. Opacity completes at
|
|
71
|
-
`OPACITY_LEAD` (60%) of the transform.
|
|
72
|
-
6. **Never scale from below 0.9.** Text scaling from zero is the #1 AI-edit tell.
|
|
73
|
-
7. **Blur-in capped at 12px**, fully resolved before the transform ends.
|
|
74
|
-
8. **Groups always stagger** (`STAGGER.tight/normal/dramatic`). Never simultaneous.
|
|
75
|
-
9. **Distance couples to duration sub-linearly** (`travelFrames()`), never linearly.
|
|
76
|
-
10. **Anything that moves fast is motion-blurred** (see Smoothness system). No hard edge may jump
|
|
77
|
-
across the frame unblurred.
|
|
78
|
-
11. **Readable hold:** text stays fully visible >= `readFrames(text)` (min 0.9s, +55ms/word).
|
|
79
|
-
12. **Continuity:** every transition inherits the outgoing motion (see below).
|
|
80
|
-
|
|
81
|
-
### Continuity (what makes it feel connected, not cut together)
|
|
82
|
-
|
|
83
|
-
- **Shared elements never re-enter.** If an element exists across two beats, `morph()` its
|
|
84
|
-
position/size/radius between layouts; never exit and re-animate it. (TransitionTest: the
|
|
85
|
-
eyebrow dot stays on screen and grows into the next card's icon tile.)
|
|
86
|
-
- **Velocity handoff.** An exit toward a direction is answered by an entrance continuing that
|
|
87
|
-
direction — `handoff(exitTo)`.
|
|
88
|
-
- **Overlap, never gap.** The next beat starts before the previous one settles —
|
|
89
|
-
`nextBeatAt(prevSettled)`.
|
|
90
|
-
- **One camera over cuts.** Lay scenes out on one canvas and glide a camera between them
|
|
91
|
-
(`src/lib/camera.ts`) instead of hard-cutting between unrelated layouts. Content that should
|
|
92
|
-
stay put during a move (shared elements) lives in screen space, outside the camera.
|
|
93
|
-
- **Nothing is cut off.** Compute exit start times backward from the end so the slowest,
|
|
94
|
-
most-staggered exit completes on or before the last frame.
|
|
95
|
-
- **Sound glues cuts.** Whooshes start `TRANSITION.sfxLeadMs` before a visual change and tail
|
|
96
|
-
`sfxTailMs` after.
|
|
97
|
-
|
|
64
|
+
## The 12 motion laws
|
|
65
|
+
|
|
66
|
+
1. **No linear easing** — except constant-velocity loops/scrolls (mark with `// motion-ok`).
|
|
67
|
+
2. **Entrances ease-out (`EASE.out`), exits ease-in (`EASE.in`), on-screen A-to-B moves ease-in-out (`EASE.inOut`).**
|
|
68
|
+
3. **Exits are faster than entrances** — `EXIT_RATIO` (0.65). Use `exitFrames()`.
|
|
69
|
+
4. **Max 2–3 animated properties per element.** No fade + scale + rotate + blur together.
|
|
70
|
+
5. **Never opacity alone.** Pair with 8–24px travel or scale >= 0.94. Opacity completes at
|
|
71
|
+
`OPACITY_LEAD` (60%) of the transform.
|
|
72
|
+
6. **Never scale from below 0.9.** Text scaling from zero is the #1 AI-edit tell.
|
|
73
|
+
7. **Blur-in capped at 12px**, fully resolved before the transform ends.
|
|
74
|
+
8. **Groups always stagger** (`STAGGER.tight/normal/dramatic`). Never simultaneous.
|
|
75
|
+
9. **Distance couples to duration sub-linearly** (`travelFrames()`), never linearly.
|
|
76
|
+
10. **Anything that moves fast is motion-blurred** (see Smoothness system). No hard edge may jump
|
|
77
|
+
across the frame unblurred.
|
|
78
|
+
11. **Readable hold:** text stays fully visible >= `readFrames(text)` (min 0.9s, +55ms/word).
|
|
79
|
+
12. **Continuity:** every transition inherits the outgoing motion (see below).
|
|
80
|
+
|
|
81
|
+
### Continuity (what makes it feel connected, not cut together)
|
|
82
|
+
|
|
83
|
+
- **Shared elements never re-enter.** If an element exists across two beats, `morph()` its
|
|
84
|
+
position/size/radius between layouts; never exit and re-animate it. (TransitionTest: the
|
|
85
|
+
eyebrow dot stays on screen and grows into the next card's icon tile.)
|
|
86
|
+
- **Velocity handoff.** An exit toward a direction is answered by an entrance continuing that
|
|
87
|
+
direction — `handoff(exitTo)`.
|
|
88
|
+
- **Overlap, never gap.** The next beat starts before the previous one settles —
|
|
89
|
+
`nextBeatAt(prevSettled)`.
|
|
90
|
+
- **One camera over cuts.** Lay scenes out on one canvas and glide a camera between them
|
|
91
|
+
(`src/lib/camera.ts`) instead of hard-cutting between unrelated layouts. Content that should
|
|
92
|
+
stay put during a move (shared elements) lives in screen space, outside the camera.
|
|
93
|
+
- **Nothing is cut off.** Compute exit start times backward from the end so the slowest,
|
|
94
|
+
most-staggered exit completes on or before the last frame.
|
|
95
|
+
- **Sound glues cuts.** Whooshes start `TRANSITION.sfxLeadMs` before a visual change and tail
|
|
96
|
+
`sfxTailMs` after.
|
|
97
|
+
|
|
98
98
|
---
|
|
99
99
|
|
|
100
|
-
## Smoothness system (every one of these was a real defect found by motion-check)
|
|
101
|
-
|
|
102
|
-
- **Use the components, not raw transforms.** `<Presence>`, `<MaskReveal>`, `<HighlightMark>`,
|
|
103
|
-
`<RollingNumber>` add velocity motion blur automatically. Anything else that moves wraps its
|
|
104
|
-
moving element in `<VelocityBlur vx vy>` with `perFrame()` velocities.
|
|
105
|
-
- **Velocity motion blur** (`VelocityBlur`): directional blur sized to this frame's movement with
|
|
106
|
-
a 180-degree shutter; fades to zero as the element settles. Near-free to render.
|
|
107
|
-
- **Wipes** use `wipeMask(p, perFrame(...))`: the leading edge softens with speed. Never wipe with
|
|
108
|
-
a hard `clipPath` edge.
|
|
109
|
-
- **Camera moves**: wrap the camera canvas in a full-frame `VelocityBlur` with `bleed={0}` and
|
|
110
|
-
`overflow: hidden`, velocity from `cameraShot` (see TransitionTest).
|
|
111
|
-
- **Zooms / rotations** (not translations): use `<MotionBlur active>` (temporal sampling, centred
|
|
112
|
-
on the frame so toggling it never shifts timing). It costs 10x render time while active —
|
|
113
|
-
enable only during the move. Never use `@remotion/motion-blur`'s `CameraMotionBlur`: it samples
|
|
114
|
-
ahead of the frame, so switching it on/off causes a timing hitch.
|
|
115
|
-
- **Counters roll, never tick.** Use `<RollingNumber>`. A counting number changes glyphs in single
|
|
116
|
-
frames as it slows, which motion-check flags as pops.
|
|
117
|
-
- **Never `will-change`.** It makes each parallel render tab cache text at a different sub-pixel
|
|
118
|
-
position, so settled elements flicker between 4 versions. (Lint enforces this.)
|
|
119
|
-
- **Screen recordings used as b-roll usually scroll in steps** (they judder). Use a still frame with a
|
|
120
|
-
smooth `ScreenView` pan instead, and blur names on the still.
|
|
121
|
-
- **Presence `dur` sets entrance AND exit length.** `dur="instant"` makes exits last 3 frames (a snap) —
|
|
122
|
-
for containers that only fade in, use at least `"base"`.
|
|
123
|
-
- **Final renders are supersampled at `--scale=2`**, then downscaled to 1080x1920. At 1x, Chrome
|
|
124
|
-
snaps text to whole pixels, so the slow tail of every ease-out steps ("move 1px, hold, move 1px")
|
|
125
|
-
and motion-check reports stutters. Run motion-check with the same `--scale`.
|
|
126
|
-
- **Frame rate:** match the footage. If footage is 60fps, build at 60 — per-frame jumps halve.
|
|
127
|
-
All tokens are in ms, so compositions work at either rate.
|
|
128
|
-
|
|
100
|
+
## Smoothness system (every one of these was a real defect found by motion-check)
|
|
101
|
+
|
|
102
|
+
- **Use the components, not raw transforms.** `<Presence>`, `<MaskReveal>`, `<HighlightMark>`,
|
|
103
|
+
`<RollingNumber>` add velocity motion blur automatically. Anything else that moves wraps its
|
|
104
|
+
moving element in `<VelocityBlur vx vy>` with `perFrame()` velocities.
|
|
105
|
+
- **Velocity motion blur** (`VelocityBlur`): directional blur sized to this frame's movement with
|
|
106
|
+
a 180-degree shutter; fades to zero as the element settles. Near-free to render.
|
|
107
|
+
- **Wipes** use `wipeMask(p, perFrame(...))`: the leading edge softens with speed. Never wipe with
|
|
108
|
+
a hard `clipPath` edge.
|
|
109
|
+
- **Camera moves**: wrap the camera canvas in a full-frame `VelocityBlur` with `bleed={0}` and
|
|
110
|
+
`overflow: hidden`, velocity from `cameraShot` (see TransitionTest).
|
|
111
|
+
- **Zooms / rotations** (not translations): use `<MotionBlur active>` (temporal sampling, centred
|
|
112
|
+
on the frame so toggling it never shifts timing). It costs 10x render time while active —
|
|
113
|
+
enable only during the move. Never use `@remotion/motion-blur`'s `CameraMotionBlur`: it samples
|
|
114
|
+
ahead of the frame, so switching it on/off causes a timing hitch.
|
|
115
|
+
- **Counters roll, never tick.** Use `<RollingNumber>`. A counting number changes glyphs in single
|
|
116
|
+
frames as it slows, which motion-check flags as pops.
|
|
117
|
+
- **Never `will-change`.** It makes each parallel render tab cache text at a different sub-pixel
|
|
118
|
+
position, so settled elements flicker between 4 versions. (Lint enforces this.)
|
|
119
|
+
- **Screen recordings used as b-roll usually scroll in steps** (they judder). Use a still frame with a
|
|
120
|
+
smooth `ScreenView` pan instead, and blur names on the still.
|
|
121
|
+
- **Presence `dur` sets entrance AND exit length.** `dur="instant"` makes exits last 3 frames (a snap) —
|
|
122
|
+
for containers that only fade in, use at least `"base"`.
|
|
123
|
+
- **Final renders are supersampled at `--scale=2`**, then downscaled to 1080x1920. At 1x, Chrome
|
|
124
|
+
snaps text to whole pixels, so the slow tail of every ease-out steps ("move 1px, hold, move 1px")
|
|
125
|
+
and motion-check reports stutters. Run motion-check with the same `--scale`.
|
|
126
|
+
- **Frame rate:** match the footage. If footage is 60fps, build at 60 — per-frame jumps halve.
|
|
127
|
+
All tokens are in ms, so compositions work at either rate.
|
|
128
|
+
|
|
129
129
|
---
|
|
130
130
|
|
|
131
|
-
## Design rules
|
|
132
|
-
|
|
133
|
-
**Read `STYLE.md` before any design decision.** It is the house style (type scale, layout, motion,
|
|
134
|
-
sound, approved and rejected beats) and wins over anything below or in a reference. Update it
|
|
135
|
-
whenever the user approves or rejects something.
|
|
136
|
-
|
|
137
|
-
- Everything visual comes from `src/design/tokens.ts`, which is yours to define.
|
|
138
|
-
- **Brand essentials:** your display typeface only, at every weight (headlines/stats 800). One accent: accent
|
|
139
|
-
`your accent` on ink and cream/white. No blue, no purple, no serif. Signature emphasis is the accent
|
|
140
|
-
marker behind the key phrase — use `<HighlightMark>`; don't invent other emphasis styles.
|
|
141
|
-
Headlines are short two-part fragments with the payoff highlighted. Numbers are shown raw and
|
|
142
|
-
bold ("$1.3M", "11x") and roll in. Eyebrows are uppercase pills with a accent-ringed dot.
|
|
143
|
-
Radii are generous, shadows soft, buttons/badges pills.
|
|
144
|
-
- Secondary text uses `COLOR.fgSecondary`; `COLOR.fgMuted` fails contrast on cream — decoration only.
|
|
145
|
-
- **User style decisions (first project):**
|
|
146
|
-
- Captions are **crisp white** (`CAPTION` token, tight + soft dark shadow). Never ink text with a light glow.
|
|
147
|
-
Over the cream background white is invisible, so in card layouts captions go **inside the video
|
|
148
|
-
card's bottom edge** on the card's dark scrim (`StageState.scrim`).
|
|
149
|
-
- Big headline text is **accent with a glow** (`HeroBlock` / `HeroTag`, `heroGlow()`).
|
|
150
|
-
- Pointer is a **solid accent arrow** like the reference (`Cursor`), ~68px.
|
|
151
|
-
- Brand logos are **real full-colour logos** (`LogoIcon`, SVG Logos CC0 via `src/design/logos.json` —
|
|
152
|
-
extract only the icons used). Never approximate a logo that isn't in the set; use a neutral
|
|
153
|
-
icon and ask for the official file (Klaviyo is missing).
|
|
154
|
-
- A corner tag (e.g. "11 MINUTES" pill) is removed when the video returns full screen.
|
|
155
|
-
- **Text behind the subject must stay readable:** the head covers only the lower ~20–30% of the
|
|
156
|
-
headline. Head height changes shot to shot (leaning forward lifts it ~80px) — check a still of
|
|
157
|
-
EVERY hero moment and raise the block (`top`; put labels above as `eyebrow`) where needed.
|
|
158
|
-
- Keep accent highlights away from the accent background glow so they don't disappear into it.
|
|
159
|
-
- Stats use proportional figures, not tabular (tabular makes "11" look gappy in your display typeface).
|
|
160
|
-
- **Web design systems do not map 1:1 to video.** Keep colour, font families/weights, type-scale
|
|
161
|
-
ratios, radii, spacing rhythm, iconography and imagery style — but rescale sizes for a
|
|
162
|
-
1080-wide frame viewed on a phone (body roughly 40–48px, not 16px). Web UI components mostly
|
|
163
|
-
do not apply.
|
|
164
|
-
- Respect safe zones: `LAYOUT.safeTop` / `LAYOUT.safeBottom` for Reels/Shorts UI.
|
|
165
|
-
- Text contrast >= 4.5:1 against whatever is behind it, including over footage.
|
|
166
|
-
- Draw graphics in code (SVG/CSS) so every part can animate. Use flat images only for things
|
|
167
|
-
that must be real (logos, screenshots, photos). Avoid AI-generated imagery for anything the
|
|
168
|
-
viewer is meant to look at.
|
|
169
|
-
- Icons: SVG drawn in code or an installed icon library, never image files.
|
|
170
|
-
|
|
131
|
+
## Design rules
|
|
132
|
+
|
|
133
|
+
**Read `STYLE.md` before any design decision.** It is the house style (type scale, layout, motion,
|
|
134
|
+
sound, approved and rejected beats) and wins over anything below or in a reference. Update it
|
|
135
|
+
whenever the user approves or rejects something.
|
|
136
|
+
|
|
137
|
+
- Everything visual comes from `src/design/tokens.ts`, which is yours to define.
|
|
138
|
+
- **Brand essentials:** your display typeface only, at every weight (headlines/stats 800). One accent: accent
|
|
139
|
+
`your accent` on ink and cream/white. No blue, no purple, no serif. Signature emphasis is the accent
|
|
140
|
+
marker behind the key phrase — use `<HighlightMark>`; don't invent other emphasis styles.
|
|
141
|
+
Headlines are short two-part fragments with the payoff highlighted. Numbers are shown raw and
|
|
142
|
+
bold ("$1.3M", "11x") and roll in. Eyebrows are uppercase pills with a accent-ringed dot.
|
|
143
|
+
Radii are generous, shadows soft, buttons/badges pills.
|
|
144
|
+
- Secondary text uses `COLOR.fgSecondary`; `COLOR.fgMuted` fails contrast on cream — decoration only.
|
|
145
|
+
- **User style decisions (first project):**
|
|
146
|
+
- Captions are **crisp white** (`CAPTION` token, tight + soft dark shadow). Never ink text with a light glow.
|
|
147
|
+
Over the cream background white is invisible, so in card layouts captions go **inside the video
|
|
148
|
+
card's bottom edge** on the card's dark scrim (`StageState.scrim`).
|
|
149
|
+
- Big headline text is **accent with a glow** (`HeroBlock` / `HeroTag`, `heroGlow()`).
|
|
150
|
+
- Pointer is a **solid accent arrow** like the reference (`Cursor`), ~68px.
|
|
151
|
+
- Brand logos are **real full-colour logos** (`LogoIcon`, SVG Logos CC0 via `src/design/logos.json` —
|
|
152
|
+
extract only the icons used). Never approximate a logo that isn't in the set; use a neutral
|
|
153
|
+
icon and ask for the official file (Klaviyo is missing).
|
|
154
|
+
- A corner tag (e.g. "11 MINUTES" pill) is removed when the video returns full screen.
|
|
155
|
+
- **Text behind the subject must stay readable:** the head covers only the lower ~20–30% of the
|
|
156
|
+
headline. Head height changes shot to shot (leaning forward lifts it ~80px) — check a still of
|
|
157
|
+
EVERY hero moment and raise the block (`top`; put labels above as `eyebrow`) where needed.
|
|
158
|
+
- Keep accent highlights away from the accent background glow so they don't disappear into it.
|
|
159
|
+
- Stats use proportional figures, not tabular (tabular makes "11" look gappy in your display typeface).
|
|
160
|
+
- **Web design systems do not map 1:1 to video.** Keep colour, font families/weights, type-scale
|
|
161
|
+
ratios, radii, spacing rhythm, iconography and imagery style — but rescale sizes for a
|
|
162
|
+
1080-wide frame viewed on a phone (body roughly 40–48px, not 16px). Web UI components mostly
|
|
163
|
+
do not apply.
|
|
164
|
+
- Respect safe zones: `LAYOUT.safeTop` / `LAYOUT.safeBottom` for Reels/Shorts UI.
|
|
165
|
+
- Text contrast >= 4.5:1 against whatever is behind it, including over footage.
|
|
166
|
+
- Draw graphics in code (SVG/CSS) so every part can animate. Use flat images only for things
|
|
167
|
+
that must be real (logos, screenshots, photos). Avoid AI-generated imagery for anything the
|
|
168
|
+
viewer is meant to look at.
|
|
169
|
+
- Icons: SVG drawn in code or an installed icon library, never image files.
|
|
170
|
+
|
|
171
171
|
---
|
|
172
172
|
|
|
173
|
-
## Compositing: text behind the subject
|
|
174
|
-
|
|
175
|
-
Layer order, bottom to top:
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
background plate (designed, or the original footage)
|
|
179
|
-
text / graphics <- 1–3px blur to sit on the background's focal plane
|
|
180
|
-
subject cutout <- same clip, frame-aligned
|
|
181
|
-
light wrap <- blurred background screened onto the subject's inner edge, 15–30%
|
|
182
|
-
grain + grade <- applied over everything so layers share one look
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
- **The cutout must come from the same clip as its background plate**, frame-aligned. Never
|
|
186
|
-
combine a cutout from one take with footage from another.
|
|
187
|
-
- **Green screen:** key once to a transparent intermediate in `work/` (not per render). Clean up
|
|
188
|
-
with spill suppression, ~0.5px choke, 0.5–1px feather. Temporal smoothing on the alpha
|
|
189
|
-
prevents edge flicker.
|
|
190
|
-
- **Paired clips (the user's standard delivery):** Video 1 = original; Video 2 = the same clip with the
|
|
191
|
-
background replaced by flat green. Use Video 2 **only to build the matte (alpha)** and take the
|
|
192
|
-
subject's colour from Video 1 — this removes green fringe/spill entirely, because the subject pixels
|
|
193
|
-
never touched green. Before building, verify the pair: identical duration, fps, resolution and
|
|
194
|
-
frame count, and that the subject lines up on the same frame (a 1-frame offset makes a halo or ghost).
|
|
195
|
-
Any VFR conform must be applied identically to both. If the background-removal tool can export real
|
|
196
|
-
transparency, that is even better than green.
|
|
197
|
-
- **Supplied cutouts** must have real transparency (ProRes 4444, WebM with alpha, or PNG sequence).
|
|
198
|
-
An MP4 cannot hold transparency — if one arrives, stop and tell the user.
|
|
199
|
-
- Play transparent video with `<OffthreadVideo transparent src={staticFile(...)} />`.
|
|
200
|
-
- Text behind a moving subject gets 0.85–0.95x counter-parallax; static text reads as a sticker.
|
|
201
|
-
- Text should animate in while already partly occluded, not appear fully and then get covered.
|
|
202
|
-
- Pull text colour toward the footage's black/white points; pure white over graded footage looks
|
|
203
|
-
pasted on.
|
|
204
|
-
|
|
173
|
+
## Compositing: text behind the subject
|
|
174
|
+
|
|
175
|
+
Layer order, bottom to top:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
background plate (designed, or the original footage)
|
|
179
|
+
text / graphics <- 1–3px blur to sit on the background's focal plane
|
|
180
|
+
subject cutout <- same clip, frame-aligned
|
|
181
|
+
light wrap <- blurred background screened onto the subject's inner edge, 15–30%
|
|
182
|
+
grain + grade <- applied over everything so layers share one look
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
- **The cutout must come from the same clip as its background plate**, frame-aligned. Never
|
|
186
|
+
combine a cutout from one take with footage from another.
|
|
187
|
+
- **Green screen:** key once to a transparent intermediate in `work/` (not per render). Clean up
|
|
188
|
+
with spill suppression, ~0.5px choke, 0.5–1px feather. Temporal smoothing on the alpha
|
|
189
|
+
prevents edge flicker.
|
|
190
|
+
- **Paired clips (the user's standard delivery):** Video 1 = original; Video 2 = the same clip with the
|
|
191
|
+
background replaced by flat green. Use Video 2 **only to build the matte (alpha)** and take the
|
|
192
|
+
subject's colour from Video 1 — this removes green fringe/spill entirely, because the subject pixels
|
|
193
|
+
never touched green. Before building, verify the pair: identical duration, fps, resolution and
|
|
194
|
+
frame count, and that the subject lines up on the same frame (a 1-frame offset makes a halo or ghost).
|
|
195
|
+
Any VFR conform must be applied identically to both. If the background-removal tool can export real
|
|
196
|
+
transparency, that is even better than green.
|
|
197
|
+
- **Supplied cutouts** must have real transparency (ProRes 4444, WebM with alpha, or PNG sequence).
|
|
198
|
+
An MP4 cannot hold transparency — if one arrives, stop and tell the user.
|
|
199
|
+
- Play transparent video with `<OffthreadVideo transparent src={staticFile(...)} />`.
|
|
200
|
+
- Text behind a moving subject gets 0.85–0.95x counter-parallax; static text reads as a sticker.
|
|
201
|
+
- Text should animate in while already partly occluded, not appear fully and then get covered.
|
|
202
|
+
- Pull text colour toward the footage's black/white points; pure white over graded footage looks
|
|
203
|
+
pasted on.
|
|
204
|
+
|
|
205
205
|
---
|
|
206
206
|
|
|
207
|
-
## Per-video pipeline
|
|
208
|
-
|
|
209
|
-
1. **Ingest:** probe every clip (fps, resolution, colour, alpha).
|
|
210
|
-
- **Phone footage is usually variable frame rate (VFR).** Conform it to constant frame rate
|
|
211
|
-
with ffmpeg before use, or it stutters and drifts out of sync in Remotion.
|
|
212
|
-
- Conform everything to one fps. Never mix frame rates.
|
|
213
|
-
2. **Spine:** word-level timings + music beats -> `work/<video>/spine.json`.
|
|
214
|
-
Cut pauses/filler from word gaps. All animation timing reads from the spine.
|
|
215
|
-
- If the user supplies a script or SRT, it is the **text truth** (spelling, names, brand words):
|
|
216
|
-
force-align that exact text to the audio with WhisperX's aligner. Never use SRT timings
|
|
217
|
-
directly — they are line-level and padded for readability, not word-accurate.
|
|
218
|
-
- With no script, transcribe with WhisperX, then show the transcript for correction before building.
|
|
219
|
-
3. **Cutouts:** key green screen or validate supplied cutouts (see above).
|
|
220
|
-
4. **Beat sheet:** from the script and the user's marked punch lines, write a short plan — which
|
|
221
|
-
moment gets which treatment — and confirm with the user before building.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
207
|
+
## Per-video pipeline
|
|
208
|
+
|
|
209
|
+
1. **Ingest:** probe every clip (fps, resolution, colour, alpha).
|
|
210
|
+
- **Phone footage is usually variable frame rate (VFR).** Conform it to constant frame rate
|
|
211
|
+
with ffmpeg before use, or it stutters and drifts out of sync in Remotion.
|
|
212
|
+
- Conform everything to one fps. Never mix frame rates.
|
|
213
|
+
2. **Spine:** word-level timings + music beats -> `work/<video>/spine.json`.
|
|
214
|
+
Cut pauses/filler from word gaps. All animation timing reads from the spine.
|
|
215
|
+
- If the user supplies a script or SRT, it is the **text truth** (spelling, names, brand words):
|
|
216
|
+
force-align that exact text to the audio with WhisperX's aligner. Never use SRT timings
|
|
217
|
+
directly — they are line-level and padded for readability, not word-accurate.
|
|
218
|
+
- With no script, transcribe with WhisperX, then show the transcript for correction before building.
|
|
219
|
+
3. **Cutouts:** key green screen or validate supplied cutouts (see above).
|
|
220
|
+
4. **Beat sheet:** from the script and the user's marked punch lines, write a short plan — which
|
|
221
|
+
moment gets which treatment — and confirm with the user before building.
|
|
222
|
+
- **Read their saved references first** (`editing_os_references`). They are the whole reason
|
|
223
|
+
the edit should look like theirs rather than like the defaults, and a plan written without
|
|
224
|
+
them is a plan written for anybody. Say which reference each decision came from, so the
|
|
225
|
+
user can see their own taste being applied and correct it when it is being misread.
|
|
226
|
+
- Where references are silent, the defaults in STYLE.md apply. Where references and defaults
|
|
227
|
+
disagree, the reference wins — it is a real preference, and the default is only a sensible
|
|
228
|
+
starting point.
|
|
229
|
+
5. **Build** in `src/compositions/<Video>.tsx` from components + helpers + tokens only.
|
|
230
|
+
6. **Verify** (below), then show the user.
|
|
231
|
+
7. **Sound:** the user adds SFX and music themselves. Deliver a cue list (timestamps of every
|
|
232
|
+
transition and hit, with suggested whoosh start = `TRANSITION.sfxLeadMs` before the change) so
|
|
233
|
+
they can place sounds quickly. Render without music unless asked.
|
|
234
|
+
8. **Render** at `--scale=2`, downscaled to 1080x1920 unless told otherwise.
|
|
235
|
+
|
|
229
236
|
---
|
|
230
237
|
|
|
231
|
-
## Audio standard (audio is half the reel — the user will not accept a bad mix)
|
|
232
|
-
|
|
233
|
-
What went wrong on an early video: the voice itself was bit-for-bit intact (measured against the source),
|
|
234
|
-
but 2.3–3.5s whoosh files and a 2.4s riser kept playing UNDER the speech, which made the voice sound
|
|
235
|
-
wrong. Claude cannot hear, so the mix must be engineered and measured, never guessed.
|
|
236
|
-
|
|
237
|
-
1. **The voice is never touched.** Render the picture `--muted`. The voice in every deliverable is the
|
|
238
|
-
original recording's audio (stream-copied, or at most one encode), plus only a single gain change.
|
|
239
|
-
No limiter, no dynamic normaliser (ffmpeg `loudnorm` single-pass pumps), no repeated AAC encodes.
|
|
240
|
-
2. **Sound effects are short and placed in gaps.** Trim every SFX to what the motion needs (whoosh
|
|
241
|
-
0.4–0.8s, hits 0.3–0.6s) with a 60–120ms fade-out. Nothing longer than ~0.8s may sit under a spoken
|
|
242
|
-
word unless it is at least 24 dB under the voice. Risers go in pauses, not under speech.
|
|
243
|
-
3. **Duck SFX under the voice**: mix with ffmpeg `sidechaincompress` keyed from the voice (SFX drop
|
|
244
|
-
~6 dB while a word is spoken), and high-pass whooshes/impacts around 120–150 Hz so they don't muddy it.
|
|
245
|
-
4. **Measure before delivering** (the window scan in the project folder used `f32le` PCM from ffmpeg):
|
|
246
|
-
voice-vs-mix difference per 0.5s window — any window where SFX energy is within 12 dB of the
|
|
247
|
-
voice while a word is spoken gets fixed. Final: -14 LUFS integrated, true peak <= -1 dBTP, one
|
|
248
|
-
AAC encode at 256k.
|
|
249
|
-
5. **Always also deliver stems + a cue sheet**: `voice.wav`, `sfx.wav` (the placed, trimmed SFX bus),
|
|
250
|
-
and `SFX-CUES.txt` with numbered, timecoded SFX files — so the user can rebalance in Premiere in
|
|
251
|
-
minutes. Picture-only MP4 alongside.
|
|
252
|
-
6. The user picks and judges sounds by ear; Claude says plainly that it cannot hear and asks for
|
|
253
|
-
timecoded audio notes on the first draft.
|
|
254
|
-
|
|
238
|
+
## Audio standard (audio is half the reel — the user will not accept a bad mix)
|
|
239
|
+
|
|
240
|
+
What went wrong on an early video: the voice itself was bit-for-bit intact (measured against the source),
|
|
241
|
+
but 2.3–3.5s whoosh files and a 2.4s riser kept playing UNDER the speech, which made the voice sound
|
|
242
|
+
wrong. Claude cannot hear, so the mix must be engineered and measured, never guessed.
|
|
243
|
+
|
|
244
|
+
1. **The voice is never touched.** Render the picture `--muted`. The voice in every deliverable is the
|
|
245
|
+
original recording's audio (stream-copied, or at most one encode), plus only a single gain change.
|
|
246
|
+
No limiter, no dynamic normaliser (ffmpeg `loudnorm` single-pass pumps), no repeated AAC encodes.
|
|
247
|
+
2. **Sound effects are short and placed in gaps.** Trim every SFX to what the motion needs (whoosh
|
|
248
|
+
0.4–0.8s, hits 0.3–0.6s) with a 60–120ms fade-out. Nothing longer than ~0.8s may sit under a spoken
|
|
249
|
+
word unless it is at least 24 dB under the voice. Risers go in pauses, not under speech.
|
|
250
|
+
3. **Duck SFX under the voice**: mix with ffmpeg `sidechaincompress` keyed from the voice (SFX drop
|
|
251
|
+
~6 dB while a word is spoken), and high-pass whooshes/impacts around 120–150 Hz so they don't muddy it.
|
|
252
|
+
4. **Measure before delivering** (the window scan in the project folder used `f32le` PCM from ffmpeg):
|
|
253
|
+
voice-vs-mix difference per 0.5s window — any window where SFX energy is within 12 dB of the
|
|
254
|
+
voice while a word is spoken gets fixed. Final: -14 LUFS integrated, true peak <= -1 dBTP, one
|
|
255
|
+
AAC encode at 256k.
|
|
256
|
+
5. **Always also deliver stems + a cue sheet**: `voice.wav`, `sfx.wav` (the placed, trimmed SFX bus),
|
|
257
|
+
and `SFX-CUES.txt` with numbered, timecoded SFX files — so the user can rebalance in Premiere in
|
|
258
|
+
minutes. Picture-only MP4 alongside.
|
|
259
|
+
6. The user picks and judges sounds by ear; Claude says plainly that it cannot hear and asks for
|
|
260
|
+
timecoded audio notes on the first draft.
|
|
261
|
+
|
|
255
262
|
---
|
|
256
263
|
|
|
257
|
-
## Verification (required before saying anything is done)
|
|
258
|
-
|
|
259
|
-
Claude cannot watch video. Quality is checked with frames and maths, and the user makes the
|
|
260
|
-
final call at playback speed. Be explicit about that when reporting.
|
|
261
|
-
|
|
262
|
-
1. `npm run check` passes.
|
|
263
|
-
2. `npm run motion-check -- <Comp> --scale=2` reports **no POP, CUT or STUTTER**. Allow intentional
|
|
264
|
-
cuts with `--allow=<frame>`. For each FAST warning, render that frame and confirm the moving
|
|
265
|
-
edge is blurred. Read the motion timeline for dead air and rhythm.
|
|
266
|
-
3. Render stills and **look at them**: first frame, each element mid-entrance, peak-speed frames
|
|
267
|
-
(blur visible), fully settled (crisp), mid-exit, and the **last frame** (clean).
|
|
268
|
-
4. Check: no text collides with the subject's face, safe zones respected, contrast holds,
|
|
269
|
-
no clipped descenders (g, p, y, commas) in masked text.
|
|
270
|
-
5. Report what was verified and what still needs the user's eyes at full speed.
|
|
271
|
-
|
|
264
|
+
## Verification (required before saying anything is done)
|
|
265
|
+
|
|
266
|
+
Claude cannot watch video. Quality is checked with frames and maths, and the user makes the
|
|
267
|
+
final call at playback speed. Be explicit about that when reporting.
|
|
268
|
+
|
|
269
|
+
1. `npm run check` passes.
|
|
270
|
+
2. `npm run motion-check -- <Comp> --scale=2` reports **no POP, CUT or STUTTER**. Allow intentional
|
|
271
|
+
cuts with `--allow=<frame>`. For each FAST warning, render that frame and confirm the moving
|
|
272
|
+
edge is blurred. Read the motion timeline for dead air and rhythm.
|
|
273
|
+
3. Render stills and **look at them**: first frame, each element mid-entrance, peak-speed frames
|
|
274
|
+
(blur visible), fully settled (crisp), mid-exit, and the **last frame** (clean).
|
|
275
|
+
4. Check: no text collides with the subject's face, safe zones respected, contrast holds,
|
|
276
|
+
no clipped descenders (g, p, y, commas) in masked text.
|
|
277
|
+
5. Report what was verified and what still needs the user's eyes at full speed.
|
|
278
|
+
|
|
272
279
|
---
|
|
273
280
|
|
|
274
|
-
## Remotion gotchas
|
|
275
|
-
|
|
276
|
-
- Never use CSS `transition`/`animation` — drive everything from `useCurrentFrame()`.
|
|
277
|
-
- Never use `Math.random()` — use `random(seed)` from `remotion`.
|
|
278
|
-
- Never use `will-change` (render-tab flicker, see Smoothness system).
|
|
279
|
-
- **`<Presence>` owns its element's `transform` and `opacity`.** Any extra transform (centring with
|
|
280
|
-
`translateX(-50%)`) or opacity (fading content) passed in `style` is silently overwritten — put it
|
|
281
|
-
on an inner wrapper. This bug appeared twice in the first project (off-centre tag, labels that
|
|
282
|
-
never faded).
|
|
283
|
-
- em-based spacing (gaps, padding) resolves against the element's own font-size: set `fontSize`
|
|
284
|
-
on the container, or word gaps collapse.
|
|
285
|
-
- Masked text needs travel > 100% and container padding, or descenders stay visible.
|
|
286
|
-
- Load fonts through `@remotion/fonts` (brand your display typeface is local in `assets/fonts/`) so renders wait for them.
|
|
287
|
-
|
|
281
|
+
## Remotion gotchas
|
|
282
|
+
|
|
283
|
+
- Never use CSS `transition`/`animation` — drive everything from `useCurrentFrame()`.
|
|
284
|
+
- Never use `Math.random()` — use `random(seed)` from `remotion`.
|
|
285
|
+
- Never use `will-change` (render-tab flicker, see Smoothness system).
|
|
286
|
+
- **`<Presence>` owns its element's `transform` and `opacity`.** Any extra transform (centring with
|
|
287
|
+
`translateX(-50%)`) or opacity (fading content) passed in `style` is silently overwritten — put it
|
|
288
|
+
on an inner wrapper. This bug appeared twice in the first project (off-centre tag, labels that
|
|
289
|
+
never faded).
|
|
290
|
+
- em-based spacing (gaps, padding) resolves against the element's own font-size: set `fontSize`
|
|
291
|
+
on the container, or word gaps collapse.
|
|
292
|
+
- Masked text needs travel > 100% and container padding, or descenders stay visible.
|
|
293
|
+
- Load fonts through `@remotion/fonts` (brand your display typeface is local in `assets/fonts/`) so renders wait for them.
|
|
294
|
+
|
|
288
295
|
---
|
|
289
296
|
|
|
290
|
-
## Feedback format from the user
|
|
291
|
-
|
|
292
|
-
Notes arrive as timecode + specific issue ("0:14 title lands 3 frames late, bounce too strong").
|
|
293
|
-
Translate each note into token or timing changes; if a note conflicts with a law, say so and ask.
|
|
294
|
-
|
|
297
|
+
## Feedback format from the user
|
|
298
|
+
|
|
299
|
+
Notes arrive as timecode + specific issue ("0:14 title lands 3 frames late, bounce too strong").
|
|
300
|
+
Translate each note into token or timing changes; if a note conflicts with a law, say so and ask.
|
|
301
|
+
|
|
295
302
|
---
|
|
296
303
|
|
|
297
304
|
## What is already installed
|
package/template/STYLE.md
CHANGED
|
@@ -1,165 +1,179 @@
|
|
|
1
|
-
<!-- This is YOUR style guide
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
- **
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
1
|
+
<!-- This is YOUR style guide, and it starts deliberately half-empty.
|
|
2
|
+
|
|
3
|
+
Parts 1 to 6 are craft standards: things that hold for any brand, most of them
|
|
4
|
+
measured rather than argued. Leave them alone until you have a reason not to, and
|
|
5
|
+
your edits will come out clean rather than random.
|
|
6
|
+
|
|
7
|
+
Parts 7 and 8 are yours and begin blank. Every time you approve or reject something,
|
|
8
|
+
write it down there. That is the half that makes edits look like YOURS instead of
|
|
9
|
+
merely competent, and it is the half nobody can hand you. -->
|
|
10
|
+
|
|
11
|
+
# House style
|
|
12
|
+
|
|
13
|
+
What every edit must look, move and sound like. `CLAUDE.md` says *how* to build; this
|
|
14
|
+
file says *what it must come out like*.
|
|
15
|
+
|
|
16
|
+
When this file and a reference disagree, this file wins unless you say otherwise.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Your identity
|
|
21
|
+
|
|
22
|
+
Everything visual comes from `src/design/tokens.ts`. That file is the single source of
|
|
23
|
+
your typeface, your colours, your spacing and your type scale — change it there and every
|
|
24
|
+
video changes with it. Never hard-code a colour or a font family into a composition.
|
|
25
|
+
|
|
26
|
+
- **Type:** one display typeface. Heavy weights for headlines, numbers and hero words;
|
|
27
|
+
medium for labels and pointers.
|
|
28
|
+
- **Colour:** one accent, plus ink and a light ground. Resist a second accent — two
|
|
29
|
+
accents read as a template, one reads as a brand.
|
|
30
|
+
- On footage: accent text, with a soft glow so it survives a busy frame.
|
|
31
|
+
- On a light ground: ink text, with the accent used only to mark the word that matters.
|
|
32
|
+
|
|
33
|
+
## 2. Type scale
|
|
34
|
+
|
|
35
|
+
Sizes are a starting ladder, not a law. What matters is that you keep to *a* ladder.
|
|
36
|
+
|
|
37
|
+
| Role | 16:9 (1920x1080) | 9:16 (1080x1920) | Notes |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| Hero word | 200–320px | 130–220px | One on screen at a time, never two |
|
|
40
|
+
| Headline | ~116px | ~100px | Tight tracking, around -0.03em |
|
|
41
|
+
| Big number | ~170px | ~150px | Tabular digits while a counter runs |
|
|
42
|
+
| Label / eyebrow | ~40px | ~32px | Uppercase, open tracking, ~0.14em |
|
|
43
|
+
| Pointer / list item | ~42px | ~36px | |
|
|
44
|
+
| Captions | 46px | 42px | Crisp white, bold, soft dark shadow |
|
|
45
|
+
|
|
46
|
+
**If a word needs to be bigger than the ladder to feel important, the layout is wrong,
|
|
47
|
+
not the size.** Oversized type is the most common way an edit starts looking amateur.
|
|
48
|
+
|
|
49
|
+
## 3. Layout
|
|
50
|
+
|
|
51
|
+
- **The speaker stays full screen by default.** Rounded cards and frames around a talking
|
|
52
|
+
head make the edit look assembled rather than shot. A card is fine as a *transition*,
|
|
53
|
+
not as a container.
|
|
54
|
+
- Put text in the clear space the shot already gives you: sky, a wall, out-of-focus
|
|
55
|
+
background. Check where the head lands on every cut before committing a position.
|
|
56
|
+
- Captions live in one consistent zone per layout, over a dark area. They hide while the
|
|
57
|
+
same words are on screen as a graphic, and never linger into the next scene.
|
|
58
|
+
- Graphics are built from type, numbers, real screenshots and real footage. Decorative
|
|
59
|
+
shapes that mean nothing age badly and read as filler.
|
|
60
|
+
|
|
61
|
+
## 4. Motion
|
|
62
|
+
|
|
63
|
+
- The motion laws in `CLAUDE.md`, always. Eased, motion-blurred, nothing pops into place.
|
|
64
|
+
- **Zoom through jump cuts.** A small push on the cut hides the join; a hard snap exposes it.
|
|
65
|
+
- **Hard cuts only as a deliberate burst** — a few beats of solid colour synced to the
|
|
66
|
+
words, then back to smooth. Everything else morphs from one state to the next.
|
|
67
|
+
- Cover anything off-camera — reading, looking away, a fumble — with a graphic or a cut.
|
|
68
|
+
- Counters start at zero and only go up. No grey placeholder digits.
|
|
69
|
+
- Vary your shot lengths. Cutting everything to the same duration is the clearest sign
|
|
70
|
+
an edit was made by a machine rather than by someone making decisions.
|
|
71
|
+
|
|
72
|
+
## 5. Sound (half the reel)
|
|
73
|
+
|
|
74
|
+
- **The voice is never processed.** No reverb, no heavy compression, no "enhancement".
|
|
75
|
+
- Sound effects are short — whooshes 0.4–0.8s, hits 0.3–0.6s — faded, and placed in the
|
|
76
|
+
gaps between words rather than under them.
|
|
77
|
+
- Every new visual gets its own fitting sound. Reusing a sound that belonged to a
|
|
78
|
+
different look is the audio version of a template.
|
|
79
|
+
- **Subtle beats loud.** Big cinematic impacts on text almost always read as too much.
|
|
80
|
+
- Hand over voice and SFX stems plus a timecoded cue sheet with every delivery.
|
|
81
|
+
|
|
82
|
+
## 6. Colour, film looks and presets
|
|
83
|
+
|
|
84
|
+
**Most of a look comes from the shoot, not the grade.** Golden hour or one good window,
|
|
85
|
+
light behind or beside the subject, background well behind the subject, white balance
|
|
86
|
+
fixed rather than auto. Automated grading is a starting point and only when the footage's
|
|
87
|
+
light already resembles the reference — on mismatched light it will look wrong, and you
|
|
88
|
+
should trust your eye over any automatic match.
|
|
89
|
+
|
|
90
|
+
| Transition | When |
|
|
91
|
+
|---|---|
|
|
92
|
+
| whipPan | Between unrelated shots. Never twice in a row. |
|
|
93
|
+
| push | Moving forward through a list or a sequence. |
|
|
94
|
+
| maskWipe | A calm reveal. Pairs with a soft sound. |
|
|
95
|
+
| colourFlip | A burst on a phrase. Two or three, then back to smooth. |
|
|
96
|
+
| matchCut | Only when both shots share a shape or a direction. |
|
|
97
|
+
| dip | Changing subject without drama. |
|
|
98
|
+
|
|
99
|
+
| Caption look | When |
|
|
100
|
+
|---|---|
|
|
101
|
+
| clean | Default. Works over almost anything. |
|
|
102
|
+
| block | Busy or bright footage, where white alone gets lost. |
|
|
103
|
+
| highlight | Keeps the eye on the word being spoken. |
|
|
104
|
+
| pop | Fast edits. Not over heavy motion. |
|
|
105
|
+
|
|
106
|
+
| Film look | When |
|
|
107
|
+
|---|---|
|
|
108
|
+
| none | Graphics, screen recordings, anything where text is the subject. |
|
|
109
|
+
| clean | Default for a talking head. Enough grain to stop flat areas banding. |
|
|
110
|
+
| film | B-roll and travel. The one to reach for first. |
|
|
111
|
+
| super8 | Memory and nostalgia moments only. Never a whole video. |
|
|
112
|
+
| cinema | A held, wide, quiet shot. |
|
|
113
|
+
|
|
114
|
+
**Three things here were measured, not guessed. Do not quietly undo them:**
|
|
115
|
+
|
|
116
|
+
- Grain composites **normally**, not with `overlay`. On flat cream or flat ink there are
|
|
117
|
+
no midtones, and overlay grain measures 0.000 stddev — the layer does nothing at all.
|
|
118
|
+
- Grain is paid for in black level — blacks lift measurably at medium strength. Raise it
|
|
119
|
+
per shot when a nostalgia moment is worth milkier blacks; never raise the default.
|
|
120
|
+
- Halation blooms **highlights only**. The plate is crushed to black before it is blurred
|
|
121
|
+
and screened back. Without that crush, a bright frame blooms end to end and the blacks
|
|
122
|
+
go brown.
|
|
123
|
+
|
|
124
|
+
Speed ramps are eased, never a hard speed switch. Below 0.4x needs 50fps or higher source
|
|
125
|
+
footage — you cannot rescue slow motion that was not shot for it.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 7. Where these defaults end and you begin
|
|
130
|
+
|
|
131
|
+
The sections above are **defaults**: a starting point tuned so that a video made on day one,
|
|
132
|
+
before you have told the system anything, comes out clean rather than embarrassing. Captions
|
|
133
|
+
sit at a readable size with a measured shadow, cuts are eased, grain is restrained, the voice
|
|
134
|
+
is untouched.
|
|
135
|
+
|
|
136
|
+
Defaults are also the reason an edit can come out *anonymous*. They are what everybody gets.
|
|
137
|
+
Three things move an edit from the default toward yours, in increasing order of power:
|
|
138
|
+
|
|
139
|
+
**1. Your tokens.** `src/design/tokens.ts` carries your typeface, your colours, your scale.
|
|
140
|
+
This makes an edit *yours to look at* immediately.
|
|
141
|
+
|
|
142
|
+
**2. Your references.** Saved moments from edits you admire, each with a timecode and a note
|
|
143
|
+
on what you like about that exact moment. These are read before the plan for every video, and
|
|
144
|
+
they beat the defaults wherever the two disagree — a default is a guess that suits everyone,
|
|
145
|
+
a reference is a fact about you.
|
|
146
|
+
|
|
147
|
+
Roughly: **none** gives you clean and forgettable. **Three** is enough to spot a pattern.
|
|
148
|
+
**Seven or eight** is enough to tell a preference from a coincidence, and it is where edits
|
|
149
|
+
start looking authored.
|
|
150
|
+
|
|
151
|
+
**3. This file, as it fills up.** Sections 8 and 9 are the part no default can supply and no
|
|
152
|
+
competitor can copy, because they are a record of decisions only you have made. Every entry
|
|
153
|
+
narrows the next edit toward what you actually want.
|
|
154
|
+
|
|
155
|
+
Nothing here learns on its own. It gets better because the brief gets richer — so the ten
|
|
156
|
+
minutes spent writing down why you rejected something is the highest-return ten minutes
|
|
157
|
+
available to you.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 8. Approved (your effects library)
|
|
162
|
+
|
|
163
|
+
<!-- Empty on purpose. When something works, write it down here: what it is, and where
|
|
164
|
+
you approved it. Next time you can ask for it by name instead of describing it
|
|
165
|
+
again, and every future video inherits the decision. -->
|
|
166
|
+
|
|
167
|
+
| Beat | What it is | Where you approved it |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| | | |
|
|
170
|
+
|
|
171
|
+
## 9. Rejected (don't do these again)
|
|
172
|
+
|
|
173
|
+
<!-- This table is worth more than the one above. A list of things you have ruled out is
|
|
174
|
+
the fastest way to stop an edit drifting back toward generic, because it removes
|
|
175
|
+
options rather than adding them. Add a line every time you say "not that". -->
|
|
176
|
+
|
|
177
|
+
| What | Why | Where |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| | | |
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
<!-- This is YOUR style guide, and it starts deliberately half-empty.
|
|
2
|
+
|
|
3
|
+
Parts 1 to 6 are craft standards: things that hold for any brand, most of them
|
|
4
|
+
measured rather than argued. Leave them alone until you have a reason not to, and
|
|
5
|
+
your edits will come out clean rather than random.
|
|
6
|
+
|
|
7
|
+
Parts 7 and 8 are yours and begin blank. Every time you approve or reject something,
|
|
8
|
+
write it down there. That is the half that makes edits look like YOURS instead of
|
|
9
|
+
merely competent, and it is the half nobody can hand you. -->
|
|
10
|
+
|
|
11
|
+
# House style
|
|
12
|
+
|
|
13
|
+
What every edit must look, move and sound like. `CLAUDE.md` says *how* to build; this
|
|
14
|
+
file says *what it must come out like*.
|
|
15
|
+
|
|
16
|
+
When this file and a reference disagree, this file wins unless you say otherwise.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Your identity
|
|
21
|
+
|
|
22
|
+
Everything visual comes from `src/design/tokens.ts`. That file is the single source of
|
|
23
|
+
your typeface, your colours, your spacing and your type scale — change it there and every
|
|
24
|
+
video changes with it. Never hard-code a colour or a font family into a composition.
|
|
25
|
+
|
|
26
|
+
- **Type:** one display typeface. Heavy weights for headlines, numbers and hero words;
|
|
27
|
+
medium for labels and pointers.
|
|
28
|
+
- **Colour:** one accent, plus ink and a light ground. Resist a second accent — two
|
|
29
|
+
accents read as a template, one reads as a brand.
|
|
30
|
+
- On footage: accent text, with a soft glow so it survives a busy frame.
|
|
31
|
+
- On a light ground: ink text, with the accent used only to mark the word that matters.
|
|
32
|
+
|
|
33
|
+
## 2. Type scale
|
|
34
|
+
|
|
35
|
+
Sizes are a starting ladder, not a law. What matters is that you keep to *a* ladder.
|
|
36
|
+
|
|
37
|
+
| Role | 16:9 (1920x1080) | 9:16 (1080x1920) | Notes |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| Hero word | 200–320px | 130–220px | One on screen at a time, never two |
|
|
40
|
+
| Headline | ~116px | ~100px | Tight tracking, around -0.03em |
|
|
41
|
+
| Big number | ~170px | ~150px | Tabular digits while a counter runs |
|
|
42
|
+
| Label / eyebrow | ~40px | ~32px | Uppercase, open tracking, ~0.14em |
|
|
43
|
+
| Pointer / list item | ~42px | ~36px | |
|
|
44
|
+
| Captions | 46px | 42px | Crisp white, bold, soft dark shadow |
|
|
45
|
+
|
|
46
|
+
**If a word needs to be bigger than the ladder to feel important, the layout is wrong,
|
|
47
|
+
not the size.** Oversized type is the most common way an edit starts looking amateur.
|
|
48
|
+
|
|
49
|
+
## 3. Layout
|
|
50
|
+
|
|
51
|
+
- **The speaker stays full screen by default.** Rounded cards and frames around a talking
|
|
52
|
+
head make the edit look assembled rather than shot. A card is fine as a *transition*,
|
|
53
|
+
not as a container.
|
|
54
|
+
- Put text in the clear space the shot already gives you: sky, a wall, out-of-focus
|
|
55
|
+
background. Check where the head lands on every cut before committing a position.
|
|
56
|
+
- Captions live in one consistent zone per layout, over a dark area. They hide while the
|
|
57
|
+
same words are on screen as a graphic, and never linger into the next scene.
|
|
58
|
+
- Graphics are built from type, numbers, real screenshots and real footage. Decorative
|
|
59
|
+
shapes that mean nothing age badly and read as filler.
|
|
60
|
+
|
|
61
|
+
## 4. Motion
|
|
62
|
+
|
|
63
|
+
- The motion laws in `CLAUDE.md`, always. Eased, motion-blurred, nothing pops into place.
|
|
64
|
+
- **Zoom through jump cuts.** A small push on the cut hides the join; a hard snap exposes it.
|
|
65
|
+
- **Hard cuts only as a deliberate burst** — a few beats of solid colour synced to the
|
|
66
|
+
words, then back to smooth. Everything else morphs from one state to the next.
|
|
67
|
+
- Cover anything off-camera — reading, looking away, a fumble — with a graphic or a cut.
|
|
68
|
+
- Counters start at zero and only go up. No grey placeholder digits.
|
|
69
|
+
- Vary your shot lengths. Cutting everything to the same duration is the clearest sign
|
|
70
|
+
an edit was made by a machine rather than by someone making decisions.
|
|
71
|
+
|
|
72
|
+
## 5. Sound (half the reel)
|
|
73
|
+
|
|
74
|
+
- **The voice is never processed.** No reverb, no heavy compression, no "enhancement".
|
|
75
|
+
- Sound effects are short — whooshes 0.4–0.8s, hits 0.3–0.6s — faded, and placed in the
|
|
76
|
+
gaps between words rather than under them.
|
|
77
|
+
- Every new visual gets its own fitting sound. Reusing a sound that belonged to a
|
|
78
|
+
different look is the audio version of a template.
|
|
79
|
+
- **Subtle beats loud.** Big cinematic impacts on text almost always read as too much.
|
|
80
|
+
- Hand over voice and SFX stems plus a timecoded cue sheet with every delivery.
|
|
81
|
+
|
|
82
|
+
## 6. Colour, film looks and presets
|
|
83
|
+
|
|
84
|
+
**Most of a look comes from the shoot, not the grade.** Golden hour or one good window,
|
|
85
|
+
light behind or beside the subject, background well behind the subject, white balance
|
|
86
|
+
fixed rather than auto. Automated grading is a starting point and only when the footage's
|
|
87
|
+
light already resembles the reference — on mismatched light it will look wrong, and you
|
|
88
|
+
should trust your eye over any automatic match.
|
|
89
|
+
|
|
90
|
+
| Transition | When |
|
|
91
|
+
|---|---|
|
|
92
|
+
| whipPan | Between unrelated shots. Never twice in a row. |
|
|
93
|
+
| push | Moving forward through a list or a sequence. |
|
|
94
|
+
| maskWipe | A calm reveal. Pairs with a soft sound. |
|
|
95
|
+
| colourFlip | A burst on a phrase. Two or three, then back to smooth. |
|
|
96
|
+
| matchCut | Only when both shots share a shape or a direction. |
|
|
97
|
+
| dip | Changing subject without drama. |
|
|
98
|
+
|
|
99
|
+
| Caption look | When |
|
|
100
|
+
|---|---|
|
|
101
|
+
| clean | Default. Works over almost anything. |
|
|
102
|
+
| block | Busy or bright footage, where white alone gets lost. |
|
|
103
|
+
| highlight | Keeps the eye on the word being spoken. |
|
|
104
|
+
| pop | Fast edits. Not over heavy motion. |
|
|
105
|
+
|
|
106
|
+
| Film look | When |
|
|
107
|
+
|---|---|
|
|
108
|
+
| none | Graphics, screen recordings, anything where text is the subject. |
|
|
109
|
+
| clean | Default for a talking head. Enough grain to stop flat areas banding. |
|
|
110
|
+
| film | B-roll and travel. The one to reach for first. |
|
|
111
|
+
| super8 | Memory and nostalgia moments only. Never a whole video. |
|
|
112
|
+
| cinema | A held, wide, quiet shot. |
|
|
113
|
+
|
|
114
|
+
**Three things here were measured, not guessed. Do not quietly undo them:**
|
|
115
|
+
|
|
116
|
+
- Grain composites **normally**, not with `overlay`. On flat cream or flat ink there are
|
|
117
|
+
no midtones, and overlay grain measures 0.000 stddev — the layer does nothing at all.
|
|
118
|
+
- Grain is paid for in black level — blacks lift measurably at medium strength. Raise it
|
|
119
|
+
per shot when a nostalgia moment is worth milkier blacks; never raise the default.
|
|
120
|
+
- Halation blooms **highlights only**. The plate is crushed to black before it is blurred
|
|
121
|
+
and screened back. Without that crush, a bright frame blooms end to end and the blacks
|
|
122
|
+
go brown.
|
|
123
|
+
|
|
124
|
+
Speed ramps are eased, never a hard speed switch. Below 0.4x needs 50fps or higher source
|
|
125
|
+
footage — you cannot rescue slow motion that was not shot for it.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 7. Where these defaults end and you begin
|
|
130
|
+
|
|
131
|
+
The sections above are **defaults**: a starting point tuned so that a video made on day one,
|
|
132
|
+
before you have told the system anything, comes out clean rather than embarrassing. Captions
|
|
133
|
+
sit at a readable size with a measured shadow, cuts are eased, grain is restrained, the voice
|
|
134
|
+
is untouched.
|
|
135
|
+
|
|
136
|
+
Defaults are also the reason an edit can come out *anonymous*. They are what everybody gets.
|
|
137
|
+
Three things move an edit from the default toward yours, in increasing order of power:
|
|
138
|
+
|
|
139
|
+
**1. Your tokens.** `src/design/tokens.ts` carries your typeface, your colours, your scale.
|
|
140
|
+
This makes an edit *yours to look at* immediately.
|
|
141
|
+
|
|
142
|
+
**2. Your references.** Saved moments from edits you admire, each with a timecode and a note
|
|
143
|
+
on what you like about that exact moment. These are read before the plan for every video, and
|
|
144
|
+
they beat the defaults wherever the two disagree — a default is a guess that suits everyone,
|
|
145
|
+
a reference is a fact about you.
|
|
146
|
+
|
|
147
|
+
Roughly: **none** gives you clean and forgettable. **Three** is enough to spot a pattern.
|
|
148
|
+
**Seven or eight** is enough to tell a preference from a coincidence, and it is where edits
|
|
149
|
+
start looking authored.
|
|
150
|
+
|
|
151
|
+
**3. This file, as it fills up.** Sections 8 and 9 are the part no default can supply and no
|
|
152
|
+
competitor can copy, because they are a record of decisions only you have made. Every entry
|
|
153
|
+
narrows the next edit toward what you actually want.
|
|
154
|
+
|
|
155
|
+
Nothing here learns on its own. It gets better because the brief gets richer — so the ten
|
|
156
|
+
minutes spent writing down why you rejected something is the highest-return ten minutes
|
|
157
|
+
available to you.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 8. Approved (your effects library)
|
|
162
|
+
|
|
163
|
+
<!-- Empty on purpose. When something works, write it down here: what it is, and where
|
|
164
|
+
you approved it. Next time you can ask for it by name instead of describing it
|
|
165
|
+
again, and every future video inherits the decision. -->
|
|
166
|
+
|
|
167
|
+
| Beat | What it is | Where you approved it |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| | | |
|
|
170
|
+
|
|
171
|
+
## 9. Rejected (don't do these again)
|
|
172
|
+
|
|
173
|
+
<!-- This table is worth more than the one above. A list of things you have ruled out is
|
|
174
|
+
the fastest way to stop an edit drifting back toward generic, because it removes
|
|
175
|
+
options rather than adding them. Add a line every time you say "not that". -->
|
|
176
|
+
|
|
177
|
+
| What | Why | Where |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| | | |
|