Independent visual research / Public editionReviewed 05 Sep 2026
Motion fieldnotesOpenAI film study
About this study

Unpublished local test candidate. Synthetic only; not production readiness.

Guide / Markdown · Toolchain / ZIP

Recording → capture → edit

This is the production handoff for the existing Remotion project. It reuses RecordingClock, alignToRecording, the Trail bitmap/camera adaptation, the bundled fonts, and the OBS worksheet. It is not another editor or playback synchronizer. Read RECORDING_ALIGNMENT.md, ASSET_ADAPTATION.md and the relevant RECIPE_GEOMETRY.md entries alongside it.

Boundary: preserve the supplied talking head outside public/. OBS plays that recording, including its only narration. Google Slides plays the separate silent presentation. No compositing, replacement voice, duplicated narration, or default music. Real production rendering requires the single consolidated storyboard/demo approval. A synthetic-only pass never establishes Poe behavior, human approval, or actual OBS/Slides/Zoom readiness.

1. Prepare a supported local environment

The tested profiles are Linux x86-64, Node 24.13.1, CPython 3.14.7 for media checks, and CPython 3.13 for the optional local ASR adapter. Other platforms are untested. FFmpeg/ffprobe with libx264 and a working Chrome/Chromium installation are explicit prerequisites. HOST_SETUP.md records the browser library and network-interface failure modes encountered on the test host.

npm ci
npm run typecheck
npm test
python3.14 -m venv .media-env
.media-env/bin/python -m pip install --require-hashes -r requirements-linux-py314.lock
python3 scripts/test-media.py
export PRODUCTION_PYTHON="$PWD/.media-env/bin/python"
export REMOTION_BROWSER_EXECUTABLE=/path/to/working/chrome-headless-shell

Initial dependency/browser/model provisioning can require internet. No source media, transcript, capture, or composition is uploaded by the included tools. To reproduce offline, prefetch the locked wheels, npm ci dependencies and browser/model, then use pip --no-index --find-links wheelhouse --require-hashes. The original study's six-distribution lock is retained; the Remotion dependency lock is extended only for the optional browser capture/playback adapter.

2. Inspect the recording before selecting recipes

Put the supplied file under private/, not under the served asset directory. The inspector hashes it, records actual stream metadata, compares decoded PCM tracks, and creates an untrimmed 16 kHz mono analysis derivative. Duplicate tracks do not imply multiple speakers. If distinct tracks exist, it refuses to guess. Inspect them and repeat with an explicit stream index:

python3 scripts/media.py --report private/inspect-run.json inspect \
  --source private/recording.mp4 --out private/intake --audio-stream 1

The selected stream's original offset relative to the container start is retained. ASR time on analysis.wav is mapped back by that offset; do not trim leading silence and then call the new clock original recording time.

For optional local transcription, provision a supported faster-whisper model directory through your authorized tooling. The adapter never downloads one:

python3.13 -m venv .asr-env
.asr-env/bin/python -m pip install --require-hashes -r requirements-asr-linux-py313.lock
.asr-env/bin/python scripts/transcribe.py --audio private/intake/analysis.wav \
  --model /path/to/local/model --out private/raw-asr.json
python3 scripts/media.py --report private/transcript-run.json import-asr \
  --intake private/intake/intake.json --asr private/raw-asr.json \
  --out private/transcript.json --engine faster-whisper-1.2.1 \
  --revision MODEL_REVISION --proper-nouns PRODUCT_NAME

Another authorized ASR tool may supply segments[].words[] with word, start, end, and optional probability, relative to the analysis WAV. Retain its raw file, engine/revision and command. The supplied adapter records every model file hash, parameters and software version. Do not describe estimated word decimals as human-certified timing or infer measured vocal stress from meaning.

The importer flags words whose first 120 ms fall below a triage acoustic threshold. The default is −35 dBFS over 20 ms windows, adjustable at inspection; it is not a universal silence detector. Keep the raw times. Add review decisions under review_decisions with uncertainty_id, status (resolved or accepted-uncertain), reason, and evidence. For real production also require human_verified: true after that review. Do not delete uncertain words.

