<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aleksander mako</title>
    <description>The latest articles on DEV Community by Aleksander mako (@aleksander_mako_1d1cd1320).</description>
    <link>https://dev.to/aleksander_mako_1d1cd1320</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4126234%2F5d65260b-25f9-49e2-8b4c-468ce115cef1.jpg</url>
      <title>DEV Community: Aleksander mako</title>
      <link>https://dev.to/aleksander_mako_1d1cd1320</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aleksander_mako_1d1cd1320"/>
    <language>en</language>
    <item>
      <title>The Surprisingly Expensive Problem Behind MP4 Fast Start</title>
      <dc:creator>Aleksander mako</dc:creator>
      <pubDate>Thu, 17 Sep 2026 14:46:00 +0000</pubDate>
      <link>https://dev.to/aleksander_mako_1d1cd1320/the-surprisingly-expensive-problem-behind-mp4-fast-start-3o0h</link>
      <guid>https://dev.to/aleksander_mako_1d1cd1320/the-surprisingly-expensive-problem-behind-mp4-fast-start-3o0h</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs63d5km6555ykkujpsuy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs63d5km6555ykkujpsuy.png" alt="Fast Start" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have been working on a browser-based video editor for a while now, and as a result I have run into plenty of video-related problems. While documenting as many of them as I could remember, I came back to one of my favourites: a problem for which I really struggled to find a satisfying solution.&lt;/p&gt;

&lt;p&gt;Simply stated, I discovered that my implementation could require &lt;strong&gt;roughly twice the size of a video file in RAM just to optimize an MP4 for fast start&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Optimizing a video for fast start matters when serving video on the web because it allows playback to begin before the entire file has been downloaded. This can improve the user experience and, when the video is important to the initial page render, can also affect loading performance such as Largest Contentful Paint.&lt;/p&gt;

&lt;p&gt;Fast start itself is not a Google ranking factor, although Core Web Vitals are used by Google's ranking systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  But what exactly does fast start mean?
&lt;/h2&gt;

&lt;p&gt;In a normal MP4, the file contains a box called &lt;code&gt;moov&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can think of it as the &lt;strong&gt;index of the video&lt;/strong&gt;. It contains metadata that tells a player where the encoded samples are located, how large they are, when they should be decoded and presented, and which samples are keyframes.&lt;/p&gt;

&lt;p&gt;For fast start, we want that index near the beginning of the file rather than at the end.&lt;/p&gt;

&lt;p&gt;FFmpeg's &lt;code&gt;faststart&lt;/code&gt; option does exactly this by running a second pass and moving the &lt;code&gt;moov&lt;/code&gt; box to the beginning.&lt;/p&gt;

&lt;p&gt;Without this optimization, a player may need to fetch the end of the file before it has enough information to start playback. With &lt;code&gt;moov&lt;/code&gt; near the front, the player can discover the structure of the video early and begin requesting and decoding the media it needs.&lt;/p&gt;

&lt;p&gt;To understand why moving this box is more complicated than it sounds, we need a few MP4 fundamentals.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few MP4 fundamentals
&lt;/h2&gt;

&lt;p&gt;An MP4 is made up of &lt;strong&gt;boxes&lt;/strong&gt;. A real file can contain many of them, but three are particularly useful for this explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ftyp&lt;/code&gt;, which describes the file format and compatibility;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mdat&lt;/code&gt;, which contains the encoded media data;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;moov&lt;/code&gt;, which contains the metadata describing that media.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is another complication: &lt;strong&gt;encoded video is not necessarily processed in the same order in which we eventually watch it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A video stream can have a decode order and a presentation order. Some frames depend on other frames, including frames that may appear later in playback. The decoder therefore sometimes needs to process frames in one order and display them in another.&lt;/p&gt;

&lt;p&gt;The container metadata is what allows all of this to be reconstructed.&lt;/p&gt;

&lt;p&gt;Among other things, the tables inside &lt;code&gt;moov&lt;/code&gt; tell the demuxer where samples live in the file and how they relate to time. This is why we cannot simply jump to an arbitrary byte offset, assume it contains H.264, and start decoding meaningful video from there.&lt;/p&gt;

&lt;p&gt;A straightforward MP4 muxer can therefore do something very convenient: write the media data first, learn where everything ended up, and write the &lt;code&gt;moov&lt;/code&gt; metadata afterwards.&lt;/p&gt;

