I replaced my Loom subscription with a single app I build myself: what Claude Code builds in an afternoon moves the buy-versus-build line

Screen capture, a camera bubble, live transcript, YouTube upload with real subtitles and chapters - all browser APIs, one local file, built with Claude Code. The constraint that looked like a bug became the best feature.

I replaced my Loom subscription with a single app I build myself: what Claude Code builds in an afternoon moves the buy-versus-build line — title card, livain.com

My screen recorder is one HTML file. It sits in a folder on my Mac, served by a small Python script on localhost, and it does screen capture with a draggable camera bubble, a 3-2-1 countdown, pause and resume, virtual backgrounds, a live transcript, and an upload straight to YouTube as unlisted with a real subtitle track and auto-generated chapters. No extension to package, no app to sign, nothing to subscribe to.

I built it with Claude Code in three hours because I wanted to stop paying for Loom. The interesting part isn't the saving. It's that the question "should I buy this or build it?" now has a different answer than it did two years ago, and I don't think most teams have re-asked it.

The first decision was the cheapest one

I started by asking whether this should be a Chrome extension or a small native Mac app. The answer was neither. Every capability I needed is a plain browser API: getDisplayMedia for the screen, getUserMedia for camera and microphone, a canvas to composite the two, and MediaRecorder to write the file. An extension would have added packaging and distribution overhead for no additional capability. A Swift app would have been ten times the work for the same result.

Pipeline diagram: getDisplayMedia and getUserMedia feed a canvas composite, MediaRecorder writes one webm file, uploaded via the YouTube API

That is the judgement call that decided how long the project took, and it happened before a line of code existed. Knowing which layer of the stack can already do the thing is not something the tooling tells you — it's the part you bring.

Tim Brown's line in Change by Design has never been more literally true: time to first prototype is a good measure of the vitality of an innovation culture. When that time collapses to an afternoon, "we'll just license something" stops being automatically correct.

The constraint became the best feature

The first version recorded fine but I couldn't see where my face bubble was while presenting, and I had no controls without switching back to the recorder tab. The fix was an always-on-top floating window using the Document Picture-in-Picture API — a real window you can populate with arbitrary HTML, showing a live composited mini-preview, a timer, and the bubble, draggable right there.

Then I hit what looked like a bug. When recording the entire screen rather than a single window, that floating preview appears in the recording, because a full-screen capture includes always-on-top windows. Hall of mirrors. Ugly.

Except that is the physics of screen capture working exactly as specified, and once I stopped treating it as a defect it became the feature I'd actually wanted. In full-screen mode the floating window now is the camera bubble: it fills with the camera feed, the composited digital bubble switches off so there's no double face, and I drag and resize a real operating-system window over the thing I'm presenting. What I block is what the viewer sees — which is the one thing a composited overlay can never honestly show you.

You don't get that from a specification. You get it from building the thing, watching it do something stupid, and recognising that the stupid behaviour is the answer to a different question.

The time went into unglamorous places

The flashy parts were quick. What ate "hours":

Chrome was serving yesterday's build. I spent twenty minutes convinced a whole redesign hadn't shipped — the page in front of me was the previous day's UI, while curl proved the server was handing out the new file. Python's stock HTTP server sends no Cache-Control header, so Chrome cheerfully reused a cached copy. The fix was a fifteen-line server subclass sending no-store, bound to localhost only. Every minute spent arguing about whether a feature shipped was a minute spent on a caching header.

file:// never persists a camera permission; localhost does. That single fact is the difference between granting microphone and camera access on every recording and granting it once, and it's why the whole thing is served rather than opened as a file.

Subtitles needed length rules, not just text. The first real upload produced caption cues three lines tall, because I'd passed whole speech-recognition phrases straight through. Splitting each phrase into cues under about eighty-four characters, with a mid-cue break near forty, and distributing the timing proportionally by text length, is the difference between a caption track and a wall. The YouTube captions endpoint will happily accept the wall.

Language had to be named, not inferred. The Web Speech API can't auto-detect, and when I let the model infer the target language from the transcript it produced an English description with a German title. Naming the language explicitly in the prompt fixed it. Inference is where these systems are weakest precisely when the input is ambiguous.

What I didn't build

This is not a Loom competitor and I have no intention of making it one. There's no team library, no sharing permissions, no viewer analytics, no cross-browser support, and it can't capture full-screen system audio on macOS because Chrome won't give it to me. I built the ninety percent of one product that I personally use, for one person, on one browser, on one machine.

That narrowing is the whole economics of it. A product has to handle everyone; a tool has to handle you. I've made the same trade twice recently — designing an app in Claude before building it, and standing up a client performance dashboard in a day — and in both cases what made it viable was refusing the general case.

The shift worth paying attention to isn't that AI writes code. It's that the cost of a tool built for exactly one workflow has fallen below the cost of adopting a general one — and deciding which ninety percent you need is still a judgement about your own work that no model will make for you. That's the part I keep saying is where the remaining leverage lives.

Go and look at your subscription list with that in mind. Not to cancel everything — some of those tools genuinely earn their keep. But a few of them are one HTML file and an afternoon.

Sources & further reading

External
Chrome for Developers — Picture-in-Picture for any element, not just video
MDN — MediaDevices.getDisplayMedia()
MDN — MediaRecorder
MDN — Web Speech API
YouTube Data API — Captions: insert

Related posts
I designed an app in Claude before building it. Claude Code shipped it in a day.
I built a client performance dashboard in a day with Claude Code
Utility over hype: the business case for the $599 Mac
The death of generic AI: why deep domain expertise is the only real leverage left

Subscribe to Remco Livain

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe
Work with me →×