<?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: MartinDelophy</title>
    <description>The latest articles on DEV Community by MartinDelophy (@martindelophy).</description>
    <link>https://dev.to/martindelophy</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%2F4029567%2Fc8d453a4-d3ea-4275-b7ce-fbece2440c21.png</url>
      <title>DEV Community: MartinDelophy</title>
      <link>https://dev.to/martindelophy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/martindelophy"/>
    <language>en</language>
    <item>
      <title>What It Takes to Run an AI Video Editor Locally in the Browser</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Tue, 25 Aug 2026 08:33:27 +0000</pubDate>
      <link>https://dev.to/martindelophy/what-it-takes-to-run-an-ai-video-editor-locally-in-the-browser-103g</link>
      <guid>https://dev.to/martindelophy/what-it-takes-to-run-an-ai-video-editor-locally-in-the-browser-103g</guid>
      <description>&lt;p&gt;Most AI video tools begin with an upload button.&lt;/p&gt;

&lt;p&gt;That is convenient for the application developer, but it changes the product for the user. Raw footage can be large, personal, slow to transfer, and expensive to process repeatedly. For a video editor, uploading is not a one-time action either: every trim, caption, effect, and export can create another round trip.&lt;/p&gt;

&lt;p&gt;I wanted to explore a different constraint: &lt;strong&gt;how much of an AI video-editing workflow can stay inside a modern browser?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question became &lt;a href="https://video-editor.ai-creator.top/" rel="noopener noreferrer"&gt;Timeline Studio&lt;/a&gt;, an open-source, local-first AI video editor with a multi-track timeline, captions, voiceovers, visual effects, browser AI tools, and offline export.&lt;/p&gt;

&lt;p&gt;The interesting part was not putting a familiar editor UI on a webpage. It was making media, AI inference, model delivery, timeline state, preview, and export behave like one coherent system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local-first is an architectural constraint
&lt;/h2&gt;

&lt;p&gt;For supported workflows, project media is processed in the browser instead of being uploaded to an editing backend. This changes several engineering decisions at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inference needs browser-compatible runtimes;&lt;/li&gt;
&lt;li&gt;model downloads must be lazy, resumable, cached, and versioned;&lt;/li&gt;
&lt;li&gt;timeline operations need deterministic state rather than server-side session magic;&lt;/li&gt;
&lt;li&gt;preview must stay responsive while export remains reproducible;&lt;/li&gt;
&lt;li&gt;failures need to explain browser or hardware limitations without hiding them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WebGPU is the main compute path for heavier models. WASM remains important for operations where it is more stable or broadly compatible. ONNX gives the project a practical interchange format, but converting a model is only the beginning. A model that technically loads can still be unusable because of memory pressure, unsupported operators, slow graph initialization, or inconsistent numerical output across execution providers.&lt;/p&gt;

&lt;p&gt;The result is a mixed runtime rather than a single “run everything on WebGPU” switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model delivery is part of the product
&lt;/h2&gt;

&lt;p&gt;A local model still has to reach the user once.&lt;/p&gt;

&lt;p&gt;Timeline Studio lazy-loads AI artifacts only when a feature is first used. The service worker owns the persistent model cache, while later runs reuse the cached files. Models are pinned to known revisions so an upstream change cannot silently alter an editing workflow.&lt;/p&gt;

&lt;p&gt;The project also mirrors model artifacts across Hugging Face and ModelScope. Chinese and domestic sessions prefer ModelScope; other sessions prefer Hugging Face. If the preferred provider is unavailable, the application can fall back to the other mirror.&lt;/p&gt;

&lt;p&gt;The important detail is that both providers map to one cache identity. A fallback should not create a second full copy of the same model on the user's device.&lt;/p&gt;

&lt;p&gt;This sounds like infrastructure work—and it is—but it directly affects the editing experience. “Generate music” should not look like a fresh model download every time. A cache miss should not become a mysterious network exception. A pinned model should carry its license and source notes with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A responsive preview and a deterministic export are different jobs
&lt;/h2&gt;

&lt;p&gt;Video editors need immediate feedback. Native media playback and a live canvas make trimming and positioning feel responsive, but they are not enough for final export.&lt;/p&gt;

&lt;p&gt;Real-time playback can vary with decoding speed, dropped frames, tab scheduling, and device load. If final rendering simply records whatever happened on screen, two exports of the same project can drift.&lt;/p&gt;

&lt;p&gt;Timeline Studio therefore treats the timeline as declarative project state and uses a separate offline rendering path for export. Clips, source trims, transforms, captions, overlays, audio, effects, and keyframes are evaluated against explicit timestamps. WebCodecs is used for MP4/WebM composition where available, with a compatibility path for browsers that need it.&lt;/p&gt;

&lt;p&gt;The two paths have different performance goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preview:&lt;/strong&gt; respond quickly enough to edit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export:&lt;/strong&gt; evaluate the same project state consistently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They still need shared geometry, timing, interpolation, and effect definitions. Otherwise the editor develops the most damaging kind of bug: a preview that looks correct and an export that does not.&lt;/p&gt;

&lt;p&gt;This is why small visual features can require surprisingly deep work. A timed ripple effect, for example, is not just a CSS animation. Its seeded placement, beat timing, grayscale-to-color reveal, wave propagation, and decay must all be derived from the same deterministic parameters in both preview and export.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI output should become editable media
&lt;/h2&gt;

&lt;p&gt;Another design decision was to avoid treating AI as a collection of isolated demo buttons.&lt;/p&gt;

&lt;p&gt;Generated or analyzed results should return to the editing model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automatic captions become timed caption segments;&lt;/li&gt;
&lt;li&gt;generated voiceovers become audio clips;&lt;/li&gt;
&lt;li&gt;separated vocals and instrumentals become independent audio tracks;&lt;/li&gt;
&lt;li&gt;AI music is added to the user's assets instead of silently replacing the timeline;&lt;/li&gt;
&lt;li&gt;repair and subject-isolation results remain reviewable and editable;&lt;/li&gt;
&lt;li&gt;portable .timeline projects preserve the composition as the source of truth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The browser currently supports workflows including multilingual voice generation, Whisper-based captions, local AI music, smart framing, object or watermark repair, restoration, vocal separation, and talking-avatar generation. Not every device will run every large model comfortably, so the UI has to expose setup progress, cancellation, caching, and compatibility honestly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did not fit the local-first story
&lt;/h2&gt;

&lt;p&gt;There is a temptation to claim that moving inference into the browser removes every tradeoff. It does not.&lt;/p&gt;

&lt;p&gt;The first model download may be substantial. GPU memory varies widely. WebGPU behavior still differs across browser and driver combinations. Mobile devices require more conservative paths. Some models become slower or less reliable after conversion, even when their quality looked good in the original research environment.&lt;/p&gt;

&lt;p&gt;Local-first also does not mean “offline from the first visit.” The application shell and requested models must be downloaded before they can be cached. A more accurate promise is: &lt;strong&gt;supported editing workflows can run without uploading the user's project media to an editing backend.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That narrower statement is less dramatic, but it is testable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open source it?
&lt;/h2&gt;

&lt;p&gt;Browser media work sits at the intersection of WebCodecs, WebGPU, ONNX, audio processing, timeline UX, caching, and export. Many of the hardest problems are integration problems, and they benefit from reproducible bug reports and implementations that can be inspected.&lt;/p&gt;

&lt;p&gt;Timeline Studio is available under the MIT License on &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. The repository includes the editor, multilingual documentation, portable project tooling, and an agent skill for inspecting, editing, diffing, and rendering timeline projects.&lt;/p&gt;

&lt;p&gt;There is still plenty to improve: broader headless render parity, more reliable cross-device export, a larger versioned command registry, and better recovery when browser AI reaches hardware limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Launching today
&lt;/h2&gt;

&lt;p&gt;Timeline Studio is launching on &lt;a href="https://www.producthunt.com/products/timeline-studio-2?launch=timeline-studio-2" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt; today.&lt;/p&gt;

&lt;p&gt;If local-first creative software interests you, try the editor and share your honest feedback. I am especially interested in where the browser-local model feels clear, where setup is confusing, and which real editing workflow breaks first.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Best Feature I Shipped Was Removing Friction: Rebuilding the UX of a Browser Video Editor</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Mon, 24 Aug 2026 08:30:27 +0000</pubDate>
      <link>https://dev.to/martindelophy/the-best-feature-i-shipped-was-removing-friction-rebuilding-the-ux-of-a-browser-video-editor-33k</link>
      <guid>https://dev.to/martindelophy/the-best-feature-i-shipped-was-removing-friction-rebuilding-the-ux-of-a-browser-video-editor-33k</guid>
      <description>&lt;p&gt;When I first shared &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio&lt;/a&gt;, it had around 80 GitHub stars.&lt;/p&gt;

&lt;p&gt;The technical premise was already there: a local-first video editor that runs in the browser, with a multi-track timeline, voiceovers, captions, effects, and offline export.&lt;/p&gt;

&lt;p&gt;The user experience was not.&lt;/p&gt;

&lt;p&gt;Some early feedback was blunt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Interesting project, but the interface feels clunky.&lt;/p&gt;

&lt;p&gt;There are a lot of features, but some interactions feel unintuitive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That feedback was fair. I had spent too much time proving that browser video editing was possible and not enough time asking whether ordinary editing actions behaved the way people expected.&lt;/p&gt;

&lt;p&gt;The project has since passed 500 GitHub stars. The number is nice, but the more meaningful milestone was going back and fixing the small frustrations that made the entire editor feel harder than it needed to be.&lt;/p&gt;

&lt;p&gt;This is a post about those fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  A feature can work and still be wrong
&lt;/h2&gt;

&lt;p&gt;The early version had split, zoom, scrolling, track locking, audio separation, mobile controls, and export settings.&lt;/p&gt;

&lt;p&gt;On paper, those features existed.&lt;/p&gt;

&lt;p&gt;In practice, they often exposed the implementation instead of matching the user's mental model.&lt;/p&gt;

&lt;p&gt;For example, the split action originally required an explicitly selected clip. A user could place the playhead in the middle of the main video, click the scissors button, and still be told to select a clip first.&lt;/p&gt;

&lt;p&gt;The code was consistent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;selectedClip -&amp;gt; split(selectedClip, playheadTime)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interaction was not.&lt;/p&gt;

&lt;p&gt;The user was looking at the main visual under the playhead. They had already communicated enough intent.&lt;/p&gt;

&lt;p&gt;The current rule is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if a clip is explicitly selected:
    split that clip
else:
    find the main visual under the playhead
    select and split it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicit selections are still respected, but the common action now has a useful default.&lt;/p&gt;

&lt;p&gt;This change added no new capability. It simply removed a question the editor should never have asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lock the meaning of a continuous gesture
&lt;/h2&gt;

&lt;p&gt;Timeline editors usually need several wheel behaviors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vertical track scrolling&lt;/li&gt;
&lt;li&gt;horizontal timeline panning&lt;/li&gt;
&lt;li&gt;timeline zoom&lt;/li&gt;
&lt;li&gt;Shift-modified panning&lt;/li&gt;
&lt;li&gt;Ctrl/Cmd wheel zoom&lt;/li&gt;
&lt;li&gt;trackpad pinch zoom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My initial implementation kept resolving the wheel behavior from whatever happened to be under the pointer.&lt;/p&gt;

&lt;p&gt;That sounds reasonable until the timeline moves.&lt;/p&gt;

&lt;p&gt;Imagine starting a vertical scroll over empty timeline space. As the tracks move, a clip slides under the stationary pointer. If the editor resolves the target again, the gesture can suddenly change from scrolling tracks to zooming the timeline.&lt;/p&gt;

&lt;p&gt;From the user's perspective, the editor has changed its mind halfway through an action.&lt;/p&gt;

&lt;p&gt;The fix was to treat a continuous wheel sequence as one gesture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gestureTarget = hitTest(pointerPositionAtStart)
gestureMode = resolveMode(gestureTarget, modifierKeys)

while the gesture continues:
    keep gestureMode stable

after a short pause:
    allow the next gesture to resolve again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting behavior is predictable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;start over empty timeline space to scroll track lanes&lt;/li&gt;
&lt;li&gt;start over a clip to zoom the timeline&lt;/li&gt;
&lt;li&gt;use Shift for horizontal panning&lt;/li&gt;
&lt;li&gt;use Ctrl/Cmd or pinch for explicit zoom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is not the exact mapping. It is that the mapping does not mutate while the user is still performing the same physical gesture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Users manipulate clips, not source asset IDs
&lt;/h2&gt;

&lt;p&gt;A split video often produces several timeline clips that reference the same source file.&lt;/p&gt;

&lt;p&gt;Internally, that might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sourceAssetId: video-001

clip A -&amp;gt; source range 0s–5s
clip B -&amp;gt; source range 5s–12s
clip C -&amp;gt; source range 12s–20s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An early version of "Separate audio" relied too heavily on the shared source asset ID. That made whole-asset matching convenient, but it violated what the user had actually asked for.&lt;/p&gt;

&lt;p&gt;When the command comes from clip B's context menu, the expected result is the audio for 5s–12s—not new mappings for every sibling clip backed by &lt;code&gt;video-001&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The current behavior operates on the exact timeline segment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preserve its source trim&lt;/li&gt;
&lt;li&gt;preserve its playback speed&lt;/li&gt;
&lt;li&gt;place the extracted audio on an audio lane&lt;/li&gt;
&lt;li&gt;mute the corresponding picture-in-picture clip to prevent doubled sound&lt;/li&gt;
&lt;li&gt;select and reveal the resulting audio&lt;/li&gt;
&lt;li&gt;leave untouched sibling clips alone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whole-asset matching still makes sense when an unsplit source asset is intentionally dragged onto a source-audio track. It does not make sense for a clip-scoped menu action.&lt;/p&gt;

&lt;p&gt;The lesson was simple: internal identity is not the same thing as interaction scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic layout should not rearrange confirmed work
&lt;/h2&gt;

&lt;p&gt;Audio lane placement caused a similar problem.&lt;/p&gt;

&lt;p&gt;When a new voice clip overlapped existing audio, an automatic placement algorithm could move an existing clip to another lane. The layout became technically valid, but the user's previously arranged work changed without permission.&lt;/p&gt;

&lt;p&gt;Now existing clips stay where they are.&lt;/p&gt;

&lt;p&gt;New voice or audio clips find another available lane, or a new ordinary audio lane is materialized when necessary. AI music always routes to the dedicated music track. Split audio can still be moved vertically between normal audio lanes, but adding something new never displaces something already confirmed.&lt;/p&gt;

&lt;p&gt;Automation should solve the new placement problem, not reopen old decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the primary visual in view
&lt;/h2&gt;

&lt;p&gt;Once a project contains overlays, captions, source audio, voiceovers, and music, vertical scrolling becomes unavoidable.&lt;/p&gt;

&lt;p&gt;Letting every track scroll together meant the main visual could disappear while the user worked on lower lanes. That removed the most important reference point in the composition.&lt;/p&gt;

&lt;p&gt;The main visual track is now pinned directly below the ruler. Overlay and lower tracks scroll underneath it.&lt;/p&gt;

&lt;p&gt;The persistent scrollbar chrome is hidden, but both horizontal and vertical scrolling remain functional. The pinned track's lower edge also acts as the upper boundary for vertical drag auto-scroll, so cross-lane moves still behave correctly.&lt;/p&gt;

&lt;p&gt;This required more than &lt;code&gt;position: sticky&lt;/code&gt;. Pointer hit testing, drag targets, auto-scroll boundaries, and main-to-overlay or overlay-to-main moves all had to use the same geometry.&lt;/p&gt;

&lt;p&gt;The visible result is much less dramatic: the main picture simply stops getting lost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile is not desktop with smaller buttons
&lt;/h2&gt;

&lt;p&gt;The first mobile layout was essentially the desktop editor compressed into a narrow viewport.&lt;/p&gt;

&lt;p&gt;It technically contained the same features. It was also exhausting to use.&lt;/p&gt;

&lt;p&gt;The redesigned mobile workspace follows a different hierarchy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preview first&lt;/li&gt;
&lt;li&gt;timeline immediately below it&lt;/li&gt;
&lt;li&gt;a centered playhead with the timeline moving around it&lt;/li&gt;
&lt;li&gt;clip-specific actions after selection&lt;/li&gt;
&lt;li&gt;properties inside a focused bottom drawer&lt;/li&gt;
&lt;li&gt;touch-sized controls&lt;/li&gt;
&lt;li&gt;no desktop keyboard-shortcut guide&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Desktop and mobile still edit the same project model. They do not need to expose that model through the same interface.&lt;/p&gt;

&lt;p&gt;Responsive design is not preserving every panel at every width. It is preserving the user's task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small state mismatches create large trust problems
&lt;/h2&gt;

&lt;p&gt;Several fixes were almost embarrassingly small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clicking the Export button a second time now closes the export popover.&lt;/li&gt;
&lt;li&gt;Icon-only timeline controls have localized tooltips on hover and keyboard focus.&lt;/li&gt;
&lt;li&gt;Locked tracks retain a subdued treatment, but their clips no longer gain a dashed border that looks like selection.&lt;/li&gt;
&lt;li&gt;"Analyze person" and "Analyze object" use the primary action style whenever they are actionable; the neutral style is reserved for "Cancel analysis."&lt;/li&gt;
&lt;li&gt;Generated music and converted voices go to the asset library instead of silently modifying the timeline.&lt;/li&gt;
&lt;li&gt;Repeated voice generations append after the current voiceover end instead of stacking at 0 seconds or an unchanged playhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these belongs in an impressive model benchmark.&lt;/p&gt;

&lt;p&gt;Together, they answer a more important question: can the user predict what will happen after the next click?&lt;/p&gt;

&lt;h2&gt;
  
  
  The product changed when the question changed
&lt;/h2&gt;

&lt;p&gt;At the beginning, I kept asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can this run in a browser?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Can WebCodecs export the composition? Can WebGPU run the model? Can the timeline support another track type? Can an agent modify the project?&lt;/p&gt;

&lt;p&gt;Those were useful questions, but they produced a technology demonstration.&lt;/p&gt;

