<?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: Atomcut</title>
    <description>The latest articles on DEV Community by Atomcut (atomcut).</description>
    <link>https://dev.to/atomcut</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%2Forganization%2Fprofile_image%2F14797%2F847e4ee7-bbb5-4194-b1d0-55274b6510d4.png</url>
      <title>DEV Community: Atomcut</title>
      <link>https://dev.to/atomcut</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/atomcut"/>
    <language>en</language>
    <item>
      <title>Add animated captions to a video in the browser, free</title>
      <dc:creator>Shayan</dc:creator>
      <pubDate>Wed, 16 Sep 2026 16:46:46 +0000</pubDate>
      <link>https://dev.to/atomcut/add-animated-captions-to-a-video-in-the-browser-free-1pg1</link>
      <guid>https://dev.to/atomcut/add-animated-captions-to-a-video-in-the-browser-free-1pg1</guid>
      <description>&lt;p&gt;AtomCut adds word-by-word, karaoke-style captions to a video in your browser: you type the words, cut them into cues, sync the timing, style the active word, and export an MP4. AtomCut is a free motion design and video editor that runs in the browser, no account, no install.&lt;/p&gt;

&lt;p&gt;There's one thing it doesn't do yet: it doesn't listen to your audio and write the words for you. You type the script, and you time it. That's slower than a one-click auto-transcribe, and it's also why the timing is exactly what you want and not what a speech model guessed.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Import your clip
&lt;/h2&gt;

&lt;p&gt;Drag your video onto the canvas, or use &lt;strong&gt;Import media&lt;/strong&gt; in the Media panel and then &lt;em&gt;Place on frame&lt;/em&gt;. It lands on its own track with its sound attached; the composition below is a 1920×1080 frame, but a vertical 1080×1920 reel is one click away in the new-project dialog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faq84nxxeuuyseh35lbyy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faq84nxxeuuyseh35lbyy.webp" alt="The AtomCut studio: a talking-head clip on the canvas, the caption above it on Track 1 and the video on Track 3 in the timeline" width="800" height="470"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The whole studio. The caption sits on the track above the video, so it draws on top.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Type the words as a text layer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;+ Clip → Text&lt;/strong&gt; in the timeline header adds a text layer at the playhead. Open &lt;em&gt;Content&lt;/em&gt; in the inspector and type what's said, exactly as it's said. This is the one string every caption cue will be a span of, so get the words right here.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Turn it into a caption and cut it into cues
&lt;/h2&gt;

&lt;p&gt;In the same &lt;em&gt;Content&lt;/em&gt; section, switch on &lt;strong&gt;Captions&lt;/strong&gt;. That seeds one cue per word across the clip and gives the spoken word a highlight you can see immediately. (There's also &lt;strong&gt;+ Clip → Caption&lt;/strong&gt; if you'd rather start with a caption and type into it.)&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Cues&lt;/strong&gt; tab appears on the right rail. Its &lt;em&gt;re-cut&lt;/em&gt; menu recuts the same text one word per cue, one line per cue, or one letter per cue; word-level is the karaoke look most people want. Each cue is a span of your original string, so retyping a word in the cue list later doesn't touch any other cue's timing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftiy3qk188oygc6xi6z4c.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftiy3qk188oygc6xi6z4c.webp" alt="The caption selected on the canvas with the Animate tab open: a Scale In animation per word, 260 ms, with its easing curve" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A caption is a text layer, so it takes any text animation: here Scale In, per word.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Time the cues
&lt;/h2&gt;

&lt;p&gt;Two ways to do it. Tap sync plays the clip and lets you tap a button in time with each word, which stamps that cue's start where you tapped. Or spread every cue evenly across the clip's duration with one click, then drag individual cue boundaries by hand where the even spacing is off. You can also give a cue a word from its neighbour, split one cue in two, or merge two into one, all from the same cue list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fno4i341yp8x18olh1fyo.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fno4i341yp8x18olh1fyo.webp" alt="The Cues panel: Tap sync button, re-cut and even controls, and eight word cues with their durations, the fifth one active at the playhead" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Cues panel. The lit row is the word under the playhead.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Style the word being spoken
&lt;/h2&gt;

&lt;p&gt;The inspector for a caption has two scopes at the top: &lt;strong&gt;Text&lt;/strong&gt; (the whole layer) and &lt;strong&gt;Focus&lt;/strong&gt; (the word being spoken). Pick &lt;em&gt;Focus&lt;/em&gt; and every field you touch overrides only that word: its colour, a highlight colour with its own radius and padding, and a &lt;em&gt;Focus pop&lt;/em&gt; scale. The focus is a style range on the same text layer, not a separate object, so it stays attached to its word as you keep editing cues around it.&lt;/p&gt;

