defnotmid

Projects / 05

onimite

Make videos by writing a script, or by asking your coding agent to. One small program turns the script into an MP4, plays it while you edit, and tells you what's wrong with it.

  • Odin
  • Lua 5.4
  • MIT
  • 17.6 MB installed
  • GPU or --software
  • Linux · macOS
Source on GitHub ↗
onimite saga: a two-minute film about onimite, made with onimite. Slow and dramatic, then K-pop, then a twist, at a tempo that runs from 54 to 168 BPM, with a soundtrack the script synthesizes itself. It is laid out so an agent can change any part of it by reading only that part (examples/onimite_saga). This 1280×720 cut of its 6852 frames rendered in 11.5 seconds.

What it is

A video is a video.lua file: scenes, text, shapes, images, clips, shaders, music and voice, and how they move. onimite renders it to an MP4 on all your cores and the GPU, plays it in a window that reloads every time the file is saved, and checks it: frames and contact sheets as PNGs, loudness numbers, and a list of problems such as clipped text, missing fonts or sound off the beat.

That last part is why it works for coding agents. An agent can't watch a video, but it can read what onimite reports about one, so it can write a video, look at it, find what's wrong and fix it, the way it does with code.

Make videos with your agent

  1. 01 Install the skill

    onimite-video is a skill that teaches an agent the script API, how to design motion and sound, and how to check its own work.

    npx skills add https://defnotmid.com
    
    # or, in Claude Code
    /plugin marketplace add defnotmid/onimite
    /plugin install onimite-video@onimite

    npx skills installs it for Claude Code, Codex, Cursor, OpenCode and the other agents it knows. Any other agent that can run commands: ask it to install the skill at that link into its skills directory.

  2. 02 Ask for a video

    Say what you want in plain words, with any media you have in media/:

    Make a 30-second launch video for my app: dark background, our logo from media/logo.svg, three feature cards on the beat, a synthesized soundtrack, and word captions for a voice-over that says the tagline.
  3. 03 It writes and checks the script

    The agent writes video.lua, renders frames and contact sheets to look at, runs onimite inspect and audio analyze, and fixes what they flag before it hands anything over.

  4. 04 Watch it, ask for changes

    onimite preview video.lua plays it with sound and reloads as the agent edits. Say what to change; the final onimite render writes the MP4.

The skill on GitHub ↗Script API reference ↗

Prebuilt binaries come with the first release; until then the skill builds onimite from source, which needs the Odin compiler.

By the numbers

faster than fframes
4.5×
tiktok example: 6.34 s vs 28.7 s wall
of CPU for the same video
2.4 s
tiktok example: fframes uses 595 s
peak memory
343 MB
beta example: fframes peaks at 28 GB
to install, all of it
17.6 MB
binary + SDL3; fframes' toolchain, crates and first build: 3.4 GB

BENCHMARK.md full run, 2026-10-12, against fframes' main of that day: median of 3 at 1920×1080 on a Ryzen 9 9900X3D and an RX 9070 XT. Install sizes from examples/why_onimite/facts.lua.

What's in it

  1. 01All your cores

    Frame builders each load the script into their own Lua state and record frames in parallel; one thread draws them on the GPU in order. The output doesn't depend on the thread count.

  2. 02Built for agents

    frame, strip, onion and snapshot show exactly what's on screen; inspect flags missing media, clipped text, sync drift and script errors. Every command speaks --json with stable error codes, and a skill teaches Claude Code or Codex to use it.

  3. 03Voices with word timings

    say() speaks a line through ottis and hands back every word's start and stop, so captions, cues and a mascot's mouth land on the word. Lines are cached on disk by content.

  4. 04Everything ovg draws

    Paths, text, images, SVG and Lottie with per-id overrides, masks, clip paths, blend modes and every SVG filter primitive, plus SkSL and multipass Shadertoy shaders through oksl.

  5. 05Sound that's measured

    Tracks with gain, pan, fades, voice ducking and a master limiter; audio analyze reports LUFS, LRA, true peak, clipping and silence per scene, and audio onsets finds the beat.

  6. 06Encoded by odecs

    H.264 or H.265 through Vulkan Video when the GPU has it, the native encoder otherwise; ProRes 4444 and VP9 alpha clips work as inputs.

  7. 07Data in, videos out

    Feed props from JSON or --set, or render one video per row of a JSON or CSV batch, with {field} placeholders in the output names.

  8. 08Live preview

    A window with sound, scrubbing and a timeline of thumbnails and waveforms that hot reloads the script, its modules, shaders and media on save.

  9. 09fframes-compatible

    The same commands, outputs and exit codes as fframes' project CLI, the same range syntax (3.2s, 50%, Intro@end, a..b), and all 17 fframes examples ported 1:1.

Use it

video { width = 1920, height = 1080, fps = 30, background = "#ffffff" }

local vo = say("vo", "Hello there.", { voice = "alba" })   -- spoken by ottis, with word times

scene { "Intro", duration = 2, audio = { { "vo", start = 0.3, voice = true } }, render = function(f)
  local y = animate(f, { { start = 0, stop = 0.4, from = 60, to = 0, easing = ease_out } })
  group({ transform = translate(0, y), opacity = animate(f, { { start = 0, stop = 0.3, from = 0, to = 1 } }) }, function()
    rect { x = 160, y = 240, w = 600, h = 120, rx = 24, fill = "#0ea5e9" }
    text { "Hello", x = 200, y = 320, font = "Inter", size = 48, weight = 600, fill = "#ffffff" }
  end)
end }

scene { "Outro", duration = 3, overlap = { previous = 0.5 }, render = function(f) ... end }

The family