&lt;p&gt;The editor started becoming a product when the question changed to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What does the user reasonably expect to happen here?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question led to fewer interruptions, stable gestures, clip-scoped actions, conservative automation, clearer state, and a mobile interface built around touch rather than CSS breakpoints.&lt;/p&gt;

&lt;p&gt;Timeline Studio is still evolving. It combines a real multi-track editor with local-first browser AI, portable &lt;code&gt;.timeline&lt;/code&gt; projects, and deterministic offline export. There are still plenty of rough edges to find.&lt;/p&gt;

&lt;p&gt;But if you tried an early version and found the UI clunky, I would genuinely like to know whether the same problems still stand—and what remains confusing today.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live editor:&lt;/strong&gt; &lt;a href="https://video-editor.ai-creator.top/" rel="noopener noreferrer"&gt;https://video-editor.ai-creator.top/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most useful feedback is not "add another AI model."&lt;/p&gt;

&lt;p&gt;It is: "I expected this action to do X, but it did Y."&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>AI Video Generation Is Expensive—So I Built a 15-Second Remix Workflow</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Sat, 22 Aug 2026 09:11:55 +0000</pubDate>
      <link>https://dev.to/martindelophy/ai-video-generation-is-expensive-so-i-built-a-15-second-remix-workflow-1ib7</link>
      <guid>https://dev.to/martindelophy/ai-video-generation-is-expensive-so-i-built-a-15-second-remix-workflow-1ib7</guid>
      <description>&lt;p&gt;Generating AI video looks effortless in a demo: write a prompt, wait a minute, and receive a cinematic shot.&lt;/p&gt;

&lt;p&gt;In practice, the expensive part is not only the subscription or the credits. It is the uncertainty. A usable five-second clip may require several generations because the face changes, the motion breaks, the composition drifts, or the shot simply does not fit the rest of the sequence.&lt;/p&gt;

&lt;p&gt;That led me to a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if creators did not have to generate every frame from scratch?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I tested a more practical workflow: start with video material I am authorized to use, analyze it for high-impact moments, rebuild the pacing, replace the original audio, and keep the result as an editable timeline instead of a disposable render.&lt;/p&gt;

&lt;p&gt;The tool behind the experiment is &lt;strong&gt;Timeline Studio&lt;/strong&gt;, an open-source, browser-based video editor:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;GitHub: &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;MartinDelophy/ai-video-editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&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%2Fl7tjvd1yjht8y6o7472r.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%2Fl7tjvd1yjht8y6o7472r.png" alt="A cinematic frame selected for the final 15-second edit" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The experiment
&lt;/h2&gt;

&lt;p&gt;The input was simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one source video of roughly two minutes;&lt;/li&gt;
&lt;li&gt;one music track of more than five minutes;&lt;/li&gt;
&lt;li&gt;a second video containing a specific three-second ending shot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The target was a &lt;strong&gt;15-second short-form edit&lt;/strong&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple memory-like fragments;&lt;/li&gt;
&lt;li&gt;a clear emotional build;&lt;/li&gt;
&lt;li&gt;a transition in the middle;&lt;/li&gt;
&lt;li&gt;a different final shot;&lt;/li&gt;
&lt;li&gt;the original source audio removed;&lt;/li&gt;
&lt;li&gt;a musical highlight near &lt;strong&gt;1:20&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;a real ending, rather than an abrupt cutoff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final structure looked like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Editorial function&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0–3s&lt;/td&gt;
&lt;td&gt;Establish the character and atmosphere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3–7s&lt;/td&gt;
&lt;td&gt;Build a fragmented memory rhythm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Around 7s&lt;/td&gt;
&lt;td&gt;Use a short flash transition as an emotional hinge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7–12s&lt;/td&gt;
&lt;td&gt;Increase energy while protecting readable hero frames&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12–15s&lt;/td&gt;
&lt;td&gt;Switch to the requested ending shot and fade to black&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The final three seconds came from &lt;strong&gt;2:48–2:51&lt;/strong&gt; of the second source. Its embedded audio was muted, so the entire edit used only one clean music track.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why “highlight detection” is not random trimming
&lt;/h2&gt;

&lt;p&gt;A common automation mistake is to cut a long video into equal intervals and keep the most active sections.&lt;/p&gt;

&lt;p&gt;That produces motion, but not necessarily meaning.&lt;/p&gt;

&lt;p&gt;For this experiment, candidate moments were evaluated with several kinds of evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;audio-energy change;&lt;/li&gt;
&lt;li&gt;subject-aware motion and frame difference;&lt;/li&gt;
&lt;li&gt;shot-change confidence;&lt;/li&gt;
&lt;li&gt;expression change for a tracked face;&lt;/li&gt;
&lt;li&gt;clarity around the main subject.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A practical scoring model can combine these signals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;highlight_score =
    0.30 * audio_energy_change
  + 0.25 * subject_motion
  + 0.20 * shot_change_confidence
  + 0.15 * expression_change
  + 0.10 * subject_clarity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the score is only a candidate signal. It should not override continuity, intentional stillness, anticipation, or the most important result frame.&lt;/p&gt;

&lt;p&gt;After saliency analysis, each retained beat still needs an editorial role: setup, rise, pre-impact, peak, aftershock, or bridge. Without that hierarchy, every shot receives equal weight and the montage feels flat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the musical high point
&lt;/h2&gt;

&lt;p&gt;The user requested the highlight near 1:20, so I searched around that region instead of blindly cutting from exactly 80 seconds.&lt;/p&gt;

&lt;p&gt;The selected range was approximately &lt;strong&gt;80.5–95.5 seconds&lt;/strong&gt;. That gave the 15-second edit a more natural musical phrase and enough room for a controlled ending.&lt;/p&gt;

&lt;p&gt;A simplified FFmpeg extraction looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-ss&lt;/span&gt; 80.5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-t&lt;/span&gt; 15 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; input.aac &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="s2"&gt;"afade=t=in:st=0:d=0.15,afade=t=out:st=14.3:d=0.7"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:a aac &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-b&lt;/span&gt;:a 192k &lt;span class="se"&gt;\&lt;/span&gt;
  music-highlight.m4a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does four important things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;starts close to the requested musical moment;&lt;/li&gt;
&lt;li&gt;limits the result to exactly 15 seconds;&lt;/li&gt;
&lt;li&gt;avoids a hard entrance;&lt;/li&gt;
&lt;li&gt;fades the final 0.7 seconds so the music and picture resolve together.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The loudest passage is not automatically the best passage. A useful music highlight also needs a readable beat, a complete phrase, an emotional lift, and a point where the ending can land.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the “memory fragment” feeling
&lt;/h2&gt;

&lt;p&gt;A memory montage is not just a color preset.&lt;/p&gt;

&lt;p&gt;The feeling came from combining several editorial decisions:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Short, non-contiguous fragments
&lt;/h3&gt;

&lt;p&gt;The first 12 seconds use eight short clips instead of one continuous excerpt. The clips come from different source times and are reorganized around emotional progression.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A restrained flash transition
&lt;/h3&gt;

&lt;p&gt;A brief flash near the middle separates two emotional phases. It is intentionally short and placed away from the decisive frame.&lt;/p&gt;

&lt;p&gt;Transitions should clarify structure. If an effect hides the action viewers need to see, it is working against the edit.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A protected ending
&lt;/h3&gt;

&lt;p&gt;The requested ending shot occupies exactly 12–15 seconds. The final 0.7 seconds fade to black, giving the piece a deliberate closing gesture.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. One coherent audio bed
&lt;/h3&gt;

&lt;p&gt;All embedded source audio is muted. Keeping only the selected music highlight avoids doubled sound and makes later remixing predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow stayed editable
&lt;/h2&gt;

&lt;p&gt;A rendered MP4 is only the delivery artifact. The actual source of truth is the editable timeline.&lt;/p&gt;

&lt;p&gt;The project contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eight memory fragments;&lt;/li&gt;
&lt;li&gt;one three-second ending clip;&lt;/li&gt;
&lt;li&gt;source-time trims for every segment;&lt;/li&gt;
&lt;li&gt;a middle flash transition;&lt;/li&gt;
&lt;li&gt;a final fade;&lt;/li&gt;
&lt;li&gt;one music segment;&lt;/li&gt;
&lt;li&gt;muted embedded audio;&lt;/li&gt;
&lt;li&gt;normalized output dimensions and frame rate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because editing is iterative. If the ending needs to start 300 milliseconds earlier, I should not have to reconstruct a giant filter graph or repeat the full analysis.&lt;/p&gt;

&lt;p&gt;Timeline Studio stores the edit as a &lt;code&gt;.timeline&lt;/code&gt; project, so clips, timing, transitions, audio, and effects can continue to be adjusted visually or through automation.&lt;/p&gt;

&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%2Fjk563euuezkov32zedbn.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%2Fjk563euuezkov32zedbn.png" alt="Timeline Studio production log showing the ending replacement, frame-rate normalization, muted source audio, and final fade" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The screenshot above captures part of the actual production process. The ending source ran at 30 fps, while the main sequence used 29 fps, so the render pipeline normalized the final output and fitted the new shot to the project resolution without reintroducing its original sound.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical validation
&lt;/h2&gt;

&lt;p&gt;A video is not finished when the encoder exits successfully.&lt;/p&gt;

&lt;p&gt;For the final result, I verified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duration: &lt;strong&gt;15.000 seconds&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;resolution: &lt;strong&gt;1906 × 1080&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;frame rate: &lt;strong&gt;29 fps&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;total frames: &lt;strong&gt;435&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;video codec: &lt;strong&gt;H.264&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;audio codec: &lt;strong&gt;AAC stereo&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;full decode: successful;&lt;/li&gt;
&lt;li&gt;the cut at 12 seconds;&lt;/li&gt;
&lt;li&gt;the fade between 14.3 and 15 seconds;&lt;/li&gt;
&lt;li&gt;no embedded audio leaking from the ending clip.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basic metadata inspection can be automated with &lt;code&gt;ffprobe&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-show_entries&lt;/span&gt; &lt;span class="nv"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;duration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-show_entries&lt;/span&gt; &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;index,codec_name,width,height,r_frame_rate,channels &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-of&lt;/span&gt; json output.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also recommend decoding the complete output once instead of trusting container metadata alone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="nt"&gt;-i&lt;/span&gt; output.mp4 &lt;span class="nt"&gt;-f&lt;/span&gt; null -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That catches broken frames and stream errors that a successful export message may miss.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this can be cheaper than generation-only production
&lt;/h2&gt;

&lt;p&gt;This workflow does not replace generative video. It changes where generation is used.&lt;/p&gt;

&lt;p&gt;Generation is excellent when a story requires a shot that does not exist. But when usable footage already exists, repeatedly generating near-duplicates is often a poor use of time and credits.&lt;/p&gt;

&lt;p&gt;A hybrid pipeline can be more efficient:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;reuse authorized footage where it already works;&lt;/li&gt;
&lt;li&gt;analyze and restructure it;&lt;/li&gt;
&lt;li&gt;generate only the missing shots;&lt;/li&gt;
&lt;li&gt;import those shots as editable source media;&lt;/li&gt;
&lt;li&gt;validate the finished sequence as one coherent piece.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The scarce skill is gradually moving from “Can I generate an image?” to “Can I select, structure, pace, and finish a story?”&lt;/p&gt;

&lt;h2&gt;
  
  
  A necessary note about copyright
&lt;/h2&gt;

&lt;p&gt;“Remix” does not mean downloading and reposting somebody else’s work.&lt;/p&gt;

&lt;p&gt;Use footage that you created, generated, licensed, purchased, or received permission to modify. Check whether the license permits derivatives and commercial use. Keep provenance and watermarks when required, and verify music, likeness, and brand rights separately.&lt;/p&gt;

&lt;p&gt;Good second creation adds a new structure, viewpoint, explanation, or experience. Removing a watermark and uploading the same content is not a creative workflow—and may violate both rights and platform policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Timeline Studio
&lt;/h2&gt;

&lt;p&gt;Timeline Studio is my attempt to connect local media analysis, browser-based editing, and deterministic rendering in one workflow.&lt;/p&gt;

&lt;p&gt;The project is useful for experiments involving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;content-aware highlight extraction;&lt;/li&gt;
&lt;li&gt;short-form montage generation;&lt;/li&gt;
&lt;li&gt;music highlight selection;&lt;/li&gt;
&lt;li&gt;editable transitions and effects;&lt;/li&gt;
&lt;li&gt;caption and voice workflows;&lt;/li&gt;
&lt;li&gt;AI-generated footage as source media;&lt;/li&gt;
&lt;li&gt;local-first media processing;&lt;/li&gt;
&lt;li&gt;reusable &lt;code&gt;.timeline&lt;/code&gt; projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this direction is useful to you, take a look at the repository:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Issues, feedback, and contributions are welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thought
&lt;/h2&gt;

&lt;p&gt;AI video generation lowers the cost of producing footage, but more footage does not automatically create better stories.&lt;/p&gt;

&lt;p&gt;Generation determines what material is available. Editing determines what the audience experiences.&lt;/p&gt;

&lt;p&gt;For independent creators, the sustainable advantage may not be generating everything from zero. It may be building a repeatable system that knows what to keep, what to cut, when to peak, and how to end.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>AI Video Editing Should Be More Than Auto-Cutting: Teaching an Agent Professional Post-Production</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Wed, 19 Aug 2026 08:02:37 +0000</pubDate>
      <link>https://dev.to/martindelophy/ai-video-editing-should-be-more-than-auto-cutting-teaching-an-agent-professional-post-production-4dke</link>
      <guid>https://dev.to/martindelophy/ai-video-editing-should-be-more-than-auto-cutting-teaching-an-agent-professional-post-production-4dke</guid>
      <description>&lt;p&gt;Most AI video editors can already select clips, remove silence, generate captions, add music, and cut on the beat.&lt;/p&gt;

&lt;p&gt;That sounds impressive—until you watch the result.&lt;/p&gt;

&lt;p&gt;The shots may be technically correct, but the edit often has no hierarchy. The pacing feels templated. Color jumps between cameras. Subject edges flicker. A product reveal passes too quickly. The editor preview looks right, but the exported file does not.&lt;/p&gt;

&lt;p&gt;The problem is not always the model.&lt;/p&gt;

&lt;p&gt;In many systems, the agent has learned how to &lt;strong&gt;operate editing controls&lt;/strong&gt;, but not how to &lt;strong&gt;reason like an editor, colorist, or compositor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We are building &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio&lt;/a&gt;, an open-source AI video editor focused on editable projects, local-first media workflows, and verifiable output.&lt;/p&gt;

&lt;p&gt;In our latest update, we expanded the Timeline Studio video-editing skill with professional guidance for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;source-time speed curves&lt;/li&gt;
&lt;li&gt;Color Wheels and shot matching&lt;/li&gt;
&lt;li&gt;person, product, and object cutouts&lt;/li&gt;
&lt;li&gt;subject-aware outlines&lt;/li&gt;
&lt;li&gt;effect ordering and export validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can inspect the exact update in &lt;a href="https://github.com/MartinDelophy/ai-video-editor/commit/df26d6460117c4c570b3cfb7ea320a3f91edca36" rel="noopener noreferrer"&gt;this commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The goal is simple: stop treating these capabilities as feature labels and start teaching the agent &lt;strong&gt;when to use them, why they matter, how to validate them, and when a result should be rejected&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap between an automatic edit and a professional edit
&lt;/h2&gt;

&lt;p&gt;Automatic editing usually answers questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which clips are relevant?&lt;/li&gt;
&lt;li&gt;Where are the silent sections?&lt;/li&gt;
&lt;li&gt;What captions should be generated?&lt;/li&gt;
&lt;li&gt;Where are the music beats?&lt;/li&gt;
&lt;li&gt;In what order should the shots appear?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Professional post-production adds a different layer of reasoning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where does an action actually begin?&lt;/li&gt;
&lt;li&gt;Which frame contains the clearest consequence?&lt;/li&gt;
&lt;li&gt;Should the approach be accelerated while the result stays readable?&lt;/li&gt;
&lt;li&gt;Why do two adjacent shots feel visually disconnected?&lt;/li&gt;
&lt;li&gt;Is a detected bounding box good enough for compositing?&lt;/li&gt;
&lt;li&gt;Should the background be removed, or should the subject be emphasized while preserving context?&lt;/li&gt;
&lt;li&gt;Did the final export retain the timing, grade, matte, and edge treatment seen in the editor?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not minor details. They determine whether a video feels intentionally directed or mechanically assembled.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Speed curves should follow the action, not a template
&lt;/h2&gt;

&lt;p&gt;A common automated speed ramp looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1x -&amp;gt; 2x -&amp;gt; 0.5x -&amp;gt; 1x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It creates motion, but it does not necessarily create meaning.&lt;/p&gt;

&lt;p&gt;A useful speed curve begins with the source-time structure of the shot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;action onset
-&amp;gt; anticipation
-&amp;gt; approach
-&amp;gt; contact or reveal
-&amp;gt; readable result
-&amp;gt; release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only after identifying those anchors should the agent change timing.&lt;/p&gt;

&lt;p&gt;For a product reveal, a motivated curve might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;normal speed
-&amp;gt; compress low-information travel
-&amp;gt; slow at the first unobstructed product frame
-&amp;gt; hold the hero result
-&amp;gt; return to normal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a software tutorial, the agent can accelerate cursor travel and waiting time, but it should return to normal speed before the click, state change, number, or result the viewer must understand.&lt;/p&gt;

&lt;p&gt;The skill also defines rejection conditions. A speed curve should fail review if it causes unreadable action, damaged dialogue, repeated boundary frames, visible stutter, broken audio continuity, or a weaker payoff than the original shot.&lt;/p&gt;

&lt;p&gt;The key principle is to preserve source-time reasoning even after the clip is retimed.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Color matching comes before a “cinematic” look
&lt;/h2&gt;

&lt;p&gt;Applying the same LUT or filter to every clip does not make a sequence consistent.&lt;/p&gt;

&lt;p&gt;Two shots can share the same preset and still disagree in white balance, exposure, black level, highlight color, skin tone, product color, saturation, and contrast.&lt;/p&gt;