&lt;p&gt;By then all of the offsets and timing information are known.&lt;/p&gt;

&lt;p&gt;Unfortunately, that gives us exactly the layout we do not want for fast start.&lt;/p&gt;

&lt;p&gt;So we move &lt;code&gt;moov&lt;/code&gt; to the front.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving &lt;code&gt;moov&lt;/code&gt; breaks the offsets
&lt;/h2&gt;

&lt;p&gt;And this creates an amusing problem: &lt;code&gt;moov&lt;/code&gt; itself contains offsets pointing to the media data.&lt;/p&gt;

&lt;p&gt;Once we insert &lt;code&gt;moov&lt;/code&gt; before that media data, those offsets are no longer correct.&lt;/p&gt;

&lt;p&gt;Suppose some media previously started at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;header + X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After inserting a &lt;code&gt;moov&lt;/code&gt; box of size &lt;code&gt;M&lt;/code&gt; before it, that same data is now roughly at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;header + M + X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relevant chunk offsets inside the metadata therefore have to be rewritten to point to their new positions.&lt;/p&gt;

&lt;p&gt;This is an important detail of the format: &lt;strong&gt;chunk offsets are absolute file offsets&lt;/strong&gt;, so moving metadata in front of the media changes them.&lt;/p&gt;

&lt;p&gt;The algorithm itself is conceptually simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the existing structure.&lt;/li&gt;
&lt;li&gt;Move &lt;code&gt;moov&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Adjust the affected offsets.&lt;/li&gt;
&lt;li&gt;Write the rearranged MP4.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where the new file gets written
&lt;/h2&gt;

&lt;p&gt;The interesting problem for me was &lt;strong&gt;where the new file gets written&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The usual fast-start implementation is a second pass that produces rearranged output. If the original file is kept while the new one is being written, peak storage approaches the size of the input plus the size of the output.&lt;/p&gt;

&lt;p&gt;In other words, &lt;strong&gt;roughly twice the video size&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On a normal machine, that usually means temporary disk usage.&lt;/p&gt;

&lt;p&gt;I was doing it with an &lt;strong&gt;FFmpeg WASM build whose filesystem lived in WASM-backed memory&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That changed the problem completely.&lt;/p&gt;

&lt;p&gt;By the time the last byte of the optimised video had been written, I could have both the original file and almost an entire second copy sitting in memory at the same time.&lt;/p&gt;

&lt;p&gt;In practice, the process needs additional working memory as well, so the true peak can be even higher.&lt;/p&gt;

&lt;p&gt;For a &lt;strong&gt;100 MB video&lt;/strong&gt;, this is annoying.&lt;/p&gt;

&lt;p&gt;For a &lt;strong&gt;multi-gigabyte video&lt;/strong&gt;, it becomes an architectural problem.&lt;/p&gt;

&lt;p&gt;And because this editor runs entirely inside the browser, the machine doing the work belongs to the user. Memory is limited, browser environments have their own constraints, and the situation becomes even more restrictive on mobile devices, which I also want to support.&lt;/p&gt;

&lt;p&gt;That was the part I originally underestimated.&lt;/p&gt;

&lt;p&gt;Moving one piece of metadata from the end of a file to the beginning sounds almost trivial.&lt;/p&gt;

&lt;p&gt;Doing it when the file might itself be larger than the memory available to your application is a very different problem.&lt;/p&gt;

&lt;p&gt;I am glad I ran into it, because otherwise I probably would never have dug this far into how MP4 files are actually laid out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I did instead
&lt;/h2&gt;

&lt;p&gt;I eventually reworked the pipeline around &lt;strong&gt;WebCodecs together with browser file APIs&lt;/strong&gt;, which allowed me to rely on file-backed storage instead of keeping the entire transformation inside FFmpeg WASM's in-memory filesystem.&lt;/p&gt;

&lt;p&gt;WebCodecs itself handles encoding and decoding; browser file APIs are what provide the file-backed part.&lt;/p&gt;

