I want to create a video template for feature launches. this should have a few main "scenes":
Basically when someone wants to make a video for a feature, they'll give us it a one-sentence tldr, 3 key points/benefits, and an optional CTA (the action we want people to take), and the mp4 clips they want use to use (we won't create the clips programmatically), and we'll give them a feature video with their content embedded.
A couple questions I have:
one thing that I'm thinking is how to express this
I’m going to inspect the current Remotion setup and load the remotion-best-practices skill first, then I’ll map your scene model into a concrete template API and, if the repo supports it, scaffold the template directly.
continue
I’ve confirmed the repo is already a small Remotion template, so I’m reading the current composition and the existing spec next. After that I’ll turn your scene ideas into a stable prop shape and wire it into code rather than keeping this abstract.
The existing composition is still using the old title/hook/problem/solution model, so I’m going to replace that with a scene-driven schema built around your actual inputs: one TLDR, three key points, optional CTA, and uploaded MP4 clips. Then I’ll wire example data and keep the scene logic explicit enough that non-engineers can see how content maps into the video.
I’ve got the shape now: the cleanest way to express this is not “hand-author every scene,” but “author the launch content once, then derive scenes from it.” I’m updating the repo around that model so the template stays reusable while the actual videos stay simple to author.
I’m about to switch the composition over to actual clip-based scenes and add the media package Remotion recommends for embedded videos. After that I’ll update the spec format so a feature launch can be defined with structured data instead of ad hoc copy fields.
The package add pulled @remotion/media at 4.0.432, while the app is on 4.0.381. I’m checking whether that mismatch landed in package.json; if it did, I’ll normalize versions before editing code so the template doesn’t inherit a dependency skew.
I’m editing the type layer first so the rest of the template has a solid contract: one content model for the authoring side, one derived scene model for the rendering side. Then I’ll swap the composition to render those scenes sequentially.
The new spec shape and rendering flow are in place. I’m running typecheck now to catch API mismatches, especially around Remotion media props and the Zod-backed composition schema.
Typecheck found one Remotion API mismatch: pauseWhenBuffering isn’t available on the installed @remotion/media version. I’m removing that prop and rerunning checks, then I’ll do a quick repo diff to make sure the dependency versions and docs line up with the new template.
I noticed the checked-in sample spec still pointed at clip files that don’t exist in the repo. I’m converting that sample to use empty clip sources so the repository can render a placeholder version immediately, while the README still shows the real MP4 path format authors should use.
The template is rendering now against the placeholder sample, which is useful because it verifies the scene timing and layout without needing actual MP4 assets yet. I’m letting that finish, then I’ll do a final pass on the changed files and summarize the authoring model in concrete terms.
The render completed successfully and produced a placeholder MP4, so the new scene system is functionally wired. I’m grabbing exact line references now so I can answer your “how should this be expressed?” question against the code that’s actually in the repo, not a hypothetical sketch.
Implemented the template as a two-layer system: authoring data and derived scenes.
The authoring contract now lives in src/types.ts:1 and the scene expansion logic is in src/template.ts:1. That means the right way to express this is not “write every scene by hand,” but “fill one structured spec,” and the code turns that into: intro, hero demo, alternating key point text/demo scenes, then a branded ender. The composition itself is in src/FeatureVideo.tsx:135, src/FeatureVideo.tsx:274, src/FeatureVideo.tsx:404, and src/FeatureVideo.tsx:515. Root now validates props with Zod and auto-computes duration from the scene list in src/Root.tsx:51.
For actual videos, the expression is now a simple markdown/YAML spec, not custom React per feature. heroDemo.src is the full-screen clip, and each keyPoints[].demo.src is the clip for that benefit. The scaffold and docs are updated in scripts/new-spec.ts:32 and README.md:40, and the render pipeline reads that schema in scripts/render-video.ts:34. I also added @remotion/media and aligned Remotion package versions in package.json:13.
Verified with bun run check and a full render. The placeholder sample rendered successfully to out/instant-feature-videos-placeholder.mp4. One caveat: the branded ender currently uses the existing logo SVG plus a text wordmark because the repo only had traces-logo.svg; if you want the official wordmark asset, add it under public/ and I can swap that in directly.
SPIN up the server and show me what this looks like
I’m starting the Remotion Studio server now and then I’ll grab a few representative frames from the rendered placeholder video so you can see the actual look without having to scrub the timeline yourself.
The studio process is up but I need the actual bind URL from its startup logs. I’m polling that and the frame extraction in parallel now.
I have the studio URL and extracted preview frames. I’m checking the generated images once so I don’t hand you broken previews or awkward capture points.
Studio is running at http://localhost:3010. I left it up so you can scrub the composition directly.
This is the current look using the placeholder sample render at out/instant-feature-videos-placeholder.mp4. The demo scenes are placeholders right now because the sample spec has empty src values.