&lt;p&gt;The updated skill uses a disciplined Color Wheels workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inspect representative native frames.&lt;/li&gt;
&lt;li&gt;Correct temperature and tint.&lt;/li&gt;
&lt;li&gt;Establish global exposure and luminance.&lt;/li&gt;
&lt;li&gt;Shape shadows, midtones, and highlights independently.&lt;/li&gt;
&lt;li&gt;Adjust saturation last.&lt;/li&gt;
&lt;li&gt;Compare adjacent shots at the actual cut boundary.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Timeline Studio exposes controls for Shadows, Midtones, Highlights, Global Offset, Temperature, Tint, and Saturation.&lt;/p&gt;

&lt;p&gt;For portraits, the agent must preserve plausible skin, lips, teeth, eyes, and hair.&lt;/p&gt;

&lt;p&gt;For product shots, it must protect packaging, logos, materials, and brand colors. The background can move toward a complementary palette; the product itself should not be recolored merely to create a dramatic grade.&lt;/p&gt;

&lt;p&gt;Color parameters can be keyframed, but static correction remains the default. Animated grading should only be used when lighting or narrative intent genuinely changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Detection is not the same as a usable cutout
&lt;/h2&gt;

&lt;p&gt;Modern vision models can detect a person or product quickly. But a bounding box is only a region proposal.&lt;/p&gt;

&lt;p&gt;A production-ready cutout requires a stable alpha matte.&lt;/p&gt;

&lt;p&gt;For people, the agent needs to inspect hair, fingers, gaps between limbs, semi-transparent fabric, motion blur, held objects, occlusion, and re-entry.&lt;/p&gt;

&lt;p&gt;For products and objects, it needs to preserve handles, straps, holes, thin structures, transparent packaging, reflective edges, labels, logos, and the correct instance when similar objects appear.&lt;/p&gt;

&lt;p&gt;The workflow separates three stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;detect the target
-&amp;gt; generate the silhouette matte
-&amp;gt; validate temporal stability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For video, validation cannot stop at the first frame. The matte should be checked at fast-motion intervals, occlusions, shot boundaries, exits, re-entries, and the final frame.&lt;/p&gt;

&lt;p&gt;The result should be rejected if it shows target switching, missing body or product parts, edge chatter, stale masks, lag, or simplified geometry that damages the subject.&lt;/p&gt;

&lt;p&gt;Only after the raw matte passes review should the agent add a new background, depth, shadow, glow, or outline.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Outlines can preserve context while directing attention
&lt;/h2&gt;

&lt;p&gt;Removing the background is not always the right choice.&lt;/p&gt;

&lt;p&gt;In tutorials, interviews, product demonstrations, and documentary footage, the environment may contain information the viewer needs. A restrained subject outline can improve attention without destroying context.&lt;/p&gt;

&lt;p&gt;A simple routing rule works well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Need a new environment or foreground/background layering?
Use a cutout.

Need to preserve the environment but improve subject acquisition?
Use an outline.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful outline scenarios include presenter emphasis, product callouts, freeze-frame introductions, before/after comparisons, transitions between live footage and graphics, and small-screen attention guidance.&lt;/p&gt;

&lt;p&gt;The outline must be derived from a verified alpha matte—not from a detection rectangle.&lt;/p&gt;

&lt;p&gt;Its width, opacity, softness, glow, and shadow should be judged at the actual delivery size. An outline that looks subtle in a zoomed desktop preview may become overpowering on a phone, or disappear completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Professionalism comes from effect orchestration
&lt;/h2&gt;

&lt;p&gt;Adding more effects does not automatically create a better video.&lt;/p&gt;

&lt;p&gt;An agent with access to cutouts, outlines, depth, parallax, glow, Color Wheels, and speed ramps can easily over-process a shot unless every layer has an editorial job.&lt;/p&gt;

&lt;p&gt;A product hero shot might follow this order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;technical color match
-&amp;gt; product matte validation
-&amp;gt; background composition
-&amp;gt; restrained shadow or outline
-&amp;gt; motivated speed curve around the reveal
-&amp;gt; readable result hold
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A presenter shot may need much less:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;person cutout
-&amp;gt; supporting graphics behind the presenter
-&amp;gt; subtle outline only where contrast requires it
-&amp;gt; normal speed during speech
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before adding an effect, the agent should be able to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does it separate the subject?&lt;/li&gt;
&lt;li&gt;Does it clarify evidence?&lt;/li&gt;
&lt;li&gt;Does it improve rhythm?&lt;/li&gt;
&lt;li&gt;Does it support a narrative transition?&lt;/li&gt;
&lt;li&gt;Does it preserve the decisive frame?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the effect has no clear function, it should not be added.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The exported video—not the editor state—is the deliverable
&lt;/h2&gt;

&lt;p&gt;A correct editor preview does not guarantee a correct export.&lt;/p&gt;

&lt;p&gt;Complex projects can lose or alter grading state, alpha masks, edge treatment, time mapping, keyframe interpolation, or effect ordering.&lt;/p&gt;

&lt;p&gt;The delivery workflow is therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;preserve the editable project
-&amp;gt; preview the complete timeline
-&amp;gt; export the video
-&amp;gt; decode the exported file
-&amp;gt; compare matching timestamps
-&amp;gt; verify color, alpha, edges, and timing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent should retain the editable &lt;code&gt;.timeline&lt;/code&gt; project and verify the actual media file instead of trusting a success notification.&lt;/p&gt;

&lt;p&gt;There is also an important implementation boundary: advanced Color Wheels, speed curves, vision-derived masks, and subject effects currently belong to the editor/browser execution path. The headless renderer does not yet provide full parity for these features.&lt;/p&gt;

&lt;p&gt;We document that limitation instead of pretending every rendering path behaves identically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why encode this knowledge in a skill?
&lt;/h2&gt;

&lt;p&gt;A capable model can understand video concepts, but repeatable production work still benefits from explicit operational guidance.&lt;/p&gt;

&lt;p&gt;The skill provides routing rules, execution order, source-time reasoning, validation criteria, rejection conditions, current capability boundaries, and editable-project requirements.&lt;/p&gt;

&lt;p&gt;This turns “the editor supports Color Wheels” into something much more useful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Match adjacent shots, protect identity-bearing colors, compare the real cut boundary, reject clipped or unstable results, and verify the export.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same principle applies to speed curves, cutouts, and outlines.&lt;/p&gt;

&lt;p&gt;Features become professional capabilities only when the agent knows how to reason about them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;Automatic trimming, captions, music matching, and beat cuts are rapidly becoming baseline features.&lt;/p&gt;

&lt;p&gt;The next generation of AI video tools will compete on deeper questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can the agent understand the visual consequence of an action?&lt;/li&gt;
&lt;li&gt;Can it build a real hierarchy of setup, rise, peak, and release?&lt;/li&gt;
&lt;li&gt;Can it preserve skin, products, and brand identity during grading?&lt;/li&gt;
&lt;li&gt;Can it produce temporally stable subject masks?&lt;/li&gt;
&lt;li&gt;Can it choose the smallest justified visual treatment?&lt;/li&gt;
&lt;li&gt;Can it validate the final render?&lt;/li&gt;
&lt;li&gt;Can it leave behind a project a human editor can continue modifying?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the direction we are exploring with Timeline Studio.&lt;/p&gt;

&lt;p&gt;If you are working on AI agents, browser-local ML, automated editing, media pipelines, or editable video formats, take a look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor/commit/df26d6460117c4c570b3cfb7ea320a3f91edca36" rel="noopener noreferrer"&gt;The professional post-production skill update&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback, issues, and stars are welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>machinelearning</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Connected Codex for Chrome to an Open-Source Video Editing Skill—Here’s What Changed</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Mon, 17 Aug 2026 10:06:20 +0000</pubDate>
      <link>https://dev.to/martindelophy/i-connected-codex-for-chrome-to-an-open-source-video-editing-skill-heres-what-changed-38ac</link>
      <guid>https://dev.to/martindelophy/i-connected-codex-for-chrome-to-an-open-source-video-editing-skill-heres-what-changed-38ac</guid>
      <description>&lt;p&gt;AI can already write scripts, generate images, synthesize voices, and summarize videos. Yet real video production still feels fragmented.&lt;/p&gt;

&lt;p&gt;You watch a reference on YouTube. You open a product website in another tab. You copy timestamps into notes, download authorized assets, write narration, generate voice clips, and then rebuild all of that context inside an editor.&lt;/p&gt;

&lt;p&gt;Every step may contain AI, but the steps do not share a working memory.&lt;/p&gt;

&lt;p&gt;That is why the new &lt;a href="https://learn.chatgpt.com/docs/chrome-extension" rel="noopener noreferrer"&gt;Codex Chrome extension&lt;/a&gt; caught my attention. When combined with an editing-specific agent skill and an editor built around portable timelines, it creates something more useful than another “generate video” button:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A browser-aware agent that can turn researched context into an editable video project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have been exploring this workflow with &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio&lt;/a&gt;, an open-source, local-first browser video editor, and its &lt;code&gt;edit-timeline-studio&lt;/code&gt; agent skill.&lt;/p&gt;

&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%2Fg8yvsav37hv955vfd8dj.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%2Fg8yvsav37hv955vfd8dj.png" alt="Timeline Studio multi-track editor" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The missing link was not generation
&lt;/h2&gt;

&lt;p&gt;Most AI video conversations focus on generation quality: longer clips, better motion, more consistent characters, or faster inference.&lt;/p&gt;

&lt;p&gt;Those improvements matter, but editing is a different problem.&lt;/p&gt;

&lt;p&gt;A real edit contains hundreds of decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which source moments should survive?&lt;/li&gt;
&lt;li&gt;Where should a spoken phrase end?&lt;/li&gt;
&lt;li&gt;Is a repeated shot building anticipation or just wasting time?&lt;/li&gt;
&lt;li&gt;Does the subject stay readable after reframing?&lt;/li&gt;
&lt;li&gt;Is every visible caption backed by audible speech?&lt;/li&gt;
&lt;li&gt;Should picture timing follow the narration, or should narration be rushed to fit a predetermined cut?&lt;/li&gt;
&lt;li&gt;Can a human revise the result without starting again?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An agent that only clicks an editor is a faster mouse. An agent that only understands a webpage is a better researcher. The interesting system appears when browser context, editorial reasoning, and a real project model are connected.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Codex for Chrome changes
&lt;/h2&gt;

&lt;p&gt;OpenAI introduced Codex for Chrome on May 7, 2026. Later browser updates added several capabilities that are unusually relevant to content workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;referencing open Chrome tabs;&lt;/li&gt;
&lt;li&gt;bringing highlighted page text into a conversation;&lt;/li&gt;
&lt;li&gt;opening Ask ChatGPT from a page's context menu;&lt;/li&gt;
&lt;li&gt;using timestamped transcripts when captions are available on YouTube;&lt;/li&gt;
&lt;li&gt;working with sites where the user is already signed in;&lt;/li&gt;
&lt;li&gt;inspecting DOM, styles, console output, network traffic, and performance through Developer Mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important change is not simply that an agent can open a URL. It can work with the browser environment in which research is already happening.&lt;/p&gt;

&lt;p&gt;Open a reference video and the transcript can become structured evidence. Open a product website and the agent can verify which capabilities are actually visible. Open an authorized asset source and the agent can organize candidates without repeatedly asking the user to copy page context into chat.&lt;/p&gt;

&lt;p&gt;Browser understanding is the perception layer. It still needs an editing layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  An editing skill, not a mega-prompt
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://video-editor.ai-creator.top/" rel="noopener noreferrer"&gt;Timeline Studio&lt;/a&gt; is a local-first AI video editor that runs in the browser. It combines a multi-track timeline with captions, voiceovers, music, visual effects, transitions, and offline export.&lt;/p&gt;

&lt;p&gt;The repository also ships an agent skill named &lt;code&gt;edit-timeline-studio&lt;/code&gt;. The skill is not a single prompt that says “make this cinematic.” It defines how an agent should inspect, plan, execute, and verify an edit.&lt;/p&gt;

&lt;p&gt;Among other things, it requires an agent to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspect duration, dimensions, media type, and audio before editing;&lt;/li&gt;
&lt;li&gt;analyze representative frames, speech, OCR, motion, and subject regions;&lt;/li&gt;
&lt;li&gt;classify the job as a talking-head cleanup, tutorial, highlight reel, multi-speaker edit, promotion, or reference reconstruction;&lt;/li&gt;
&lt;li&gt;record keep, remove, shorten, and reorder decisions against source time;&lt;/li&gt;
&lt;li&gt;build narration from short physical voice assets and lock the audio spine before timing the picture;&lt;/li&gt;
&lt;li&gt;verify captions against audible speech;&lt;/li&gt;
&lt;li&gt;inspect boundaries, transitions, audio behavior, and the final decoded render;&lt;/li&gt;
&lt;li&gt;deliver both a rendered video and a reopenable &lt;code&gt;.timeline&lt;/code&gt; project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The editable project remains the source of truth. The render is an output, not the only artifact.&lt;/p&gt;

&lt;h2&gt;
  
  
  A three-layer video agent
&lt;/h2&gt;

&lt;p&gt;The combined architecture is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Codex Chrome extension
  authorized tabs, signed-in pages, selected text, timestamped transcripts
                              ↓
edit-timeline-studio skill
  evidence analysis, narrative planning, edit decisions, execution, validation
                              ↓
Timeline Studio
  tracks, clips, captions, voiceovers, music, effects, .timeline project, render
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer has a distinct responsibility.&lt;/p&gt;

&lt;p&gt;Chrome answers: &lt;strong&gt;What is happening in the user's web context?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The skill answers: &lt;strong&gt;What editorial decisions should be made, and how should they be verified?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Timeline Studio answers: &lt;strong&gt;Where do those decisions live so that a human can continue editing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This separation matters. It prevents browser automation from being mistaken for editorial judgment, and it prevents AI output from collapsing into an opaque one-shot render.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow 1: reconstruct why a reference video works
&lt;/h2&gt;

&lt;p&gt;Asking an AI to “summarize this video” rarely produces an actionable edit plan. A serious reference reconstruction needs to identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;shot and sub-shot boundaries;&lt;/li&gt;
&lt;li&gt;repeated source families;&lt;/li&gt;
&lt;li&gt;speed ramps, holds, and reversals;&lt;/li&gt;
&lt;li&gt;transition anatomy;&lt;/li&gt;
&lt;li&gt;subject center, scale, and movement path;&lt;/li&gt;
&lt;li&gt;changes in look or filter state;&lt;/li&gt;
&lt;li&gt;the relationship between retained audio, narration, captions, and picture;&lt;/li&gt;
&lt;li&gt;setup, rise, pre-impact, peak, aftershock, and bridge beats.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the reference open in Chrome, the agent can use the available transcript and page context as one evidence lane. Local analysis can then inspect the actual media for timing, motion, composition, and audio.&lt;/p&gt;

&lt;p&gt;A task can begin like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Chrome analyze the reference video in my current tab and use its timestamped
transcript when available. Identify the narrative sections and verified page
context.

Then use the edit-timeline-studio skill to reconstruct the shot order,
repetitions, speed changes, transitions, subject movement, and tension curve.
Use only media I provide or media with an explicit platform-provided download
and suitable reuse rights. Deliver an editable .timeline project and a verified
render. Mark anything that cannot be established from evidence.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is no longer just an explanation of the video. It is an explanation expressed as an editable timeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow 2: turn a product website into a narrative, not a feature reel
&lt;/h2&gt;

&lt;p&gt;Many AI-generated product videos are feature lists with animated typography. Motion is present, but no transformation occurs.&lt;/p&gt;

&lt;p&gt;A better promotional structure gives each example a complete loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;context → friction → product action → visible result → consequence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Chrome extension can help an agent inspect an authorized product journey across the homepage, feature pages, documentation, and the actual interface. The agent can build a coverage manifest and distinguish verified behavior from marketing claims.&lt;/p&gt;

&lt;p&gt;The editing skill can then organize multiple visually distinct examples into a larger arc:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;problem → transformation → proof → payoff → call to action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Narration is created as short breath-group assets first. Captions and picture timing are derived from the accepted speech sequence, rather than globally speeding up a voice to hit an arbitrary runtime.&lt;/p&gt;

&lt;p&gt;This is especially useful for open-source projects. A README tells people what a project contains. A narrative video can show which part of someone's workflow actually changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow 3: close the loop between editor development and visual QA
&lt;/h2&gt;

&lt;p&gt;The Chrome integration is also useful while building Timeline Studio itself.&lt;/p&gt;

&lt;p&gt;With Developer Mode, Codex can inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOM and applied styles after timeline interactions;&lt;/li&gt;
&lt;li&gt;WebGPU or ONNX Runtime initialization failures;&lt;/li&gt;
&lt;li&gt;worker messages, model requests, and caching behavior;&lt;/li&gt;
&lt;li&gt;runtime errors in the console;&lt;/li&gt;
&lt;li&gt;responsive inspector layouts;&lt;/li&gt;
&lt;li&gt;performance problems during preview or export.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the same time, Codex can work with the local repository and terminal. That creates a tight loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;observe the rendered problem
→ inspect runtime evidence
→ locate the implementation
→ make a scoped change
→ reopen and verify the UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a browser application that combines a multi-track timeline, media decoding, WebGPU inference, workers, and offline rendering, that shared loop is much more useful than debugging from a screenshot alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two execution paths instead of pretending every click is deterministic
&lt;/h2&gt;

&lt;p&gt;Timeline Studio uses two automation paths.&lt;/p&gt;

&lt;p&gt;The versioned command runner directly inspects and modifies portable &lt;code&gt;.timeline&lt;/code&gt; archives. It supports semantic diffs and transactional operations for the commands it registers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run agent &lt;span class="nt"&gt;--&lt;/span&gt; project.inspect /projects/demo.timeline
npm run agent &lt;span class="nt"&gt;--&lt;/span&gt; project.diff /projects/edit-plan.json
npm run agent &lt;span class="nt"&gt;--&lt;/span&gt; project.run /projects/edit-plan.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser path handles AI generation, visual preview, rich rendering, effects, and operations that are not yet available through the command contract.&lt;/p&gt;

