Yapatar
Turns a voice recording + an avatar image into a transparent-background video of the avatar pulsing with the voice — glow, rings that fire on transients, a spectrum-deformed outline, a waveform ring. The user composites it over their screencast.
Project root ($ROOT below): find it, don't assume it. Try in order —
- the current working directory, if it contains
src/render.jsand apackage.jsonnamedyapatar ~/Projects/yapatarfind ~ -name render.js -path '*yapatar*' -maxdepth 6 2>/dev/null | head -1
If none hit, ask the user where they cloned it. Requires ffmpeg on PATH and Node 20+.
First run
cd $ROOT && [ -d node_modules ] || npm install
--codec hevc needs hevc_videotoolbox, which is macOS-only. On Linux use prores or
png; the renderer checks and says so rather than failing obscurely.
The loop
The user tunes the look in a browser; you render the file. Both directions are wired
through settings.json, so neither of you has to retype values.
1. Start the preview server (background — it must keep running):
cd $ROOT && node src/serve.js
2. Open the preview. You can preconfigure the look with query params, which is how you propose a style without touching the user's sliders:
http://localhost:8777/preview.html?hueA=200&hueB=310&glow=140&blob=14
Params: style, preset, hueA hueB (0-360), bounce (0-30), glow (0-200),
blob (0-30), range (6-30, lower = more per-syllable movement).
Styles: pulse (default), constellation (QAM symbol lattice), waterfall (radial
spectrogram), packets (framed data bursts), handshake (carrier lock + symbols).
Palettes: --preset modem is the modem.dev teal/cream. Or set --colorA/--colorB hex.
Tell the user to bring the Chrome window to the front and press ▶ Play test audio or 🎙 Use microphone — Chrome pauses the render loop and suspends audio for background tabs, so a backgrounded preview looks frozen and reads as broken.
3. The user tunes, then presses 💾 Save settings for the agent, which writes
$ROOT/settings.json.
4. Read it back and render. render.js picks up settings.json automatically;
explicit flags override it:
cd $ROOT && node src/render.js --audio ~/take01.wav --avatar ~/me.png --codec hevc
It prints the resolved config: line — check it matches what the user tuned.
Alternatively the user can press 🎬 Render the final file in the page and get a download link without a terminal — the browser uploads the bytes to the local server, which runs the same renderer. Use that when they have no path handy for their files.
5. Report the output path. Be explicit about which file is which:
out/avatar_alpha.mov— transparent, carries the source audio so it can be lined up by waveform. This is the one to import. Remind them to mute that audio track once positioned, or use--no-audio.out/preview_opaque.mp4— flattened onto a solid background for eyeballing only.
If the user reports a hard-edged grey or dark rectangle around the overlay, the file is probably fine and the NLE is ignoring the alpha. Ask in this order:
- the clip's composite mode (Resolve: Inspector -> Settings -> Composite; must be a mode that respects alpha) - this is the usual answer
- whether they imported
preview_opaque.mp4instead ofavatar_alpha.mov - the codec - some tools silently ignore Apple HEVC alpha;
--codec proresalways works
Verify the file before chasing the renderer: extract a frame with ffmpeg and check the area outside the effects is transparent rather than black.
A soft circular haze is a different issue (glow spread); a bright white halo is an alpha premultiply mismatch.
Choosing a codec
| size for 30 min | when | |
|---|---|---|
--codec hevc |
~1.3 GB | default choice for anything over a couple of minutes |
--codec prores |
~27 GB | short clips, or a workflow that demands ProRes 4444 |
--codec png |
in between | lossless RGBA, slow to decode |
ProRes is a fixed ~15 MB per second of runtime regardless of content. Warn the user before rendering a long take as ProRes.
Options
--audio --avatar --outdir --fps --size --codec --gain --range --style
--preset --colorA --colorB --hueA --hueB --bounce --glow --blob --alpha
--no-audio --no-preview --settings <path>
Point --audio at the screen recording itself if the voice is in it — ffmpeg extracts the
audio, which also guarantees sync.
Alpha
Output is premultiplied by default, because Resolve and most NLEs composite that way.
If the user reports a white halo or a glowing blob around the avatar, that is straight
alpha being composited as premultiplied. Either re-render with the default --alpha premultiplied, or tell them to set Clip Attributes -> Alpha Mode -> Straight in Resolve.
A dark or muddy halo is the opposite mismatch: try --alpha straight.
Notes
- Renders ~20x faster than realtime (30 min of audio in ~91 s), peak RAM ~1.2 GB at 30 min. RAM grows linearly with duration; a multi-hour file would need chunking.
- The avatar is circle-cropped and centred.
assets/avatar.pngis a generated placeholder — swap in the user's real image. - Browsers cannot expose a picked file's real directory, so the preview's generated command uses the filename plus a "folder" field the user fills in. Don't promise full paths.
- Requires
ffmpegon PATH.