My Girlfriend's Dead — animated fan video
2026A 161-second animated cartoon, drawn entirely in code and synced live to the song.
- Role
- Everything — storyboard, character rig, props, animation, timing
- Stack
- Canvas 2D Vanilla JS YouTube IFrame API Node
Problem
An unofficial music video for a two-and-a-half-minute punk song, built with no animation software, no asset pipeline and no budget. It had to be funny, keep up with a fast vocal, and stay on the right side of copyright — the song may not be hosted anywhere I control.
The first attempt failed. It guessed the structure from the tempo, stretched ten scenes across the runtime, and the joke did not land: the visuals drifted out of step with the song, and every scene sat still for far too long.
Approach
- Measure the song instead of guessing it. I ran the vocal through Whisper, read the real phrase boundaries off the transcript, and cut the timeline to those rather than to bar maths.
- Shots, not scenes. The video is 36 shots averaging about 4.5 seconds, so something on screen changes roughly every time a line does.
- A character rig, not drawings. Everything is flat-2D shapes on a canvas: a skeleton with hip sockets, a swappable head, and poseable limbs. One pose function drives every shot.
- Scenes as pure functions of time.
drawFrame(ctx, t)maps global song time to a shot and draws it. The same code drives the live page and an offline MP4 render, so there is exactly one version of the animation. - Audio stays on YouTube. The page embeds the official player and reads
getCurrentTime()every frame. Nothing is re-hosted, and no lyrics are ever rendered on screen.
Outcome
- 36 shots covering the full 161 seconds, with no dead frames
- Renders to both the browser and a 1280×720 H.264 MP4 at 30fps from one source
- Deploys to two hosts from a single commit: GitHub Pages and Cloudflare Pages
What I learned
- Timing is the whole joke. Every change that made this funny was a timing change. Getting real phrase boundaries out of the audio did more than any redraw.
- Constraint pushed the design. Because a scene is a pure function of time, I could scrub to any second and see it instantly. That made iterating cheap enough to actually iterate.
- Keep the copyright line bright. Fan work still has to respect the rights holder: stream the song from the official player, draw your own art, never reproduce the lyrics.
Watch it at typosbro.me/girlfriends-dead. The source lives in the site repository.