Write reusable components

A reusable Odori component is a React component. Keep its presentation configurable through props, read the shared brand, and add a preview fixture so it can be reviewed independently in Studio.

Create a component

Create videos/components/headline/headline.tsx. This component adapts its typography and spacing to the design scale:

import {Fill, useBrand, useDesignScale} from "odori";

export function Headline({title}: {title: string}) {
  const brand = useBrand();
  const scale = useDesignScale();
  return (
    <Fill style={{
      justifyContent: "center",
      padding: 96 * scale,
      background: brand.colors.background,
      color: brand.colors.foreground,
      fontFamily: brand.typography.sans,
    }}>
      <h1 style={{fontSize: 88 * scale, margin: 0}}>{title}</h1>
    </Fill>
  );
}

Use props for content that changes between videos. Use the brand for shared visual decisions. See layouts and brands to define those defaults.

Add a preview fixture

Create videos/components/headline/headline.preview.tsx beside the implementation:

import {defineComponentPreview} from "odori/preview";
import {Headline} from "./headline";

export default defineComponentPreview({
  title: "Headline",
  category: "Typography",
  component: Headline,
  canvas: {width: 1920, height: 1080, duration: "4s"},
  controls: {
    title: {type: "text", defaultValue: "Meet the new editor."},
  },
  examples: [
    {name: "Short", props: {title: "Ship it."}},
    {name: "Long", props: {title: "A better place to build together."}},
  ],
});

Start Studio with pnpm odori dev and open Components. Test both examples, then check portrait and square formats. Scaling preserves proportions; it does not guarantee that a long headline fits every aspect ratio.

Use it in a video

Import the implementation into a scene. Do not import the preview fixture into the production video:

import {Scene} from "odori";
import {Headline} from "../components/headline/headline";

export function Opening() {
  return (
    <Scene id="opening" duration="4s">
      <Headline title="Meet the new editor." />
    </Scene>
  );
}

Preview fixtures describe development controls and sample props. They are discovered separately from exportable video entries.

Organize shared and local code

Put code shared by several videos under videos/components/. Keep a video-specific component beside that video's entry, optionally in a local components/ directory. A directory alone does not create a video; discovery looks for entry filenames.

For installed registry components, keep odori.lock.json in version control. Review upstream changes with pnpm odori diff before updating edited source. See installing components.

On this page