Candidate construction guide · native Resolve not tested
From a card to a reading sheet
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-card-to-reading --variant default --out out/pulse-card-to-reading-default.mp4
node --experimental-strip-types scripts/render.mjs --recipe pulse-card-to-reading --variant adaptation --out out/pulse-card-to-reading-adaptation.mp4
node --experimental-strip-types scripts/verify.mjs out/pulse-card-to-reading-default.mp4
node --experimental-strip-types scripts/verify.mjs out/pulse-card-to-reading-adaptation.mp4
Expected: 1920×1080, 60/1 fps, 300 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: a balcony-layout sketch with original potted-plant art; adaptation: a sky-journal exercise with an original observatory/notebook illustration. Both replace the source medical topic entirely.
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-card-to-reading.json').read_text())
content = recipe['defaults']
content['section1'] = '1 / Map the little space'
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-card-to-reading', contentPath: 'inputs/my-content.json'});
console.log(checked.expected, checked.assets);
JS
node --experimental-strip-types scripts/render.mjs --recipe pulse-card-to-reading --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: 4ff1dbad2966dd7ca0126ffda2ebbed2764df9a13c1268b02c605e963d25abb6.
Source window [2160, 2460) =
36–41 seconds.
Local frame f maps to source frame 2160 + 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 300 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–66: a held feed card, with a small authored 40–61 press/release scale excursion. No pointer or click sound is invented.
- 67–92: feed darkens. A separate sheet starts moving below the viewport at 70 with local Y 1280; first faint visible entry is about75, clear at76. It reaches 410 at 82, 132 at 100 and 112 at 112. The feed art and article art reference the same selected SVG.
- Article scrolling is a child transform, not sheet travel: local Y 0 through 120, −176 at 142, −470 at 184; hold to 218; −580 at 247. The shell and sheet top do not move with this content.
- At 247, a held camera key makes a discrete 1→2.1 close crop about (960,540); Y jumps to −710 then settles to −822 at 268. The lower article and composer fill the frame. This is not another scroll.
- 286: placeholder/voice bars disappear and send arrow appears. 287: blank-input caret appears. End at 299 without a typed request or send.
Fusion: complete manual construction
- Set composition/output 1920×1080, square pixels, 60 fps, local frames
0–299 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-camera [group] -> phone-camera_Merge
phone-shell [rect] -> phone-shell_Merge
phone-viewport [group] -> phone-viewport_Merge
feed-heading [text] -> feed-heading_Merge
feed-card [group] -> feed-card_Merge
feed-card-bg [rect] -> feed-card-bg_Merge
feed-art [image] -> feed-art_Merge
feed-title [text] -> feed-title_Merge
feed-summary [text] -> feed-summary_Merge
feed-add [path] -> feed-add_Merge
feed-save [path] -> feed-save_Merge
feed-dimmer [rect] -> feed-dimmer_Merge
reading-sheet [group] -> reading-sheet_Merge
article-paper [rect] -> article-paper_Merge
article-scroll [group] -> article-scroll_Merge
article-art [image] -> article-art_Merge
article-title [text] -> article-title_Merge
article-intro [text] -> article-intro_Merge
section-one [text] -> section-one_Merge
section-two [text] -> section-two_Merge
section-three [text] -> section-three_Merge
article-line-0 [text] -> article-line-0_Merge
article-line-1 [text] -> article-line-1_Merge
article-line-2 [text] -> article-line-2_Merge
article-line-3 [text] -> article-line-3_Merge
article-line-4 [text] -> article-line-4_Merge
article-line-5 [text] -> article-line-5_Merge
article-line-6 [text] -> article-line-6_Merge
article-line-7 [text] -> article-line-7_Merge
article-line-8 [text] -> article-line-8_Merge
article-line-9 [text] -> article-line-9_Merge
article-line-10 [text] -> article-line-10_Merge
article-line-11 [text] -> article-line-11_Merge
article-line-12 [text] -> article-line-12_Merge
article-controls [group] -> article-controls_Merge
controls-surface [rect] -> controls-surface_Merge
article-save [path] -> article-save_Merge
article-close [path] -> article-close_Merge
article-menu-dot [ellipse] -> article-menu-dot_Merge
followup [group] -> followup_Merge
followup-add-bg [ellipse] -> followup-add-bg_Merge
followup-add [path] -> followup-add_Merge
followup-input [rect] -> followup-input_Merge
followup-placeholder [text] -> followup-placeholder_Merge
followup-caret [rect] -> followup-caret_Merge
followup-voice-bg [ellipse] -> followup-voice-bg_Merge
followup-send [path] -> followup-send_Merge
followup-wave-0 [rect] -> followup-wave-0_Merge
followup-wave-1 [rect] -> followup-wave-1_Merge
followup-wave-2 [rect] -> followup-wave-2_Merge
followup-wave-3 [rect] -> followup-wave-3_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 |
|---|---|---|
phone-camera.y |
3 | -822 → 0 |
phone-camera.scale |
2 | 1 → 2.1 |
feed-card.scale |
4 | 0.98 → 1 |
feed-dimmer.opacity |
3 | 0 → 1 |
reading-sheet.y |
4 | 112 → 1280 |
article-scroll.y |
6 | -580 → 0 |
Checkpoints
| Local / excerpt frame | Source frame | Frame-derived source seconds | Expected candidate state |
|---|---|---|---|
| 0 | 2160 | 36.000000 | Illustrated feed card inside cropped phone. |
| 40 | 2200 | 36.666667 | Press-scale excursion begins. |
| 50 | 2210 | 36.833333 | Card is near its minimum press size. |
| 66 | 2226 | 37.100000 | Feed alone before dimming. |
| 67 | 2227 | 37.116667 | Dimmer starts. |
| 69 | 2229 | 37.150000 | No article sheet yet. |
| 70 | 2230 | 37.166667 | Sheet motion starts below the visible viewport; no visible sheet yet. |
| 82 | 2242 | 37.366667 | Sheet rises above the dimmed feed. |
| 100 | 2260 | 37.666667 | Sheet near its open Y. |
| 112 | 2272 | 37.866667 | Sheet settled. |
| 120 | 2280 | 38.000000 | Article scroll starts only after sheet settles. |
| 142 | 2302 | 38.366667 | First content-scroll intermediate. |
| 184 | 2344 | 39.066667 | First scroll ends; sheet Y unchanged. |
| 218 | 2378 | 39.633333 | Second article scroll starts. |
| 246 | 2406 | 40.100000 | Last phone overview. |
| 247 | 2407 | 40.116667 | Hard close crop, lower article/composer. |
| 268 | 2428 | 40.466667 | Close crop settled. |
| 285 | 2445 | 40.750000 | Placeholder and voice bars still present. |
| 286 | 2446 | 40.766667 | Blank focus / send-arrow state. |
| 287 | 2447 | 40.783333 | Caret in empty input. |
| 299 | 2459 | 40.983333 | Empty focused composer at cutoff; no typed answer. |
Differences and open review
Largest gap: The original illustrated runner, tonal shading, phone shadow and medical article are not reproduced. This geometric artwork and shorter live-type article preserve the sheet/scroll/crop sequence, not its exact physics, text density, source illustration or native UI styling.
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:
3287ae59069ec702708af927088ec6377573c0c5293602fc5648daa0dc02b3c1. - Active-only ZIP SHA-256:
b1cb3caa2c17a74149a4bd37e516a5b4b27409521c2d95c26872afd2b4743cdd. 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.
Additional frozen output discrepancy
The current final composer crosses the actual bottom edge at local247–299. Its full capsule, controls and lower margin still need a separately rendered correction; the247 cut and286 blank/287 caret remain unchanged.