Skip to content
Esc
navigateopen⌘Jpreview

Changelog

A release note as a cut: what changed, the diff that proves it, and the upgrade line.

16:9 · every frame here is the frame odori export writes.

The files

A block is a directory, not a bundle. Pick a file to read the source it ships with.

videos/changelog/components/diff-proof/end-card/stage/title-reveal/
videos/changelog/video.tsx
import {Audio, Scene, Video, defineVideoMetadata} from "odori";
import {DiffProof} from "../components/diff-proof/diff-proof";
import {EndCard} from "../components/end-card/end-card";
import {Stage} from "../components/stage/stage";
import {TitleReveal} from "../components/title-reveal/title-reveal";
import {productLayout} from "../layout";
import {changelogInput} from "./schema";

/**
 * A release note as a video: what changed, the diff that proves it, and where
 * to get it. Swap the diff lines and the three strings and this ships.
 */
export const metadata = defineVideoMetadata({
  title: "Changelog",
  description: "A release note: the change, the diff, and the upgrade line.",
  duration: "12s",
  layout: productLayout,
  schema: changelogInput,
  tags: ["changelog", "release"],
  thumbnailFrame: 40,
});

export default function ChangelogVideo({version, headline, upgrade}: {version: string; headline: string; upgrade: string}) {
  return (
    <Video>
      <Scene id="opening" duration="4s" name="Opening">
        <Stage>
          <TitleReveal title={headline} detail={`${version} · shipped this week.`} />
        </Stage>
      </Scene>
      <Scene id="diff" duration="5s" name="Diff">
        {/* A generated cue: the score lives in videos/components/ui-key. */}
        {/* A curve, not a number: the click ducks away as the diff settles. */}
        <Audio src="ui.key" from="0.3s" gain={(frame) => (frame < 3 ? 0.5 : 0.2)} />
        <Stage grid={false}>
          <DiffProof
            title="videos/launch/video.tsx"
            lines={[
              {text: "<Video>", kind: "context"},
              {text: '  <Scene duration="4s">', kind: "removed"},
              {text: '  <Scene id="opening" duration="4s" name="Opening">', kind: "added"},
              {text: "    <TitleReveal title={headline} />", kind: "context"},
              {text: "  </Scene>", kind: "context"},
              {text: "</Video>", kind: "context"},
            ]}
          />
        </Stage>
      </Scene>
      <Scene id="end" duration="3s" name="End">
        <Stage>
          <EndCard title="Named scenes." detail="Readable timelines, unchanged renders." callToAction={upgrade} />
        </Stage>
      </Scene>
    </Video>
  );
}

Remix it

Scaffold a project, install the components this block uses, then paste the entry into videos/changelog/video.tsx. Every file above is yours to edit from that point on.

pnpm create odori@latest my-video
pnpm odori add @odori/stage @odori/title-reveal @odori/diff-proof @odori/end-card

Other blocks