> The core issue is that browsers are real-time systems. They render frames when they can, skip frames under load, and tie animations to wall-clock time. If your screenshot takes 200ms but your animation expects 16ms frames, you get a stuttery, unwatchable mess.
But by faking the performance of your webpage, maybe you are lying to your potential users too?
I've done similar shenanigans before. That main loop is probably simplified? It won't work well with anything that uses timing primitives for debouncing (massively slowing such code down, only progressing with each frame). Also a setInterval with, say 5ms may not "look" the same when it's always 1000/fps milliseconds later instead (if you're capturing at 24fps/30fps, that would be a huge difference).
What you should do is put everything that was scheduled on a timeline (every setTimeout, setInterval, requestAnimationFrame), then "play" through it until you arrive at the next frame, rather than calling each setTimeout/setInterval callback only for each frame.
Also their main loop will let async code "escape" their control. You want to make sure the microtask queue is drained before actually capturing anything. If you don't care about performance, you can use something like await new Promise(resolve => setTimeout(resolve, 0)) for this (using the real setTimeout) before you capture your frame. Use the MessageChannel trick if you want to avoid the delay this causes.
For correctness you should also make sure to drain the queue before calling each of the setTimeout/setInterval callbacks.
I'm leaning towards that code being simplified, since they'd probably have noticed the breakage this causes. Or maybe, given that this is their business, their whole solution is vibe-coded and they have no idea why it's sometimes acting strange. Anyone taking bets?
Crazy that this approach seems to be the preferred way to do it. How hard would it be to implement the recording in the browser engine? There you could do it perfectly, right?
This is the correct solution. However you'd need someone that knows C++ well, knows Chrome internals, is familiar with video stuff, audio stuff, knows Chromium rendering pipeline, possibly some GPU APIs as well. That person would cost huge amounts of money due to the required knowledge and complexity.
And then you'd need to maintain the code so it works with future Chrome versions.
Don’t forget the requirement of not dropping frames under load. The browser engine might have assumed that requirement throughout the entire code base.
This post smells of LLM throughout. Not just the structure (many headings, bullet lists), but the phrasing as well. A few obvious examples:
- no special framework. No library buy-in. Just a URL
- Advance clock. Fire callbacks. Capture. Repeat. Every frame is deterministic, every time.
- We render dozens of frames that nobody will ever see, just to keep Chrome's compositor from going stale.
- The fundamental insight that you could monkey-patch browser time APIs ... is genuinely clever
- Where we diverged
The whole post is like this, but these examples stand out immediately. We haven't quite collectively put a name on this style of writing yet, but anyone who uses these tools daily knows how to spot it immediately.
I'm okay with using LLMs as editors and even drafters, but it's a sign of laziness and carelessness when your entire post feels written by an LLM and the voice isn't your own.
It feels inauthentic and companies like replit should consider the impact on their brand before just letting people write these kind of phoned-in blog posts. Especially after the catastrophe that was the Cloudflare Matrix incident (which they later "edited" and never owned up to).
And the lede is buried at the very end: This is just a vibe-coded modification of https://github.com/Vinlic/WebVideoCreator, and instead of making their changes open source since they're "standing on the shoulders of giants", the modifications are now proprietary.
In the end, being an AI company is no excuse for bad writing.
You forgot the first part. the famous x,y, and z: "by virtualizing time itself, patching key browser audio APIs, and waging war against headless Chrome's quirks.
Yes, this kind of writing is rampant on X. Once you know it's coming from an LLM (mostly ChatGPT in my opinion as it uses this style often) you can't unsee it. And that immediately makes me skip it.
Unfortunately, people seem to organically love this sort of writing, since at least one or two of these get to near the top half of the front page here every day.
I'm not even against using AI per se, but when something is obviously written in ChatGPTese I'm not going to read it if I don't have to.
I don't have an issue with any particular form of writing, it's just that the current generation of LLMs often write this way and it's an indicator of possible LLM use.
"We X, just to keep Y from Z" and its variations are a pattern I've seen come up a lot.
I did this a few years ago. The approach these guys are taking is kinda hacky compared to other better ways - and I've tried most of them.
It works but only in a limited way there's lots of problems and caveats that come up.
I dropped it in the end partly because of all the problems and edge cases, partly because its a solution looking for a problem an AI essentially wipes out any demand for generating video in browsers.
I ended up writing code that modified chromium and grabbed the frames directly from deep in the heartof the rendering system.
It was a big technical challenge and a lot of fun but as I say, fairly pointless.
And there are other solutions that are arguably better - like recording video with OBS / the GPU nvenc engine / with a hardware video capture dongle and there's other ways too that are purely software in Linux that work extremely well.
You can see some of the results I got from my work here:
Using OBS won't make your sluggish animation seem buttery smooth though. This seems to be the point of replit's attempt here. Perfect frame pacing.
On top you could use that technique to record at frame-rates higher than native. There's no reason why you shouldn't be able to redraw a basic page with some animations at a few hundred fps.
Ha, my first thought is that I'd likely break this system. My page synchronizes its animation playback rate to an audio worklet, because I need to do both anyway, and some experimentation determined that syncing to audio resulted in smooth frame pacing across most browsers. This means that requestAnimationFrame has the very simple job of presenting the most recently rendered frame. It ignores the system time and, if there isn't a new frame to present yet, does nothing.
About 20 years ago there was a similar problem with demoscene creations. It was hard to capture demos in realtime in all their glory. So one guy created a tool[1] that waited for a frame render and presented proper time to demo so that frames would be paced properly. "All popular ways of getting time into the program are wrapped aswell - timeGetTime, QueryPerformanceCounter, you name it. This is necessary so .kkapture can make the program think it runs at a fixed framerate (whatever you specified)."
29 comments
[ 2.6 ms ] story [ 63.3 ms ] threadBut by faking the performance of your webpage, maybe you are lying to your potential users too?
What you should do is put everything that was scheduled on a timeline (every setTimeout, setInterval, requestAnimationFrame), then "play" through it until you arrive at the next frame, rather than calling each setTimeout/setInterval callback only for each frame.
Also their main loop will let async code "escape" their control. You want to make sure the microtask queue is drained before actually capturing anything. If you don't care about performance, you can use something like await new Promise(resolve => setTimeout(resolve, 0)) for this (using the real setTimeout) before you capture your frame. Use the MessageChannel trick if you want to avoid the delay this causes.
For correctness you should also make sure to drain the queue before calling each of the setTimeout/setInterval callbacks.
I'm leaning towards that code being simplified, since they'd probably have noticed the breakage this causes. Or maybe, given that this is their business, their whole solution is vibe-coded and they have no idea why it's sometimes acting strange. Anyone taking bets?
And then you'd need to maintain the code so it works with future Chrome versions.
https://source.chromium.org/chromium/chromium/src/+/main:com...
- no special framework. No library buy-in. Just a URL
- Advance clock. Fire callbacks. Capture. Repeat. Every frame is deterministic, every time.
- We render dozens of frames that nobody will ever see, just to keep Chrome's compositor from going stale.
- The fundamental insight that you could monkey-patch browser time APIs ... is genuinely clever
- Where we diverged
The whole post is like this, but these examples stand out immediately. We haven't quite collectively put a name on this style of writing yet, but anyone who uses these tools daily knows how to spot it immediately.
I'm okay with using LLMs as editors and even drafters, but it's a sign of laziness and carelessness when your entire post feels written by an LLM and the voice isn't your own.
It feels inauthentic and companies like replit should consider the impact on their brand before just letting people write these kind of phoned-in blog posts. Especially after the catastrophe that was the Cloudflare Matrix incident (which they later "edited" and never owned up to).
And the lede is buried at the very end: This is just a vibe-coded modification of https://github.com/Vinlic/WebVideoCreator, and instead of making their changes open source since they're "standing on the shoulders of giants", the modifications are now proprietary.
In the end, being an AI company is no excuse for bad writing.
I'm not even against using AI per se, but when something is obviously written in ChatGPTese I'm not going to read it if I don't have to.
what's the issue with this one? it sounds like something I might write, tbh.
"We X, just to keep Y from Z" and its variations are a pattern I've seen come up a lot.
It works but only in a limited way there's lots of problems and caveats that come up.
I dropped it in the end partly because of all the problems and edge cases, partly because its a solution looking for a problem an AI essentially wipes out any demand for generating video in browsers.
I ended up writing code that modified chromium and grabbed the frames directly from deep in the heartof the rendering system.
It was a big technical challenge and a lot of fun but as I say, fairly pointless.
And there are other solutions that are arguably better - like recording video with OBS / the GPU nvenc engine / with a hardware video capture dongle and there's other ways too that are purely software in Linux that work extremely well.
You can see some of the results I got from my work here:
https://www.youtube.com/watch?v=1Tac2EvogjE
https://www.youtube.com/watch?v=ZwqMdi-oMoo
https://www.youtube.com/watch?v=6GXts_yNl6s
https://www.youtube.com/watch?v=KzFngReJ4ZI
https://www.youtube.com/watch?v=LA6VWZcDANk
In the end if you want to capture browser video - use OBS or ffmpeg with nvenc or something - all the fancy footwork isn’t needed.
On top you could use that technique to record at frame-rates higher than native. There's no reason why you shouldn't be able to redraw a basic page with some animations at a few hundred fps.
[1] https://www.farbrausch.de/~fg/kkapture/
Short sentences. Plenty of newlines. Enumerate everything. Always.
> The page behind that URL might use framer-motion, plain CSS animations [...]
And the code example does something with css:
`await seekCSSAnimations(currentTime); // sync CSS`