<?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: Vinamra Sareen</title>
    <description>The latest articles on DEV Community by Vinamra Sareen (@vinamrasareen).</description>
    <link>https://dev.to/vinamrasareen</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%2F140679%2F0ba5d9cb-1930-4c1b-a931-2858c60327eb.jpg</url>
      <title>DEV Community: Vinamra Sareen</title>
      <link>https://dev.to/vinamrasareen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vinamrasareen"/>
    <language>en</language>
    <item>
      <title>Miraiclip: an open-source engine for building video editors in the browser</title>
      <dc:creator>Vinamra Sareen</dc:creator>
      <pubDate>Tue, 22 Sep 2026 05:52:17 +0000</pubDate>
      <link>https://dev.to/vinamrasareen/miraiclip-an-open-source-engine-for-building-video-editors-in-the-browser-2obi</link>
      <guid>https://dev.to/vinamrasareen/miraiclip-an-open-source-engine-for-building-video-editors-in-the-browser-2obi</guid>
      <description>&lt;p&gt;I've been building &lt;strong&gt;&lt;a href="https://github.com/comaniacs/miraiclip" rel="noopener noreferrer"&gt;Miraiclip&lt;/a&gt;&lt;/strong&gt; — an open-source, framework-agnostic library for building video editors in the browser — and it's now on npm under MIT. This post covers what it is, the one design decision everything hangs on, and a few hard-won lessons from making video actually work in a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Every browser video editor ends up rebuilding the same difficult parts: frame-accurate playback, an undo/redo system that never corrupts state, and exports that match what the preview showed. These are engine problems, not product problems — but there's no engine to reach for, so every team pays for them again.&lt;/p&gt;

&lt;p&gt;Miraiclip is that engine. It is deliberately &lt;strong&gt;not&lt;/strong&gt; an editor app. There's no timeline UI, no buttons — the core is headless: project state, a microsecond-precision timeline, and a full command history, with rendering delivered as a separate layer. You bring the UI (React, Vue, Svelte, vanilla — the core has zero UI dependencies).&lt;/p&gt;

&lt;h2&gt;
  
  
  One design decision: everything is a command
&lt;/h2&gt;

&lt;p&gt;Instead of calling imperative methods that mutate state, you dispatch descriptive commands. Every command is deterministic, validated against a schema, serializable, and invertible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createProject&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@miraiclip/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createProject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;asset/add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;intro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/media/intro.mp4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;durationUs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;track/add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip/add&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;trackId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;video-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;assetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;intro&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;startUs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;            &lt;span class="c1"&gt;// timeline position in microseconds&lt;/span&gt;
    &lt;span class="na"&gt;durationUs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 5 seconds&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Batch commands into one undoable transaction&lt;/span&gt;
&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip/split&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clipId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;atUs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;newClipId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip-1b&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip/move&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;clipId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;clip-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;startUs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;undo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things fall out of this decision without being bolted on:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Undo/redo&lt;/strong&gt; — commands are invertible, so history is exact, replayable, and inspectable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collaboration&lt;/strong&gt; — every state change is emitted as granular RFC-6902 JSON patches. Command and patch streams are the substrate for multiplayer editing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;patches&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;patches&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// [{ op: "replace", path: "/clips/clip-1/startUs", value: 1000000 }]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;AI control&lt;/strong&gt; — commands are plain descriptive data with a published catalog and JSON schemas. An LLM can read project state and generate valid edit sequences; the command catalog doubles as a tool definition. A human clicking a UI, an LLM planning an edit, and a sync layer replaying a collaborator's changes all speak the same language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playback and export
&lt;/h2&gt;

