Candidate construction guide · native Resolve not tested
Suggestions become one request
An original SVG/code Remotion recipe and a complete manual DaVinci Resolve /
Fusion handoff. One source-grounded treatment, two original content variants.
This is a candidate, not source-fidelity acceptance or a tested native .setting.
This worker did not render an output or run Resolve. Later parent renders need
their own hashes/review; this statement is not a claim about the parent's current queue.
Public download: prepare once
Use a fresh kit directory. The public package supplies core-publication-v08.zip,
active-assets.zip, handoff.py, this README, guide.json, controls.csv,
fusion-controls.csv, overlay-manifest.json, provenance.json, and test_kit.py.
No private worker, repository checkout, generator, source clip or inputs/ helper
is needed. This overlay contains only this recipe and its active original SVGs.
Both content variants are embedded in the recipe. Do not add old raster/video ZIPs.
# Run in the downloaded kit root. Both ZIPs contain project/ at their top level.
python3 -m zipfile -e core-publication-v08.zip .
python3 -m zipfile -e active-assets.zip .
python3 handoff.py verify --guide guide.json --project project
python3 handoff.py frames --guide guide.json --project project > controls-regenerated.csv
cmp controls.csv controls-regenerated.csv
Do not unpack either ZIP into project/ again: that creates project/project/.
Core first, overlay second. The public tests verify the exact ZIP members and hashes;
the handoff command verifies the recipe, native clock and selected SVG bytes only.
Remotion: parent or recipient renders
Prerequisites: Node ≥22.18, Python 3, FFmpeg/FFprobe and an explicitly installed
supported Chromium. Preserve the pinned package lock and core README. Rendering
does not auto-download a browser; set REMOTION_BROWSER_EXECUTABLE to its existing
executable when needed. Do not place persistent browser profiles in an evidence tree.
cd project
npm ci
node --experimental-strip-types scripts/render.mjs --recipe pulse-prompt-collapse --variant default --out out/pulse-prompt-collapse-default.mp4
node --experimental-strip-types scripts/render.mjs --recipe pulse-prompt-collapse --variant adaptation --out out/pulse-prompt-collapse-adaptation.mp4
node --experimental-strip-types scripts/verify.mjs out/pulse-prompt-collapse-default.mp4
node --experimental-strip-types scripts/verify.mjs out/pulse-prompt-collapse-adaptation.mp4
Expected: 1920×1080, 60/1 fps, 420 frames, no audio. Keep each adjacent
.manifest.json with its MP4. The renderer refuses pre-existing outputs; use a
fresh filename for each revision. Do not add holds to synchronized comparisons.
These are the actual commands from the archived renderer, not a hypothetical API.
Change the content, not the clock
default: paper objects, studio rituals and a weekly sketching request; adaptation: garden colours, evening skies and a monthly colour-study request. The final typed copy differs and remains deliberately incomplete in both.
Every string/color/media slot and its contract is in recipe.fields and in
guide.json → editableSubstitutions. Text is live Geist from the core's
public/fonts/Geist.ttf; retain public/fonts/OFL.txt. Do not use a system fallback.
SVG art has no text, raster, external links or font dependency. Replace it with
your own standalone SVG at the declared viewport/aspect ratio and with an accurate
rights declaration. Do not flatten or trace source footage.
To make a custom JSON, run from project/:
python3 - <<'PY'
import json
from pathlib import Path
recipe = json.loads(Path('recipes/pulse-prompt-collapse.json').read_text())
content = recipe['defaults']
content['typed'] = 'Make a weekly notebook drawing prompt.'
Path('inputs').mkdir(exist_ok=True)
Path('inputs/my-content.json').write_text(json.dumps(content, indent=2) + '\n')
PY
node --experimental-strip-types --input-type=module - <<'JS'
import {prepareInput} from './scripts/lib.mjs';
const checked = await prepareInput({projectRoot: process.cwd(), recipeId: 'pulse-prompt-collapse', contentPath: 'inputs/my-content.json'});
console.log(checked.expected, checked.assets);
JS
node --experimental-strip-types scripts/render.mjs --recipe pulse-prompt-collapse --content inputs/my-content.json --out out/my-content.mp4
node --experimental-strip-types scripts/verify.mjs out/my-content.mp4
The custom-content preflight does not render, measure browser glyphs or execute
Resolve. It checks the real core input contract and asset bytes. The renderer's
font gate then rejects overflowing lines; shorten copy, never shrink or retime it.
Custom assets are no longer the frozen guide.svgAssets contract: retain their new
render manifest and review the substitution. handoff.py verify still verifies
the two frozen built-in variants, not an arbitrary custom JSON. SVG-only policy
is stricter than the core's general media API; run the supplied test's SVG checker
or inspect replacement SVG resources before using new artwork.
The offline tests also check nominal advances from the actual archived Geist
cmap/hmtx tables and all text-box heights. This is an unshaped default-font
metric check, not the renderer's browser shaping or a Resolve Text+ fit verdict.
Source and clock
Research film: Introducing ChatGPT Pulse. The film link, publication date
(2025-09-25) and master SHA are retained queue metadata,
not a new online lookup. Only the accepted excerpt was rehashed and inspected.
Master SHA: 1f5b53975635fd21b69f85194b35559a0397c69343acc89235acebe4e8fd0966 (inherited, not rehashed).
Excerpt SHA: cf1328d3b99d1173d1275d559d2d5203ebc35b8c73d2f9693464d18f7b73bd82.
Source window [3060, 3480) =
51–58 seconds.
Local frame f maps to source frame 3060 + f and excerpt frame
f (zero lead offset). Seconds are exact frame/60 arithmetic, not newly measured
source PTS. Header/decode checks confirm 60/1 and 420 consecutive excerpt frames.
The retained study's 2ms PTS statement is inherited, not a new master-PTS check.
All frames were viewed statically in ordered 480×270 labeled sheets; selected
boundary/cutoff stills were also viewed at native excerpt resolution 960×540.
That is not moving-source review, not full-resolution viewing of every frame,
not full-film inspection, and not evidence of source-quality equivalence.
provenance.json binds each sheet range/hash and native still ordinal/hash without
shipping research images as presentation inputs. Positions, easing and styling below
are chosen adaptation values; only explicitly labeled cut observations are frame-exact.
Choreography
- 0–55: retain the phone-footer context and a 39–52 button press/release. At 56 cut to suggestions. Do not trim this lead to make the collapse start earlier.
- 56–88: stack scales .84→1 around (960,540). Rows are 1400×168px, pitch 204px, inside a fixed clip; visible text is live.
- 120–144: list shifts −204px; the initially lower row becomes central. 210–234: shift reaches −408px and the free-note row becomes central. A fourth row can overlap the visibility fringe during travel; this is one stack treatment.
- 278–298: top/bottom rows clear while the middle surface remains. 298–309: its leading mark fades; 300–312: its placeholder moves 168→62px locally. Controls grow separately at 310–323.
- 324–361: empty placeholder/caret phase. At 362, placeholder and microphone/voice bars switch off and send arrow/typed layer switch on. Characters arrive at 363+2n, n=0…28. Local 419 shows only 29 characters, not the entire supplied sentence; no submit follows.
Fusion: complete manual construction
- Set composition/output 1920×1080, square pixels, 60 fps, local frames
0–419 inclusive. Disable optical flow, motion blur and automatic retiming.
No MediaIn of the research clip.
resolveApplicationVerifiedremains false. - Work every intermediate branch on a transparent 4096×4096 square domain,
padding the design origin by (1024,1024). This preserves negative positions
and child overflow. Do not crop each branch to 1920×1080. The phone viewport
clips long content before parent camera magnification. Final crop only after
the root merge: design rectangle starts at (1024,1024), size 1920×1080, with
no resize. Composite over opaque white
RootPaper, thenMediaOut1. - Construct the hierarchy below back to front at every level. Each child
finishes into its parent's transparent merge chain. The last child output feeds
that group's
Construct, then its own mask/transform/alpha.guide.fusionNodeslists every node, connection, raw/static control, parent and effective frame gate.guide.svgSubgraphslists every original primitive, geometry, fill and connection for both variants. Instantiate native Rectangle/Ellipse/Polygon + Background + Merge branches; no raster stand-in. SVG contain fitting precedes its box transform. - Coordinate rule: recipe pixels use top-left origin, +X right, +Y down.
Fusion mask position is
((x+1024)/4096, 1-(y+1024)/4096); width/height normalize by 4096. Local geometry is built before its layer transform. Radius is pixels: clamp to half the smaller dimension. Build rounded masks as a union of a(r,0,w−2r,h)rectangle, a(0,r,w,h−2r)rectangle and four radius-r circles centered at(r,r),(w−r,r),(r,h−r),(w−r,h−r). Union/clamp mask alpha; do not sum overlapping paint. At r=0 use one rectangle. Polygon vertices use the same normalization; preserve path subpath winding/holes. Intersectoverflow:hiddenrounded bounds andclipinsets locally. A plain group width/height or radius does not clip unless declared. Borders are inside the box. - Exact transform order avoids Fusion pivot ambiguity. Let local origin
obelayer.origin, default (0,0), and working design centerc=(1024,1024).AnchorShifttranslates by c−o;ScaleRotatehas Center/Pivot (.5,.5), Size=scale, Angle=−rotation;Positiontranslates by (x,y)+o−c. A translation(dx,dy)has Center(.5+dx/4096, .5−dy/4096). This givesparentPoint=(x,y)+o+R_clockwise(rotation)*scale*(point−o). These kits use uniform scale only. ApplyGatedMerge Blend=active*opacityonce after assembly, not to each child. Active is 1 only when the layer and every ancestor contain the local frame. End gates are exclusive. - Text+ uses the exact live content, font weight, box, line advance and tracking
in each node's
textControls. The listedfontSize/4096is only a starting Size estimate, not a calibrated conversion. Match actual glyph footprint and baseline using licensed Geist before review. Do not auto-fit, outline source lettering, or imply native typography equivalence. Reveal steps key StyledText on the same global frame clock, including prefix/suffix. No child-clock reset. controls.csvgives every present recipe numeric property at every native frame;fusion-controls.csvadditionally gives every layer's numeric AnchorShift, ScaleRotate, Position, Blend, size, radius and clip inputs at every frame. Use those values as frame-by-frame linear baked keys; they are not measured source controls. Between sparse recipe keys, ease according to the left key: smooth=t*t*(3-2*t), linear=t, hold=left value until the exact right key. A Bézier preset is not a substitute. Preserve the declared one-frame cuts.- Select all content/colors/art from one variant. Check all checkpoints, then compare an actual Resolve render against Remotion and the allowed source excerpt at native cadence. Native Resolve execution and moving comparison remain open.
RootPaper (opaque white working-domain Background)
phone-context [group] -> phone-context_Merge
intro-shell [rect] -> intro-shell_Merge
intro-screen [rect] -> intro-screen_Merge
intro-card-fragment [rect] -> intro-card-fragment_Merge
intro-mark [image] -> intro-mark_Merge
intro-heading [text] -> intro-heading_Merge
intro-body [text] -> intro-body_Merge
intro-question [text] -> intro-question_Merge
intro-action [group] -> intro-action_Merge
intro-action-bg [rect] -> intro-action-bg_Merge
intro-action-text [text] -> intro-action-text_Merge
intro-action-mark [image] -> intro-action-mark_Merge
suggestion-scene [group] -> suggestion-scene_Merge
stack-viewport [group] -> stack-viewport_Merge
cycling-list [group] -> cycling-list_Merge
row-0 [group] -> row-0_Merge
row-0-surface [rect] -> row-0-surface_Merge
row-0-mark [image] -> row-0-mark_Merge
row-0-copy [text] -> row-0-copy_Merge
row-1 [group] -> row-1_Merge
row-1-surface [rect] -> row-1-surface_Merge
row-1-mark [image] -> row-1-mark_Merge
row-1-copy [text] -> row-1-copy_Merge
row-1-topic [text] -> row-1-topic_Merge
row-2 [group] -> row-2_Merge
row-2-surface [rect] -> row-2-surface_Merge
row-2-mark [image] -> row-2-mark_Merge
row-2-copy [text] -> row-2-copy_Merge
row-2-topic [text] -> row-2-topic_Merge
row-3 [group] -> row-3_Merge
row-3-surface [rect] -> row-3-surface_Merge
row-3-mark [image] -> row-3-mark_Merge
row-3-copy [text] -> row-3-copy_Merge
typed-request [text] -> typed-request_Merge
idle-caret [rect] -> idle-caret_Merge
composer-voice [group] -> composer-voice_Merge
voice-disc [ellipse] -> voice-disc_Merge
voice-bar-0 [rect] -> voice-bar-0_Merge
voice-bar-1 [rect] -> voice-bar-1_Merge
voice-bar-2 [rect] -> voice-bar-2_Merge
voice-bar-3 [rect] -> voice-bar-3_Merge
send-arrow [path] -> send-arrow_Merge
composer-microphone [group] -> composer-microphone_Merge
mic-capsule [rect] -> mic-capsule_Merge
mic-base [path] -> mic-base_Merge
row-4 [group] -> row-4_Merge
row-4-surface [rect] -> row-4-surface_Merge
row-4-mark [image] -> row-4-mark_Merge
row-4-copy [text] -> row-4-copy_Merge
Final crop (1024,1024,1920,1080; no resize) -> MediaOut1
Animated controls
All static values and every original key are also present in guide.json.
| Layer.property | Keys | Authored value range |
|---|---|---|
intro-action.scale |
4 | 0.96 → 1 |
suggestion-scene.scale |
2 | 0.84 → 1 |
suggestion-scene.opacity |
2 | 0.55 → 1 |
cycling-list.y |
5 | -408 → 0 |
row-0.opacity |
3 | 0 → 0.42 |
row-1.opacity |
5 | 0 → 1 |
row-1-topic.opacity |
3 | 0 → 1 |
row-2.opacity |
7 | 0 → 1 |
row-2-topic.opacity |
4 | 0 → 1 |
row-3.opacity |
5 | 0 → 1 |
row-3-mark.opacity |
3 | 0 → 1 |
row-3-copy.x |
3 | 62 → 168 |
idle-caret.opacity |
3 | 0 → 1 |
composer-voice.scale |
2 | 0.02 → 1 |
composer-microphone.opacity |
2 | 0 → 1 |
row-4.opacity |
5 | 0 → 0.42 |
Checkpoints
| Local / excerpt frame | Source frame | Frame-derived source seconds | Expected candidate state |
|---|---|---|---|
| 0 | 3060 | 51.000000 | Phone footer, not suggestion rows. |
| 40 | 3100 | 51.666667 | Footer button press phase. |
| 55 | 3115 | 51.916667 | Last phone-context frame. |
| 56 | 3116 | 51.933333 | Cut to suggestion abstraction. |
| 88 | 3148 | 52.466667 | Stack at full authored scale. |
| 120 | 3180 | 53.000000 | First upward list cycle begins. |
| 140 | 3200 | 53.333333 | Departing top row gone. |
| 144 | 3204 | 53.400000 | Second subject occupies the center. |
| 210 | 3270 | 54.500000 | Second upward cycle begins. |
| 230 | 3290 | 54.833333 | Former first selected row gone. |
| 234 | 3294 | 54.900000 | Free-note row at the center. |
| 278 | 3338 | 55.633333 | Peripheral fade begins. |
| 298 | 3358 | 55.966667 | Peripheral rows inactive. |
| 300 | 3360 | 56.000000 | Leading mark clears as placeholder starts shifting. |
| 309 | 3369 | 56.150000 | No leading mark. |
| 310 | 3370 | 56.166667 | Separate voice/microphone growth begins. |
| 323 | 3383 | 56.383333 | Controls full size. |
| 324 | 3384 | 56.400000 | Placeholder focus/caret phase. |
| 361 | 3421 | 57.016667 | Last placeholder frame. |
| 362 | 3422 | 57.033333 | Blank typed layer, send arrow; no first character yet. |
| 363 | 3423 | 57.050000 | First original character. |
| 391 | 3451 | 57.516667 | 15 characters visible. |
| 419 | 3479 | 57.983333 | 29 characters, partial word at source cutoff; no send. |
Differences and open review
Largest gap: Suggestion words, symbols, press response, row opacity curves and input cadence are original approximations. The source uses a wand mark and different content; this kit is a promotional motion specimen, not proof of a shipping suggestion/composer interaction.
Common open gates: browser text shaping, antialiasing, actual moving-output comparison, native Fusion text/mask calibration, and native Resolve execution. No source image was traced or flattened. No source-master download, video render, dependency copy, deployment, shared-state edit or completion-count credit is part of this build.
Immutable preparation contract
- Accepted core ZIP SHA-256:
307fb6b927e35e6d73779652873d994f5c3e36cb7deba65f22fa64748057a0de. - Recipe SHA-256:
85e517b17b5fa431cd6b0d3174a93e7f3830e6bd6cc49b8cad4b91e90d078514. - Active-only ZIP SHA-256:
0ad414c494ce7f51eeae0b965e988147bc0ec9469e903c4c7202698237267f77. overlay-manifest.jsonenumerates every ZIP member and exact byte length/hash; archive members startproject/. It also binds guide, controls and provenance.provenance.jsonbinds the exact selected queue record, source excerpt, retained metadata and actual archived core members. It is an audit, not a runtime dependency.
From kit root, after preparation, run python3 test_kit.py --project project --core core-publication-v08.zip.
This runs focused offline checks and actual-core default/adaptation/custom-content
preflights, with negative content cases. No browser, Resolve or video encoding.
Repository/provenance replay is optional historical auditing; source clips and the
private worker are never prerequisites for rendering or this public handoff.