&lt;p&gt;The distinction is deliberate: deterministic project operations belong in the command layer; visual or UI-only operations belong in the browser layer and require visible verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the editable project matters
&lt;/h2&gt;

&lt;p&gt;If an AI video tool returns only an MP4, every correction becomes a regeneration problem.&lt;/p&gt;

&lt;p&gt;Timeline Studio treats &lt;code&gt;.timeline&lt;/code&gt; as a portable project archive containing project structure and media. After the agent finishes, a human can still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;adjust a cut;&lt;/li&gt;
&lt;li&gt;replace one voice segment;&lt;/li&gt;
&lt;li&gt;move a caption;&lt;/li&gt;
&lt;li&gt;change music;&lt;/li&gt;
&lt;li&gt;revise a transition;&lt;/li&gt;
&lt;li&gt;replace media and export again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI should remove repetitive setup work without removing authorship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Powerful browser access needs narrow boundaries
&lt;/h2&gt;

&lt;p&gt;Browser-aware agents also create real security and rights-management questions. A practical workflow should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;grant site access per task or domain rather than allowing every site by default;&lt;/li&gt;
&lt;li&gt;enter credentials only in the browser, never in chat;&lt;/li&gt;
&lt;li&gt;treat page content as untrusted input;&lt;/li&gt;
&lt;li&gt;use web footage only through publisher- or platform-provided downloads with suitable item-level rights;&lt;/li&gt;
&lt;li&gt;preserve watermarks and provenance;&lt;/li&gt;
&lt;li&gt;require human confirmation for publishing, paid generation, permission changes, or deletion;&lt;/li&gt;
&lt;li&gt;keep media processing local when the capability supports it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The browser is a powerful perception and action surface. It should not become an invisible permission bypass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live editor:&lt;/strong&gt; &lt;a href="https://video-editor.ai-creator.top/" rel="noopener noreferrer"&gt;video-editor.ai-creator.top&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill directory:&lt;/strong&gt; &lt;a href="https://skills.sh/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;skills.sh/MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install the skill through skills.sh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add MartinDelophy/ai-video-editor &lt;span class="nt"&gt;--skill&lt;/span&gt; edit-timeline-studio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or install it for Codex with GitHub CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh skill &lt;span class="nb"&gt;install &lt;/span&gt;MartinDelophy/ai-video-editor edit-timeline-studio &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--agent&lt;/span&gt; codex &lt;span class="nt"&gt;--scope&lt;/span&gt; user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The next step is not a bigger Generate button
&lt;/h2&gt;

&lt;p&gt;The next generation of AI editing will not be defined only by faster models or longer generated clips.&lt;/p&gt;

&lt;p&gt;It will also depend on whether an agent can enter the creator's real information environment, understand why material matters, make explainable editorial decisions, validate the result, and leave those decisions on a timeline that a human still controls.&lt;/p&gt;

&lt;p&gt;Codex for Chrome gives the agent browser context. The Timeline Studio skill provides an editing discipline. Timeline Studio turns those decisions into a portable project.&lt;/p&gt;

&lt;p&gt;That combination is the interesting part: not AI replacing the timeline, but AI finally learning how to work inside one.&lt;/p&gt;

&lt;p&gt;If you are interested in browser media, WebCodecs, WebGPU, ONNX Runtime, agent skills, or editable AI workflows, I would love your feedback and contributions on &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/chrome-extension" rel="noopener noreferrer"&gt;OpenAI: Chrome extension documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.chatgpt.com/docs/changelog" rel="noopener noreferrer"&gt;OpenAI: ChatGPT &amp;amp; Codex changelog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Building a Safe Video-Editing Agent for DeepSeek Harness</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Sat, 15 Aug 2026 09:34:03 +0000</pubDate>
      <link>https://dev.to/martindelophy/building-a-safe-video-editing-agent-for-deepseek-harness-2n1a</link>
      <guid>https://dev.to/martindelophy/building-a-safe-video-editing-agent-for-deepseek-harness-2n1a</guid>
      <description>&lt;p&gt;Large language models can explain how a video &lt;em&gt;should&lt;/em&gt; be edited. But safely editing a real project is a different problem.&lt;/p&gt;

&lt;p&gt;If you ask an agent to “convert this project to 9:16, keep the captions, save a copy, and render an MP4,” the hard part is not understanding the sentence. The hard part is making sure the agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;selects the correct project, track, and clips;&lt;/li&gt;
&lt;li&gt;does not overwrite the original;&lt;/li&gt;
&lt;li&gt;does not execute the same operation twice after a retry;&lt;/li&gt;
&lt;li&gt;does not write from a stale project revision;&lt;/li&gt;
&lt;li&gt;cannot read or write outside the approved workspace;&lt;/li&gt;
&lt;li&gt;and verifies that the rendered video actually exists and is valid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To explore this problem, I built and open-sourced &lt;strong&gt;dsh-timeline-studio-plugin&lt;/strong&gt;, a community plugin that connects DeepSeek Harness to Timeline Studio’s deterministic &lt;code&gt;.timeline&lt;/code&gt; command layer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugin: &lt;a href="https://github.com/MartinDelophy/dsh-timeline-studio-plugin" rel="noopener noreferrer"&gt;MartinDelophy/dsh-timeline-studio-plugin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Editor: &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This is a community integration for Timeline Studio. It is not part of DeepSeek Harness core and is not an official DeepSeek project.&lt;/p&gt;
&lt;/blockquote&gt;

&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%2Fraw.githubusercontent.com%2FMartinDelophy%2Fdsh-timeline-studio-plugin%2Fmain%2Fdocs%2Fimages%2Fplayer-flow.svg" 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%2Fraw.githubusercontent.com%2FMartinDelophy%2Fdsh-timeline-studio-plugin%2Fmain%2Fdocs%2Fimages%2Fplayer-flow.svg" alt="From a natural-language request to an editable Timeline Studio project" width="1600" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the plugin does
&lt;/h2&gt;

&lt;p&gt;The plugin is not another video editor UI. It is an automation bridge between an agent and the editor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timeline Studio&lt;/strong&gt; remains responsible for the visual timeline, media processing, browser-local AI features, preview, and the final creative experience. &lt;strong&gt;dsh-timeline-studio-plugin&lt;/strong&gt; exposes a small, deterministic tool surface that DeepSeek Harness can call.&lt;/p&gt;

&lt;p&gt;The workflow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Natural-language request
  ↓
DeepSeek Harness
  ↓
Read-only project inspection
  ↓
Structured edit plan
  ↓
Semantic diff
  ↓
Transactional apply to a new .timeline project
  ↓
Render and validate MP4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model decides &lt;em&gt;what should happen&lt;/em&gt;. The command layer decides whether that operation is allowed and valid for the current project state.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the user sees
&lt;/h2&gt;

&lt;p&gt;The user first adds a local workspace containing a &lt;code&gt;.timeline&lt;/code&gt; project and its media assets.&lt;/p&gt;

&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%2F70e9425mk7i8zf56go6u.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%2F70e9425mk7i8zf56go6u.png" alt="DeepSeek Harness workspace screen" width="799" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A safe first prompt is deliberately read-only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inspect the Timeline Studio project in this workspace. Tell me its duration, aspect ratio, tracks, and media. Do not modify any files yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After reviewing the result, the user can continue with an editing request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Change the project to 9:16. Show me the planned diff first. If it is valid, save it as a new project without overwriting the original, then render an MP4.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The plugin has no separate visual panel. Its work appears in Harness tool calls and in the resulting &lt;code&gt;.timeline&lt;/code&gt; and MP4 files. Rich visual inspection and manual refinement still happen in Timeline Studio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seven tools, three responsibilities
&lt;/h2&gt;

&lt;p&gt;The first version exposes seven model tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeline_studio_project_inspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inspect revision, duration, ratio, tracks, media inventory, and warnings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeline_studio_track_inspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;List clips on a track in timeline order&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeline_studio_clip_inspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inspect source mapping, timing, transforms, and relationships&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeline_studio_transcript_inspect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Inspect captions, word timing, speakers, and audio links&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeline_studio_project_diff&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Validate an edit plan against the real command registry without writing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeline_studio_project_apply&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Apply a validated plan transactionally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;timeline_studio_project_render&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Render and validate an H.264/AAC MP4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&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%2Fraw.githubusercontent.com%2FMartinDelophy%2Fdsh-timeline-studio-plugin%2Fmain%2Fdocs%2Fimages%2Fcapabilities.svg" 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%2Fraw.githubusercontent.com%2FMartinDelophy%2Fdsh-timeline-studio-plugin%2Fmain%2Fdocs%2Fimages%2Fcapabilities.svg" alt="Three capability groups: understand, edit safely, and deliver" width="1600" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the agent does not rewrite project JSON directly
&lt;/h2&gt;

&lt;p&gt;The shortest implementation would be to send the entire project JSON to the model and ask it to return a modified copy.&lt;/p&gt;

&lt;p&gt;That is also the least reliable approach.&lt;/p&gt;

&lt;p&gt;Syntactically valid JSON can still be semantically invalid for the editor. The model might reference a deleted clip, place media on the wrong track, invent an unsupported property, or repeat an operation that was already committed.&lt;/p&gt;

&lt;p&gt;Instead, the agent produces a structured edit plan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schemaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/projects/input.timeline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"baseRevision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dryRun"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"set-ratio-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"project.set_ratio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9:16"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"project"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/projects/output.timeline"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plan is checked against Timeline Studio’s real command registry before it is allowed to write anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diff before apply
&lt;/h2&gt;

&lt;p&gt;Every edit goes through two distinct stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;timeline_studio_project_diff
  ↓ only after a successful diff
timeline_studio_project_apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The diff stage does not write the output project. It checks questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does the command exist?&lt;/li&gt;
&lt;li&gt;Are the arguments valid?&lt;/li&gt;
&lt;li&gt;Does the target clip still exist?&lt;/li&gt;
&lt;li&gt;Does &lt;code&gt;baseRevision&lt;/code&gt; match the current project?&lt;/li&gt;
&lt;li&gt;Has the operation ID already been used?&lt;/li&gt;
&lt;li&gt;Do all input and output paths stay inside the approved roots?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A wrong chat response can be regenerated. A wrong local write can damage a user’s project. That is why the preview step is a required safety gate rather than an optional UX enhancement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making retries safe with revisions and operation IDs
&lt;/h2&gt;

&lt;p&gt;Agent tool calls can be retried because of cancellations, process failures, network interruptions, or replanning.&lt;/p&gt;

&lt;p&gt;The plugin uses two mechanisms to make those retries predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project revision
&lt;/h3&gt;

&lt;p&gt;Inspection returns the current revision. The edit plan must include it as &lt;code&gt;baseRevision&lt;/code&gt;. If the project has changed since inspection, a new write based on the stale revision is rejected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Idempotent operation ID
&lt;/h3&gt;

&lt;p&gt;Every operation has a stable ID. Resubmitting an ID that has already been applied becomes a no-op instead of adding the same clip or modification twice.&lt;/p&gt;

&lt;p&gt;Together, these checks provide optimistic concurrency control and idempotent execution for agent-driven edits.&lt;/p&gt;

&lt;h2&gt;
  
  
  File access boundaries belong in code, not prompts
&lt;/h2&gt;

&lt;p&gt;Video editing requires access to project files, source media, and render outputs. A system prompt saying “do not leave the workspace” is not a security boundary.&lt;/p&gt;

&lt;p&gt;The plugin requires explicit &lt;code&gt;allowedRoots&lt;/code&gt; configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dsh-timeline-studio-plugin'&lt;/span&gt;
  &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;timelineStudioRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/absolute/path/web_player&lt;/span&gt;
    &lt;span class="na"&gt;allowedRoots&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/absolute/path/projects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Projects, plans, imported media, and output files must all resolve inside those roots. The implementation also blocks symbolic-link escapes.&lt;/p&gt;

&lt;p&gt;This is a general rule I find useful for agent tooling: &lt;strong&gt;if a restriction can be enforced deterministically, enforce it in code instead of asking the model to remember it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;The currently verified environment is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DeepSeek Harness &lt;code&gt;0.1.0-rc.6&lt;/code&gt; Developer Preview&lt;/li&gt;
&lt;li&gt;Node.js &lt;code&gt;22.20+&lt;/code&gt; or &lt;code&gt;24+&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a local Timeline Studio repository with dependencies installed&lt;/li&gt;
&lt;li&gt;FFmpeg and ffprobe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install the GitHub repository as a DSH Web-profile bundle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dsh plugin &lt;span class="nt"&gt;--profile&lt;/span&gt; web add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"github:MartinDelophy/dsh-timeline-studio-plugin#main"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then start Harness with absolute paths for Timeline Studio and the project workspace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TIMELINE_STUDIO_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/absolute/path/web_player &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;TIMELINE_PROJECTS_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/absolute/path/projects &lt;span class="se"&gt;\&lt;/span&gt;
dsh &lt;span class="nt"&gt;--profile&lt;/span&gt; web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bundle stays disabled when &lt;code&gt;TIMELINE_STUDIO_ROOT&lt;/code&gt; is missing, so an incomplete installation does not break an existing Harness profile.&lt;/p&gt;

&lt;p&gt;After restarting, open &lt;strong&gt;Settings → Plugins → Plugin list&lt;/strong&gt; and search for &lt;code&gt;timeline&lt;/code&gt;.&lt;/p&gt;

&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%2F6dd5s1knn5y6v93mjj19.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%2F6dd5s1knn5y6v93mjj19.png" alt="Timeline Studio plugin enabled and mounted in DeepSeek Harness" width="800" height="690"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the configuration is enabled and the Cordis status is mounted, the plugin is ready. Users do not call the mount identifier manually; they simply describe the editing task in a Harness conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was tested end to end
&lt;/h2&gt;

&lt;p&gt;Registering tools is not enough. The project also exercises the real DeepSeek Harness and Cordis pipeline.&lt;/p&gt;

&lt;p&gt;The verified path covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DSH bundle installation;&lt;/li&gt;
&lt;li&gt;automatic Cordis mounting;&lt;/li&gt;
&lt;li&gt;registration of all seven tools;&lt;/li&gt;
&lt;li&gt;inspection of a real &lt;code&gt;.timeline&lt;/code&gt; project;&lt;/li&gt;
&lt;li&gt;confirmation that diff performs no project write;&lt;/li&gt;
&lt;li&gt;revision and idempotency checks during apply;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;allowedRoots&lt;/code&gt; and symbolic-link boundary enforcement;&lt;/li&gt;
&lt;li&gt;cancellation propagation to the Timeline Studio subprocess;&lt;/li&gt;
&lt;li&gt;reinspection of the generated project;&lt;/li&gt;
&lt;li&gt;MP4 rendering and output validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The local checks are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run check
&lt;span class="nv"&gt;TIMELINE_STUDIO_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/absolute/path/web_player npm run &lt;span class="nb"&gt;test&lt;/span&gt;:e2e
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DeepSeek Harness is still a Developer Preview, so breaking changes are possible. The plugin intentionally keeps the Harness adapter thin and leaves editing behavior in Timeline Studio. If the host interface changes, the integration layer can evolve without rewriting the editor’s command engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the editable project matters
&lt;/h2&gt;

&lt;p&gt;Many AI video systems return only a final render. That works for one-shot generation, but it makes small follow-up changes expensive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;extend a shot by half a second;&lt;/li&gt;
&lt;li&gt;correct one caption;&lt;/li&gt;
&lt;li&gt;lower the music;&lt;/li&gt;
&lt;li&gt;create a vertical variant;&lt;/li&gt;
&lt;li&gt;or reuse the same project for another campaign.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This workflow returns both the video and an editable &lt;code&gt;.timeline&lt;/code&gt; project. The agent can handle repetitive, structured, verifiable work, while the creator keeps control over the final cut.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;The interesting part of an agent that edits video is not just whether the model understands editing vocabulary. The real engineering questions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What can the agent access?&lt;/li&gt;
&lt;li&gt;Which project revision is it acting on?&lt;/li&gt;
&lt;li&gt;Was the operation already executed?&lt;/li&gt;
&lt;li&gt;Can the edit be previewed before writing?&lt;/li&gt;
&lt;li&gt;Can the result be validated afterward?&lt;/li&gt;
&lt;li&gt;Can a human continue editing the result?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;dsh-timeline-studio-plugin&lt;/code&gt; is an open-source attempt to answer those questions with a small deterministic tool layer around a real editor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/MartinDelophy/dsh-timeline-studio-plugin" rel="noopener noreferrer"&gt;dsh-timeline-studio-plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issues, feedback, and contributions are welcome.&lt;/p&gt;

</description>
      <category>aiai</category>
    </item>
    <item>
      <title>How Four Color Wheels Work in Video Editing—and How I Built Them in the Browser</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Wed, 12 Aug 2026 08:11:53 +0000</pubDate>
      <link>https://dev.to/martindelophy/how-four-color-wheels-work-in-video-editing-and-how-i-built-them-in-the-browser-2jfd</link>
      <guid>https://dev.to/martindelophy/how-four-color-wheels-work-in-video-editing-and-how-i-built-them-in-the-browser-2jfd</guid>
      <description>&lt;h2&gt;
  
  
  I built this in an open-source browser video editor
&lt;/h2&gt;

&lt;p&gt;I recently added a complete desktop color-wheels workflow to &lt;strong&gt;Timeline Studio&lt;/strong&gt;, an open-source, local-first video editor that runs in the browser.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live editor:&lt;/strong&gt; &lt;a href="https://video-editor.ai-creator.top" rel="noopener noreferrer"&gt;https://video-editor.ai-creator.top&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;separate wheels for shadows, midtones, highlights, and global offset;&lt;/li&gt;
&lt;li&gt;temperature, tint, and global saturation controls;&lt;/li&gt;
&lt;li&gt;hue, saturation, and luminance controls for every wheel;&lt;/li&gt;
&lt;li&gt;independent keyframes for all 15 grading properties;&lt;/li&gt;
&lt;li&gt;shortest-path hue interpolation;&lt;/li&gt;
&lt;li&gt;the same animated grade in preview, transitions, and final export;&lt;/li&gt;
&lt;li&gt;a desktop-focused interface, while the mobile web editor keeps its simpler speed workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have ever opened a professional video editor and wondered why it displays four colorful circles, this article explains what they do. The second half looks at the engineering problems behind implementing them in a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a color wheel?
&lt;/h2&gt;

