Skip to main content

remotion-interactivity

Structure Remotion markup for interactivity

Aller à l'installation

Informations de source

Dépôt
remotion-dev/remotion
Dernière activité de la source
16 septembre 2026 à 14:48
Langue détectée de SKILL.md
anglais
Étoiles
59 638
Forks
4 567

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
3 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
remotion-interactivity
description
Structure Remotion markup for interactivity
version
4.0.525
By writing Remotion markup in a specific way, the Remotion Studio is able to recognize the structure of the code and makes it interactive: - Allowing items to be selected by clicking on them - Allowing drag+drop, resizing and rotation - Editing the CSS styles - Making keyframes and easing values editable If the markup is too complex for the Studio to make it interactive, then the values become grayed out. ## Make an HTML element interactive using `Interactive` Every HTML and SVG element (except `<Img>`, it already is interactive) such as `<div>` can be turned interactive using `Interactive`: ```tsx title="Interactive elements" <Interactive.Div name="Greeting card" style={{fontSize: 80, padding: 24}} > Hello </Interactive.Div> ``` This allows styles and keyframes to be set in the Studio. Be sensible, if a component has many elements, the timeline might get messy. ## Prefer inline text If text is fixed and only used once, write it directly inside the interactive element instead of extracting it into a constant. ```tsx title="Inline text" // 👍 Fixed copy stays editable <Interactive.Div name="Title"> Remotion Best Practices </Interactive.Div> ``` Use a prop or variable only when the text is dynamic or reused. ## Give interactive elements a descriptive name Add a `name` prop to elements to make them easily identifyable. Avoid computed names, hardcode them. ```tsx title="Interactive names" <> <Interactive.Div name="Hero title" style={{fontSize: 80}}> Launch day </Interactive.Div> <Img name="Avatar" src="https://remotion.media/image.jpeg" /> <Video name="Background" src="https://remotion.media/video.mp4" /> <Sequence name="Title"> Launch day </Sequence> </> ``` ## Keep all CSS styles inline The best way is to just pass a plain object to `style` - no referring to constants, no object spreading, no math. ```tsx title="Interactive example" <Interactive.Div style={{ fontSize: 80, color: 'red', }} > Hello World! </Interactive.Div> ``` ```tsx title="❌ Bad for interactivity" const baseStyle = useMemo(() => { return { fontSize: 12 // ❌ Non-inline styles are not supported } }, []); <Interactive.Div style={{ ...baseStyle, // ❌ Spreading is not supported color: RED, // ❌ Referring to constants is not supported scale: frame * 10 // ❌ Math is not supported }} > Hello World! </Interactive.Div> ``` ## Animate using `interpolate()` Write animations as inline `interpolate()` calls on the property that changes. The output range, easing, extrapolation and `output` property should use hardcoded values. The input range may additionally use `durationInFrames`, `fps`, `width` and `height` destructured directly from `useVideoConfig()`. Bare identifiers such as `durationInFrames`, multiplication with a number such as `2 * fps` or `fps * 2`, and subtraction of a number such as `durationInFrames - 1` are supported. ```tsx title="Inline values" const {fps, durationInFrames} = useVideoConfig(); // 👍 Inline values can be standardized and keyframed <Interactive.Div name="Product card" style={{ color: 'white', fontSize: 80, scale: interpolate(frame, [0, fps], [0, 1], { easing: Easing.spring({damping: 200}), output: 'perceptual-scale', extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }), rotate: interpolate(frame, [0, 1 * fps], ['0deg', '20deg'], { easing: Easing.spring({damping: 200}), extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }), translate: interpolate( frame, [durationInFrames - 30, durationInFrames], ['0px 0px', '0px 120px'], { easing: Easing.spring({damping: 200}), output: 'perceptual-scale', extrapolateLeft: 'clamp', extrapolateRight: 'clamp' } ), }} /> ``` ```tsx title="❌ Bad interactivity" const translateY = interpolate(frame, [0, 30], [0, 120]); // ❌ Math should be directly in the markup <Interactive.Div name="Product card" style={{ translate: translateY, // ❌ Only inline interpolate() calls are supported, rotate: interpolate(frame, [start, start + 10], [0, Math.PI]), // ❌ Cannot use math with arbitrary variables, cannot use constants scale: interpolate(anyVariable, [0, 30], [0, 1]) // ❌ Can only interpret the `frame` variable. }} /> ``` ## Use `scale`, `translate`, `rotate` CSS properties Avoid the `transform` CSS property. If possible, use `scale`, `rotate` and `translate` instead because only they are interactively editable. ## Keep composition metadata inline When scaffolding a composition, keep `width`, `height`, `fps`, `durationInFrames` and `defaultProps` inline and make no type assertions. The Props editor can save visual edits back to your code when `defaultProps` is an inline object literal on `<Composition>` or `<Still>`. ```tsx // 👍 Static values are in <Composition>, dynamic values are in calculateMetadata() const calculateMetadata = useMemo(async () => { const dimensions = await getDimensions(); // just an example return {width: dimensions.width, height: dimensions.height}; }); <Composition id="my-video" component={MyComponent} durationInFrames={150} fps={30} calculateMetadata={calculateMetadata} defaultProps={{title: 'Hello', color: '#0b84ff'}} /> ``` ```tsx title="Negative examples" const defaultProps = {title: 'Hello', color: '#0b84ff'}; // ❌ Don't extract defaultProps, must be inline const calculateMetadata = useMemo(() => { // ❌ Unnecessary because no calculation is being done, return {durationInFrames: 150, fps: 30, width: 1920, height: 1080}; }); <Composition id="my-video" component={MyComponent} calculateMetadata={calculateMetadata} defaultProps={{ title: 'Hello', } as Props} // ❌ Don't have type assertions, instead type MyComponent correctly /> ``` Use only `calculateMetadata()` for the part of the metadata that is dynamic. ## Effects should be inline too The effects array should not be computed. The same rules for setting keyframes as `interpolate()` apply too here: All values should also be hardcoded: Input range, output range, easing, extrapolation, `output` property. ```tsx title="Effects" // 👍 Parameters are inline and the array shape is stable <CanvasImage src={src} width={1280} height={720} effects={[ radialProgressiveBlur({ center: [0.5, 0.5], width: 1.2, height: 0.8, start: 0.2, disabled: true, rotation: interpolate(frame, [0, 120], [0, 180]), }), ]} /> const center = [0.5, 0.5] as const; const rotation = frame * 1.5; <CanvasImage src={src} width={1280} height={720} // ❌ Conditional effect is not animateable effects={enabled ? [ radialProgressiveBlur({ // ❌ Not inline center, rotation, }), ] : []} /> ``` Render separate elements if one version should have effects and another should not. ## Making your own component interactive When using `Interactive.withSchema()`, include `Interactive.baseSchema` in the schema so standard timeline controls such as trimming and visibility remain available. To make a custom userland component interactive, use: [Make a component interactive](https://www.remotion.dev/docs/studio/make-component-interactive.md) ## Video editing If a Remotion component mainly consists of video and audio clips, see [Video editing](../remotion-markup/video-editing.md) for best practices on how to structure Remotion markup so the clips are interactively editable in the timeline.
Voir sur GitHub