---
title: Video components
description: Install polished, temporal React components as source and compose them directly inside video.tsx.
---

Odori's component registry follows the shadcn model: installation copies
source into your project instead of hiding implementation behind a package.

```bash
pnpm odori add \
  @odori/stage \
  @odori/title-reveal \
  @odori/code-proof \
  @odori/terminal \
  @odori/browser-demo \
  @odori/connection-story \
  @odori/end-card
```

`pnpm odori registry` prints the catalog with each component's aspect ratios,
minimum duration, and reduced-motion behavior. Registry dependencies install
with the component that needs them.

Every component also has a page in the [component catalog](/components), one per
registry entry, where the real component plays in the browser at any frame and
format, next to its timing contract, props, and the exact source `odori add`
copies.

<FileTree>

- videos/
  - components/
    - stage/
      - stage.tsx
      - stage.preview.tsx
    - title-reveal/
      - title-reveal.tsx
      - title-reveal.preview.tsx
    - code-proof/
      - code-proof.tsx
      - code-proof.preview.tsx
    - terminal/
      - terminal.tsx
      - terminal.preview.tsx
    - end-card/
      - end-card.tsx
      - end-card.preview.tsx

</FileTree>

Use the components as ordinary React:

```tsx
<Scene id="proof" duration="8s">
  <Stage grid={false}>
    <CodeProof
      code={'export const preview = "instant";'}
      focus={[1]}
      language="tsx"
      title="videos/launch/video.tsx"
    />
  </Stage>
</Scene>
```

## Temporal contracts

Video components need more than prop types. Registry metadata describes:

- supported aspect ratios
- recommended and minimum duration
- natural entrance and exit frames
- content limits, such as maximum headline length
- reduced-motion behavior
- required fonts and audio

`odori test` and the registry test suite check these contracts, while the
copied implementation stays fully editable.

## Scale with the frame, not the width

Components multiply their design values by `useDesignScale()`, which measures
the shorter side of the frame against a 1080px reference. The same component
reads correctly at 1920x1080, 1080x1920, and 1080x1080 without a separate
vertical variant.

```tsx
const scale = useDesignScale();
<div style={{fontSize: 116 * scale, letterSpacing: "-0.045em"}}>{title}</div>;
```

## Component development in Studio

The component source stays independent from its development fixture. A sibling
`*.preview.tsx` file defines representative props, controls, duration, canvas
size, and edge cases for Studio. The fixture is similar to a Storybook story
with a deterministic frame clock.

## Reuse application components

Videos can import deterministic components from an application's root
`components/` directory. Keep those components under their existing product
ownership instead of duplicating them for video.

Add an adapter under `videos/components/product/` when the application
component expects routing, live data, or browser interaction. The adapter
supplies frozen data and disables behavior that depends on wall-clock or
application state.

## Initial component library

| Family | Components |
| --- | --- |
| Typography | Title reveal, metric callout, captions |
| Developer proof | Terminal, code proof |
| Product UI | Browser demo |
| Narrative | Connection story |
| Brand | Stage, end card |

## Install the agent quickstart

The repository also ships an agent skill that turns project evidence into a
coherent first cut and installs a small, story-specific component set:

```bash
npx skills add allenzhou101/odori \
  --skill odori-quickstart \
  --yes
```

## Source ownership

Registry provenance is recorded in `.odori/components.json`, so the CLI can tell
a pristine component from one you have edited and from one the registry has
moved past.

```bash
odori diff                 # what changed, in your project and upstream
odori diff terminal --full # the diff itself
odori update               # apply upstream changes to untouched components
```

Updates are opt-in and source-aware. A component that is both edited locally and
changed upstream is reported as diverged and left alone until you pass
`--force`.
