Video Studio
GitHub

Studio

A small Remotion studio for motion graphics

The Remotion project for personal motion graphics: a small, consistent component library (src/lib/) plus one folder per video (src/videos/<slug>/), rendered frame by frame from React.

  • 14components
  • 29motion helpers
  • 48design tokens
  • 6example videos
  • 2engines
On this page

What it is

Deterministic frames

Every frame is a pure function of the frame number: useCurrentFrame, interpolate, spring. No CSS transitions, timers or Math.random, so a still and a render always agree.

Reusable components

14 small components in src/lib: titles, staggered text, captions, counters, charts, masks, sound. Prop-driven, frame-local, safe by default.

One folder per video

Each film lives in src/videos/<slug>/ with its scenes and a timeline file, registered in Root.tsx. Copy the template to start.

Design tokens

Palette, type scale, spacing, safe margins, springs, easing and timing live in one tokens file. Change values there, never inline in a scene.

See it

LibraryShowcase, 15 s, 1920×1080 at 30 fps: every library component in one film, rendered from this project.

New here? The illustrated guide walks through the whole workflow.

Quick start

Prerequisites: Node 24 (or 20.19+ / 22.13+), ffmpeg on PATH (for stills contact sheets and sfx).

cd studio
npm install
npm run typecheck                                   # tsc --noEmit
npm run stills -- LibraryShowcase 50,130,245,350,449  # PNGs + contact sheet in out/stills/LibraryShowcase/
npm run render -- LibraryShowcase out/LibraryShowcase.mp4
npm run dev                                         # Remotion Studio preview (long-running; stop with Ctrl+C)

Scripts

ScriptWhat it does
npm run devRemotion Studio, the interactive preview
npm run render -- <CompId> [out.mp4]remotion render; e.g. npm run render -- Showcase-Vertical out/vertical.mp4
npm run stills -- <CompId> <f1,f2,...>Bundles once, renders each frame with remotion still to out/stills/<CompId>/f<frame>.png, then tiles them into contact-sheet.png with ffmpeg
npm run typechecktsc --noEmit
npm run lintESLint (Remotion rules, e.g. flags non frame-based animation) + typecheck
npm run sfxRegenerates the built-in sound cues in public/sfx/ with ffmpeg
npm run buildremotion bundle
npm run upgraderemotion upgrade (keeps all Remotion packages on one version)

out/ is gitignored.

Start a new video

  1. Copy src/videos/_template/ to src/videos/<slug>/; rename Template to your video's name.
  2. One component per scene (copy Scene.tsx), one focal point per scene, built from src/lib components and tokens only.
  3. Chain scenes in a <TransitionSeries>, with presets.wipe() / fade() / circle() and transitionTiming() between them. Duration = sum of scenes - 15 frames per transition. Keep scene lengths in a timeline.ts like the showcase does.
  4. Register the composition in src/Root.tsx inside a <Folder>, with inline id, fps={30}, width, height, durationInFrames.
  5. Judge rendered frames, not code: npm run stills -- <CompId> <scene boundaries, text-heavy frames, mid-transition frames, last frame>, open the PNGs, fix, repeat. Then render the MP4 and check it with ffprobe.

The paper trail for each video (brief, storyboard, review) lives in ../projects/<yyyy-mm-dd>-<slug>/, see the repo CLAUDE.md.

Example videos

Read these before writing a scene: each one shows the library in use.

Films

Because

The word is already cut. be stays, fore leaves, cause grows from the blade, and that same 3px mark becomes the frame.

1920×1080 · 50 s · src/videos/because

BackgroundSfxcuesfont

Library

LibraryShowcase

15 s tour of every library component. 1920x1080, 30 fps.

1920×1080 · src/videos/library-showcase

SfxcuespresetstransitionTimingBackgroundBarChartCaptionsCharStagger

Library

Showcase-Vertical

15 s tour of every library component. 1920x1080, 30 fps.

1080×1920 · 8.5 s · src/videos/library-showcase

SfxcuespresetstransitionTimingBackgroundBarChartCaptionsCharStagger

Library

TechniquesDemo

11.4 s, 1920x1080, 30 fps. One restrained piece that uses each new helper once: FragmentChain + vw ramp (scene 1), velocity-matched cut, buoyant ease + speedCurve camera + logZoom (scene 2), occluder cut, GhostType (scene 3).

1920×1080 · src/videos/techniques-demo

BackgroundCameraFragmentChainGhostTypeSafeAreaShapeMaskbuoyantfont

Reels

CapabilityReel

60 seconds, 1920×1080. Play this in Remotion Studio; do not encode an MP4 to preview it.

1920×1080 · src/videos/capability-reel

SfxcuespresetstransitionTimingBackgroundBarChartCaptionsCharStagger

Templates

Template

One scene = one component = one focal point. Copy this file per scene (Scene1Hook.tsx, Scene2Problem.tsx, ...). Frames inside a scene start at 0, whatever its position in the video.

1920×1080 · 3 s · src/videos/_template

BackgroundSafeAreaTitleReveal

New helpers from the research

Techniques that earned a place in the library after the Claude motion research. Each links to the finding it came from.

buoyant()

"Buoyant" ease: a cubic ease-out plus a half-sine bob over the WHOLE lifetime, so a rising element keeps drifting through its peak instead of freezing. Returns 0 at t=0 and exactly 1 at t=1; in between it overshoots by about bob and settles back.

velocityCut()

Velocity-matched cut: the outgoing scene accelerates and is cut at its fastest frame, the incoming scene starts at the same speed and brakes to rest, so momentum crosses the edit. Pair with velocityCutTiming(frames) using the SAME frames. Delay the incomin

FragmentChain

Film copy as fragments, not sentences (F-A2). Recipes: the animation is the verb (words before and after the demo, never describing it), stem plus rotating slot instead of a list. One accent per frame: only the newest fragment is accented.

speedCurve()

Camera driven by speed, not by position keys. The table gives speed as a share of cruise at times (0 at 0 s, 0.5 by 0.6 s, 1.0 by 1.6 s, held, easing to 0.12 at 8.3 s), the shares are smoothstepped between keys, integrated into position, and scaled so the came

GhostType

Typewriter text with a locked layout (F-C14). The FULL text is always laid out in the same inline flow; characters not typed yet are just transparent. Lines can never reflow and the box never changes height while typing. No cursor on purpose (see DESIGN_SYSTEM

Two engines

Remotion (this project) is the default: kinetic type, titles, UI demos, diagrams, data, captions, reels, templates. The HTML engine in skills/motion-studio is for narrated product films where every cut lands on a spoken word. Which one, and what each contains.

Go deeper