&lt;p&gt;The rendering layer (&lt;code&gt;@miraiclip/renderer&lt;/code&gt;) is a WebCodecs decode pipeline plus a WebGL compositor (PixiJS), with an audio-master clock:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createPixiBackend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;exportProject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;openMediabunnyDemuxer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createWebCodecsDecoderFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;createWebAudioOutput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;openMediabunnyAudio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@miraiclip/renderer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createPixiBackend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPlayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;openDemuxer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openMediabunnyDemuxer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;createDecoder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createWebCodecsDecoderFactory&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;maxOutputDimensionPx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1920&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="c1"&gt;// proxy preview&lt;/span&gt;
  &lt;span class="na"&gt;audioOutput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createWebAudioOutput&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;openAudio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openMediabunnyAudio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Offline export, faster than realtime — same compositor as the preview&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;exportProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mp4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quality&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The export renders through the &lt;strong&gt;same compositor&lt;/strong&gt; as the preview, so preview/export parity holds by construction rather than by testing luck. Output goes to MP4 or WebM, and it can stream straight into a file (&lt;code&gt;showSaveFilePicker&lt;/code&gt; writable) so long exports don't accumulate in memory. There's also &lt;code&gt;@miraiclip/server-export&lt;/code&gt;, which runs the identical pipeline in headless Chrome from Node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;miraiclip-export project.json &lt;span class="nt"&gt;--out&lt;/span&gt; final.mp4 &lt;span class="nt"&gt;--quality&lt;/span&gt; high
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keyframe animations (cubic-bézier easings), effects (color adjust, blur, chroma key), transitions with equal-power audio crossfades, and karaoke-style captions with SRT/VTT and ASR word-timestamp import are built in — and they render identically in preview, browser export, and server export, because it's one compositor everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things the browser made me learn
&lt;/h2&gt;

&lt;p&gt;A few lessons that shaped the engine, in case you're building anything media-heavy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Frame-accurate" means presented frames, not scheduled ones.&lt;/strong&gt; Callbacks tell you a frame was &lt;em&gt;scheduled&lt;/em&gt;; only reading pixels back tells you what the user actually saw. Miraiclip's test fixtures encode each frame's index as its color, so tests assert on what's really on the canvas — that's how several seek and playback bugs were caught that callback-based tests would have blessed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Export memory must be independent of timeline length.&lt;/strong&gt; Mixing an hour of audio in one &lt;code&gt;OfflineAudioContext&lt;/code&gt; buffer costs ~1.4 GB; encoding into an in-memory buffer costs the whole file. Miraiclip mixes audio in bounded sequential chunks interleaved with the frame walk and streams encoded output to disk — a demonstrated one-hour export (86,400 frames plus a full hour of audio) peaked at 165 MB of JS heap, running at 1.6× realtime on a dev laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trust nothing you can't verify with a second decoder.&lt;/strong&gt; Exports are validated by a corpus that re-decodes every file with ffmpeg — an independent decoder — checking every frame's timestamp and pixels, audio gain, and A/V sync (measured offset: 0 ms at both ends of the file). A muxer bug can't hide by round-tripping through the encoder that produced it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;Miraiclip is pre-1.0: the core model is stable in shape, but expect API changes between minor versions. Current packages: &lt;code&gt;@miraiclip/core&lt;/code&gt;, &lt;code&gt;@miraiclip/renderer&lt;/code&gt;, and &lt;code&gt;@miraiclip/server-export&lt;/code&gt;. Chromium-family browsers are the target for rendering and export (WebCodecs-based); the core runs anywhere JS runs, including Node.&lt;/p&gt;

&lt;p&gt;If you're building anything with video in the browser — an editor, a clip tool, automated video generation — I'd genuinely value your eyes on the API before it hardens.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/comaniacs/miraiclip" rel="noopener noreferrer"&gt;github.com/comaniacs/miraiclip&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs + live examples&lt;/strong&gt; (the code shown is the code that runs): &lt;a href="https://comaniacs.github.io/miraiclip/" rel="noopener noreferrer"&gt;comaniacs.github.io/miraiclip&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/@miraiclip/core" rel="noopener noreferrer"&gt;&lt;code&gt;@miraiclip/core&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions and issues welcome — and if you try it, I'd love to hear what you build.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How fastify performs better than other frameworks ?</title>
      <dc:creator>Vinamra Sareen</dc:creator>
      <pubDate>Tue, 13 Apr 2021 12:11:12 +0000</pubDate>
      <link>https://dev.to/vinamrasareen/how-fastify-performs-better-than-other-frameworks-116m</link>
      <guid>https://dev.to/vinamrasareen/how-fastify-performs-better-than-other-frameworks-116m</guid>
      <description>&lt;h3&gt;
  
  
  What is Fastify ?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprsdwo5ntebxmultu1qy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprsdwo5ntebxmultu1qy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.fastify.io/" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt; is a web framework for developing the backend of an application based on its powerful plugin architecture. &lt;code&gt;Fastify&lt;/code&gt; efficiently handles the resources of the server and helps you &lt;code&gt;serve the max&lt;/code&gt; number of &lt;code&gt;requests&lt;/code&gt; per second.&lt;/p&gt;

