CLI
Every odori command, its flags, and what it writes.
The CLI ships as @odori/cli and installs a odori binary.
pnpm add -D @odori/cli
pnpm odori --help
odori dev
Discovers the project, regenerates .odori/, and starts Studio.
odori dev --port 4300
Studio watches videos/ and reloads when a video.tsx, *.preview.tsx, or
brand module appears or disappears. The dev server also exposes the endpoints
Studio uses to request a still or an export.
Studio opens in the default browser when the shell is interactive. Pass
--no-open, set open: false in odori.config.ts, or set ODORI_OPEN=0 to
start without it. CI and piped output never open a browser.
odori dev --no-open
docsUrl in odori.config.ts sets where Studio’s documentation link points,
and defaults to the local docs site at http://localhost:4321.
odori init
Adds videos/layout.tsx, a first videos/launch/video.tsx, and
odori.config.ts to an existing project. Existing files are never overwritten.
odori new <name>
Generates videos/<name>/video.tsx with static metadata and a JSX timeline. It
wires the root layout when videos/layout.tsx exists.
odori add <components...>
Copies registry component source and its preview fixture into
videos/components/, resolves registry dependencies, and records provenance in
.odori/components.json.
odori add @odori/title-reveal @odori/end-card
odori add @odori/terminal --force
A component you have edited locally is kept, with a warning, unless --force
is passed.
odori registry
Prints the catalog grouped by family, with aspect ratios, minimum duration, and reduced-motion behavior for each component.
odori diff [components...]
Compares installed component source with the version that was installed and
with the version the registry ships today. Each component is reported as
up to date, modified locally, update available, or modified locally and updated upstream.
odori diff
odori diff terminal --full
odori update [components...]
Applies upstream changes to components you have not edited. A component that is
both edited locally and changed upstream is left alone until you review it with
odori diff and pass --force.
odori list
Prints discovered video IDs, formats, durations, source files, and the number of component previews.
odori inspect <id>
Resolves the layout, compiles the timeline in a browser, runs prepare.ts, and
freezes a manifest.
odori inspect launch
odori inspect launch --json --input '{"headline":"Ship it."}'
odori still <id>
Renders one deterministic frame.
odori still launch --frame 120 --output out/hero.png
odori test [id]
Validates contracts and representative frames for one video or all of them. It fails when default props do not satisfy the schema, when a declared duration disagrees with the compiled scene total, when a frame is blank, when content escapes the canvas, or when text is smaller than 20px at a 1080p reference.
odori export <id>
Freezes a manifest, records a job under .odori/builds/, renders every frame
through the readiness handshake, mixes the audio track, and encodes an MP4 with
FFmpeg. Frames are captured by several browser workers in parallel.
odori export launch --output out/launch.mp4
odori export launch --concurrency 8 --preset slow
odori export --retry job-88e09129a0-msw17lz9
A retry replays the frozen manifest, so it never re-resolves inputs or reruns
prepare.ts.
odori jobs
Lists recorded export jobs with status, attempts, and output path.
job-88e09129a0-msw17lz9 launch ready attempts 2 out/launch.mp4
Shared flags
| Flag | Purpose |
|---|---|
--input '<json>' |
Serializable input validated by the video schema |
--output <path> |
Output path for still and export |
--force |
Replace locally modified component source |
--json |
Machine-readable output for inspect |
--concurrency <n> |
Parallel render workers for export |
--preset <name> |
x264 preset for export, default medium |
--retry <job id> |
Re-run a recorded job from its frozen manifest |
--full |
Print the diff body in diff |
Requirements
Rendering needs Chrome or Chromium and FFmpeg. Odori looks for a browser at the
usual macOS and Linux locations, at chromePath in odori.config.ts, or at
ODORI_CHROME.