&lt;p&gt;That solution, though, deserves its own article.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>softwaredevelopment</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Scrub Huge Video Files in the Browser Without Blowing Up RAM</title>
      <dc:creator>Aleksander mako</dc:creator>
      <pubDate>Wed, 16 Sep 2026 14:45:00 +0000</pubDate>
      <link>https://dev.to/aleksander_mako_1d1cd1320/how-to-scrub-huge-video-files-in-the-browser-without-blowing-up-ram-2n8g</link>
      <guid>https://dev.to/aleksander_mako_1d1cd1320/how-to-scrub-huge-video-files-in-the-browser-without-blowing-up-ram-2n8g</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2za1c1v9a4irkbbopekm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2za1c1v9a4irkbbopekm.png" alt="Awesome Timeline" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vidstudio.app/" rel="noopener noreferrer"&gt;Vidstudio&lt;/a&gt; is a multi track video editor that works entirely inside the browser without any back end services supporting or doing any kind of heavy lifting. One of the most resource intensive features of an editor is in fact the timeline, because users need to be able to load assets and scrub back and forth along it. This article gives an overview of how the timeline works and how the RAM consumption is kept under control.&lt;br&gt;
Video editing is notoriously RAM intensive, and part of that difficulty is a question with no comfortable answer: how do you let a user preview a file that is larger than the total available RAM, and still let them ask for gigabyte 1 or gigabyte 100 of it, without crashing the system? Under these circumstances the only way to not crash the system is to not load the entire file into RAM but stream it instead. That solves the memory problem and immediately creates a different one. For a requested time instant, instead of just drawing the frame we now need to run the whole pipeline that yields the frame to be drawn. Everything below is me buying that latency back.&lt;br&gt;
The pipeline which yields a frame starts by reading a chunk of the file at the requested position, which is encoded, so we need to decode it and then display it in a two dimensional canvas in the preview. The next time the user moves the ruler ahead or back in time we need to start the process all over again. This naive implementation works, but it is not going to be efficient.&lt;br&gt;
The first source of inefficiency we can tackle is the I/O round trip to disk to fetch encoded chunks, in the case where the user happened to scrub nearby rather than really far ahead. The way to do this is to have a sample cache which responds to requests for chunks out of RAM. Caching encoded samples works fairly well here because the encoded samples are not full frames and therefore cost a fraction of the RAM to hold. The arithmetic is worth doing once: a 1080p frame sitting in a canvas is 1920 by 1080 by 4 bytes, so roughly 8MB, while the encoded packet it came out of is more likely to be a few tens of kilobytes. Two orders of magnitude for the same moment in the video, which is why you can afford to keep a lot of one and very little of the other.&lt;br&gt;
The next optimization to go after is keeping some decoded frames in RAM as well, in the proximity of the sought position, in case the user seeks nearby, since decoding is not free either. Here the 8MB figure sets the budget, so the window stays deliberately narrow. If they seek beyond your cached bounds then you have no choice but to start the pipeline again.&lt;br&gt;
Restarting the pipeline is not cheap, because once more you have to reach to disk to fetch the chunks, decode, possibly apply more effects and then draw, so we should only do it when it is really necessary. And it is in fact likely that users will seek to truly random positions along the timeline, in short succession of one another. Here we can do something smart: the last seek wins. Vidstudio does this by debouncing the seek operation for a few ms and tracking the id of the most recently started decode operation, then cancelling anything that started before it. That way only the latest seek operation ends up consuming resources on the end user's device.&lt;br&gt;
For a client side application, being frugal with the end user's resources matters, but so does the experience, and the two are in direct competition. Every one of the decisions above is the same trade made in a different place. Cache the cheap thing generously, cache the expensive thing narrowly, and throw away work the user has already changed their mind about. What the timeline does not do yet is anything clever about where in the file it starts decoding from, which turns out to be the largest cost of all. That one needs its own article.&lt;br&gt;
If you want to check out the project &lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://vidstudio.app/video-editor" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvidstudio.app%2Fog-image.png" height="" class="m-0" width=""&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://vidstudio.app/video-editor" rel="noopener noreferrer" class="c-link"&gt;
            Online Video Editor (No Upload, No Signup) | VidStudio
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Free online video editor that runs in your browser. Multi-track timeline, frame-accurate seek, powered by WebCodecs and FFmpeg WASM. Your files never leave your device.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvidstudio.app%2Fvidstudio-logo.svg" width="24" height="24"&gt;
          vidstudio.app
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://vidstudio.app/text-based-video-editor" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvidstudio.app%2Fog-image.png" height="" class="m-0" width=""&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://vidstudio.app/text-based-video-editor" rel="noopener noreferrer" class="c-link"&gt;
            Free Text-Based Video Editor (No Signup, No Upload) | VidStudio
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Edit video by editing the transcript, free and in your browser. Delete a word and the video cuts to match. Transcription runs on your device, nothing uploads, and there is no signup or watermark.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvidstudio.app%2Fvidstudio-logo.svg" width="24" height="24"&gt;
          vidstudio.app
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>It is really hard to write good software in Javascript</title>
      <dc:creator>Aleksander mako</dc:creator>
      <pubDate>Tue, 15 Sep 2026 13:46:00 +0000</pubDate>
      <link>https://dev.to/aleksander_mako_1d1cd1320/it-is-really-hard-to-write-good-software-in-javascript-44c4</link>
      <guid>https://dev.to/aleksander_mako_1d1cd1320/it-is-really-hard-to-write-good-software-in-javascript-44c4</guid>
      <description>&lt;p&gt;Six years of building Golang services gave me fewer race conditions than one year of writing Javascript. I have spent that year on &lt;a href="https://vidstudio.app/" rel="noopener noreferrer"&gt;vidstudio.app&lt;/a&gt;, an in browser client only video editor, which means I have had to write a lot of Javascript and have come to the conclusion that it is in fact a challenging language to master. The worst part is how easily I got there. Most of those races I introduced without noticing, and the one I saw coming is the one that taught me the most, because catching it is what let me say concretely why Javascript is so hard to write well.&lt;br&gt;