If you want, I can next drop in one real spec plus real MP4 paths so the preview stops showing placeholders.
btw, you should have default length for the feature demos but should use the actual video length of the cideos given
I’m changing the timing model so clip scenes fall back to defaults only when there’s no media, and otherwise use the actual source duration. First I’m checking what metadata APIs are already available in this Remotion version so I can wire it into calculateMetadata instead of hardcoding more timing.
I found two viable paths: browser-side metadata via @remotion/media-utils, or cross-environment parsing via the newer media parser. I’m checking how calculateMetadata is expected to run in this Remotion version before I pick one, because the right fix is to compute scene durations there once, not inside render-time React code.
calculateMetadata() in this Remotion build is async-capable, and the easiest reliable option is to resolve clip lengths there before the composition timeline is built. I’m inspecting the metadata return shape and then I’ll thread those computed durations into the scene builder with a clean fallback when a clip is missing or unreadable.
I need one more design choice before I patch it: whether to preserve durationInSec as a low-level fallback field or remove it from clip specs entirely. I’m checking how Remotion’s typed Composition handles “user-facing schema + internal resolved props” so I can keep the authoring surface clean while still passing resolved durations into the component.
I’m making two concrete edits: add an async clip-duration resolver in calculateMetadata(), and strip manual scene-duration assumptions out of the clip schema/docs so real MP4s drive their own scene length. I’ll also keep the current default demo timing as the fallback when a clip is missing or unreadable.
I’ve wired the timing resolution into metadata calculation. I’m cleaning up the authoring surface now so the scaffold and docs stop implying that clip durations should be manually specified for normal usage.
I’ve got the code compiling. I’m doing one functional check against a real remote MP4 now, specifically to confirm the composition frame count follows the source video length instead of the old fixed demo timing.
The frame count already confirms the change: the test composition expanded to 532 frames, which is longer than the old fixed-duration version and matches the source clip length being used twice. I’m stopping that validation render now so it doesn’t keep burning time in the background.
The timing change is in and typechecked. I’m just confirming the studio is still healthy after the hot reload so you can inspect the updated behavior immediately in the browser.
Clip timing now works the way you described.
The demo scenes keep their built-in defaults in src/template.ts, but if a src is provided the composition resolves the actual MP4 length in src/resolve-clip-durations.ts and feeds those durations through calculateMetadata() in src/Root.tsx. That also respects trimBeforeSec, trimAfterSec, and playbackRate, so scene length reflects the visible playback duration, not just the raw file.
I also removed manual clip-duration fields from the scaffold and docs so the authoring model matches the behavior now: scripts/new-spec.ts and README.md.
Verified with bun run check, and with a render using a real remote MP4 the composition expanded to 532 frames instead of the old fixed demo timing. Studio is still running at http://localhost:3010.
make videos landcape by default
Using remotion-best-practices again because this is still a Remotion template change. I’m updating the default aspect at the schema, composition defaults, and spec scaffold layers so new videos default to landscape without breaking explicit overrides.
I found every place the default was still pinned to portrait. I’m patching the schema default, the composition’s sample props, the scaffolded spec template, and the sample/doc examples so the default behavior is consistent end to end.
The defaults are updated. I’m running a typecheck and then I’ll confirm the running studio picked up the change cleanly so you can refresh straight into the landscape composition.
Landscape is now the default.
I changed the schema default in src/types.ts, the built-in composition sample in src/Root.tsx, and the generated/spec examples in scripts/new-spec.ts, specs/instant-feature-videos.md, and README.md. Explicit aspect: portrait or aspect: square still override it.
Verified with bun run check. The studio at http://localhost:3010 hot-reloaded, so a refresh should now show the sample in landscape.
look at the globals.css of documents/traces project and use that as your "design system".
Using remotion-best-practices here because this is still a Remotion styling pass. I’m going to inspect the traces app’s globals.css, pull the actual tokens and visual language from it, then restyle the video template around those primitives instead of the ad hoc palette it has now.
The CSS file lives under frontend/app/globals.css, not the repo root. I’m pulling that plus any token file it references so I can map the actual colors, radii, and typography into the Remotion scenes instead of guessing.
The Traces design system is pretty clear from globals.css: neutral surfaces, subtle contour borders, Inter, and indigo as the primary accent. I’m restyling the Remotion scenes around those tokens now, keeping the motion and scene structure but replacing the custom orange/blue cinematic palette with Traces’ actual UI language.