&lt;p&gt;A color wheel is a two-dimensional controller for expressing both a color direction and an adjustment strength.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Moving the control point toward red adds a red bias.&lt;/li&gt;
&lt;li&gt;Moving it toward blue adds a blue bias.&lt;/li&gt;
&lt;li&gt;Moving farther from the center increases the strength.&lt;/li&gt;
&lt;li&gt;Leaving it in the center adds no directional color bias.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is often more intuitive than controlling red, green, and blue with three unrelated sliders. If an image feels too cold, you can move toward orange. If it feels too warm, you can move toward blue.&lt;/p&gt;

&lt;p&gt;In a useful grading tool, however, the wheel does not simply add the same color to every pixel. A frame contains dark, medium, and bright regions, and they usually need different treatment. That is why professional editors provide multiple wheels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are there four wheels?
&lt;/h2&gt;

&lt;p&gt;One frame may contain almost-black hair, naturally exposed skin, a white shirt, and a bright window at the same time.&lt;/p&gt;

&lt;p&gt;With only one global color control, making the dark areas cooler would also make the skin and window cooler. Color-grading tools therefore divide their influence primarily by luminance range.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Wheel&lt;/th&gt;
&lt;th&gt;Main area of influence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Shadows&lt;/td&gt;
&lt;td&gt;Dark clothing, hair, night backgrounds, and unlit areas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Midtones&lt;/td&gt;
&lt;td&gt;Skin, products, walls, and most normally exposed subjects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Highlights&lt;/td&gt;
&lt;td&gt;Windows, sky, lamps, reflections, and bright surfaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Offset&lt;/td&gt;
&lt;td&gt;The overall color balance of the frame&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Shadows
&lt;/h3&gt;

&lt;p&gt;Moving the shadows slightly toward blue or cyan can make a shot feel colder and deeper. This is one ingredient commonly associated with a cinematic look.&lt;/p&gt;

&lt;p&gt;It is also easy to overdo. Excessive adjustment can turn black areas visibly blue, damage natural hair color, and make low-light regions look dirty or posterized. Subtle adjustments tend to work better than large, obvious movements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Midtones
&lt;/h3&gt;

&lt;p&gt;Midtones often contain the most important part of the image: a person's skin or the main product.&lt;/p&gt;

&lt;p&gt;If a face looks pale, moving the midtones slightly toward a warm color may help. Pushing too far can make skin yellow or red and contaminate neutral clothing and backgrounds.&lt;/p&gt;

&lt;p&gt;A safer order of operations is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Correct exposure.&lt;/li&gt;
&lt;li&gt;Correct white balance.&lt;/li&gt;
&lt;li&gt;Check whether skin and neutral objects look natural.&lt;/li&gt;
&lt;li&gt;Use the midtone wheel for a small creative adjustment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A color wheel is excellent for refinement, but it should not hide a fundamentally incorrect exposure or white balance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Highlights
&lt;/h3&gt;

&lt;p&gt;Highlights affect bright areas such as sky, windows, lamps, reflections, white clothing, and the lit side of a face.&lt;/p&gt;

&lt;p&gt;Moving highlights toward yellow or orange can strengthen the feeling of sunlight or sunset. Moving them toward blue can create a colder night or technology-oriented look.&lt;/p&gt;

&lt;p&gt;A frequent creative choice is to keep shadows slightly cool and highlights slightly warm. This creates color separation and additional depth. It does not mean that every video should use an aggressive teal-and-orange preset. Interviews, food, products, and natural scenes all have different requirements for color accuracy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Offset
&lt;/h3&gt;

&lt;p&gt;Offset affects the whole frame rather than a single luminance range.&lt;/p&gt;

&lt;p&gt;It is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the entire clip has a green cast;&lt;/li&gt;
&lt;li&gt;a shot is globally too cold or too warm;&lt;/li&gt;
&lt;li&gt;several cameras need a common starting balance;&lt;/li&gt;
&lt;li&gt;you want to establish a gentle global direction before regional adjustments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If only the shadows are green while the highlights are correct, a global offset is the wrong tool. The important question is not only &lt;em&gt;which color should change?&lt;/em&gt; but also &lt;em&gt;which luminance range should change?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the curved control beside the wheel?
&lt;/h2&gt;

&lt;p&gt;Many color-wheel interfaces place a curved control next to the circle. It usually controls luminance for that range.&lt;/p&gt;

&lt;p&gt;A complete wheel therefore represents three important values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hue:&lt;/strong&gt; which color direction to use;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saturation:&lt;/strong&gt; how strong that color direction should be;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Luminance:&lt;/strong&gt; whether the affected range should become brighter or darker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The disc handles hue and saturation, while the curved control changes luminance. Together they provide much more useful control than a decorative color picker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Color wheels are not the same as filters
&lt;/h2&gt;

&lt;p&gt;A filter is usually a predefined group of adjustments. It is excellent for reaching a recognizable style quickly.&lt;/p&gt;

&lt;p&gt;A color wheel is a manual correction and grading tool.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Filter&lt;/th&gt;
&lt;th&gt;Color wheel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Produces a quick result&lt;/td&gt;
&lt;td&gt;Provides detailed control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hides many values in a preset&lt;/td&gt;
&lt;td&gt;Exposes luminance-specific decisions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can impose the same style on every source&lt;/td&gt;
&lt;td&gt;Can preserve the character of each source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works well for rapid exploration&lt;/td&gt;
&lt;td&gt;Works well for correction and refinement&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;They can also work together. A user can apply a filter as a starting point and then repair skin, shadows, or highlights with the wheels.&lt;/p&gt;

&lt;h2&gt;
  
  
  Video color needs keyframes
&lt;/h2&gt;

&lt;p&gt;A still image can use one set of parameters. Video changes over time.&lt;/p&gt;

&lt;p&gt;A subject may walk from indoors to sunlight. Stage lighting may change from blue to red. A memory sequence may gradually lose saturation. A sunset shot may become warmer as it progresses.&lt;/p&gt;

&lt;p&gt;Keyframes allow a clip to store different grading states at different times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0s&lt;/code&gt;: neutral color;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;2s&lt;/code&gt;: midtones begin moving warmer;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4s&lt;/code&gt;: highlights gain a small yellow bias;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;6s&lt;/code&gt;: global saturation decreases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The editor interpolates between these states. Color grading stops being a fixed filter and becomes an animation that follows the content.&lt;/p&gt;

&lt;p&gt;In Timeline Studio, the keyframeable properties are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;temperature, tint, and global saturation;&lt;/li&gt;
&lt;li&gt;hue, saturation, and luminance for shadows;&lt;/li&gt;
&lt;li&gt;hue, saturation, and luminance for midtones;&lt;/li&gt;
&lt;li&gt;hue, saturation, and luminance for highlights;&lt;/li&gt;
&lt;li&gt;hue, saturation, and luminance for offset.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That produces 15 independently keyframeable properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ordinary interpolation breaks hue
&lt;/h2&gt;

&lt;p&gt;Hue is circular, not linear.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;350°&lt;/code&gt; and &lt;code&gt;10°&lt;/code&gt; are only 20 degrees apart on a color wheel. Ordinary numeric interpolation may travel from &lt;code&gt;350°&lt;/code&gt; through &lt;code&gt;180°&lt;/code&gt; to &lt;code&gt;10°&lt;/code&gt;, passing through many unrelated colors.&lt;/p&gt;

&lt;p&gt;The desired transition crosses zero:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;350° -&amp;gt; 0° -&amp;gt; 10°
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A shortest-path interpolation can be implemented like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;interpolateHue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentHue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;nextHue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&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;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nextHue&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;currentHue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;540&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentHue&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;progress&lt;/code&gt; ranges from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;. The normalized delta stays between &lt;code&gt;-180&lt;/code&gt; and &lt;code&gt;180&lt;/code&gt;, so the transition follows the shorter direction around the wheel.&lt;/p&gt;

&lt;p&gt;This is a small mathematical detail with a very visible result. Without it, animated color may unexpectedly cycle through green, cyan, or purple between two nearby red hues.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical data model
&lt;/h2&gt;

&lt;p&gt;A simplified base grade can be represented as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colorGrade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;temperature&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="na"&gt;tint&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="na"&gt;saturation&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="na"&gt;shadows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hue&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="na"&gt;saturation&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="na"&gt;luminance&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="na"&gt;midtones&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hue&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="na"&gt;saturation&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="na"&gt;luminance&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="na"&gt;highlights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hue&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="na"&gt;saturation&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="na"&gt;luminance&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="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hue&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="na"&gt;saturation&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="na"&gt;luminance&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each animated property can use a path such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colorGrade.temperature
colorGrade.shadows.hue
colorGrade.highlights.luminance
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At render time, the resolver needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find an exact keyframe at the current time if one exists.&lt;/li&gt;
&lt;li&gt;Otherwise find the nearest previous and next values for the property.&lt;/li&gt;
&lt;li&gt;Interpolate ordinary numeric properties linearly.&lt;/li&gt;
&lt;li&gt;Interpolate hue using the shortest circular path.&lt;/li&gt;
&lt;li&gt;Use the base grade before the first keyframe or when a property has no keyframes.&lt;/li&gt;
&lt;li&gt;Normalize and clamp the resolved values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Property-level keyframes are important. A user may want to animate highlight luminance without freezing every other color property into the same keyframe object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preview and export must use the same resolver
&lt;/h2&gt;

&lt;p&gt;Drawing attractive wheels is only the UI portion of the feature. A video editor is not correct unless the final export matches the editor preview.&lt;/p&gt;

&lt;p&gt;If preview and export use separate color logic, users may encounter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;different colors after export;&lt;/li&gt;
&lt;li&gt;color jumps during transitions;&lt;/li&gt;
&lt;li&gt;keyframes that work in the editor but disappear from the final video;&lt;/li&gt;
&lt;li&gt;different results for images and video clips.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Timeline Studio resolves the grade from the clip's keyframes and local time, then sends that result through the preview, transition, and offline export paths.&lt;/p&gt;

&lt;p&gt;The next clip in a transition must resolve its own local grading state as well. Otherwise the outgoing clip may be correct while the incoming clip temporarily displays a static or incorrect grade.&lt;/p&gt;

&lt;p&gt;This shared resolver was one of the most important parts of the implementation. The wheels are not decorative UI; they are editable parameters that reach the final rendered artifact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filter thumbnails should use the user's source
&lt;/h2&gt;

&lt;p&gt;Another small but important detail is filter preview imagery.&lt;/p&gt;

&lt;p&gt;A filter grid should not replace the user's image with an unrelated stock thumbnail. For an image clip, every filter card can reuse the selected image. For a video clip, the editor can reuse an extracted frame from the selected clip.&lt;/p&gt;

&lt;p&gt;Only the preview filter should change. The source image must remain the same across cards, so users can compare color treatments rather than compare different subjects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the full UI is desktop-only
&lt;/h2&gt;

&lt;p&gt;Four wheels, basic controls, value readouts, reset actions, and 15 keyframe buttons form a dense interface.&lt;/p&gt;

&lt;p&gt;Desktop users have enough space and a precise pointer. Copying the same layout directly to mobile web would create tiny wheels, accidental touches, an extremely long inspector, and competition with the timeline for screen space.&lt;/p&gt;

&lt;p&gt;For this release, Timeline Studio exposes the complete color-wheels workflow on desktop. Mobile web does not show the wheels and keeps the more focused video-speed workflow.&lt;/p&gt;

&lt;p&gt;Feature consistency does not always require identical UI on every device. The interface should reflect the precision and space available on each platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple grading order for beginners
&lt;/h2&gt;

&lt;p&gt;If you are new to color wheels, this order is a useful starting point:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Disable creative filters and inspect the original source.&lt;/li&gt;
&lt;li&gt;Correct temperature and tint.&lt;/li&gt;
&lt;li&gt;Check exposure and preserve useful shadow and highlight detail.&lt;/li&gt;
&lt;li&gt;Inspect midtones, especially skin or the main product.&lt;/li&gt;
&lt;li&gt;Add subtle separation to shadows and highlights.&lt;/li&gt;
&lt;li&gt;Use offset only when the whole frame needs a global correction.&lt;/li&gt;
&lt;li&gt;Toggle the grade on and off frequently because human vision adapts quickly.&lt;/li&gt;
&lt;li&gt;Add keyframes when lighting changes over time instead of forcing one static grade onto the whole clip.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;The four wheels can be remembered simply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shadows:&lt;/strong&gt; dark regions;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Midtones:&lt;/strong&gt; subjects and skin;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highlights:&lt;/strong&gt; bright regions and the character of light;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offset:&lt;/strong&gt; the entire frame.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good grading is rarely about pushing every control to a dramatic value. It usually comes from several small, intentional adjustments that preserve the identity of the footage while supporting its mood.&lt;/p&gt;

&lt;p&gt;The complete implementation is open source. You can inspect the UI, property keyframes, shortest-path hue interpolation, preview composition, transition handling, and export integration in the repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live editor:&lt;/strong&gt; &lt;a href="https://video-editor.ai-creator.top" rel="noopener noreferrer"&gt;https://video-editor.ai-creator.top&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If browser-based video editing, React, WebCodecs, local AI, or deterministic media export interests you, issues and pull requests are welcome. If the project is useful, a GitHub star also helps more developers discover it.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a Browser-Native AI Video Editor: Timeline Synchronization, WebGPU, and Worker Architecture</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Tue, 11 Aug 2026 08:41:24 +0000</pubDate>
      <link>https://dev.to/martindelophy/building-a-browser-native-ai-video-editor-timeline-synchronization-webgpu-and-worker-architecture-1el</link>
      <guid>https://dev.to/martindelophy/building-a-browser-native-ai-video-editor-timeline-synchronization-webgpu-and-worker-architecture-1el</guid>
      <description>&lt;p&gt;Modern browsers can now do work that once required a native desktop application. WebGPU exposes GPU compute, WebAssembly brings mature runtimes to the web, WebCodecs provides lower-level media primitives, and Web Workers let us move expensive tasks away from the UI thread.&lt;/p&gt;

&lt;p&gt;But getting an AI model to run once in a browser is very different from building a video editor that remains predictable during a long editing session.&lt;/p&gt;

&lt;p&gt;I recently completed a substantial infrastructure update to &lt;strong&gt;Timeline Studio&lt;/strong&gt;, a local-first browser AI video editor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor/releases/tag/v1.0.2" rel="noopener noreferrer"&gt;v1.0.2&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://video-editor.ai-creator.top" rel="noopener noreferrer"&gt;https://video-editor.ai-creator.top&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The release changed 37 files and added roughly 1,400 lines. The work focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stable dragging, splitting, reordering, and cross-track movement;&lt;/li&gt;
&lt;li&gt;synchronization between project time and media time;&lt;/li&gt;
&lt;li&gt;reusable timeline frame data;&lt;/li&gt;
&lt;li&gt;explicit high-performance WebGPU adapter selection;&lt;/li&gt;
&lt;li&gt;persistent AI workers and reusable inference sessions;&lt;/li&gt;
&lt;li&gt;centralized model caching through a service worker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article explains the engineering decisions behind that update.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. A timeline is a constrained data model, not a row of draggable rectangles
&lt;/h2&gt;

&lt;p&gt;A first timeline prototype can position clips with a simple pixel conversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startTime&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pixelsPerSecond&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;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;pixelsPerSecond&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dragging appears equally straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextStartTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;originalStartTime&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;deltaX&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;pixelsPerSecond&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A production clip, however, contains more than a visual position:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt; &lt;span class="o"&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;segment-001&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;visual-track&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;startTime&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="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;trimStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;trimEnd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sourceDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;playbackRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;locked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single move may need to enforce all of these rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the clip cannot begin before zero;&lt;/li&gt;
&lt;li&gt;it cannot exceed the project boundary;&lt;/li&gt;
&lt;li&gt;its position may snap to other edit points;&lt;/li&gt;
&lt;li&gt;a locked track cannot accept it;&lt;/li&gt;
&lt;li&gt;it may not overlap another clip on the same track;&lt;/li&gt;
&lt;li&gt;its media type must be compatible with the target track;&lt;/li&gt;
&lt;li&gt;related caption and audio state must remain valid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When each React component implements its own version of those rules, dragging, duplication, cutting, and reordering eventually disagree.&lt;/p&gt;

&lt;p&gt;The update moves timeline decisions into a shared domain layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pointer coordinates
       ↓
timeline coordinates
       ↓
candidate start time
       ↓
bounds and snapping constraints
       ↓
track routing and collision checks
       ↓
atomic project-state update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI collects input and renders a preview. Domain logic determines the final valid result.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. New clips must not rearrange existing work
&lt;/h2&gt;

&lt;p&gt;A common way to handle overlapping audio is to redistribute every clip until no overlap remains. The algorithm succeeds, but the user's earlier track arrangement changes unexpectedly.&lt;/p&gt;

&lt;p&gt;The new rule is deliberately asymmetric:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A new clip may search for an available track, but existing clips keep their lanes.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findTrackForNewAudio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newClip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;track&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;tracks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;hasOverlap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clips&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newClip&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;track&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createAudioTrack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Asset semantics also matter. AI-generated music belongs on the dedicated music track rather than whichever voice track happens to be empty:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resolveAudioTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ai-music&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;MUSIC_TRACK_ID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;findAvailableVoiceTrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A track is not merely a visual group. It may define mixing behavior, caption relationships, mute and solo behavior, volume defaults, and export rules.&lt;/p&gt;

&lt;p&gt;Automatic routing should therefore preserve both user intent and media meaning.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Separate project time from media time
&lt;/h2&gt;

&lt;p&gt;A video editor has at least two clocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project time&lt;/strong&gt; describes where a clip appears in the final composition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Media time&lt;/strong&gt; describes which position in the source file should be decoded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suppose seconds 10–20 of a source video are placed at seconds 30–40 of the project. At project time 33, the video element should display source time 13.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getMediaTimeAtTimelineTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timelineTime&lt;/span&gt;&lt;span class="p"&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;localTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;timelineTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startTime&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;mediaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trimStart&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="nx"&gt;localTime&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;playbackRate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trimStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trimEnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mediaTime&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping this transformation independent from the DOM makes it reusable for trimming, splitting, playback-rate changes, clip movement, and multiple clips referencing the same source asset.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Do not write video.currentTime on every frame
&lt;/h2&gt;