&lt;p&gt;It is the most popular framework in town not because of it’s user base but because of the fact it is the &lt;code&gt;most fastest&lt;/code&gt; framework available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why use Fastify ?
&lt;/h3&gt;

&lt;p&gt;There are many alternatives in market, then why focus on &lt;code&gt;fastify&lt;/code&gt; ?&lt;br&gt;
If you have worked with backend applications before you might have heard of some popular frameworks such as &lt;code&gt;express&lt;/code&gt;, &lt;code&gt;koa&lt;/code&gt;, &lt;code&gt;hapi or restify&lt;/code&gt;. Out of these the most popular framework has been &lt;code&gt;Express.js&lt;/code&gt;, due to its wide use and community support it is always at the top of charts. But in terms of performance it is not.&lt;/p&gt;

&lt;p&gt;A good way to understand is by comparison.&lt;/p&gt;

&lt;p&gt;Have a look at these comparisons I did between &lt;code&gt;fastify&lt;/code&gt; and &lt;code&gt;express&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first image is of express, where we have used &lt;code&gt;autocannon (a benchmarking tool)&lt;/code&gt;.The number of requests served by express is &lt;code&gt;14k&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3k72h7jijqvnkttczsq3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3k72h7jijqvnkttczsq3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When compared to fastify, it outperforms express. The number of requests served per second is 28K, two times than that of express.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12hcbezwllvrcrm66fjx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12hcbezwllvrcrm66fjx.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also checkout this link, for benchmarks with other frameworks : &lt;a href="https://www.fastify.io/benchmarks/" rel="noopener noreferrer"&gt;Benchmarks&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reasons for performance
&lt;/h3&gt;

&lt;p&gt;One of the primary reasons for the performance of fastify is because of its dependencies. Some of the dependencies that fastify uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;find-my-way&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pino&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fast-json-stringify&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fastify-helmet&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And might be few others too.&lt;/p&gt;

