🏁 victorylap Devlog #1 (two days in and i already made like 200 mistakes)
TL;DR
- started victorylap, my main summer project. one command, npx victorylap, turns any git repo into a brag video
- built the first video frame by hand in html, 1920x1080, amber on black
- promoted it to a real Hyperframes composition and rendered my first mp4. the pipeline works
- test data for the demo frame comes from the free-claude-code repo
What This Actually Is
every dev has repos that die quietly on github. you build something real, push it, and nobody ever sees it. victorylap turns the
repo itself into a short video you can post. it reads your readme, file tree and git history, an ai writes a script about what you
built, and the whole thing renders to mp4 on your own machine.
that last part is the point. no render server, no paid api, no upload. your computer does the work so it stays free forever.
credit where it’s due: the idea comes from the /brag skill for claude code, and the render engine is Hyperframes. i’m not porting
brag, i’m remaking it as a standalone product. same engine, my own analyzer, my own templates, free llm for the script. the
original creators get named in every version of this.
Day 1, the Frame
wrote one hardcoded html file. project name huge, a tagline, three stats. the data is real, it’s from free-claude-code, which i’m
using as the test repo all summer.
it broke immediately. the name rendered tiny and almost invisible. three separate causes: i never typed the .project-name css
block, forgot color on body so the text defaulted to black, and typed .tagLine with a capital L so the selector never matched. two
different bugs producing the same symptom taught me more about css inheritance than any tutorial has.
Day 2, the Render
Hyperframes doesn’t screenshot a plain page. it needs a composition, which is html with a contract: a root div with data-duration,
clips with data-start and data-track-index, and one paused gsap timeline registered on window.__timelines.
lint caught a missing data-start on the root. validate ran it in headless chrome, clean. render gave me an mp4.
then it gave me a black one.
turns out i had typed all my fixes into template.html, the day 1 file, while the renderer reads video/index.html. did that twice.
closed the old tab in vscode and the problem stopped existing. also found height: 180px where 1080px should have been, which would
have rendered the whole video as a squished strip.
second render worked. five seconds, text staggering in, my first programmatically rendered video.
What I Learned
the paused timeline is the core trick of the whole engine. a normal browser animation plays on the browser’s clock, so recording it
means racing it in real time and hoping no frame drops. Hyperframes refuses to race. the timeline is created paused, and the
renderer takes ownership of time itself. it seeks to 0.000s, screenshots, seeks to 0.033s, screenshots, three hundred times for a
ten second video. then ffmpeg stitches the stills into video. every frame is exact because nothing was ever actually moving.
deterministic time is why the same file renders identically on any machine.