Editable project and production handoff
Download the complete toolchain ZIP · Recording → capture → edit / Markdown · Worked synthetic transfer
Editing with Remotion
Thirteen original silent studies and a 50-second sequence. These are runnable adaptations of inspected editing patterns, not recovered OpenAI projects or product demonstrations. The source films, product data and brand assets are deliberately absent from this download.
Run from a fresh directory
Use Node.js 22.18 or newer and npm. Install the exact dependency graph in the
included lockfile; do not substitute npm install remotion@latest.
npm ci
npm run typecheck
npm test
npx remotion browser ensure
npm run preview
The last command opens Remotion Studio. Choose a composition in the left-hand
list and play it. The initial install and browser download require internet;
the compositions themselves make no external asset requests. Linux needs the
Remotion system requirements.
If a supported Chrome installation is already present, use the CLI's
--browser-executable=/path/to/chrome option. The batch script instead accepts
REMOTION_BROWSER_EXECUTABLE; that variable is optional and not a required
private path.
From a second terminal in the project directory:
npm run render -- TitleCut out/title.mp4 --codec=h264 --pixel-format=yuv420p --muted
npm run render -- StudySequence out/sequence.mp4 --codec=h264 --pixel-format=yuv420p --muted
npm run render:all -- out
The batch command bundles once, renders all thirteen studies and the sequence,
and writes out/render-manifest.json. Every composition is 1280 × 720,
16:9, 30 fps, silent H.264 MP4. CLI configuration and batch options explicitly
use PNG frame capture and BT.709 conversion, with yuv420p output. These are research settings, not approval of
final presentation delivery settings. Remotion's own
license applies to the dependency; evaluate
its terms before commercial production. This bundle does not grant an upstream
software license or permission to reuse source films.
Pick an edit
| Composition | Use it to… | Protect across the edit |
|---|---|---|
TitleCut |
Build a premise, hold it, cut to a formed surface | Full title reading interval; no simultaneous UI action |
ChapterReturn |
Interrupt a task with a new chapter, then return | Exact original task state; no hidden result change |
PunchCut |
Make a small region immediately readable | Same artifact across the crop discontinuity |
CameraPush |
Move attention through an established workspace | Common transform for every workspace layer; settle before action |
FocusType |
Aim at a field before the request appears | Stable baseline and complete request before leaving |
SelectionContext |
Identify scope, reveal its action, restore context | Selected object, attached action, fixed outer frame |
ScrollMask |
Bring a destination into a fixed viewport | Header stays still; reading starts after travel |
SplitResult |
Make room for a result while retaining the request | Container arrives before content; completed content before the hold |
ObjectContext |
Move the same request into another container | Semantic identity; a cut is not a claimed morph |
CaptionCut |
Retain an identifier across a shot change | Caption stays in screen space, outside the camera transform |
MotifMontage |
Compare variants through a recurring silhouette | Consistent motif; holds long enough for the intended comparison |
DensityCollapse |
Reduce a busy wall to a sparse takeaway | Shared group transform, explicit clearing before the title |
QuietEnding |
Give a finished proof a quiet exit | Proof first, brief original-mark construction, stable final hold |
Read the source interval and discrepancy notes on the published chapter before treating one of these as appropriate for a real presentation.
Inputs and units
src/model.ts is the input contract. src/Edits.tsx implements every edit.
src/visuals.tsx supplies the complete original window, artwork, typography,
pointer and camera. src/Root.tsx registers the compositions and assembles the
sequence. The project has no omitted components or external design package.
| Input | Type / limits | Meaning |
|---|---|---|
title |
1–42 characters | Premise or takeaway; type-on may reflow as it grows |
prompt |
1–58 characters | Same original request throughout a sequence |
result |
1–52 characters | Short visible result label, not an invented product claim |
label |
1–28 characters | Artifact identifier / window label |
accent |
Six-digit hex color | Original artwork and emphasis; check contrast after changing |
action |
Integer local frame | First action or departure from the established state |
change |
Integer local frame | Decisive cut, completed travel, or start of content reveal |
settle |
Integer local frame | First frame of the final quiet state |
hold |
Integer, at least 30 | Frames after settle; changes total duration without speeding motion |
focusX, focusY |
0.2–0.8 | Target in the full 1280 × 720 design frame, normalized |
zoom |
1–2 | Final workspace scale for the camera examples |
Require action < change <= settle. Duration is settle + hold, computed by
calculateMetadata; there is no second manually maintained duration field.
Frame ranges are half-open. For example, a cut at frame 54 leaves shot A visible
through frame 53 and starts shot B at frame 54. At 30 fps, that is 1.8 seconds.
Source films have different frame rates; convert their source PTS to seconds
before mapping into this project. Do not equate source frame 54 with output
frame 54.
Phase meanings by composition
| Composition | action → change |
change → settle |
Final hold |
|---|---|---|---|
| TitleCut | Reveal title characters | Complete title remains | Hard cut at settle, formed workspace |
| ChapterReturn | Cut to title; reveal characters | Complete title remains | Cut back at settle, unchanged task |
| PunchCut | Wide view remains | Hard crop at change |
Same crop; default change = settle |
| CameraPush | Chosen eased camera travel | Camera holds | Action label appears at settle; camera remains fixed |
| FocusType | Pointer approaches the input | Request types in | Complete request, pointer removed; no submit implied |
| SelectionContext | Selection appears; camera moves closer | Action appears; camera restores context | Same selection and action |
| ScrollMask | Content moves 360 design pixels behind mask | Destination remains | Destination remains; no new camera move |
| SplitResult | Request pane narrows; empty preview appears | Preview content fades and settles | Complete result beside request |
| ObjectContext | Isolated input holds | Cut to phone; four blank frames, then request/art return | Same request and result in phone |
| CaptionCut | Identifier appears on wide view | Crop cut at change |
Identifier is unchanged in frame space |
| MotifMontage | First variation appears at action |
Further cuts spaced by change - action |
Last variant; keep settle after the last cut |
| DensityCollapse | Output wall moves upward slightly | Whole wall scales toward center | Wall removed, title present |
| QuietEnding | Cut from proof to sparse ending | Three bars build with four-frame stagger | Completely stable original mark |
The character caps prevent common overflow cases; they are not a proof that any string in any language will fit. Test the longest title, widest glyphs and actual line breaks. For more content, redesign the layout or split the beat. Do not silently shrink essential text until it is unreadable.
Adapt a study
Create custom-edit.json:
{
"title": "Make the result readable.",
"result": "One clear result, ready for review.",
"accent": "#365c78",
"hold": 150
}
npm run render -- TitleCut out/custom-title.mp4 --props=custom-edit.json --codec=h264 --pixel-format=yuv420p --muted
Only supplied fields override composition defaults. Here the title cut remains
at frame 84 and the final hold becomes 150 frames: 234 frames / 7.8 seconds
total. To move the cut itself, change settle, not hold. If moving any phase
boundary, preserve phase ordering and inspect the boundary frames.
The camera uses full-frame coordinates. At zoom z, the target lands at the
center using translation (640 - focusX × 1280 × z,
360 - focusY × 720 × z). Captions sit outside that transform. A scroll instead
translates only the document inside an overflow: hidden viewport. These are
different operations, with different layer ownership.
Adapt the 50-second sequence
The eight beats in sequenceBeats in src/model.ts total 1,500 frames:
| Interval | Edit | Role |
|---|---|---|
| 0–5 s | TitleCut | Premise and formed surface |
| 5–10 s | CameraPush | Identify the selected study |
| 10–17 s | FocusType | Establish the request |
| 17–24 s | SplitResult | Make room for its original result |
| 24–30 s | ChapterReturn | Pause for comparison, retain task state |
| 30–36 s | MotifMontage | Compare the same silhouette in three treatments |
| 36–42 s | ObjectContext | Carry request and artwork into another context |
| 42–50 s | QuietEnding | Return to proof, then leave a quiet tail |
Create custom-sequence.json:
{
"title": "A small exhibition, clearly told.",
"prompt": "Compare three exhibition studies.",
"result": "Three studies prepared for review.",
"label": "EXHIBITION / REVIEW",
"accent": "#365c78",
"extraHold": 60
}
npm run render -- StudySequence out/custom-sequence.mp4 --props=custom-sequence.json --codec=h264 --pixel-format=yuv420p --muted
This is 1,560 frames / 52 seconds. extraHold accepts 0–300 frames and extends
only the final quiet tail. To change individual beats, edit sequenceBeats and
its matching phase overrides; its runtime assertion rejects a duration mismatch.
Keep a task's content shared across shots rather than creating unrelated fixtures.
The sequence is a composed study, not a claim that one source film uses this edit list.
Replace neutral graphics with real footage
The original geometry is suitable for research comparisons, not for claiming
product behavior. Obtain permitted captures from the actual application. Keep
the capture, pointer and UI overlays under one camera; keep editorial captions
outside it. For a raster capture that fills the frame, start with at least
output width × maximum zoom pixels of capture width. Settle before reading,
and check the final MP4 at 640 × 360 meeting-view size. Never draw an invented
success over a failed interaction. Declared edits can omit waiting, but their
duration is not measured application latency.
Verify the file, not just Studio
Use FFmpeg and ffprobe on PATH:
ffprobe -v error -show_entries stream=codec_type,codec_name,width,height,r_frame_rate,nb_frames -show_entries format=duration -of json out/custom-sequence.mp4
ffmpeg -v error -i out/custom-sequence.mp4 -f null -
Confirm 1280 × 720, 30/1 fps, 52 seconds for the adaptation above, and no audio stream. Play the whole file. Inspect both frames around each hard cut, the camera's middle frames, text at its longest state, masks at their edges, and the last few seconds for accidental movement. A passing decoder does not prove readability, semantic continuity or a good edit. The chapter's verification report states which checks were actually run.
The production approval boundary
These examples do not authorize final all-hands rendering. For a presentation, derive timing from the supplied talking-head recording and its real pauses. Keep the talking head in OBS and the separate, silent presentation video in Google Slides. Do not composite them or duplicate narration. Use a recognizable opening transition as a manual cue, then measure the actual reaction/startup offset in rehearsal; do not assume zero delay.
If the talking head starts at presentation time S, recording time h maps to
S + h. Reuse the OBS worksheet: for cue C, observed reactions [Rmin,Rmax],
tail onset T, usable performance end E<=H, last speech L, and buffer B,
require C+Rmax+max(T,L) <= P <= C+Rmin+E-B, plus visual proof/reading completion.
Unknown calibration or usable-tail bounds block readiness. The opening lead-in and ending buffer are separate.
If the wave/pause is absent, raise it in review; never manufacture it. Obtain
one consolidated storyboard/demo approval, including real captures, chosen
techniques, exact offsets, buffer and export settings, before production.
Asset provenance
All diagrams, text, pointers and geometric artwork in src are original to
this study. The two bundled DejaVu font files carry their own permission notice
in public/fonts/LICENSE.txt. The downloadable project contains no OpenAI
font, logo, footage, source demo data, private product material or user recording.
The added examples/transfer recording, app and captures are explicitly
synthetic and original, not user recordings or product data. The
production packet guide provides the executable
recording-to-capture-to-edit path, approval gates, encoded checks and limits.
Research excerpts remain separately credited on the site. Preserve the font
notice when redistributing the project.
Implementation references: Sequence timing, metadata from props, render CLI, renderMedia. The numerical easing, geometry, colors and output durations are chosen defaults, not recovered source-film specifications.
For a checked schedule against an actual recording, read
RECORDING_ALIGNMENT.md. The included
alignToRecording helper maps proof anchors to local recipe frames, rejects
overlapping shots and inadequate reading holds, and checks both sides of the
real ending-buffer window. npm test includes its explicitly synthetic clock
tests; those tests do not claim that any supplied recording has been aligned.
API_VERIFICATION.md records the official API contracts,
including the important difference between CLI config and programmatic render
settings.
ASSET_ADAPTATION.md is a complete worked two-recipe
example with new original assets, its own entry point, font loading, camera-safe
masks, registration, cumulative timing, and exact preview/render commands.
RECIPE_GEOMETRY.md lists each study's pixel coordinates,
layer ownership, original asset requirements, and constraints when substituting
different captures or artwork.
Auditable project files
- API_VERIFICATION.md
- ASSET_ADAPTATION.md
- HOST_SETUP.md
- PRODUCTION_PACKET.md
- README.md
- RECIPE_GEOMETRY.md
- RECORDING_ALIGNMENT.md
- examples/trail/Sequence.tsx
- examples/trail/assets.tsx
- examples/trail/index.tsx
- examples/trail/model.ts
- examples/trail/test.mjs
- examples/transfer/capture-actions-evidence.json
- examples/transfer/capture-actions.json
- examples/transfer/capture-observations.json
- examples/transfer/demo.html
- examples/transfer/input/recording.mp4
- examples/transfer/intake/intake.json
- examples/transfer/make-packet.py
- examples/transfer/packet.json
- examples/transfer/raw-asr.json
- examples/transfer/source-capture.webm
- examples/transfer/tail-observations.json
- examples/transfer/timing-private.json
- examples/transfer/transcript.json
- package-lock.json
- package.json
- public/fonts/DejaVuSans-Bold.ttf
- public/fonts/DejaVuSans.ttf
- public/fonts/LICENSE.txt
- remotion.config.ts
- requirements-asr-linux-py313.lock
- requirements-linux-py314.lock
- scripts/capture.mjs
- scripts/fetch.py
- scripts/loopback.cjs
- scripts/media.py
- scripts/playback.mjs
- scripts/prepare-example.py
- scripts/production.mjs
- scripts/render-all.mjs
- scripts/test-media.py
- scripts/test-model.mjs
- scripts/test-production.mjs
- scripts/test-recording-timing.mjs
- scripts/transcribe.py
- src/Edits.tsx
- src/Production.tsx
- src/Root.tsx
- src/index.ts
- src/model.ts
- src/production.ts
- src/recording-timing.ts
- src/visuals.tsx
- tsconfig.json