&lt;p&gt;The obvious synchronization operation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doing this continuously forces the browser to seek repeatedly. That can cause decoder churn, visual jitter, black frames, and unnecessary CPU use.&lt;/p&gt;

&lt;p&gt;Instead, compare the current media position with the calculated target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;drift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;targetTime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSeeking&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;drift&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_ALLOWED_DRIFT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During normal playback, the media element advances on its own and small drift is tolerated. During timeline scrubbing, exact frame feedback matters more, so synchronization happens immediately.&lt;/p&gt;

&lt;p&gt;Both paths are called “synchronization,” but they optimize for different outcomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;playback optimizes for continuity;&lt;/li&gt;
&lt;li&gt;scrubbing optimizes for precision.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Make timeline frames part of the media asset
&lt;/h2&gt;

&lt;p&gt;Thumbnail frames are not just decoration. They help users identify content and find cut points.&lt;/p&gt;

&lt;p&gt;If those frames live only in temporary component state, they are easy to lose after splitting, copying, or moving a clip. A generated video may even appear as a blank block or one stretched cover frame.&lt;/p&gt;

&lt;p&gt;The asset now carries compact sampled frames:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;videoAsset&lt;/span&gt; &lt;span class="o"&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-001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;trackFrameDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;trackFrames&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="na"&gt;time&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="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&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="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same data can be reused by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the media-library card;&lt;/li&gt;
&lt;li&gt;the main visuals track;&lt;/li&gt;
&lt;li&gt;overlay tracks;&lt;/li&gt;
&lt;li&gt;multiple clips created from a split;&lt;/li&gt;
&lt;li&gt;browser-generated video assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rendering code selects frames based on the clip's trim range and visual width without rewriting the source frame data.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. WebGPU does not necessarily choose the fastest GPU
&lt;/h2&gt;

&lt;p&gt;A typical WebGPU setup begins with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAdapter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a dual-GPU machine, the browser may prefer an integrated adapter to save power. That can be reasonable for ordinary UI rendering but expensive for ONNX Runtime and generative workloads.&lt;/p&gt;

&lt;p&gt;For compute-heavy paths, the project now uses an explicit default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestAdapter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;powerPreference&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-performance&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;An explicit caller override must still win:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;normalizeAdapterOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;powerPreference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;powerPreference&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high-performance&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides a high-performance default without breaking callers that intentionally request &lt;code&gt;low-power&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The policy is shared across AI music, speech, face processing, video repair, and super-resolution workers.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Handling requestAdapter calls inside third-party runtimes
&lt;/h2&gt;

&lt;p&gt;Not every adapter request is made by application code. A pinned runtime may internally call &lt;code&gt;requestAdapter()&lt;/code&gt; without options.&lt;/p&gt;

&lt;p&gt;When upgrading the dependency immediately would introduce compatibility risk, a narrowly scoped initialization wrapper can provide the missing default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalRequestAdapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;gpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestAdapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;originalRequestAdapter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;powerPreference&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-performance&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;options&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details are essential:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep the patch scoped to the relevant worker or initialization phase.&lt;/li&gt;
&lt;li&gt;Spread explicit options after the default so the caller retains control.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The original method should be restored after initialization. This is a compatibility strategy, not a preferred permanent API.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. AI latency is more than inference time
&lt;/h2&gt;

&lt;p&gt;The delay users experience usually contains several stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;download artifacts
       ↓
write cache
       ↓
read model files
       ↓
create inference sessions
       ↓
preprocess inputs
       ↓
run inference
       ↓
postprocess outputs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optimizing only model execution may leave most of the perceived delay untouched.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download independent artifacts in parallel
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;artifacts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;modelFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;downloadModelFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create large GPU sessions serially
&lt;/h3&gt;

&lt;p&gt;Initializing several large WebGPU sessions at once can create a sharp memory and GPU-resource peak. Parallel downloading combined with serial session creation is usually a safer balance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep initialized workers alive
&lt;/h3&gt;

&lt;p&gt;Terminating a worker after every generation discards the expensive model sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;first use
   ↓
start worker
   ↓
initialize models
   ↓
generation 1
   ↓
generation 2
   ↓
release when the page closes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The UI should also distinguish &lt;strong&gt;model setup&lt;/strong&gt; from &lt;strong&gt;content generation&lt;/strong&gt;. A repeated generation should not look like another model download.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Give one component ownership of persistent model caching
&lt;/h2&gt;

&lt;p&gt;If the page, inference workers, and service worker all write to Cache Storage, a large model can be stored more than once.&lt;/p&gt;

&lt;p&gt;Timeline Studio makes the shared service worker the only persistent cache writer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inference worker
       ↓ model request
service worker
       ├─ normalize provider URLs
       ├─ resolve immutable model identity
       ├─ preflight storage capacity
       ├─ evict stale model families
       └─ write Cache Storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hugging Face and ModelScope may use different URLs for equivalent artifacts. Those URLs are normalized to one cache identity based on the model, immutable revision, and file path.&lt;/p&gt;

&lt;p&gt;A cache write failure also does not necessarily mean the current inference must fail. If the artifact is already available in memory, the task can continue; only the next session may need to download it again.&lt;/p&gt;

&lt;p&gt;That distinction separates a performance degradation from a functional failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Never expose “Failed to fetch” as the complete error
&lt;/h2&gt;

&lt;p&gt;A browser's generic &lt;code&gt;Failed to fetch&lt;/code&gt; message is nearly useless to an end user.&lt;/p&gt;

&lt;p&gt;The application layer should distinguish at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no network connection;&lt;/li&gt;
&lt;li&gt;an unavailable model mirror;&lt;/li&gt;
&lt;li&gt;insufficient browser storage;&lt;/li&gt;
&lt;li&gt;unavailable WebGPU support;&lt;/li&gt;
&lt;li&gt;model initialization failure;&lt;/li&gt;
&lt;li&gt;user cancellation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toUserFacingError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isNetworkError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The model server is unavailable. Check your connection and retry.&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isStorageError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Browser storage is full. This run will try an in-memory fallback.&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isAbortError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The operation was cancelled.&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The model could not be initialized.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful error should answer three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What failed?&lt;/li&gt;
&lt;li&gt;Can the current task continue?&lt;/li&gt;
&lt;li&gt;What can the user do next?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Resulting architecture
&lt;/h2&gt;

&lt;p&gt;The refactored flow is easier to reason about:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user interaction
       ↓
timeline commands and constraints
       ↓
project state
       ├─ segment placement
       ├─ track routing
       ├─ caption relationships
       └─ sampled track frames
                ↓
media synchronization
       ├─ project time
       ├─ source-media time
       └─ drift correction
                ↓
AI workers
       ├─ model lifecycle
       ├─ WebGPU adapter policy
       └─ cancellation
                ↓
centralized model cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important outcome is not the number of new features. It is the clearer separation of responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;timeline components no longer invent their own placement rules;&lt;/li&gt;
&lt;li&gt;media-time conversion is independent from UI state;&lt;/li&gt;
&lt;li&gt;WebGPU, worker lifecycle, and model caching form shared infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Validation
&lt;/h2&gt;

&lt;p&gt;The release was checked with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs ESLint, TypeScript checking, and the Vite production build. The release completed with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;zero ESLint errors;&lt;/li&gt;
&lt;li&gt;successful TypeScript validation;&lt;/li&gt;
&lt;li&gt;successful production build;&lt;/li&gt;
&lt;li&gt;GitHub release &lt;code&gt;v1.0.2&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;successful production deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final takeaways
&lt;/h2&gt;

&lt;p&gt;The difficult part of a browser-native AI video editor is not running a single model. It is keeping timeline state, media elements, React state, workers, GPU sessions, and local caches consistent throughout a real editing session.&lt;/p&gt;

&lt;p&gt;The most reusable lessons from this update are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Treat the timeline as a constrained domain model.&lt;/li&gt;
&lt;li&gt;Do not let new assets silently rearrange existing work.&lt;/li&gt;
&lt;li&gt;Separate project time from source-media time.&lt;/li&gt;
&lt;li&gt;Use different synchronization policies for playback and scrubbing.&lt;/li&gt;
&lt;li&gt;Explicitly request a high-performance WebGPU adapter for compute workloads.&lt;/li&gt;
&lt;li&gt;Download artifacts in parallel but initialize large GPU sessions serially.&lt;/li&gt;
&lt;li&gt;Reuse initialized workers and inference sessions.&lt;/li&gt;
&lt;li&gt;Give the service worker exclusive ownership of persistent model caching.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Browsers are becoming local compute platforms, not just document viewers. Turning those capabilities into a dependable creative tool requires careful boundaries around time, state, storage, and GPU resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor/releases/tag/v1.0.2" rel="noopener noreferrer"&gt;v1.0.2 release&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://video-editor.ai-creator.top" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>react</category>
      <category>webgpu</category>
    </item>
    <item>
      <title>Running Chinese TTS Fully in the Browser: Migrating from Piper to Kokoro 1.1 FP16</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Sat, 08 Aug 2026 09:22:18 +0000</pubDate>
      <link>https://dev.to/martindelophy/running-chinese-tts-fully-in-the-browser-migrating-from-piper-to-kokoro-11-fp16-4cpd</link>
      <guid>https://dev.to/martindelophy/running-chinese-tts-fully-in-the-browser-migrating-from-piper-to-kokoro-11-fp16-4cpd</guid>
      <description>&lt;p&gt;When an AI video editor needs text-to-speech, the easiest solution is usually a hosted API: send the script to a server, wait a few seconds, and download the audio.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio&lt;/a&gt;, we deliberately took a harder route. We want voice generation to run on the user's device, inside the browser, alongside the editable timeline.&lt;/p&gt;

&lt;p&gt;In Timeline Studio v1.0.0, we replaced our previous Chinese Piper/VITS ONNX voices with a browser-ready FP16 build of &lt;strong&gt;Kokoro multi-lang v1.1&lt;/strong&gt;. The new path provides two female and two male voices, handles Chinese text with inline English, and still performs synthesis locally through sherpa-onnx WASM.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live editor:&lt;/strong&gt; &lt;a href="https://video-editor.ai-creator.top/" rel="noopener noreferrer"&gt;video-editor.ai-creator.top&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hugging Face Space:&lt;/strong&gt; &lt;a href="https://huggingface.co/spaces/haixin/timeline-studio" rel="noopener noreferrer"&gt;haixin/timeline-studio&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If browser AI, WebAssembly, ONNX, or open-source video editing interests you, a GitHub star is greatly appreciated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why move away from Piper for Chinese?
&lt;/h2&gt;

&lt;p&gt;Piper was a pragmatic starting point. Its ONNX models are relatively compact, the browser deployment path is well understood, and it allowed us to build a local TTS workflow without depending on a metered cloud service.&lt;/p&gt;

&lt;p&gt;But the quality bar changes when TTS becomes part of a video editor.&lt;/p&gt;

&lt;p&gt;It is no longer enough for a model to simply pronounce a sentence. Product demos, tutorials, explainers, and narrative videos need more natural pacing, clearer voice choices, and reliable handling of modern Chinese copy that often contains English names and technical terms.&lt;/p&gt;

&lt;p&gt;Consider this sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;使用 Timeline Studio，让 AI video editing 直接在浏览器里完成。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Splitting it into separate Chinese and English clips creates avoidable problems: speaker identity can change, pacing can jump, and the sentence loses its natural context. We wanted one speaker to generate the complete utterance.&lt;/p&gt;

&lt;p&gt;Kokoro multi-lang v1.1 gave us a better foundation for that experience.&lt;/p&gt;

&lt;p&gt;Piper has not disappeared from Timeline Studio. It still powers browser voices for German, Spanish, French, Italian, and Brazilian Portuguese. This migration only replaces the Chinese Piper route.&lt;/p&gt;

&lt;h2&gt;
  
  
  A browser model is more than an ONNX file
&lt;/h2&gt;

&lt;p&gt;Choosing a model was the easy part. Turning it into a dependable browser feature required much more work.&lt;/p&gt;

&lt;p&gt;A server can assume a controlled filesystem, abundant memory, a long-running process, and predictable model storage. A browser must deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;first-use download size;&lt;/li&gt;
&lt;li&gt;memory and bandwidth pressure;&lt;/li&gt;
&lt;li&gt;main-thread responsiveness;&lt;/li&gt;
&lt;li&gt;storage quotas;&lt;/li&gt;
&lt;li&gt;interrupted or incomplete downloads;&lt;/li&gt;
&lt;li&gt;regional model availability;&lt;/li&gt;
&lt;li&gt;immutable model versions;&lt;/li&gt;
&lt;li&gt;cache migration across application releases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A model that produces one successful sample on a developer machine is a demo. A product feature must download, verify, initialize, cache, reuse, upgrade, and fail clearly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Converting Kokoro 1.1 to FP16
&lt;/h2&gt;

&lt;p&gt;We converted the selected Kokoro multi-lang v1.1 bundle to FP16 and packaged it for the sherpa-onnx WASM TTS runtime.&lt;/p&gt;

&lt;p&gt;The resulting browser pipeline looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User script
    ↓
Chinese/English text normalization
    ↓
Voice ID → speaker ID
    ↓
Kokoro multi-lang v1.1 FP16
    ↓
sherpa-onnx WASM in a Web Worker
    ↓
Float32 PCM samples
    ↓
WAV encoding in the browser
    ↓
Timeline Studio asset library
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FP16 reduces storage, transfer, and runtime memory-bandwidth pressure relative to FP32 while preserving the voice quality we need.&lt;/p&gt;

&lt;p&gt;It is not magic. The first run still requires a substantial model download, and synthesis speed depends on the device, browser, available memory, and script length. The goal was not to pretend the cost had disappeared, but to make a higher-quality multilingual TTS model practical in a local browser workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping inference off the main thread
&lt;/h2&gt;

&lt;p&gt;Model initialization and synthesis are compute-heavy operations. Running them on the main thread would make an editor feel frozen.&lt;/p&gt;

&lt;p&gt;Timeline Studio creates a dedicated worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/kokoro-multilang.worker.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&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;init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;baseUrls&lt;/span&gt;&lt;span class="p"&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 UI thread handles the script, selected voice, progress display, and timeline state. The worker downloads and verifies the runtime bundle, initializes sherpa-onnx WASM, creates the offline TTS session, and generates the samples.&lt;/p&gt;

&lt;p&gt;A synthesis request is intentionally small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&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;generate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;sid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;speed&lt;/span&gt;&lt;span class="p"&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 generated sample buffer is returned as a transferable object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&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;result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sampleRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sampleRate&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;tts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sampleRate&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;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Transferring the underlying &lt;code&gt;ArrayBuffer&lt;/code&gt; avoids copying a potentially large block of PCM data.&lt;/p&gt;

&lt;p&gt;The worker stays alive after initialization, so repeated generations in the same editing session reuse the warm runtime instead of downloading and initializing the model again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four voices, one shared model
&lt;/h2&gt;

&lt;p&gt;We selected four speakers with distinct roles:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Timeline Studio voice&lt;/th&gt;
&lt;th&gt;Upstream speaker&lt;/th&gt;
&lt;th&gt;Character&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qinglan / 晴岚&lt;/td&gt;
&lt;td&gt;&lt;code&gt;zf_001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Natural, clear female voice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ruoxi / 若溪&lt;/td&gt;
&lt;td&gt;&lt;code&gt;zf_073&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Softer female voice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yunzhou / 云舟&lt;/td&gt;
&lt;td&gt;&lt;code&gt;zm_009&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Steady, natural male voice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jingche / 景澈&lt;/td&gt;
&lt;td&gt;&lt;code&gt;zm_010&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Younger, brighter male voice&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Internally, product voice IDs map to the four speaker slots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SPEAKER_IDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;zh_f_qinglan&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="na"&gt;zh_f_ruoxi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;zh_m_yunzhou&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;zh_m_jingche&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All four voices share the same FP16 model. Switching speakers does not trigger another full model download.&lt;/p&gt;

&lt;p&gt;We also provide a real preview generated by the matching speaker for every selectable voice. A voice card should never play a placeholder sample from a different speaker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping mixed Chinese and English in one utterance
&lt;/h2&gt;

&lt;p&gt;Before synthesis, Timeline Studio normalizes the text while preserving Han characters, Latin characters, numbers, whitespace, and common punctuation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;normalized&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^\p&lt;/span&gt;&lt;span class="sr"&gt;{Script=Han}&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="sr"&gt;{Script=Latin}0-9&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;，。！？；：、,.!?;:()&lt;/span&gt;&lt;span class="se"&gt;\-]&lt;/span&gt;&lt;span class="sr"&gt;/gu&lt;/span&gt;&lt;span class="p"&gt;,&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt; &lt;/span&gt;&lt;span class="se"&gt;\t]&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/ *&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sr"&gt;+ */g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;。&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;。&lt;/span&gt;&lt;span class="se"&gt;]{2,}&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;。&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="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important product rule is that mixed-language copy remains one linguistic utterance. We do not split a Chinese sentence simply because it contains "WebGPU", "API", or an English product name.&lt;/p&gt;

&lt;p&gt;That preserves speaker identity, punctuation-driven pauses, and editing simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel downloads with integrity checks
&lt;/h2&gt;

&lt;p&gt;The browser bundle includes the WASM binary, JavaScript runtime, wrapper code, model data, and supporting resources. Large data is divided into parts described by a manifest.&lt;/p&gt;

&lt;p&gt;The worker downloads manifest entries in parallel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entries&lt;/span&gt; &lt;span class="o"&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;manifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;manifest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&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;resources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;fetchAndVerify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onChunk&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each entry includes its expected byte length and SHA-256 digest. The worker verifies individual downloads, reassembles the model data in manifest order, and verifies the completed payload again before creating the TTS session.&lt;/p&gt;

