Skip to main content

muvid

Tools to make music videos. Orchestrates the local ecosystem (falaw, lookbook, lacing, an, mixing) into a song-to-video pipeline. The user is the director; an agent (Claude in the terminal, or the local web UI) drives the stages.

Status: v0+. The pipeline (init → transcribe → align → cast → environments → script → render → compose) works end to end. Render strategies: lipsync, image_to_video, text_to_video, animation, still. CLI, Claude skill (.claude/skills/muvid/), and a single-page local UI all dispatch to the same Python functions. The v0 audit follow-up (improvement_ideas.md) shipped pluggable aligners, cost rollups + --budget, structured falaw progress events streamed to .muvid/fal_events.jsonl, end-to-end smoke fixture, lacing as the SSOT for word timings (no redundant whisper passes inside an), and a muvid.contracts adapter layer to sibling-package shapes. See misc/docs/design.md for the design rationale and misc/docs/alignment_references.md for the lyric-alignment literature muvid builds on.

muvid has two independent halves: the AI narrative pipeline above, and muvid.visualize — a lightweight, deterministic, ffmpeg-only path that turns a song and a cover into an audio-reactive visualizer video (no AI, no network).

Install

pip install muvid              # core: CLI + muvid.visualize (needs ffmpeg + mixing)
pip install 'muvid[ai]'        # the narrative pipeline (falaw, lacing, lookbook)
pip install 'muvid[ui]'        # FastAPI + uvicorn for the web UI

The narrative pipeline depends on local sibling packages (falaw, lookbook, lacing); with editable installs, install them first and use pip install -e ./muvid[ai]. muvid.visualize needs only mixing.

System: ffmpeg and ffprobe on PATH. Env (pipeline only): ELEVENLABS_API_KEY (transcription), FAL_KEY (fal.ai generation).

muvid.visualize — audio + cover → video

Turn a song into a publishable music video, without the AI pipeline:

from muvid.visualize import render_audio_video, list_visuals, verify_video, report

# Simplest: the cover on a 16:9 canvas, held for the song, loudness-normalized.
result = render_audio_video("song.wav", image="cover.png")

# Pick a visualizer (list_visuals() -> still, ken_burns, cqt, spectrum, waves,
# bars, scope), or pass "auto" / your own callable.
render_audio_video("song.wav", image="cover.png", visual="cqt", normalize=True)

# Check what you produced before shipping it.
print(report(verify_video(result.path, audio="song.wav")))