&lt;p&gt;For the look in these screenshots we didn't style anything by hand: the Library's &lt;em&gt;Text looks&lt;/em&gt; has a &lt;strong&gt;Captions&lt;/strong&gt; group (Subtitle, Punch, Karaoke, Clean Sub, Boxed, Shout, Ticker, Whisper), and &lt;em&gt;Karaoke&lt;/em&gt; applied to the selected layer gives the green band with the spoken word switching to white. A caption look carries its own idea of the spoken word, so applying one restyles the lit word too. Everything else in the caption can carry its own reveal preset and stagger, the same system that drives any AtomCut text animation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9hdv8km258150g4eypxw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9hdv8km258150g4eypxw.webp" alt="The Focus scope of the caption inspector: four highlight overrides (colour, radius, padding) and a Focus pop scale of 106 %" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Focus scope: the overrides that apply only to the word being spoken.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Export
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://atomcut.net/docs/exporting" rel="noopener noreferrer"&gt;Export&lt;/a&gt; as MP4, WebM or GIF. Every export is free with no watermark, capped at 720p; the one-time $29 adds HD, 4K and transparent export if you need more than social-post resolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh5fkr9ftd5sws1dr1cq4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh5fkr9ftd5sws1dr1cq4.webp" alt="The Export dialog on the Video tab: MP4 video, 720p HD, 30 fps, include sound on" width="800" height="916"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Export, Video tab. 720p is the free ceiling; the one-time licence unlocks the sizes above it.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AtomCut does not transcribe your audio. There's no speech-to-text step: you type the caption's text yourself and time the cues by tapping along or dragging, rather than getting a rough auto-transcript to clean up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Questions people ask
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does AtomCut transcribe my audio automatically?&lt;/strong&gt;&lt;br&gt;
No. You type the words as a text layer, then convert them to a caption and cut them into cues. If you already have an SRT or a transcript, you'd paste the text in and time the cues from there rather than importing timed subtitles directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I give one word a different look from the rest?&lt;/strong&gt;&lt;br&gt;
Yes. Select a run of letters or words in the caption and give that span its own animation or style, independent of the rest of the layer, without splitting it into a separate text layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this work on a tablet?&lt;/strong&gt;&lt;br&gt;
The drawing and timeline tools share one workspace at every size, so tap-syncing cues works the same on a tablet as it does with a mouse.&lt;/p&gt;

&lt;p&gt;Once your cues are timed, the next thing worth trying is a sound on every word instead of just a style change — see &lt;a href="https://atomcut.net/blog/kinetic-typography-with-sound" rel="noopener noreferrer"&gt;kinetic typography with a sound per letter&lt;/a&gt; or the full reference at &lt;a href="https://atomcut.net/docs/text-animation" rel="noopener noreferrer"&gt;/docs/text-animation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://app.atomcut.net" rel="noopener noreferrer"&gt;app.atomcut.net&lt;/a&gt; — free, no account, works offline.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>video</category>
      <category>tutorial</category>
      <category>design</category>
    </item>
    <item>
      <title>I built a motion design studio in the browser. Here's what it took.</title>
      <dc:creator>Shayan</dc:creator>
      <pubDate>Wed, 16 Sep 2026 15:46:53 +0000</pubDate>
      <link>https://dev.to/atomcut/i-built-a-motion-design-studio-in-the-browser-heres-what-it-took-3ic1</link>
      <guid>https://dev.to/atomcut/i-built-a-motion-design-studio-in-the-browser-heres-what-it-took-3ic1</guid>
      <description>&lt;p&gt;&lt;a href="https://atomcut.net" rel="noopener noreferrer"&gt;AtomCut&lt;/a&gt; started as a tool that was supposed to animate text. Today it's an infinite canvas above a multi-track timeline, in the browser, where you can keyframe anything, paint with a wet watercolour brush, track motion, add captions that follow a voice, and export to MP4, GIF, SVG or Lottie. It's free, there's no account, and it works offline.&lt;/p&gt;

&lt;p&gt;This is the honest version of how it got there, because the tidy version ("I had a vision and executed") isn't useful to anyone building something ambitious on their own time.&lt;/p&gt;

&lt;h2&gt;
  
  
  It started as a typing animation
&lt;/h2&gt;

&lt;p&gt;The folder is still called &lt;code&gt;typomation&lt;/code&gt;. The first thing it did was type words onto a frame, one letter at a time, with a sound on each keystroke, so a short clip could have a title that arrived the way a typewriter would put it there.&lt;/p&gt;

&lt;p&gt;The problem with a tool that only does one thing well is that the second thing you need is always outside it. I needed a background clip under the text. Then a sound on each letter. Then the text had to move along a path. By the time I had those, I had a timeline that didn't care what kind of clip sat on it, and the question stopped being "what should a text tool do" and became "what is the smallest set of ideas that makes everything else a special case".&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule everything else hangs on
&lt;/h2&gt;

