Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Loaded automatically when the description matches the active task. Read only the reference you need — the upstream references/upstream/rules/ files are authoritative for framework APIs; sibling references in references/ cover our integration patterns (Next.js host, BullMQ workers, Lambda pipeline).
Use this skill when
Building a programmatic video where the timeline is React + JSX (titles, lower-thirds, data-driven product promos, transcriptions, charts in motion)
Writing or refactoring <Composition> / <Sequence> code with useCurrentFrame and useVideoConfig
Rendering MP4 / WebM / GIF / PNG from a React tree — CLI (npx remotion render) or programmatic (renderMedia())
Setting up rendering on AWS via @remotion/lambda (function deploy, site deploy, renderMediaOnLambda, progress / webhook)
Embedding <Player> from @remotion/player in a Next.js, React, or other web app
Parameterizing a composition with defaultProps, inputProps, and calculateMetadata (often driven by a Zod schema)
Wiring renders behind a queue (BullMQ worker) so HTTP handlers never block on long renders
The task is plain FFmpeg work (concat, trim, transcode) with no React layer involved
The task is screen recording (OBS, Loom, system capture) or live streaming
The task is exporting from a timeline-editor tool (After Effects, Premiere, DaVinci) — Remotion does not import those
The video pipeline is React Native or Flutter — Remotion runs in headless Chromium and is web-DOM-only
The user only needs a <video> tag UI / video player chrome with no programmatic rendering
The task is general 2D / canvas animation that never produces a video file (use + a canvas/animation library)
react
Purpose
Remotion turns React components into video. The mental model is simple but specific: the timeline is a pure function of useCurrentFrame(). There is no real time during render — only frame numbers at a fixed fps. Every visual decision (position, opacity, scale) is derived deterministically from the current frame, which means CSS time-based animations and tweening libraries do not work. Animation is done with interpolate() and spring() driven by the frame.
This skill carries the Remotion-team-authored canonical rules (mirrored verbatim under references/upstream/) plus our integration layer: how Remotion plugs into our Next.js apps via <Player> and Server Actions, how renders are offloaded to BullMQ workers that bundle once and reuse the serveUrl, how @remotion/lambda is deployed for high-throughput cloud rendering, and the Linux/AWS gotchas we have hit in production. When canonical Remotion knowledge and our integration recommendations disagree, upstream wins on framework APIs and we override on infra.
Capabilities
Compositions and the frame model
A <Composition> declares an id, a React component, and the fixed shape of the output (durationInFrames, fps, width, height). Inside the component, useCurrentFrame() returns the current 0-indexed frame and useVideoConfig() returns the live shape. <Sequence from={N} durationInFrames={M}> shifts the frame for its children (so the child animates from 0) and unmounts them outside the range. <AbsoluteFill> is the standard root — full-canvas, flexbox-ready. CSS transition/@keyframes and Tailwind animate-* classes are forbidden because they depend on wall-clock time.
The CLI path is npx remotion render <id> [output]. The programmatic path is three steps: bundle() produces a serveUrl; selectComposition() resolves the chosen <Composition> and applies calculateMetadata; renderMedia() writes the file. The renderer ships its own FFmpeg — no system install required for the common path. renderStill() is the single-frame equivalent for poster images / OG cards. Long-lived workers should bundle()once at boot and reuse the serveUrl across renders.
@remotion/lambda splits a render across many AWS Lambda invocations and stitches the result via S3. One-time setup: npx remotion lambda functions deploy (per region) + npx remotion lambda sites create (per project version). At render time: renderMediaOnLambda({ region, functionName, serveUrl, composition, inputProps, codec, privacy }) returns { renderId, bucketName }. Track completion via polling getRenderProgress or via a signed webhook. progress.costs.displayCost is exposed for billing dashboards.
Compositions accept defaultProps (Studio fallback) and inputProps (runtime override). Both must be JSON-serializable; Date, Map, Set, and staticFile() references are explicitly allowed. calculateMetadata({ props, abortSignal }) runs server-side / pre-render and can change durationInFrames, width, height, fps, and reshape props. A Zod schema attached via <Composition schema={...}> gives Studio a typed editor and gives your API a re-validation contract.
@remotion/player ships a <Player> component that runs the same composition in the browser, scrubbable and interactive. Required props: component, inputProps, durationInFrames, fps, compositionWidth, compositionHeight. Composition modules reference Remotion hooks and must live behind a "use client" boundary — they will throw if imported into a Server Component. Server-side renderStill works inside a Node-runtime Route Handler (Edge runtime cannot launch Chromium).
Renders exceed HTTP timeouts. The right shape is HTTP enqueue → BullMQ worker renders → signed URL returned later. Workers bundle once at boot; per-worker concurrency starts at 1–2 (one render saturates 2–4 CPU cores). job.updateProgress carries phase + percent to the UI via SSE/WebSocket. Lambda-backed workers delegate the heavy lifting to AWS but follow the same lifecycle.
Static assets go under public/ and load via staticFile("name.ext"). Images: <Img> from remotion. Videos: <Video> from @remotion/media. Audio: <Audio> from @remotion/media. Google Fonts via @remotion/google-fonts is the recommended font path; local fonts via @remotion/fontsloadFont(). Always await font loading before first render — Remotion does not block on missing fonts.
Captions: references/upstream/rules/subtitles.md (entry) → display-captions.md, import-srt-captions.md, transcribe-captions.md. Transitions between scenes: references/upstream/rules/transitions.md. 3D via Three.js + React Three Fiber: references/upstream/rules/3d.md. MapLibre flyovers: references/upstream/rules/maplibre.md.
Behavioral Traits
Drives every animation from useCurrentFrame() via interpolate() or spring() — never CSS transitions, never Tailwind animate-*, never timers
Reads fps / width / height from useVideoConfig() — never hardcodes them in component bodies
Bundles once at worker / server boot and reuses serveUrl — never re-bundles per render
Re-validates inputProps via the composition's Zod schema at the API edge before enqueuing
Threads abortSignal into every fetch inside calculateMetadata so Studio cancels cleanly when props change
Marks every module that imports composition components "use client" (or imports them only from a client component) — Remotion hooks throw in RSC
Tags Route Handlers / Server Actions that touch the renderer with runtime = "nodejs" — Edge cannot launch Chromium
For renders longer than seconds, always queues via BullMQ rather than calling renderMedia inline
Loads upstream rules from references/upstream/rules/ for any composition-internal question; loads sibling refs for any infra question
Surfaces progress.costs.displayCost from Lambda renders to admin dashboards
Important Constraints
NEVER use CSS transition / @keyframes / Tailwind animate-* classes inside compositions — they depend on wall-clock time and will not render correctly
NEVER hardcode fps, durationInFrames, width, height inside a component body — read them from useVideoConfig() so the same composition reuses at 720p/1080p/4K
NEVER call renderMedia directly inside a Next.js Route Handler, Server Action, or any HTTP handler — long renders block the response. Queue them
NEVER run renders on the Edge runtime — no Chromium binary. Always runtime = "nodejs" for any render endpoint
NEVER pass non-JSON values (functions, class instances, Buffer, streams, regex) in inputProps / defaultProps — they break worker/Lambda serialization
NEVER bundle once per job in a worker — bundle at boot and reuse serveUrl; per-job bundling wastes 5–30 s of Webpack work
NEVER import composition components from a Server Component — Remotion hooks need a client runtime context
ALWAYS pre-load fonts (@remotion/google-fontswaitUntilDone() or equivalent) before first render; Remotion does not silently wait for fonts
ALWAYS install Chromium's Linux system libs (libnss3, libatk1.0-0, libgbm1, etc.) on a bare Ubuntu server before running renders
ALWAYS thread abortSignal into fetches inside calculateMetadata — Studio re-runs it on every prop edit
Related Skills
90%-popularity filter applied — only mainstream choices that pair with Remotion in 2026 projects.
Foundation
react — React 19 runtime; the entire composition tree is React
typescript — props typed via Zod-inferred types; composition schemas
nodejs — server-side bundler/renderer runs on Node 24
How to use: navigate to the specific file relevant to the task. For composition-internal questions start with upstream/rules/*; for infra/integration questions start with the sibling files in references/.