---
description: Remotion composition and animation conventions
globs: ["src/**/*.{ts,tsx}", "remotion.config.ts"]
alwaysApply: false
---

# Remotion

## Commands
- Preview: `npx remotion studio` · Render: `npx remotion render <CompositionId> out/video.mp4` · Still: `npx remotion still <CompositionId> out/frame.png --frame=30`
- Typecheck and lint with the repo scripts before reporting done. Never upgrade one `remotion`/`@remotion/*` package alone; all must share the same version.

## Rules
- Every visual change is a pure function of the frame: read `useCurrentFrame()` and `useVideoConfig()` (`fps`, `width`, `height`, `durationInFrames`). No CSS transitions/animations, `setTimeout`, `requestAnimationFrame` or `Date.now()`; they render differently on each frame or worker.
- Animate with `interpolate(frame, [start, end], [from, to], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' })` and `spring({ frame, fps, config })`. Express timings in seconds × `fps`, not magic frame numbers.
- Register compositions in `src/Root.tsx` with `id`, `component`, `durationInFrames`, `fps`, `width`, `height` and `defaultProps`. Give props a zod `schema` so they are editable in the Studio and validated on render.
- Time shots with `<Sequence from={...} durationInFrames={...}>` or `<Series>`; inside a sequence, `useCurrentFrame()` is relative to its start.
- Layout with `<AbsoluteFill>`; keep each scene in its own component file under `src/scenes/`.
- Assets go in `public/` and load via `staticFile('name.png')`. Use Remotion's media components (`<Img>`, `<Audio>`, `<OffthreadVideo>`/`<Video>` as the installed version documents), never raw `<img>`/`<video>`, so rendering waits for them.
- Data or font loading: wrap in `delayRender()`/`continueRender()` (or `calculateMetadata` for data that changes duration). Always handle errors with `cancelRender(err)` so a render never hangs.
- Seeded randomness only: `random('seed-string')`, never `Math.random()`.
- Keep text in props, not hardcoded, so the same composition renders many variants.

## Done when
Studio preview plays the changed scene without warnings and a test render of the composition finishes.
