Deft
Ask AI

Search

Search skills, authors and topics

remotion-dev / skills

remotion-markup

Structure Remotion scenes with markup patterns for layout, typography, and reusable video UI.

Install

npx skills add https://github.com/remotion-dev/skills --skill remotion-markup
metadata
tags: composition, still, folder, props, metadata

A <Composition> defines the component, width, height, fps and duration of a renderable video.

Source-editable registrations

Give each composition or still that should be edited independently in the Studio its own authored JSX node. Use a JSX string literal for id, and keep its metadata and editable default values directly on that node.

Programmatic registration is suitable when the generated compositions are intentionally controlled as one source template and do not need to be reordered, duplicated, deleted or edited individually in the Studio.

tsx
type Props = {  readonly title: string;};
export const MyComposition = ({title}: Props) => <h1>{title}</h1>;
tsx
import {Composition} from 'remotion';import {MyComposition} from './MyComposition';
export const RemotionRoot = () => {  return (    <>      <Composition        id="Launch"        component={MyComposition}        durationInFrames={180}        fps={30}        width={1920}        height={1080}        defaultProps={{title: 'Launch'}}      />      <Composition        id="Recap"        component={MyComposition}        durationInFrames={240}        fps={30}        width={1920}        height={1080}        defaultProps={{title: 'Recap'}}      />    </>  );};

Both registrations can reuse the same component. Keeping them as separate JSX nodes gives each one its own source-editing target.

Default Props and scaffold metadata

Pass defaultProps to provide initial values for your component.
Values must be JSON-serializable (Date, Map, Set, and staticFile() are supported). Use defaultProps for composition-wide values that should be visible and editable before the video renders.

Keep data owned by a child editor on that child's JSX node. For example, captions that should remain editable in the Caption editor belong as an inline array on <BasicCaptions>, not in composition defaultProps or a component prop. See Displaying captions (display-captions.md in the remotion-captions skill).

For Studio editing, keep defaultProps as an inline object literal on <Composition> or <Still>. Keep values that should be written back directly in the object instead of deriving them from a loop variable. Do not store it in a variable, import it, spread it, create it with a helper, or wrap it in satisfies. Use type declarations for props rather than interface to ensure defaultProps type safety.

tsx
import {Composition} from 'remotion';import {MyComposition} from './MyComposition';
const defaultProps = { title: "Hello World" };
export const RemotionRoot = () => {  return (    <>      {/* 👍 Inline metadata and defaults */}      <Composition        id="MyComposition"        component={MyComposition}        durationInFrames={100}        fps={30}        width={1080}        height={1080}        defaultProps={{ title: "Hello World" }}      />
      {/* 👎 Hidden defaults cannot be saved back by Studio */}      <Composition        id="OtherComposition"        component={MyComposition}        durationInFrames={100}        fps={30}        width={1080}        height={1080}        defaultProps={defaultProps}      />    </>  );};

Folders

Use <Folder> to organize compositions in the sidebar.
Folder names can only contain letters, numbers, and hyphens.

tsx
import { Composition, Folder } from "remotion";
export const RemotionRoot = () => {  return (    <>      <Folder name="Marketing">        <Composition id="Promo" /* ... */ />        <Composition id="Ad" /* ... */ />      </Folder>      <Folder name="Social">        <Folder name="Instagram">          <Composition id="Story" /* ... */ />          <Composition id="Reel" /* ... */ />        </Folder>      </Folder>    </>  );};

Stills

Use <Still> for single-frame images. It does not require durationInFrames or fps.

tsx
import { Still } from "remotion";import { Thumbnail } from "./Thumbnail";
export const RemotionRoot = () => {  return (    <Still      id="Thumbnail"      component={Thumbnail}      width={1280}      height={720}    />  );};

Dynamic duration, width, and height

Use calculateMetadata to make dimensions, duration, or props dynamic based on input props, fetched data, or asset metadata.

Nesting compositions within another

To render a composition's component inside another composition, use <Sequence> with width and height when the nested content needs its own dimensions.

When the nested scene should have its own editable Studio timeline, use the connected composition structure [blocked].

tsx
<>  <Video src="https://remotion.media/video.mp4" />  <Sequence    width={1920}    height={1080}  >    <OverlayComponent />  </Sequence></>