Creating custom components
Build your own caption and callout components with the CaptionProps and CalloutProps contract.
A custom component is a React component that receives a standard set of props from the renderer and returns JSX. This page walks through the contract and a complete example.
The contract
Every overlay component receives props from the OverlayLayer. There are two contracts — one for captions, one for callouts.
CaptionProps
| Prop | Type | Default |
|---|---|---|
name | | - |
type | | - |
| Prop | Description |
|---|---|
overlay.text | The caption text the author wrote in demo.ts. |
opacity | A 0–1 fade computed from fromFrame/durationInFrames. The layer ramps in over 12 frames and out over 12 frames. Use this to fade your component. |
overlay.fromFrame | The frame this caption appears. |
overlay.durationInFrames | How many frames the caption stays visible. |
CalloutProps
| Prop | Type | Default |
|---|---|---|
name | | - |
type | | - |
| Prop | Description |
|---|---|
overlay.title | Required callout title. |
overlay.description | Optional description text. |
opacity | Same 0–1 fade as captions. |
box | The target's on-screen bounding box, already transformed by the camera. Position your callout relative to this. BoundingBox = { x, y, width, height } in stage coordinates. |
Rules for a good component
Every component runs inside a Remotion composition. Import
useCurrentFrame from "remotion" and derive animation from the frame
number. Never use setTimeout, requestAnimationFrame, or side effects —
Remotion requires pure, frame-deterministic rendering.
Always pass { extrapolateLeft: "clamp", extrapolateRight: "clamp" } to
interpolate so values don't overshoot outside the input range:
The layer computes a fade-in/fade-out for you. Multiply your own opacity
by the opacity prop so the overlay ramps correctly:
Complete example: remocn.pulse-callout
A callout that pulses (scales up and down) while visible.
1. Create the component file
2. Register it in your entry
3. Use it in a demo
4. Render
What's exported from @democraft/remotion
For building components, the package exports:
| Export | Purpose |
|---|---|
CaptionProps, CalloutProps | The prop contracts. |
VisualRegistry | The registry type. |
defineVisualRegistry(...entries) | Build a custom registry extending defaults. |
defaultVisualRegistry | The built-in registry (all motion.* + remocn.*). |
Caption, Callout, KineticCaption, GlassCallout | The built-in components (to extend or reference). |
ProductDemoVideo, defaultProductDemoProps | The composition component and its default props. |
remocnAdapter(options?) | The remocn adapter factory. |
Experimental
Component schemas (zod-based prop validation) and theme presets are planned but not yet implemented. Today, the renderer string is validated only at render time. An explicit unknown ID fails with the registered renderer list; it never silently falls back to a default.
Next steps
- Custom entry — the full entry point setup.
- Components overview — the namespace convention and built-in catalog.