Watch the source's actual gesture and ending. Retain tail-observations.json with source_sha256, evidence_kind: "visual-inspection", start_seconds, end_seconds, and observations. Noisy but calm footage can be usable; an audio silence threshold cannot establish a wave or pose. The worked fixture has a raw first-word estimate at 0 although its acoustic onset is near 0.9 s; it also misrecognizes a name and a number. Those uncertainties remain visible.

3. Derive the review packet

Use examples/transfer/packet.json as a complete worked input, not as a timing preset. src/production.ts is the typed contract and executable validator. The schemaVersion is 1. Paths in a packet are relative to the downloaded project root; every input is bound by SHA-256. Generate a binding with sha256sum relative/file or Python's hashlib.file_digest.

For each segments entry, fromFrame/endFrame are half-open local output frames. mode: "play" advances capture time at 1× from sourceStartSeconds; mode: "hold" uses a specific already captured frame. Omitted waits require an exact gap in omissions with afterLocalFrame, source start/end, reason, and a visible disclosure. The adapter renders that disclosure for two seconds. Do not accelerate an actual interaction or reset an object's identity silently.

Choose motion.kind from hold, cut, or push; actionFrame, changeFrame, zoom, focusX/Y use the existing full-frame camera geometry. Motion must end before proof. evidenceKind: "proposed-edit" distinguishes these choices from reference.evidenceKind: "source-observation". Source timestamps and easing values are not interchangeable evidence.

First anchor completed proof to a recorded phrase, then work backward. Keep native product motion when it communicates the action; do not add a camera move to every shot. Account for actual capture waits and reading time. The provided reading budget is a proposed floor to test with a reader at meeting size, not a guarantee. If necessary, omit a documented wait, shorten surplus holds, choose a cut, or bring a conflict to review. Do not rewrite fixed speech.

4. Capture real behavior and import encoded PTS

Use the product-native collaborative browser when available. If it explicitly reports unavailable, the included optional adapter can record a permitted local or authenticated browser surface. It uses real browser actions, never generated result graphics. Credentials/account setup must be authorized separately; the example does not grant access or make external writes.

node scripts/capture.mjs --url http://127.0.0.1:8765/demo.html \
  --actions examples/transfer/capture-actions.json --out private/capture \
  --browser "$REMOTION_BROWSER_EXECUTABLE" --width 1920 --height 1080
python3 scripts/media.py --report private/capture-import.json capture \
  --source private/capture/capture.webm --out public/captures/demo \
  --kind native-recording --useful-region 0 0 1920 1080

The action list supports click, select, fill, wait, and assert-text; see the worked list for the exact fields. Preserve the action ledger and actual result. Its wall times are not encoded PTS. Import the actual file, inspect decoded frames around initiation/arrival/settlement, and enter capture-relative seconds from capture.json. Every decoded frame is hashed. Native browser capture here has measured 25 fps cadence; replay holds each captured frame until the next PTS. This is not a claim of 30/60 fps native capture.

--useful-region x y width height is the inspected useful rectangle, not the container dimensions by default. Check the moving capture for letterboxing, browser UI, downscaled content and interpolation. Useful width/height must cover output dimensions times maximum zoom. If not, recapture closer or reduce the crop. The supplied adapter cannot make padded low-resolution content sharper.

5. One review, then the checked render

Consolidate the timed storyboard, demo plan/results, transcript decisions, reference choices, original identity, capture map/omissions, cue, measured range, usable tail, export profile and unresolved constraints into the single review. check validates the packet but is not approval:

node scripts/production.mjs check private/packet.json out/review-check
node scripts/production.mjs digest private/packet.json

The digest covers all packet fields except approval, including input hashes. For approved real work set approval.state: "approved", planSha256 to that digest, and humanEvidence to the retained authorization's path/hash. Do not author the human's approval yourself. A material packet change invalidates it. Synthetic studies instead use mode: "synthetic-study" and approval.state: "synthetic-only"; they cannot be represented as production-ready.

