OpenAI Film Fieldnotes

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

  1. 0–66: a held feed card, with a small authored 40–61 press/release scale excursion. No pointer or click sound is invented.
  2. 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.
  3. 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.
  4. 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.
  5. 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

  1. 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. resolveApplicationVerified remains false.
  2. 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, then MediaOut1.
  3. 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.fusionNodes lists every node, connection, raw/static control, parent and effective frame gate. guide.svgSubgraphs lists 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.
  4. 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. Intersect overflow:hidden rounded bounds and clip insets locally. A plain group width/height or radius does not clip unless declared. Borders are inside the box.
  5. Exact transform order avoids Fusion pivot ambiguity. Let local origin o be layer.origin, default (0,0), and working design center c=(1024,1024). AnchorShift translates by c−o; ScaleRotate has Center/Pivot (.5,.5), Size=scale, Angle=−rotation; Position translates by (x,y)+o−c. A translation (dx,dy) has Center (.5+dx/4096, .5−dy/4096). This gives parentPoint=(x,y)+o+R_clockwise(rotation)*scale*(point−o). These kits use uniform scale only. Apply Gated Merge Blend=active*opacity once after assembly, not to each child. Active is 1 only when the layer and every ancestor contain the local frame. End gates are exclusive.
  6. Text+ uses the exact live content, font weight, box, line advance and tracking in each node's textControls. The listed fontSize/4096 is 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.
  7. controls.csv gives every present recipe numeric property at every native frame; fusion-controls.csv additionally 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.
  8. 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

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.