&lt;p&gt;A successful HTTP status is not enough. Proxies, partial caches, and interrupted connections can all return incomplete model data. Integrity verification prevents corrupted weights from reaching inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hugging Face and ModelScope mirrors
&lt;/h2&gt;

&lt;p&gt;Model availability is a product issue, especially for a browser application serving users in different regions.&lt;/p&gt;

&lt;p&gt;We mirror the voice bundle in repositories we control on both Hugging Face and ModelScope, pinned to immutable provider revisions.&lt;/p&gt;

&lt;p&gt;Timeline Studio prefers ModelScope for Chinese and domestic sessions and Hugging Face elsewhere. If the preferred route fails, it attempts the other mirror.&lt;/p&gt;

&lt;p&gt;The two providers use different URLs and revisions for the same artifacts, so we canonicalize them to one internal cache identity. Otherwise, a browser could store two copies of the same large model after a network route changes.&lt;/p&gt;

&lt;p&gt;The source may change; the model identity should not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache migration matters
&lt;/h2&gt;

&lt;p&gt;Timeline Studio also uses local models for captions, music, vision, voice conversion, and other features. Browser storage cannot be treated as unlimited.&lt;/p&gt;

&lt;p&gt;Before loading the Kokoro bundle, the application preflights available storage. During upgrades, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;removes legacy FP32 Kokoro files;&lt;/li&gt;
&lt;li&gt;avoids duplicate Piper caches;&lt;/li&gt;
&lt;li&gt;migrates unchanged files to the new canonical revision;&lt;/li&gt;
&lt;li&gt;deletes changed manifest or model parts;&lt;/li&gt;
&lt;li&gt;evicts stale voice families when capacity is tight.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not glamorous work, but it separates a one-release demo from a browser AI application that can continue evolving.&lt;/p&gt;

&lt;h2&gt;
  
  
  TTS is only the beginning of the workflow
&lt;/h2&gt;

&lt;p&gt;Timeline Studio is not a standalone text-to-speech page.&lt;/p&gt;

&lt;p&gt;A generated WAV becomes an editable media asset. The user can audition it, regenerate it, place it on the voiceover track, trim and move it, generate captions, mix it with source audio and music, and export the final project to MP4 or WebM.&lt;/p&gt;

&lt;p&gt;The current voice routing is deliberately model-specific:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language or use case&lt;/th&gt;
&lt;th&gt;Browser model&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Chinese and mixed Chinese/English&lt;/td&gt;
&lt;td&gt;Kokoro multi-lang v1.1 FP16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;English&lt;/td&gt;
&lt;td&gt;Kokoro 82M ONNX&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;German, Spanish, French, Italian, Brazilian Portuguese&lt;/td&gt;
&lt;td&gt;Piper/VITS ONNX&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We prefer specialized, verified paths over claiming that one model is best for every language.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this migration delivered
&lt;/h2&gt;

&lt;p&gt;The final change included more than replacing two entries in a voice picker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kokoro multi-lang v1.1 replaced the Chinese Piper route;&lt;/li&gt;
&lt;li&gt;the model was converted and packaged as FP16;&lt;/li&gt;
&lt;li&gt;sherpa-onnx WASM runs synthesis locally;&lt;/li&gt;
&lt;li&gt;a persistent Web Worker keeps the editor responsive;&lt;/li&gt;
&lt;li&gt;two female and two male voices share one model;&lt;/li&gt;
&lt;li&gt;mixed Chinese/English scripts remain one utterance;&lt;/li&gt;
&lt;li&gt;model parts download in parallel and are SHA-256 verified;&lt;/li&gt;
&lt;li&gt;Hugging Face and ModelScope provide pinned fallback mirrors;&lt;/li&gt;
&lt;li&gt;both providers share one cache identity;&lt;/li&gt;
&lt;li&gt;storage preflight and cache migration support future releases;&lt;/li&gt;
&lt;li&gt;generated audio enters the editable video timeline instead of ending as a demo file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;Running AI in the browser is not simply a matter of moving an ONNX file to the frontend.&lt;/p&gt;

&lt;p&gt;A production-quality local feature needs a model delivery system, an isolated runtime, integrity checks, regional routing, cache ownership, upgrade behavior, honest progress reporting, and a clear place in the user's workflow.&lt;/p&gt;

&lt;p&gt;That engineering work is less visible than a model benchmark, but it is what turns local inference into a usable creative tool.&lt;/p&gt;

&lt;p&gt;Timeline Studio is open source under the MIT License:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Try it online:&lt;/strong&gt; &lt;a href="https://video-editor.ai-creator.top/" rel="noopener noreferrer"&gt;https://video-editor.ai-creator.top/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this work is useful to you, please consider starring the repository, opening an issue, or contributing.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>opensource</category>
      <category>javascript</category>
    </item>
    <item>
      <title>From Natural Language to an Editable Video: Inside Timeline Studio's Agent Skill</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Fri, 07 Aug 2026 08:51:59 +0000</pubDate>
      <link>https://dev.to/martindelophy/from-natural-language-to-an-editable-video-inside-timeline-studios-agent-skill-4f08</link>
      <guid>https://dev.to/martindelophy/from-natural-language-to-an-editable-video-inside-timeline-studios-agent-skill-4f08</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;One instruction, one rendered video, and one editable &lt;code&gt;.timeline&lt;/code&gt; project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Repositories
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Examples and reproducible workflows — start here
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/MartinDelophy/timeline-studio-handbook" rel="noopener noreferrer"&gt;Timeline Studio Skills Handbook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Handbook contains reference-video remakes, product promotions, multilingual localization, narrative marketing videos, and science explainers. Each case includes as much reproducible evidence as possible: the prompt, result video, editing decisions, and an editable &lt;code&gt;.timeline&lt;/code&gt; project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main repository
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;MartinDelophy/ai-video-editor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main repository contains the browser video editor, Agent Skill, timeline command protocol, local AI integrations, and build and deployment configuration.&lt;/p&gt;

&lt;p&gt;Install the Skill with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add MartinDelophy/ai-video-editor &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--skill&lt;/span&gt; edit-timeline-studio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why video production needs more than another generation API
&lt;/h2&gt;

&lt;p&gt;Generative AI has made it easy to create text, images, speech, music, and captions independently. Producing one complete video is still a fragmented process.&lt;/p&gt;

&lt;p&gt;A short video may require all of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inspecting and organizing source media;&lt;/li&gt;
&lt;li&gt;selecting useful shots;&lt;/li&gt;
&lt;li&gt;designing the narrative and pacing;&lt;/li&gt;
&lt;li&gt;generating or cleaning narration;&lt;/li&gt;
&lt;li&gt;creating and synchronizing captions;&lt;/li&gt;
&lt;li&gt;adding music, overlays, transitions, and effects;&lt;/li&gt;
&lt;li&gt;exporting and decoding the result;&lt;/li&gt;
&lt;li&gt;preserving a project that can still be edited later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most AI tools solve one item on this list. The creator still moves files between services and manually rebuilds timing relationships.&lt;/p&gt;

&lt;p&gt;Timeline Studio's &lt;code&gt;edit-timeline-studio&lt;/code&gt; Skill treats the entire process as an executable workflow. Its goal is not merely to produce an MP4. It also preserves an editable &lt;code&gt;.timeline&lt;/code&gt; project that a human can reopen and refine.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Starting from a natural-language brief
&lt;/h2&gt;

&lt;p&gt;The user describes the intended result rather than a sequence of UI operations:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Turn these product demo clips into a roughly 40-second vertical promo. Preserve the real product interaction, add English narration and captions, and deliver both the video and an editable project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Skill decomposes that request into a controlled sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;inspect the named assets;&lt;/li&gt;
&lt;li&gt;analyze video, audio, speech, and text;&lt;/li&gt;
&lt;li&gt;record editorial decisions;&lt;/li&gt;
&lt;li&gt;build a declarative edit plan;&lt;/li&gt;
&lt;li&gt;apply timeline operations;&lt;/li&gt;
&lt;li&gt;run browser-local AI or rich editor features when required;&lt;/li&gt;
&lt;li&gt;validate the project and rendered output.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Natural-language brief
        ↓
Media analysis → Editorial decisions → Edit plan
        ↓
Transactional timeline operations
        ↓
AI speech, captions, music, and effects
        ↓
Project validation → Video validation
        ↓
MP4/WebM + editable .timeline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Skill is therefore more than a prompt template. It defines what the Agent must inspect, how it should execute the edit, and what evidence is required before the task can be called complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Analyze before cutting
&lt;/h2&gt;

&lt;p&gt;A common automatic-editing failure is to start cutting before understanding the media.&lt;/p&gt;

&lt;p&gt;Silence does not necessarily mean that a section is disposable. It may contain a product result, a useful reaction, intentional tension, or the preparation for an important action.&lt;/p&gt;

&lt;p&gt;Depending on the task, Timeline Studio can inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duration, resolution, frame rate, and audio presence;&lt;/li&gt;
&lt;li&gt;representative frames;&lt;/li&gt;
&lt;li&gt;speech transcripts and OCR text;&lt;/li&gt;
&lt;li&gt;shot-change evidence;&lt;/li&gt;
&lt;li&gt;subject position, scale, and motion;&lt;/li&gt;
&lt;li&gt;global and subject-region optical flow;&lt;/li&gt;
&lt;li&gt;audio-energy changes;&lt;/li&gt;
&lt;li&gt;visual clarity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The analysis is converted into a source-time decision record rather than immediately mutating the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"assetId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"product-demo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sourceStart"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;12.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sourceEnd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;19.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shorten"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"keepStart"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;14.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"keepEnd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;18.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Preserve the complete interaction and remove repeated setup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.92&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protectSourceAudio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes keep, remove, shorten, and reorder decisions explainable and reviewable.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Turning the brief into declarative timeline commands
&lt;/h2&gt;

&lt;p&gt;Once the plan is ready, the Agent uses stable project, track, asset, and clip identifiers wherever the command registry supports the requested operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run agent &lt;span class="nt"&gt;--&lt;/span&gt; project.inspect /path/to/project.timeline
npm run agent &lt;span class="nt"&gt;--&lt;/span&gt; project.diff /path/to/edit-plan.json
npm run agent &lt;span class="nt"&gt;--&lt;/span&gt; project.run /path/to/edit-plan.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;project.inspect&lt;/code&gt; reads the project, tracks, clips, media, and captions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;project.diff&lt;/code&gt; validates the plan and calculates a non-writing semantic diff.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;project.run&lt;/code&gt; transactionally applies the validated plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simplified edit plan looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"projectRevision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operationId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"update-product-intro-v2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timed.move"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"clipId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"voice-intro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"caption.update"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"clipId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"caption-intro"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Let AI handle the repetitive editing work."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.8&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Making Agent edits safe
&lt;/h2&gt;

&lt;p&gt;Video editing needs many of the same guarantees as other stateful systems. A plan may update visuals, captions, narration, and music together. A partial result is often unusable.&lt;/p&gt;

&lt;p&gt;The command layer therefore uses several safeguards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Revision checks:&lt;/strong&gt; reject a plan if the project changed after the plan was created.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preconditions:&lt;/strong&gt; verify that clips, tracks, media, and expected state still exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transactions:&lt;/strong&gt; apply one user-visible intent as a complete unit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency:&lt;/strong&gt; use a stable &lt;code&gt;operationId&lt;/code&gt; so retrying a request does not duplicate media or captions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic diffs:&lt;/strong&gt; show meaningful project changes before writing the new archive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These mechanisms separate a reliable production Agent from a UI automation demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Two execution paths
&lt;/h2&gt;

&lt;p&gt;Timeline Studio does not pretend that every editor feature is already a mature headless API. It uses two complementary paths.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Typical work&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Versioned command layer&lt;/td&gt;
&lt;td&gt;Project inspection, media import, clip timing, captions, track operations, portable archive output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser editor&lt;/td&gt;
&lt;td&gt;AI speech, automatic captions, advanced effects, digital humans, rich preview and full export&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Stable operations run through the command registry. Features that have not yet moved into that registry remain available through the local or hosted browser editor.&lt;/p&gt;

&lt;p&gt;After either path, the Skill reopens and verifies the project instead of assuming that a successful click or command means the edit is correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Why &lt;code&gt;.timeline&lt;/code&gt; matters
&lt;/h2&gt;

&lt;p&gt;Many AI video systems return only an MP4. That is a delivery file, not an editable source of truth.&lt;/p&gt;

&lt;p&gt;Timeline Studio uses a portable &lt;code&gt;.timeline&lt;/code&gt; archive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project.timeline
├── project.json
└── media/
    ├── visual-001.mp4
    ├── visual-002.png
    ├── voice-001.wav
    └── music-001.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project can preserve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the contiguous main Visuals track;&lt;/li&gt;
&lt;li&gt;timed picture-in-picture overlays;&lt;/li&gt;
&lt;li&gt;captions and stickers;&lt;/li&gt;
&lt;li&gt;voiceover, source audio, and music;&lt;/li&gt;
&lt;li&gt;transforms, masks, filters, animations, and keyframes;&lt;/li&gt;
&lt;li&gt;media identity and source-time mapping;&lt;/li&gt;
&lt;li&gt;canvas ratio and track state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An Agent can produce a first edit, while a human can continue working in a familiar visual timeline. Changing one caption or replacing one shot does not require regenerating the entire video.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Captions must map to audible speech
&lt;/h2&gt;

&lt;p&gt;Automatically generated videos often contain captions with missing, duplicated, or misaligned speech.&lt;/p&gt;

&lt;p&gt;Timeline Studio applies a simple invariant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If captions are enabled, every visible caption must map to exactly one audible speech clip for its full interval.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Transcribed captions bind to existing source dialogue. Agent-authored explanation or narration receives a generated or recorded voice clip instead of becoming silent text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"captionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"caption-result"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"audioClipId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"voice-result"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;18.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;22.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"One instruction can produce a project you can still edit."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final verification checks caption boundaries, real audible output, duplicate narration, loudness differences, and unexpected stereo-channel offsets.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Browser-local AI
&lt;/h2&gt;

&lt;p&gt;Timeline Studio follows a local-first architecture. Supported inference runs in the browser with technologies including WebGPU, ONNX Runtime Web, Web Workers, Cache Storage, and WebCodecs.&lt;/p&gt;

&lt;p&gt;Current editor capabilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whisper Small Q8 ONNX automatic captions;&lt;/li&gt;
&lt;li&gt;Piper/VITS Chinese voices and Kokoro English voices;&lt;/li&gt;
&lt;li&gt;multilingual browser TTS;&lt;/li&gt;
&lt;li&gt;Stable Audio 3 Small Q4 ONNX music generation;&lt;/li&gt;
&lt;li&gt;YOLOS Tiny subject detection;&lt;/li&gt;
&lt;li&gt;MODNet portrait matting;&lt;/li&gt;
&lt;li&gt;MI-GAN object removal;&lt;/li&gt;
&lt;li&gt;NanoVSR image and video enhancement;&lt;/li&gt;
&lt;li&gt;vocal and accompaniment separation;&lt;/li&gt;
&lt;li&gt;JoyVASA and LivePortrait digital-human workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Models are loaded only when a feature needs them and are reused from browser caches. Owned Hugging Face and ModelScope mirrors can provide pinned model revisions while sharing a provider-independent cache identity where possible.&lt;/p&gt;

&lt;p&gt;Local-first execution reduces remote inference cost and helps keep unpublished media on the creator's device.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Completion means more than “export succeeded”
&lt;/h2&gt;

&lt;p&gt;A completed editing request normally produces both artifacts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output/
├── result.mp4
└── result.timeline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before delivery, the Skill verifies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Visuals continuity and clip ordering;&lt;/li&gt;
&lt;li&gt;transition and overlay timing;&lt;/li&gt;
&lt;li&gt;caption-to-speech relationships;&lt;/li&gt;
&lt;li&gt;the presence of real audible audio;&lt;/li&gt;
&lt;li&gt;output dimensions, duration, and container;&lt;/li&gt;
&lt;li&gt;full video decoding;&lt;/li&gt;
&lt;li&gt;the absence of repeated tails or stalled boundaries;&lt;/li&gt;
&lt;li&gt;successful reopening of the &lt;code&gt;.timeline&lt;/code&gt; archive;&lt;/li&gt;
&lt;li&gt;archived media resolution and first-frame preview.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The render and editable project must both be usable. A single opaque output file is not considered sufficient for a complete editing task.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Current boundaries
&lt;/h2&gt;

&lt;p&gt;The browser editor already provides multi-track editing, AI captions, speech, music, visual processing, and rich composition.&lt;/p&gt;

&lt;p&gt;The command runner can inspect and modify &lt;code&gt;.timeline&lt;/code&gt; projects and render its documented portable Visuals + Voiceover + Music subset. Rich captions, stickers, complex overlays, some effects, and AI generation may still require the browser editor.&lt;/p&gt;

&lt;p&gt;The current architecture is best summarized as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stable command layer + browser compatibility layer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This boundary is intentional. The project does not describe UI automation as deterministic headless execution, and the command registry can expand without blocking users from accessing editor features today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Timeline Studio's Agent Skill is not primarily about teaching an Agent to click through a video editor. It defines a production protocol for understanding media, recording editorial decisions, applying safe timeline mutations, and verifying the result.&lt;/p&gt;

&lt;p&gt;Its key ideas are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multimodal media analysis;&lt;/li&gt;
&lt;li&gt;content-specific editing workflows;&lt;/li&gt;
&lt;li&gt;declarative timeline operations;&lt;/li&gt;
&lt;li&gt;revision checks, transactions, and idempotency;&lt;/li&gt;
&lt;li&gt;browser-local AI inference;&lt;/li&gt;
&lt;li&gt;portable, editable &lt;code&gt;.timeline&lt;/code&gt; projects;&lt;/li&gt;
&lt;li&gt;validation of both the rendered video and the underlying project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI does not need to remove the creator from the process. It can remove the repetitive work while preserving human control over facts, taste, and final editorial decisions.&lt;/p&gt;