node scripts/production.mjs render private/packet.json out/new-render

Use a new output directory. The command validates all source/capture bindings, imports the OBS clock into alignToRecording, compiles the explicit edit, renders with the existing camera/font system, encodes, probes the actual movie, fully decodes it, compares every encoded frame with the rendered reference, and rechecks source hashes. It writes a fresh .run.json status even on failure. The temporary served render assets contain only referenced capture frames and fonts, never the talking-head recording or transcript.

The output includes compiled-edit.json, expected frames/, presentation.mp4, actual encoded-check.json, and pairing.json. The encoder applies the adopted SDR study conversion and explicit H.264 color metadata; the checker requires actual BT.709 matrix, range, primaries and transfer fields. Flags/sidecars alone are not a pass. Never re-tag unknown third-party footage as if it were converted.

Every encoded frame, including motion, joins and protected holds, is compared at its actual PTS. Declared tolerance is mean RGB error below 4/255 and every 64×64 tile below 18/255. This is a lossy-encoding tolerance, not a perceptual guarantee or a detector for every possible one-pixel error. Missing reference frames, added audio, incorrect cadence/geometry/color or corrupt middle frames fail. A renderer can faithfully render a bad editorial plan; inspect that too.

6. Inspect moving output and deliver the pair

Serve only the intended local output directory. Do not serve a private project root or publish source recordings. For the permitted synthetic example:

python3 -m http.server 8766 --bind 127.0.0.1 --directory out/new-render
node scripts/playback.mjs --url http://127.0.0.1:8766/presentation.mp4 \
  --out out/playback-640 --width 640 --height 360 --browser "$REMOTION_BROWSER_EXECUTABLE"

The playback check runs the entire encoded file at 1× without seeking and records video-frame callbacks, elapsed/media clocks, displayed dimensions, errors and frame drops. Repeat at the intended meeting size and inspect text, action/result order, object identity, cut boundaries, cue and ending. Screenshots are supplemental, not a substitute for moving playback. Automated playback is not a human reading/comprehension check or an actual meeting rehearsal.

pairing.json identifies both files, nominal/observed start offsets, cue, presentation end and minimum usable reserve. Rehearse the real OBS virtual camera/virtual microphone and Slides/Zoom pair using the OBS runbook, with single narration, audience-side lip-sync, presentation alignment, and manual mute/video-off before usable tail end. Keep those gates untested until done.

Worked transfer and limits

examples/transfer/packet.json is a 33 s Moss Ledger companion derived from its 35 s synthetic recording and actual fixture runtime. It retains raw ASR errors, two identical audio tracks plus a silent track, low-level noise during the calm tail, a genuine seven-second app wait, a 5.4 s declared omission, stable object identity, a still-camera result beat and one later settled-detail push. The title cuts to the actual app at 2 s. Invented synthetic reactions .55/.65/.75 give a 2.55 s minimum usable reserve. The figure leaves its calm pose at 33 s even though the file continues to 35 s. These are fixture facts, not real calibration.

Replay without changing core constructions:

python3 scripts/prepare-example.py
node scripts/production.mjs check examples/transfer/packet.json out/example-check
node scripts/production.mjs render examples/transfer/packet.json out/example-render

The download retains the encoded synthetic recording and capture, raw ASR and intake records. It does not ship hundreds of redundant decoded PNGs. The first command decodes the supplied capture locally and refreshes the packet's bindings; it needs no network, private files or new editorial choices. Run it once in a fresh extracted project. Do not count an unprepared example as a verified packet.

To recapture, serve examples/transfer, use its action list, import the new capture and re-observe its PTS; do not reuse old wall-to-source times. Replace the capture binding/map in a new packet. The main site includes the original study verifier's bounded --only mode and corrupted-frame controls separately. Real-product access, human review, and a real meeting remain untested by this synthetic transfer.

Reference frame

Enlarged reference frame

Watch this moment on the official channel ↗