smashcut

Videos, written in TypeScript.

Put every scene in one timeline.ts: text, React components, footage, three.js, captions and music. Preview it live. Render an MP4 with one command.

npx smashcut init my-video
launch.mp4
00:00:00:00
timeline.tsFull file
export default defineVideo({
  size: [1920, 1080],
  fps: 30,
  layers: [
    series([
      group([
        three(logo3D(logoSvg)),
        text("Videos, written in TypeScript.", { at: 1.3 }),
      ], { duration: 3.4 }),
      zoom(0.7),
      group([
        framed(react(Editor, { entry: typing(code) })),
      ], camera(followTheCaret)),
      slide(0.8, { direction: "left" }),
      group([
        framed(video(asset("tour.mp4"), { trim: [1.6, 7.6] })),
        framed(react(Terminal), { chrome: "window" }),
      ], { duration: 6 }),
      zoom(0.8),
      group([
        three(logo3D(logoSvg, { settle: 1 })),
        text("smashcut", { enter: "fade-up" }),
        text("npx smashcut dev", { enter: "zoom" }),
      ]),
    ]),
    subtitles(narration, { preset: "boxed" }),
    decor.grain({ amount: 0.04 }),
  ],
  audio: [
    music(groove({ intensity, end }), { duck: 0.35 }),
    sfx.keys(typing(code), { switch: "tactile" }),
  ],
});
Timeline
Scenes

Psst: this video was rendered by smashcut from the code next to it. Click a scene, or drag the timeline.

How it works

  1. 1. Write
    my-video/
    ├ timeline.ts  the video
    ├ assets/      images, footage
    └ lib/         React components

    Write the timeline

    A video is a folder. It's plain TypeScript, so scenes are functions, timing is arithmetic, and your editor autocompletes everything.

  2. 2. Preview
    The smashcut preview: the video above a timeline with the soundtrack's waveform and a bar for every clip

    Preview it live

    npm run dev opens the video with a timeline of every clip, caption and sound. Save, and it updates. Press N to leave yourself a note.

  3. 3. Render
    $ npm run render
    Rendering frame 598/598
    Wrote out/my-video.mp4 ✓

    Render the file

    npm run render renders every frame in headless Chrome and hands them to ffmpeg, soundtrack included. Same timeline, same file, every time.

What goes on the timeline

Every kind of clip is a function. Mix them however you like: footage in a phone, captions over 3D, a camera move over a React form.

Or let your coding agent make it

Videos are code, so Claude Code, Codex or Cursor can write them. Every video folder comes with a smashcut skill and an AGENTS.md, and two commands let the agent check its own work:

  • smashcut sheet renders a contact sheet, so the agent sees the whole video in one image.
  • smashcut inspect lists every clip, caption and sound with its timing.
  • Notes you leave in the preview (press N) are saved where the agent can read and fix them.

No project yet? Add the skill to Claude Code:

/plugin install smashcut --marketplace volodymyrrudyi/smashcut
out/launch-sheet.png
A contact sheet of the launch video: twelve frames, each labelled with its time and frame number

Make your first video

You need Node 24+ and ffmpeg. The first run also installs the headless browser smashcut renders with.

Terminal
$ npx smashcut init my-video
$ cd my-video && npm install
$ npx playwright install chromium-headless-shell
$ npm run dev      # preview while you edit
$ npm run render   # out/my-video.mp4