&lt;p&gt;Explore the reproducible examples:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MartinDelophy/timeline-studio-handbook" rel="noopener noreferrer"&gt;Timeline Studio Skills Handbook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Install, run, deploy, or contribute:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;Timeline Studio main repository&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ai</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Running OpenVoice V2 in the Browser with FP16 ONNX, WebGPU, and IndexedDB</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Thu, 06 Aug 2026 08:25:18 +0000</pubDate>
      <link>https://dev.to/martindelophy/running-openvoice-v2-in-the-browser-with-fp16-onnx-webgpu-and-indexeddb-50kl</link>
      <guid>https://dev.to/martindelophy/running-openvoice-v2-in-the-browser-with-fp16-onnx-webgpu-and-indexeddb-50kl</guid>
      <description>&lt;p&gt;I recently completed a browser-local, multilingual voice-cloning workflow for Timeline Studio.&lt;/p&gt;

&lt;p&gt;The reference recording is not sent to an inference server. Audio decoding, speaker embedding extraction, tone-color conversion, preview, persistence, and timeline replacement all run inside the browser.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This post is an engineering record of the production workflow: model packaging, audio preprocessing, WebGPU and WASM execution, workers, cache behavior, tail cleanup, IndexedDB persistence, and the precision decision behind the shipped FP16 build.&lt;/p&gt;

&lt;h2&gt;
  
  
  The product workflow
&lt;/h2&gt;

&lt;p&gt;The feature is deliberately split into two stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Text input
    ↓
Select language and base TTS voice
    ↓
Generate source speech
    ↓
Upload or record a reference voice
    ↓
Extract the target speaker embedding
    ↓
Run OpenVoice V2 tone-color conversion
    ↓
Preview the converted result
    ↓
Save to My assets or replace the current timeline clip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TTS owns pronunciation, language, prosody, and linguistic content. OpenVoice V2 performs the second-stage speaker tone-color transfer.&lt;/p&gt;

&lt;p&gt;For Japanese text, the source speech is generated with a Japanese TTS voice. English uses an English source voice, and other supported languages follow the same route. A saved speaker profile can therefore be reused across languages without asking the converter to generate linguistic content itself.&lt;/p&gt;

&lt;p&gt;This separation also keeps the editing workflow predictable: users can verify the base pronunciation first, then verify the cloned tone color as a separate operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model packaging
&lt;/h2&gt;

&lt;p&gt;The browser build uses an FP16 ONNX export of the OpenVoice V2 converter. The runtime is split into two artifacts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Artifact&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reference Encoder&lt;/td&gt;
&lt;td&gt;1,637,269 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Converter&lt;/td&gt;
&lt;td&gt;64,314,222 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total&lt;/td&gt;
&lt;td&gt;65,951,491 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The total download is approximately 65.95 MB, or 62.9 MiB.&lt;/p&gt;

&lt;p&gt;The artifacts are hosted in project-owned Hugging Face and ModelScope mirrors and pinned to immutable provider revisions. Chinese and domestic sessions prefer ModelScope, while other sessions prefer Hugging Face. If the preferred provider fails, the loader falls back to the other mirror.&lt;/p&gt;

&lt;p&gt;Both providers map to one provider-independent cache identity. Switching download sources does not create duplicate local copies of the same model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audio preprocessing
&lt;/h2&gt;

&lt;p&gt;Uploaded files and browser recordings are decoded with the Web Audio API. Before inference, the runtime performs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mono downmixing;&lt;/li&gt;
&lt;li&gt;resampling to 22,050 Hz;&lt;/li&gt;
&lt;li&gt;conversion to internal Float32 PCM;&lt;/li&gt;
&lt;li&gt;level normalization;&lt;/li&gt;
&lt;li&gt;silence and low-energy tail analysis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenVoice does not receive the raw waveform directly in this browser pipeline. The worker computes a short-time Fourier transform with the following parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sample rate:  22,050 Hz
FFT size:     1,024
Hop length:   256
Frequency:    513 bins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reference encoder input is arranged as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, frameCount, 513]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The converter spectrogram uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 513, frameCount]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remaining converter inputs are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Frame mask:          [1, 1, T]
Source embedding:    [1, 256, 1]
Target embedding:    [1, 256, 1]
Noise:               [1, 192, T]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The noise tensor is generated from a deterministic seed. This makes repeated runs easier to reproduce during browser and audio-quality validation.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebGPU and WASM execution
&lt;/h2&gt;

&lt;p&gt;Inference runs through ONNX Runtime Web.&lt;/p&gt;

&lt;p&gt;The reference encoder is small and uses WASM. The converter prefers WebGPU and falls back to a WASM-only session if WebGPU session creation fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reference Encoder → WASM
Converter         → WebGPU
                 ↘ WASM fallback
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The relevant runtime configuration is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graphOptimizationLevel = "all"
WebGPU powerPreference = "high-performance"
WASM SIMD = true
WASM threads = 1–4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WASM multithreading is enabled only when the page is cross-origin isolated. This avoids promising a multithreaded execution path on pages where the required browser isolation headers are unavailable.&lt;/p&gt;

&lt;p&gt;Model bytes are downloaded in parallel, but inference sessions are initialized serially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Model downloads:      parallel
Session initialization: serial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parallel downloads reduce network wait time. Serial session creation limits the temporary memory pressure caused by constructing multiple ONNX sessions simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping inference away from the UI thread
&lt;/h2&gt;

&lt;p&gt;STFT processing and model inference can block scrolling, button feedback, and timeline interactions when executed on the main thread.&lt;/p&gt;

&lt;p&gt;The complete inference path therefore runs in a dedicated Web Worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Main thread
  │
  ├─ transfers PCM, configuration, and embeddings
  │
Web Worker
  ├─ computes STFT
  ├─ runs Reference Encoder
  ├─ runs Converter
  ├─ performs audio postprocessing
  └─ transfers converted PCM back
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PCM buffers use transferable ArrayBuffers, avoiding copies of large Float32 arrays between the UI and inference contexts.&lt;/p&gt;

&lt;p&gt;Cancellation terminates the active worker and rejects pending requests. A boolean cancellation flag alone cannot reliably interrupt an ONNX call that is already executing.&lt;/p&gt;

&lt;p&gt;The initialized worker remains alive for repeated conversions on the same page, so a second conversion does not present itself as another model setup operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing the quiet audio tail
&lt;/h2&gt;

&lt;p&gt;During testing, some converted clips contained a long, very quiet tail after the actual speech ended.&lt;/p&gt;

&lt;p&gt;This can come from residual low-energy output around padded spectrogram frames and waveform reconstruction. Cutting every result at a fixed duration would also remove natural word endings, so the cleanup is based on RMS activity.&lt;/p&gt;

&lt;p&gt;The current parameters are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RMS window:          20 ms
RMS hop:             10 ms
Minimum useful peak: 0.0025
Activity threshold:  max(0.0015, peakRms × 0.035)
Tail retained:       160 ms
Cosine fade:          40 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The worker scans backward for the final active window, keeps 160 ms of natural tail, and applies a 40 ms cosine fade.&lt;/p&gt;

&lt;p&gt;This removes low-level output that can otherwise continue for several seconds while preserving the audible ending of the sentence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output gain and limiting
&lt;/h2&gt;

&lt;p&gt;Converted audio can be slightly quieter than its source TTS clip. Timeline Studio allows audio-clip volume from 0% to 400%.&lt;/p&gt;

&lt;p&gt;Applying a linear gain of 4.0 without protection would create hard clipping, so the output path uses a soft limiter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Volume range: 0–400%
Limiter:      tanh
Drive:        1.35
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same gain envelope is used by preview and export. The volume control is therefore part of the real audio pipeline rather than a player-only adjustment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speaker profiles in IndexedDB
&lt;/h2&gt;

&lt;p&gt;Reference audio, test results, and extracted embeddings are stored locally in IndexedDB.&lt;/p&gt;

&lt;p&gt;A saved profile can contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id
name
referenceBlob
testBlob
speakerEmbedding
language
favorite
authorization
createdAt
updatedAt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This supports a reusable local voice library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;upload a clean reference recording;&lt;/li&gt;
&lt;li&gt;record a reference voice in the browser;&lt;/li&gt;
&lt;li&gt;test the cloned result;&lt;/li&gt;
&lt;li&gt;save the profile;&lt;/li&gt;
&lt;li&gt;add or remove it from favorites;&lt;/li&gt;
&lt;li&gt;reuse it for later synthesis;&lt;/li&gt;
&lt;li&gt;delete the local profile.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Persisting the speaker embedding means the reference encoder does not need to run again every time the same voice is selected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache quota is not an inference failure
&lt;/h2&gt;

&lt;p&gt;The loader attempts to store model artifacts in a versioned Cache Storage entry. Some browsers and devices can still raise QuotaExceededError for a roughly 66 MB model.&lt;/p&gt;

&lt;p&gt;The important design rule is that a cache write failure must not invalidate model bytes that have already been downloaded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Download model
    ↓
Attempt Cache Storage write
    ├─ success → reuse on later visits
    └─ failure → continue inference from memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application also requests persistent storage when available, reducing the likelihood of automatic cache eviction.&lt;/p&gt;

&lt;p&gt;Users receive a contextual message explaining that the model is running in memory. A raw “Failed to fetch” or quota exception is not exposed as the product error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the production build remains FP16
&lt;/h2&gt;

&lt;p&gt;The released browser model uses FP16.&lt;/p&gt;

&lt;p&gt;ONNX can represent Float8 formats such as E4M3 and E5M2, but current browser WebGPU and WGSL environments do not yet provide a sufficiently stable, general native FP8 execution route for this graph.&lt;/p&gt;

&lt;p&gt;An FP8 artifact may still require parts of the graph to cast or dequantize into FP16 or FP32 at runtime. Shipping that path would require validation of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;additional Cast and Dequantize nodes;&lt;/li&gt;
&lt;li&gt;unsupported operator fallbacks;&lt;/li&gt;
&lt;li&gt;CPU-to-GPU and GPU-to-CPU transfers;&lt;/li&gt;
&lt;li&gt;browser and GPU compatibility;&lt;/li&gt;
&lt;li&gt;changes in speaker similarity, noise, and quiet tails;&lt;/li&gt;
&lt;li&gt;a separate model and cache identity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current release decision is therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Production model: FP16
FP8: isolated experiment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decision is based on the effective browser execution path, not only the number printed on the weight format. FP8 will remain separate until execution coverage and audio behavior can be validated without silently expanding most of the graph back to a wider precision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting conversion to the editing timeline
&lt;/h2&gt;

&lt;p&gt;A completed conversion does not automatically overwrite the current clip.&lt;/p&gt;

&lt;p&gt;After previewing the output, users can explicitly choose to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;save the result to My assets;&lt;/li&gt;
&lt;li&gt;run another conversion;&lt;/li&gt;
&lt;li&gt;replace the current clip;&lt;/li&gt;
&lt;li&gt;restore the original audio;&lt;/li&gt;
&lt;li&gt;download the audio file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replacing a clip preserves its timeline position and editing context while updating the underlying audio asset and duration. A voice-cloning test cannot silently destroy an existing edit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final browser pipeline
&lt;/h2&gt;

&lt;p&gt;The resulting browser-local workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Multilingual TTS
→ browser audio decoding
→ resampling to 22,050 Hz
→ STFT
→ speaker embedding extraction
→ OpenVoice V2 tone-color conversion
→ low-energy tail cleanup
→ gain and soft limiting
→ IndexedDB voice persistence
→ timeline preview and replacement
→ local export
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Converting a model to ONNX was only one part of the implementation. A usable browser feature also needed model delivery, fallback execution, worker transfers, cache degradation, audio cleanup, profile persistence, and safe timeline integration to behave as one coherent system.&lt;/p&gt;

&lt;p&gt;The complete implementation and its development history are available in the repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webgpu</category>
      <category>onnx</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Built an AI Skill That Turns a URL or Raw Footage Into an Editable Video Project</title>
      <dc:creator>MartinDelophy</dc:creator>
      <pubDate>Wed, 05 Aug 2026 11:56:32 +0000</pubDate>
      <link>https://dev.to/martindelophy/i-built-an-ai-skill-that-turns-a-url-or-raw-footage-into-an-editable-video-project-13oa</link>
      <guid>https://dev.to/martindelophy/i-built-an-ai-skill-that-turns-a-url-or-raw-footage-into-an-editable-video-project-13oa</guid>
      <description>&lt;p&gt;AI video tools are getting better at producing output, but many of them still have the same limitation: they give you a finished MP4 and very little control over what happens next.&lt;/p&gt;

&lt;p&gt;If one subtitle is too fast, one voiceover sentence sounds wrong, or one product shot needs a longer pause, the easiest option is often to regenerate the whole video.&lt;/p&gt;

&lt;p&gt;I wanted a different workflow.&lt;/p&gt;

&lt;p&gt;I recently shipped a major upgrade to &lt;strong&gt;Timeline Studio&lt;/strong&gt;, an open-source, browser-based AI video editor. The new workflow can analyze a website, images, or raw footage, create a first cut, and export both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a finished video ready to publish&lt;/li&gt;
&lt;li&gt;an editable &lt;code&gt;.timeline&lt;/code&gt; project for future revisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is simple: let AI handle the time-consuming first draft, while the creator keeps control of the final edit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Skill can do
&lt;/h2&gt;

&lt;p&gt;After installing the Timeline Studio Skill, you can describe the result you want in natural language.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyze this website and create a product introduction video.
Use a professional and energetic English female voice.
Target roughly 60 seconds in 16:9.
If login is required, ask me before continuing.
Export the final video and an editable .timeline project.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Skill can then plan the content, create a narration, generate synchronized subtitles, select scenes, add background music, and apply visual emphasis.&lt;/p&gt;

&lt;p&gt;It supports several editing scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;talking-head and voice-driven videos&lt;/li&gt;
&lt;li&gt;website and SaaS walkthroughs&lt;/li&gt;
&lt;li&gt;product or brand promotion&lt;/li&gt;
&lt;li&gt;image-based videos&lt;/li&gt;
&lt;li&gt;long-form content condensation&lt;/li&gt;
&lt;li&gt;tutorials&lt;/li&gt;
&lt;li&gt;highlights and short-form clips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The editing strategy changes with the content instead of applying the same template to every project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Website promotion is more than screen recording
&lt;/h2&gt;

&lt;p&gt;For a website introduction, recording a browser session is not enough.&lt;/p&gt;

&lt;p&gt;The system first explores the publicly accessible pages and tries to understand the product, information structure, and most important features. If the key experience requires an account, it asks the user for access instead of inventing conclusions from the landing page.&lt;/p&gt;

&lt;p&gt;The resulting video can combine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stable page recordings&lt;/li&gt;
&lt;li&gt;smooth keyframed zooms&lt;/li&gt;
&lt;li&gt;lines that guide the viewer's attention&lt;/li&gt;
&lt;li&gt;a small number of accurately positioned highlights&lt;/li&gt;
&lt;li&gt;subtitles and narration aligned with the visible action&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We deliberately avoid drawing boxes around everything. Too many highlights make the video feel noisy and reduce their value.&lt;/p&gt;

&lt;p&gt;Instead, the Skill chooses between three visual treatments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zoom&lt;/strong&gt; for a core feature, result, or chart&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guide line&lt;/strong&gt; for buttons, text, and reading direction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frame&lt;/strong&gt; for a clearly bounded area that genuinely needs emphasis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical move is a smooth zoom in, a short hold, and a controlled zoom out. The camera should feel intentional and stable rather than shaky.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voiceover becomes the timing source
&lt;/h2&gt;

&lt;p&gt;One of the biggest lessons from earlier versions was that forcing narration into an exact duration can make it sound rushed and unnatural.&lt;/p&gt;

&lt;p&gt;The upgraded workflow generates the voiceover at a natural pace first. It then uses the real speech timing to determine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;caption boundaries&lt;/li&gt;
&lt;li&gt;scene changes&lt;/li&gt;
&lt;li&gt;zoom and highlight timing&lt;/li&gt;
&lt;li&gt;music volume automation&lt;/li&gt;
&lt;li&gt;ending space&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A requested duration such as 60 seconds is treated as a target, not a reason to damage the delivery. A clear 54-second or 66-second video is often better than an unnaturally compressed 60-second one.&lt;/p&gt;

&lt;h2&gt;
  
  
  An editable &lt;code&gt;.timeline&lt;/code&gt; v3 project
&lt;/h2&gt;

&lt;p&gt;The most important technical change is the project format.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;.timeline&lt;/code&gt; v3, voiceover is stored as separate sentence-level audio clips rather than one long, difficult-to-edit file. Each caption can reference its corresponding voice clip.&lt;/p&gt;

&lt;p&gt;A simplified representation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"caption"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Career planning should not depend on headlines alone."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"audioClipId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"voice-001"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"audioClip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"voice-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.2&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means you can replace one sentence, regenerate one voice clip, or adjust one subtitle without rebuilding the entire project.&lt;/p&gt;

&lt;p&gt;The project also preserves scenes, captions, voice clips, music, overlays, effects, and animation settings. The MP4 solves today's publishing need; the project file solves tomorrow's revision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing playback loops at clip boundaries
&lt;/h2&gt;

&lt;p&gt;The upgrade also addresses an editor playback issue where a segment could repeat near a clip boundary.&lt;/p&gt;

&lt;p&gt;Individual media elements are not always reliable as the master timeline clock. Decode delays and small rounding differences can cause time to move backward or make two neighboring clips appear active at the same boundary.&lt;/p&gt;

&lt;p&gt;Timeline Studio now uses a monotonic timeline wall clock as the master and synchronizes media against it. Clip activity is evaluated using half-open intervals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[start, end)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That prevents the previous clip and next clip from both being selected at the exact same timestamp.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Skill
&lt;/h2&gt;

&lt;p&gt;You can install the current release with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add MartinDelophy/ai-video-editor@v0.9.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/MartinDelophy/ai-video-editor" rel="noopener noreferrer"&gt;https://github.com/MartinDelophy/ai-video-editor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://video-editor.ai-creator.top" rel="noopener noreferrer"&gt;https://video-editor.ai-creator.top&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal is to produce a strong first cut in the time it takes to finish a coffee, without turning the result into a black box.&lt;/p&gt;

&lt;p&gt;AI performs the repetitive first-pass work. The creator still owns the timeline, the details, and the final decision.&lt;/p&gt;

&lt;p&gt;Feedback and contributions are welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