What it does, by default:

  • 16:9, never pillarboxed — square/portrait art is composed onto 1080p filled with a blurred, darkened copy of itself, sharp cover centred on top.
  • Loudness −14 LUFS (two-pass EBU R128), so a set of songs plays level.
  • Video exactly as long as the song, H.264 High / yuv420p / AAC 48 kHz, +faststart, no edit lists — what YouTube asks for.
  • A teal accent across the reactive visualizers (one tunable tint) over a muted background, so an album reads as one release whatever each cover's colours.
  • A matching thumbnail derivable from the same composition (thumbnail_image, 1280×720, under YouTube's 2 MiB cap).

Every knob is overridable (visual, size, fps, normalize, CoverLayout(...), options={...}); add your own look with register_visual. Needs only ffmpeg — every built-in visual is ffmpeg-native except Ken Burns (via burns, which comes with mixing).

Publishing these to YouTube (single song or a whole folder as an album) is the yb package's job — it renders through muvid.visualize and uploads.

30-second tour

# Bootstrap a project around a song.
muvid init ~/muvid/park-bench --song ~/Downloads/park_bench.mp3 --title "Park Bench"

# Transcribe to a draft lyrics.md (you'll edit it).
muvid transcribe ~/muvid/park-bench

# … you edit lyrics/lyrics.md to fix mishears and add [section] tags …

# Align lyrics.md against the transcript and write lyrics/alignment.annot.
muvid align ~/muvid/park-bench

# Cast a character: card, then images, then lookbook curation.
muvid character ~/muvid/park-bench maya --description "mid-30s, dark curly hair, wary eyes"
muvid character-generate ~/muvid/park-bench maya --n 6
muvid character-curate    ~/muvid/park-bench maya --k 8

# Establish an environment.
muvid environment ~/muvid/park-bench park_bench --description "wooden park bench at dusk"
muvid environment-render ~/muvid/park-bench park_bench

# Write/edit script/script.md (let an agent draft it from the lyrics + cast),
# then sync it back into project.json:
muvid script-apply ~/muvid/park-bench

# Estimate cost before committing fal calls.
muvid estimate-cost ~/muvid/park-bench

# Render every shot (optionally gated on a USD budget), then composite.
muvid render  ~/muvid/park-bench --budget=2.50
muvid compose ~/muvid/park-bench
# → ~/muvid/park-bench/output/final.mp4

# Inspect progress.
muvid status        ~/muvid/park-bench           # human-readable
muvid status --json ~/muvid/park-bench           # structured shape

# Or open the local UI (FastAPI + single HTML page).
muvid serve ~/muvid/park-bench

Pluggable aligners

muvid align --aligner=... accepts:

  • scribe-greedy (default) — Scribe transcript + greedy token-match.
  • user — caller-supplied line_index → (start, end) timings.
  • whisperx-lite — local faster-whisper, falls back to scribe-greedy if no audio_path= is given.
  • stars — singing-grade joint inference (stub; NotImplementedError).

Plug your own with muvid.align.register_aligner(name, fn, ...).

Interactive character curation

When a recipe's automatic top-k isn't quite right, replay a JSON of decisions:

# decisions.json:
# [{"keep": ["<image_id>"], "reject": [...], "stop": false}, ...]
muvid character-curate-interactive ~/muvid/park-bench maya \
    --decisions decisions.json --k 8 --present 6

How it fits the ecosystem

Concern Owner
AI media (TTS, image, video, lipsync, voice clone) falaw
Reference image curation (LoRA-style sets) lookbook
Timeline / interval annotations (lyrics, sections) lacing
Structured 2D animation (cutout characters) an
Audio/video editing + ElevenLabs Scribe mixing
Project, pipeline, dispatcher muvid

muvid is the orchestrator: a folder layout (project.json + song/, lyrics/, characters/, environments/, script/, shots/, output/), a content-addressed cache (re-render only what changed), and a uniform dispatch layer with three surfaces (CLI, skill, UI) all calling the same Python functions in muvid.facade.

Render strategies

Each shot picks one. The dispatcher resolves shared inputs (audio slice, lyric lines that fall in the shot interval, character / env anchor images) once and hands them to the strategy:

strategy use it for calls
lipsync character singing on screen falaw.animate_face
image_to_video cinematic shot, env anchor as i2v seed falaw.image_to_video
text_to_video no anchor, pure prompt falaw.text_to_video
animation stylized 2D cutout an.orchestrate
still single image held for the duration ffmpeg

The Claude skill

.claude/skills/muvid/SKILL.md walks Claude (or any agent that follows Claude Code skills) through the eight stages. It will:

  • run muvid status first to see where you are
  • pick the next stage and offer to run it
  • never re-transcribe after you've edited lyrics.md
  • never --force a render without asking
  • offer to draft script/script.md from your lyrics + cast

Layout

muvid/
  __init__.py         public surface (the facade)
  __main__.py         CLI (argh)
  schema.py           ProjectSpec, ShotSpec, SectionSpec, …
  project.py          MusicVideoProject (folder facade)
  lyrics.py           transcribe + parse/render lyrics.md
  align.py            pluggable aligners + lacing SqliteStore writer
  characters.py       cards + ref images + lookbook curation (incl. interactive)
  environments.py     cards + establishing-image generation
  script.py           script.md ↔ ShotSpec list
  cost.py             render-cost rollup over pending shots
  events.py           pipe falaw progress events → .muvid/fal_events.jsonl
  contracts.py        adapters: muvid SSOT ↔ falaw / an / lacing shapes
  renderers/
    __init__.py       dispatcher + RenderContext + caching
    lipsync.py        falaw.animate_face
    image_to_video.py falaw.image_to_video
    text_to_video.py  falaw.text_to_video
    still.py          ffmpeg single-image loop
    animation.py      handoff to `an.orchestrate` with lacing-driven lipsync
  compose.py          ffmpeg concat + overlay song audio
  facade.py           top-level verbs the CLI/skill/UI call
  ui/
    app.py            FastAPI app
    static/index.html single-page UI
.claude/skills/muvid/SKILL.md
misc/docs/design.md             full design rationale
misc/docs/improvement_ideas.md  v0 audit + post-audit follow-through

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

muvid-0.0.13.tar.gz (1.7 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

muvid-0.0.13-py3-none-any.whl (162.6 kB view details)

Uploaded Python 3

File details

Details for the file muvid-0.0.13.tar.gz.

File metadata

  • Download URL: muvid-0.0.13.tar.gz
  • Upload date:
  • Size: 1.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for muvid-0.0.13.tar.gz
Algorithm Hash digest
SHA256 7c8206566b01b6f91507bb15ca4f243e72c6c5084327e710a0fe04ca0617dd67
MD5 1bb79b6f77a131cbe370e370d00b82a7
BLAKE2b-256 b1b817d07f48dfe58f601ace4072e4a4910e898f0be37af8007e0cb7a119ac41

See more details on using hashes here.

File details

Details for the file muvid-0.0.13-py3-none-any.whl.

File metadata

  • Download URL: muvid-0.0.13-py3-none-any.whl
  • Upload date:
  • Size: 162.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for muvid-0.0.13-py3-none-any.whl
Algorithm Hash digest
SHA256 8d2b453f5f5da3aa64383bafd51f1deda06b0017f96b87a43d45d2e481b90922
MD5 dcf7fa4a3933ff6af14d2735fe321cee
BLAKE2b-256 034b5f5b3de9de4e84a1a768e5f1236ec20e6e7c5774ec47004e3df692f3501b

See more details on using hashes here.

Release history Release notifications | RSS feed

0.0.39

2 files

0.0.38

2 files

0.0.37

2 files

0.0.36

2 files

0.0.35

2 files

0.0.34

2 files

0.0.33

2 files

0.0.32

2 files

0.0.31

2 files

0.0.30

2 files

0.0.29

2 files

0.0.28

2 files

0.0.27

2 files

0.0.26

2 files

0.0.25

2 files

0.0.24

2 files

0.0.23

2 files

0.0.22

2 files

0.0.21

2 files

0.0.20

2 files

0.0.19

2 files

0.0.18

2 files

0.0.17

2 files

0.0.16

2 files

0.0.15

2 files

0.0.14

2 files

This release

0.0.13 This release

2 files

0.0.11

2 files

0.0.10

2 files

0.0.9

2 files

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page