&lt;p&gt;If we take a close look at each of these dependencies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For routing they use &lt;code&gt;find-my-way&lt;/code&gt; which avoids closure allocation, is built on a radix tree and safe to use.
Those who are not aware of closure based problems in javascript:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Variables used by closure do not get garbage collected.
2. Memory snapshot of the application increases if closures are not used properly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Fastify uses pino for logging which is more performant than other logging libraries available (&lt;code&gt;bunyan&lt;/code&gt;, &lt;code&gt;winston&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSON.stringify&lt;/code&gt; cannot be optimized by v8, so they use &lt;code&gt;fast-json-stringify&lt;/code&gt; which is schema based JSON rendering and generates code based on schema, which greatly reduces the computation overhead for identifying field types for JSON serialization.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Fastify-helmet&lt;/code&gt; performs better than other libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s been said about dependencies, there is another reason behind fastify’s performance.&lt;/p&gt;

&lt;p&gt;Its life cycle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy2lkoqj4t8zp5x4a7r5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy2lkoqj4t8zp5x4a7r5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not just about dependencies it uses but it has been designed in such a way that it optimizes with &lt;code&gt;v8&lt;/code&gt; in the best possible way.&lt;/p&gt;

&lt;p&gt;What code developer writes is used by fastify which is &lt;code&gt;pre initialized&lt;/code&gt; so it is available at the time it is requested which makes it faster, the pre initialized data structures are fast and improves and the efficiency of the fastify framework making it more performant.&lt;/p&gt;

&lt;p&gt;Please, let me know everyone if you have anything to add, or correct.&lt;/p&gt;

&lt;p&gt;References: &lt;a href="https://www.fastify.io/" rel="noopener noreferrer"&gt;Fastify&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fastify</category>
      <category>node</category>
      <category>performance</category>
      <category>frameworks</category>
    </item>
    <item>
      <title>How to improve database performance for insert queries</title>
      <dc:creator>Vinamra Sareen</dc:creator>
      <pubDate>Sun, 28 Feb 2021 07:55:09 +0000</pubDate>
      <link>https://dev.to/vinamrasareen/how-to-improve-database-performance-for-insert-queries-4gab</link>
      <guid>https://dev.to/vinamrasareen/how-to-improve-database-performance-for-insert-queries-4gab</guid>
      <description>&lt;p&gt;Hey all, this is my first blog, I have recently started working as a full stack web developer at &lt;a href="https://www.adda52rummy.com/" rel="noopener noreferrer"&gt;Adda52Rummy&lt;/a&gt; and I was assigned with a task to insert some records in database, which I thought I handled appropriately. But my manager gave me csv file of 5K records to insert to database. It was synchronous code and took some time. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fphotos.prnewswire.com%2Fprn%2F20140109%2F10086345" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fphotos.prnewswire.com%2Fprn%2F20140109%2F10086345" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;About tech Stack, I was working in Node.js with MariaDB and &lt;strong&gt;&lt;a href="https://www.fastify.io/" rel="noopener noreferrer"&gt;Fastify framework&lt;/a&gt; (performs better than express and other sever frameworks or library)&lt;/strong&gt;. I used &lt;a href="https://sequelize.org/" rel="noopener noreferrer"&gt;Sequelize&lt;/a&gt; as ORM library, it is a promise-based Node.js ORM for Postgres, MySQL, MariaDB, SQLite and Microsoft SQL Server. To improve the performance of my operations, I needed to run insert operations in multiple batches and those batches had to run in parallel. Aha! Sound nice, but to how to implement it. After spending ample time of searching I found some solution on how to do it. &lt;br&gt;
Thanks to &lt;a href="https://stackoverflow.com/a/31971563/7615305" rel="noopener noreferrer"&gt;Evan Siroky&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The solution was to use &lt;code&gt;bulkCreate&lt;/code&gt; to insert multiple batches and use &lt;a href="https://caolan.github.io/async/v3/" rel="noopener noreferrer"&gt;&lt;code&gt;asnyc.cargo&lt;/code&gt;&lt;/a&gt; function to run batches in parallel. After using this I was able to insert data in 2 seconds and guess what, I was able to insert 100K records in 5 ~ 7 seconds.&lt;/p&gt;

&lt;p&gt;Let's jump straight to code:&lt;/p&gt;

&lt;p&gt;In my controllers, &lt;strong&gt;&lt;em&gt;coupon.js&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Coupon = require("../models/coupon");

// exports.createCoupon = async (row) =&amp;gt; {
//   await Coupon.sync();
//   return Coupon.create({
//     coupon_code: row.coupon_code,
//   });
// };

// Here I am using bulkCreate
exports.createCoupon = (tasks, inserterCb) =&amp;gt; {
  Coupon.bulkCreate(tasks).then(function () {
    inserterCb();
  });
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have created a utility folder, where I have created a &lt;strong&gt;&lt;em&gt;csv-to-db.js&lt;/em&gt;_&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const fs = require("fs");
const path = require("path");
const async = require("async");
const csv = require("csv");

function csvToDb(filename, fn) {
  let input = fs.createReadStream(
    path.resolve(__dirname, "../public/assets", filename)
  );
  let parser = csv.parse({
    columns: true,
    relax: true,
  });

  let inserter = async.cargo(function (tasks, inserterCb) {
    fn(tasks, inserterCb);
  }, 1000 // -&amp;gt; task size); 

/* you can specify how many task you want to handle, I have set it to 
1000 tasks at a time parallel, I can say for 100K let's handle 
50K - 50K to take much less time, but it doesn't work that way,
 it will take maybe two or more seconds to execute input of size 50K,
 as it is large input. So take a size which execute faster but handles
 many task as possible. */

  parser.on("readable", function () {
    while ((line = parser.read())) {
      inserter.push(line);
    }
  });

  parser.on("error", function (err) {
    throw err;
  });

  parser.on("end", function (count) {
    inserter.drain();
  });

  input.pipe(parser);
}

module.exports = csvToDb;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when I call this route &lt;strong&gt;'http::/localhost:3000/coupon'&lt;/strong&gt;, this is the code that gets executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Coupon = require("../controllers/coupon");

module.exports = function routes(fastify, options, done) {
  fastify.get("/coupon", async (req, res) =&amp;gt; {
    csvToDb("filename.csv", Coupon.createCoupon);
    return { statusCode: 200, message: "sucess" };
  });

  done();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to read out.&lt;/p&gt;

&lt;p&gt;All references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/29461908/how-to-do-bulk-insert-using-sequelize-and-node-js/31971563" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/29461908/how-to-do-bulk-insert-using-sequelize-and-node-js/31971563&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://caolan.github.io/async/v3/" rel="noopener noreferrer"&gt;https://caolan.github.io/async/v3/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>performance</category>
      <category>sequelize</category>
      <category>csvparse</category>
    </item>
  </channel>
</rss>