I was reworking the export pipeline of the editor and had to replace one of my dependencies which was part of the export path. For context, my export has to demux a source file, read a section of it, decode it, draw it, apply some effect, encode it and finally assemble it, and the order of assembly in a media file is important. The dependency I wanted to replace was mp4box.js, better known as a demuxer but perfectly capable of muxing, where you hand it an encoded chunk and it synchronously consumes the chunk.&lt;br&gt;
That synchronous consume was doing more for me than I understood at the time. Because the call returned when the work was finished, the loop handing over chunks in order was also the loop that had finished writing them in order, and I never had to think about either property. The new muxer, mediabunny, hands you back a promise instead, which resolves when the pipeline is ready to receive more data. The call no longer tells me that the previous chunk has been dealt with, and the sequencing I had been getting for free turned into something I had to state out loud. I am really glad I caught this one myself, but I still had to deal with serialising the assembly of the file, and while working on it I thought that this would never have happened to me in Golang.&lt;br&gt;
The reason this would never have happened to me in Golang, C++, C# or Java is that by default you get linear program execution. The order in which I invoke the lines of code is the order they execute, and the only time that changes is when I decide to go non linear. That is a convention rather than a guarantee, since a library in any of those languages can spawn threads without telling me, but it is a strong enough convention that a library doing it silently is considered badly behaved. In Golang I decide for myself to spawn goroutines and complicate the execution flow of my program in exchange for scalability. Javascript has no such baseline. Anything that touches I/O is asynchronous whether I want it to be or not, and in the browser there is no synchronous version to fall back on, so if I need operations linearised I have to arrange that myself.&lt;br&gt;
I suspect this is why the steady pipeline of articles trying to explain the event loop is still very much active, and still eagerly consumed by the next generation of developers, just as I consumed them when I first crossed paths with Node.js. Nobody is publishing a fresh explainer every month about how a for loop executes.&lt;br&gt;
Now that I am using Javascript more frequently I can see how challenging it is. It really does take effort to write good and correct software while staying conscious of every I/O operation in your application. I take linear execution for granted in my day job, and on my side project I have to actively classify which parts of the application have to stay linear and which ones can be left to run in whatever order the event loop decides. The event loop is a powerful concept and I am not arguing that it should not exist. I am saying that it hands me a job that other runtimes do for me, and that the job never finish. &lt;br&gt;
If you are interested in the project check it out&lt;br&gt;
Here: &lt;a href="https://vidstudio.app/video-editor" rel="noopener noreferrer"&gt;video-editor&lt;/a&gt; &lt;br&gt;
and Here:&lt;a href="https://vidstudio.app/text-based-video-editor" rel="noopener noreferrer"&gt;text-based video editor&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>go</category>
    </item>
  </channel>
</rss>