&lt;p&gt;Anything that describes &lt;em&gt;what&lt;/em&gt; an animation is lives in a pure package with no DOM and no React. Anything that describes &lt;em&gt;how it's shown or edited&lt;/em&gt; lives in the app. That's the whole architecture, and every good week I had came from it.&lt;/p&gt;

&lt;p&gt;Concretely: a project is one JSON document, validated with zod, versioned. The document is at schema version 71 today, and every one of those migrations still runs, so a project from the first month opens. Rendering a frame is a pure function: &lt;code&gt;(document, time) → what you see&lt;/code&gt;. Playback, scrubbing, the MP4 exporter, the PNG sequence exporter and the Lottie exporter all call the same function. There is no "export renderer" that drifts from the "preview renderer", because there's only one.&lt;/p&gt;

&lt;p&gt;Undo is patches, not snapshots. Every mutation runs through one store that records a forward patch and an inverse patch. Undo cost is proportional to the size of the change, not the size of the project, and a continuous gesture (dragging a keyframe for two seconds) coalesces into one history entry.&lt;/p&gt;

&lt;p&gt;None of this is novel. It's the same shape Figma and Photoshop ended up at. What I'm saying is that if you &lt;em&gt;start&lt;/em&gt; there, a lot of features become a union variant and a registry row instead of a rewrite. A group on the timeline is a clip that happens to contain rows. A caption is a text clip with a cue map. A flipbook is a nested composition whose cells are drawings. When the primitives are right, the feature list grows without the codebase growing the same way.&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%2Ftbmoicuul7hr6w1ez9ju.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%2Ftbmoicuul7hr6w1ez9ju.png" alt="The AtomCut studio: a 9:16 frame on the canvas with a caption whose first word is lit at the playhead, the timeline below with a text clip and a caption clip on one track, and the typography inspector open for the two selected layers" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The studio: canvas above, timeline below. Two layers selected, the caption&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What was actually hard
&lt;/h2&gt;

&lt;p&gt;Not the effects. Thirty-six layer effects sounds like the hard part; it's the easy part, because an effect is a shader and a settings card, and the keyframe engine already animates any number.&lt;/p&gt;

&lt;p&gt;The hard parts were the ones where two true things fight:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A cropped video has two things you can move.&lt;/strong&gt; The window and the picture inside it. If you store that as one transform plus four insets, every keyframed reframe visibly swims between keys, because three animated quantities cancel to a constant that the interpolation doesn't know about. The fix was two transforms, one for the window and one for the content, and a rule that the content transform never reads the crop. It took a week to see that the bug was in the data model and not in the interpolation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A mirrored layer is a negative scale, and nothing else.&lt;/strong&gt; I had a &lt;code&gt;flipX&lt;/code&gt; flag for a while. A flag plus a sign is two fields for one fact, and they disagreed the moment a keyframe interpolated across a flip. Deleting the flag deleted a family of bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A frame rate is a grid, never a time.&lt;/strong&gt; There is no project-wide fps. Each composition carries its own, and a rate only ever quantises: it's what the ruler ticks on, what the arrow keys step by, what export iterates on. A 12 fps flipbook inside a 60 fps comp holds each cell for 83.33 ms and nothing resamples anything, so nothing can drift. The earlier version had a global rate plus overrides, and half the app read one while half read the other.&lt;/p&gt;

&lt;p&gt;The crop one cost the most. I fixed the interpolation three times before I admitted the data was wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The changelog is the spec
&lt;/h2&gt;

&lt;p&gt;Every change has to earn one line in a public changelog, written before the code: what can a user do now that they couldn't before. If I can't write that line, the change doesn't ship. It sounds like process; it's actually the fastest way I've found to kill work that only feels productive. Half of what I started never got its line.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it's bad at
&lt;/h2&gt;

&lt;p&gt;Cutting a two-hour 4K timeline. It renders in the browser; a native NLE will beat it on heavy footage. It's young, so you will find rough edges; when someone reports one, it's usually fixed in the next release, and you can watch that happen in the changelog.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;It's free and it stays free. Exports are capped at 720p; $29 once, not a subscription, removes the cap. After that, the plan is live collaboration, an assistant inside the editor that can operate the timeline, and the plugin SDK opening up.&lt;/p&gt;

&lt;p&gt;If you make anything with it, I'd like to see it. It opens at &lt;a href="https://app.atomcut.net" rel="noopener noreferrer"&gt;app.atomcut.net&lt;/a&gt; with no signup.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>javascript</category>
      <category>react</category>
    </item>
  </channel>
</rss>
