Short-form, explainer, and demo video generation via a key-optional 3-tier router. Composes scripts, oma-voice narration, oma-image/oma-slide/stock visuals, key-free captions, and a vendored Remotion compositor into reproducible run directories. Routes three modes — shorts/reels (9:16), explainer (16:9 README/code/data), and demo/walkthrough (screen capture, incl. supervised headed web-app capture of any URL). Use for video, shorts, reels, short-form, demo, explainer, walkthrough, screencast, web capture, video generation, 영상, 숏폼, 쇼츠, 릴스, 데모, 설명 영상.
72
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Generate finished .mp4 videos through a key-optional, 3-tier (CLI-first / MCP / guided) provider router while preserving deterministic asset buses (script -> timing -> render-spec), reproducible manifests, cost controls, and capture-path safety.
--mode shorts, 9:16)--mode explainer, 16:9 / 9:16)--mode demo --source file, 16:9)--mode demo --source web --url <url>) — a human drives the on-screen flow; the tool only opens a headed browser and records. Example categories are equal and illustrative only: demo, walkthrough, onboarding clip, bug repro, app-review screencast.render-spec.json--format json)oma-imageoma-slide (this skill calls it internally for explainer frames)oma-voice--source web); live streaming is out of scopeoma-explainerdemo --source file: a screen-capture file path (--capture) or Cap availabilitydemo --source web: a target --url (any URL — local/staging/prod), optional --device/--ready-selector/--show-cursor/--polish/--capture-timeout; capture size is derived from --aspect/--device (no hardcoded size); a resolvable Playwright + an interactive TTY (else the run falls back to the guided protocol).agents/results/videos/<timestamp>-<shortid>-<mode>/script.json, timing.json, render-spec.jsonaudio/, visuals/, captions.srt / captions.vtt, the rendered <mode>-<slug>.mp4manifest.json with providers, asset hashes, cost breakdown, and exit codeoutputs:
- name: video
description: rendered <mode>-<slug>.mp4 in the run directory
artifact: ".agents/results/videos/*/*.mp4"
required: true
- name: manifest
description: reproducibility record (providers, asset sha256 hashes, cost breakdown, exit code)
artifact: ".agents/results/videos/*/manifest.json"
required: true
- name: render-spec
description: deterministic compute boundary consumed by `oma video render <runDir>`
artifact: ".agents/results/videos/*/render-spec.json"
required: true
- name: captions
description: key-free caption tracks aligned to timing.json
artifact: ".agents/results/videos/*/captions.srt"
required: falseoma video generate CLI + central error module (exit codes aligned with oma search fetch)resources/remotion/ (compositor)resources/vendor-matrix.md, resources/execution-protocol.md, resources/prompt-tips.md, config/video-config.yamldemo, confirm a capture path exists (or Cap is available); otherwise enter the guided protocol.config/video-config.yaml -> env vars -> CLI flags; check output path safety and limits.demo --source web has a --url, dispatch the headed web-capture path (human-driven flow, ENTER to stop); if Playwright is unresolvable OR there is no interactive TTY, fall back to the guided protocol (no hang).demo --source file has no capture and Cap is unavailable, emit the guided capture protocol and stop (exit code maps to capture-required).order; only chain exhaustion is a stage failure.oma video doctor --install (one-time: deps + headless shell + Pretendard font); fall back to the MPT compositor where applicable (MPT itself needs a one-time oma video doctor --install-mpt).TODO(oma-deferred): whisper-cpp).<mode>-<slug>.mp4 and manifest.json exist in the run directory; all schemas validate.| Action | SSL primitive | Evidence |
|---|---|---|
| Validate brief + mode | VALIDATE | Clarification protocol, mode inference |
| Select provider strategy | SELECT | Vendor matrix, providers.*.order, availability |
| Read brief / capture | READ | Brief text, --capture path |
| Generate script | CALL_TOOL | AgentScriptProvider -> script.json |
| Synthesize narration + timing | CALL_TOOL | oma-voice -> audio/*.wav + timing.json |
| Produce visuals | CALL_TOOL | oma-image / oma-slide / stock -> visuals/* |
| Build captions | WRITE | key-free captions.srt / .vtt from timing |
| Compose render-spec | WRITE | render-spec.json (determinism boundary) |
| Render video | CALL_TOOL | Remotion / MPT compositor -> <mode>-<slug>.mp4 |
| Validate result | VALIDATE | Schema parse, manifest hashes, exit code |
| Report output | NOTIFY | Run-dir + mp4 path summary |
oma video generate, oma video doctor, oma video list-providers, oma video renderresources/remotion/), prompt tips, vendor matrix, video configoma video doctor
oma video generate "<brief>" --mode shorts --aspect auto --captions tiktok --format jsonExplainer from a README, with a deterministic seed:
oma video generate "explain this project" --mode explainer --aspect 16:9 --seed 42 --out ./outDemo from a screen capture:
oma video generate "feature walkthrough" --mode demo --capture <absolute-path>.mp4Deterministic re-render from an existing run:
oma video render .agents/results/videos/20260603-143052-ab12cd-shorts| Scope | Resource target |
|---|---|
LOCAL_FS | Briefs, captures, assets, render-spec, run dir, manifests |
PROCESS | oma-image / oma-slide CLIs, Remotion / MPT, Cap CLI, Playwright web-capture driver (subprocess) |
NETWORK | Voicebox MCP (localhost), oma-image vendor APIs, the user-supplied --url for web capture (masked in logs/manifest), optional Pexels / Pixelle / RunningHub |
CREDENTIALS | oma-image vendor auth, optional PEXELS_API_KEY / RUNNINGHUB_API_KEY. Web capture handles NO credentials — a human logs in if the flow needs it; nothing is stored or printed. |
$PWD (or --allow-external-out is set).demo --source file: the capture path exists, is absolute/$PWD-guarded, and is a valid format.demo --source web: a --url is supplied (else SchemaValidationError); a resolvable Playwright + an interactive TTY exist (else the run falls back to the guided protocol).Clarification Protocol below.cost.guardrail_usd ($0.20, configurable) or --max-usd. --yes / OMA_VIDEO_YES=1 bypass. Local/free paths carry zero cost.$PWD require --allow-external-out. --capture is absolutized, $PWD-guarded, and format-validated; external assets are copied into the run dir and hashed (no URL refs).render-spec.json + asset files (+ seed + embedded Pretendard font) are the determinism boundary. oma video doctor --install fetches the Pretendard woff2 once; if offline, the render gracefully falls back to system fonts, and byte-identical output across machines is only guaranteed once the font is present. Re-rendering the same render-spec is byte-stable; OMA_VIDEO_MOCK=1 replays golden fixtures.limits.max_duration_sec = 180, limits.max_scenes = 40 (wall-time + memory bound).--max-usd.--source file the skill guides but does not screen-record autonomously; for --source web the tool only opens a headed browser and records while the human drives the entire on-screen flow (interactive ENTER to stop). The mechanism prescribes nothing about what the flow is or what the recording is for.--url and any query tokens are masked in logs and in manifest.json; credentials are never stored or printed. Recording and all outputs are confined to the run dir. On-screen sensitive input is captured as-is — the user controls the flow. Multi-page navigation (popup / new tab / redirect) is recorded generically, with no assumption about the flow's shape.-y / no stdin) — the run falls back to guided and never hangs. Live capture is outside the determinism boundary, so the manifest records nondeterministic: true.--capture-stop duration:<sec>|selector:<css> — the driver then runs headless (resources/playwright/record.mjs --headless 1) — or expect a capture error / guided fallback..agents/results/videos/<run>/ accumulates one directory per run (assets + mp4 + manifest) and is never auto-pruned; the user deletes old run directories manually.oma search fetch (0 ok, 1 generic, 2 safety, 3 not-found, 4 invalid-input, 5 auth-required, 6 timeout).Before invoking oma video generate, the calling agent runs this checklist. If any answer is "no / unknown", clarify or infer-and-confirm with the user first.
Required signal (must be present or inferable):
demo --source web — a --url)demo: --source file (a --capture path) or --source web (a --url)? For --source web, state up front that a human drives the on-screen flow and that the tool never automates any login.Strongly recommended (ask if absent AND not inferable):
9:16 (shorts/reels), 16:9 (explainer/demo), 1:1, or auto (snaps to the mode default).tiktok (centered, static windowed cues), lower-third, or none.auto (derived from the script).none; music upbeat / calm / none. The default voice is none → a silent video with estimated caption timing. Pass --voice <profile> (a Voicebox profile) whenever narration is expected. Music is rendered offline by Strudel and mixed at −18 dB; it needs a one-time oma video doctor --install-strudel and degrades to no music without it.Amplification shortcut. For a one-line brief (e.g. "shorts about Jeju coffee"), do not pop a questionnaire if the request is genuinely simple. Instead amplify inline and show the user the inferred plan before invoking:
User: "make a short about Jeju coffee" Agent: "I'll generate this as: mode
shorts, 9:16, ~30s, oma-image stills with Ken Burns, TikTok captions, localeen, calm music. Proceed, or adjust mode/aspect/voice?"
Skip clarification when the user authored a full brief (mode + topic + aspect + captions). Respect their flags verbatim.
Output language. Narration and on-screen text are authored in the requested locale. Image-generation prompts passed to oma-image are sent in English (image models are trained predominantly on English captions); translate the user's request and show the translated version during amplification.
| Mode | Aspect | Source | Default visual | Compositor | Output |
|---|---|---|---|---|---|
shorts | 9:16 | synthetic (topic) | oma-image stills + Ken Burns; Pexels (key) · Pixelle AIGC (key) opt | Remotion · MPT alt | shorts-<slug>.mp4 |
explainer | 16:9 / 9:16 | README · code · data | oma-slide frames + oma-image diagrams + code | Remotion (deterministic) | explainer-<slug>.mp4 |
demo | 16:9 | --source file (Cap / capture file) · --source web (headed browser at --url) | raw footage (default) · Remotion intro · zoom · callouts (--polish) | Remotion polish | demo-<slug>.mp4 |
| Tier | Surface | Providers | Trigger |
|---|---|---|---|
| 1 | CLI-first (subprocess, deterministic) | Remotion render, MPT, oma-image, oma-slide, oma-voice | always available (key-free defaults) |
| 2 | MCP | Voicebox MCP (voice/timing), Pixelle-MCP (AIGC, off by default) | MCP server reachable; Pixelle needs explicit consent + key |
| 3 | Guided (human-in-the-loop) | Playwright headed web capture (--source web, human drives the flow), Cap (capture), guided protocol fallback | demo mode; web capture needs a resolvable Playwright + a TTY (else guided protocol) |
/oma-video make a 30s short about Jeju coffee
/oma-video --mode explainer --aspect 16:9 explain this project from the README
/oma-video --mode demo --source file --capture ~/recordings/walkthrough.mp4 feature demo
/oma-video --mode demo --source web --url http://localhost:3000 record my app flow
/oma-video --mode demo --source web --url <url> --ready-selector "#app" --polish onboarding clipoma video generate "<brief>" [--mode shorts|explainer|demo] \
[--aspect 9:16|16:9|1:1|auto] [--locale <lang>] \
[--captions tiktok|lower-third|none] \
[--visual auto|generate|stock|aigc|slide] \
[--voice <profile>|none] [--music upbeat|calm|cinematic|lofi|piano|none] \
[--duration <sec>|auto] [--compositor remotion|mpt] \
[--capture <path>] \
[--source file|web] [--url <url>] [--device <name>] \
[--ready-selector <css>] [--show-cursor] [--polish] \
[--capture-timeout <sec>] [--capture-stop duration:<sec>|selector:<css>] \
[--out <dir>] [--allow-external-out] \
[--max-usd <n>] [--seed <n>] [--timeout 600] [-y] \
[--dry-run] [--script <path>] \
[--format text|json] [--no-brief-in-manifest]
# --script: inject the agent-authored script.json (agent-as-key). Without it the
# CLI builds its own skeleton script from the brief — always pass the script
# the agent wrote so narration/on-screen text/visual prompts are honored.
# --source web: headed browser at --url; capture size derived from --aspect/--device (no hardcoded size).
# A human drives the on-screen flow; press ENTER to stop. NO credential automation. --url/tokens masked.
# Non-interactive (CI / -y / no TTY) or unresolvable Playwright -> falls back to the guided protocol (no hang).
# --capture-stop gives CI a non-interactive stop (duration / selector) in place of the ENTER prompt.
oma video doctor # readiness report only (no install): Node/Chromium/FFmpeg · Remotion project · Pretendard font · MPT · Playwright · Voicebox MCP · oma-image vendors · Pixelle-MCP · Cap
oma video doctor --install # one-time: vendored Remotion deps + Chrome Headless Shell + Pretendard font fetch (offline -> warn, system-font fallback)
oma video doctor --install-mpt # one-time: MoneyPrinterTurbo checkout (clone + venv + deps) for --compositor mpt
oma video doctor --install-playwright # one-time: npm i playwright + chromium (web capture)
oma video list-providers # availability + key/fallback status
oma video render <runDir> # re-render from render-spec.json (deterministic)Other skills call oma video generate --format json and parse the JSON envelope ({exitCode, runDir, manifestPath, scriptPath, renderSpecPath, warnings, error}) from stdout. There is no outputs key — read output/asset paths from the manifest at manifestPath. The deterministic boundary is render-spec.json + assets, so a downstream consumer can re-render via oma video render <runDir> without re-running script/voice/visual generation.
.agents/results/videos/
└── 20260603-143052-ab12cd-shorts/ # {timestamp}-{shortid}-{mode}
├── script.json # determinism boundary start
├── timing.json
├── render-spec.json # deterministic compute boundary
├── audio/
│ └── narration-01.wav # single narration track (ALL lines joined — not per-scene)
├── visuals/
│ └── scene-01.jpg …
├── captions.srt
├── captions.vtt
├── shorts-<slug>.mp4
└── manifest.json # reproducibility recordaudio/narration-01.wav, referenced by render-spec.audio.narration. There are no per-scene narration-NN.wav files.timing.json (voicebox-stt -> estimated; the tts-native and whisper-cpp source values are reserved but not yet wired — TODO(oma-deferred): whisper-cpp); scene boundaries and caption cues are derived from it..srt (+ .vtt) built from timing.json; render-spec.captions.file points at the .srt. The compositor renders static windowed cues — the cue active at the current frame, CSS-wrapped (no per-word animation).--music <preset> renders a BGM bed with Strudel and mixes it under narration at render-spec.audio.musicGainDb (default −18 dB). The bed is generated offline (headless Chrome + OfflineAudioContext), so it needs no key, no network, and no audio device — a 30s bed renders in well under a second.
calm (sustained pad + arpeggio), upbeat (bright plucks), cinematic (drone build to a lead), lofi (warm chords, swung ticks), piano (neoclassical arpeggio). Each preset picks its key and mode from the run seed, so the same preset sounds different run to run without a second pattern.music/bgm.wav (mixed by the compositor), music/bgm.mp3 (preview), music/bgm-raw.wav (pre-master), and music/pattern.strudel — the source that produced them, editable and re-renderable by hand.musicGainDb means the same thing for every preset. Normalisation is deliberately not loudnorm's one-pass mode, which flattens the arrangement arc.@strudel/* is AGPL-3.0-or-later while the oma CLI is MIT, so the deps are never bundled and never installed implicitly. Run oma video doctor --install-strudel once. The CLI never imports Strudel — it spawns resources/strudel/render.mjs as a subprocess, the same boundary the Remotion / Playwright projects use.audio.music stays unset (never a dangling staticFile() ref).white / pink / brown) draw from Math.random() and would break that, so the templates avoid them.Follow resources/execution-protocol.md step by step.
See resources/vendor-matrix.md for provider precheck + fallback-chain rules.
Author --script files against resources/script-schema.md (full field reference + example; schemaVersion: "1.0" is required).
Use resources/prompt-tips.md for writing effective briefs per mode.
Before submitting, run resources/checklist.md.
The vendored Remotion compositor lives at resources/remotion/ (see its README.md).
The web-capture driver lives at resources/playwright/record.mjs (runs as a subprocess under the resolved Playwright; never imported into the CLI).
The MPT fallback compositor driver lives at resources/mpt/driver.py (consumed by the CLI's mpt-project internals).
Project-specific settings: config/video-config.yaml.
Env vars: OMA_VIDEO_DEFAULT_MODE, OMA_VIDEO_DEFAULT_OUT, OMA_VIDEO_YES, PEXELS_API_KEY, RUNNINGHUB_API_KEY (+ POLLINATIONS_API_KEY via oma-image), OMA_VIDEO_MOCK, OMA_VIDEO_PLAYWRIGHT_DIR (web-capture Playwright override), OMA_VIDEO_PWTEST (opt-in web-capture e2e).
resources/execution-protocol.mdresources/vendor-matrix.mdresources/prompt-tips.mdresources/checklist.mdresources/remotion/README.md../_shared/core/context-loading.md3021301
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.