Converting html to mp4

Such an obvious problem, convert a piece of html/js/css, often with animations, to a video (mp4 or similar). We were just put before this problem for the TUG 2020 online conference. Searching the internet it turned up mostly web services, some of them even with lots of money to pay. At the end (below I will give a short history) it turned out to be rather simple.

The key is to use timesnap, a tool to take screenshots from web pages. It is actively maintained, and internally uses puppeteer, which in turn uses Google Chrome browser headless. This also means that rendering quality is very high.

So having an html file available, with all the necessary assets, either online or local, one simply creates enough single screenshots per second so that they can be assembled later on into a video with ffmpeg.

In our case, we wanted our leaders to last 10secs before the actual presentation video starts. I decided to render at 30fps, which left me with the simple invocation:

timesnap Leader.html --viewport=1920,1080 --fps=30 --duration=10 --output-pattern="leader-%03d.png"

followed by conversion of the various png images to an mp4:

ffmpeg -r 30 -f image2 -s 1920x1080 -i leader-%03d.png -vcodec libx264 -crf 25 -pix_fmt yuv420p leader.mp4

The -r is the fps, so needs to agree with the --fps above. Also the --viewport and -s values should better agree. -crf is the video quality, and -pix_fmt the pixel format.

With that very simple and quick invocation a nice leader video was ready!


It was actually more complicated than normal. For similar problems, it usually takes me about 5min of googling and a bit of scripting, but this time, it was actually a long way. Simply searching for “convert html to mp4” doesn’t give a lot but web services, often paid for. At some point I came up with the idea to use Electron and led to Electron Recorder, which looked promising, but didn’t work.

A bit more searching led me to PhantomJS, which is not developed anymore, but there was some explanation how to dump frames using phantomjs and merge them using ffmpeg, very similar to the above. Unfortunately, the rendering of the html page by phantomjs was broken, and thus not usable.

Thus I ventured off into searching for alternatives of PhantomJS, which brought me to puppeteer, and from there it wasn’t too long a way that pointed me at timesnap.

Till now it is surprising to me that such a basic task is neither well documented, so hopefully this page helps some users.

4 Responses

  1. Something probably all readers wonder about.. what are you presenting in html, so you came out with really doing screenshots and then rendering that as mp4, instead of doing that more directly. After reading the TUG2020 site, I guess the code was joining the zoom conferences and created a recording.
    Thanks, will keep this hack in mind.. at least it should be quite universally usable.

    • Hi Christian,
      that are simple leaders before the talk starts, with the title of the conference, name, title, date. But to show that Zoom didn’t hang, or the net is dead, we use a simple animation uncovering the title. Nothing fancy. See for an example.

      The actual recording of Zoom, as well as the prerecorded presentation are of course available in mp4, but before uploading them to youtube channel, we need to add a title part, and watermark, etc etc.

      The code above was really only about an html/css animation rendered in html, and then I had to split out the relevant parts from the zoom recordings, and merge the various parts – but this will be a different blog because ffmpeg is a powerful but difficult beast 😉

  2. Thanks Norbert, now I see clearer. I was suspecting Zoom would not provide mp4 then.
    That “if I can get it shown in a browser, I can get it converted to mp4” might open new perspectives to think about, actually.

    • Indeed! We used that leaders (with additional code to show a countdown timer) before the session started, simply by sharing a browser tab from zoom. It is much easier to do this things in html/css than doing a video (only that it puts then the burden onto the one doing the video editing afters – in this case me 🙂

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">