TypeWritter Start a project
Live — not a video loop

Code that types itself. Then a terminal answers back.

A dependency-free engine that replays real, syntax-highlighted source one keystroke at a time — autocomplete popovers, pasted secrets, a live gutter and status bar — then hands the last character to a shell that runs it. Everything on the right is the DOM, typing itself, right now.

Read the API
13 KB one file 0 dependencies No build step Any framework

3 files Pick a tab to run another scene — it restarts cleanly, mid‑keystroke.

13 KB One unminified file. Drop in a <script> tag and you're done.
0 Dependencies, bundlers, frameworks or build steps.
50–150ms Randomised per keystroke, so the cadence reads as a person, not a metronome.
2 Panes driven in one sequence — the editor, then the shell.

Capabilities

Six behaviours a screen recording can't give you.

A GIF can't be edited, resized, or read aloud.

Every frame here is live DOM: real text, real colours, selectable, searchable, and sharp on any display. That opens up six things a recording physically cannot do.

Typing

It types inside the highlight

Most typewriter effects print plain text and colour it afterwards. This one walks the highlighted markup itself — opening each token span, then filling it character by character. const is orange from its very first letter.

<span class="token keyword"> → c co con cons const
IntelliSense

Autocomplete that has to hunt

Give a token a list of candidates and the one it should land on. A popover opens at the caret, scrolls past the wrong guesses one at a time, then accepts the right one — the exact rhythm of an editor reading your mind a beat too slowly.

average → random → text → plaid → paymentIntents
Paste

Nobody types an API key

Tag a token with data-paste and it lands whole, in a single frame, with the column counter jumping to match. The small honesty that keeps the whole performance believable.

'sk_test_BQokikJOvBi2Hl4olfQ2' ← one frame
Gutter

Line numbers that keep up

Rows fill in as the caret crosses each newline; the rest hold vim's - placeholder. The row count is measured from the container at construction, so the gutter fits whatever height you hand it.

1 2 3 4 - - - - - - - -
Status bar

A status bar that means it

Mode, filename, line and column all read from the same cursor the typing runs on. Nothing is hardcoded — scrub the speed and the numbers stay honest.

NORMAL server.js ln 4:18
Handoff

Then the shell takes over

When the last character lands, the terminal picks up the beat: commands type at shell cadence, output streams in line by line. One continuous performance from first keystroke to exit code.

$ npm run dev ready in 412 ms

How it works

Markup in, performance out. Three moves, no configuration file.

The source is the storyboard.

There is no timeline to author and no keyframes to sync. You paste in the highlighted HTML you already have, flag the two or three tokens that deserve special treatment, and the engine derives the whole performance from it.

STEP 1

You write ordinary markup

Drop in the syntax-highlighted HTML you'd get from Prism, highlight.js, or copy-with-formatting out of your own editor. Nothing about it is special — it renders as a normal, readable code block with JavaScript switched off.

STEP 2

The engine reads it as a stream

On construction it lifts that markup out of the <pre>, blanks the element, and walks the source one character at a time — telling tag syntax from text, rebuilding each span the moment it closes, decoding entities as single keystrokes, and stopping on the tokens you flagged to run a paste or an autocomplete.

STEP 3

The shell takes the last keystroke

Every line in the console block is replayed in order: command lines type at shell cadence, output lines simply appear. When the last one lands the sequence rests, then rolls into the next file — indefinitely, and only while it's on screen.

What you writeHTML
<pre class="actual-code" id="CodeToAnimate">
<span class="token keyword">const</span> stripe =
  require('stripe')(<span
     class="token string"
     data-paste="'sk_test_BQokik…'">'sk_test_BQokik…'</span>);

<span class="token keyword">await</span> stripe.<span
     data-has-options="average,random,paymentIntents"
     data-find-option="paymentIntents">paymentIntents</span>
</pre>

<div class="console">
  <div class="single-line command-input">
    <span class="command">node server.js</span>
  </div>
</div>
What playsTimeline
  • 0.00sconst types letter by letter, orange from the first keypress
  • 1.10sSpaces cost nothing; words carry a randomised 50–150 ms delay
  • 2.40sThe secret arrives whole — one frame, column counter jumps
  • 4.05sPopover opens at the caret; wrong guesses scroll past at 200 ms each
  • 5.30spaymentIntents is accepted, popover dismissed, typing resumes
  • 8.60sLast character lands — the terminal takes the beat

Integrate

One constructor, five options, three attributes. That's the whole surface.

Small enough to read in a coffee break.

The entire public API is a constructor, .start() and .stop(). Everything else is expressed in the markup, where it belongs — and the file that runs this page is the same one you would drop into yours.

index.htmlSetup
<script src="TypeWritter.js"></script>
<script>
  const tw = new TypeWritter('#CodeEditor', {
    typeSpeed:       100,
    typeSpeedOffset: 50,
    optionNextDelay: 200,
    codeLineHeight:  18
  });

  tw.start();
</script>

Options

OptionDefaultWhat it controls
typeSpeed100 Upper bound of the random delay added to each keystroke, in milliseconds.
typeSpeedOffset50 The floor under that random delay, so no character ever appears instantly.
optionNextDelay200 How long the autocomplete popover dwells on each wrong suggestion before moving on.
codeLineHeight18 Line height used to work out how many gutter rows fit the container.
scenes Optional list of files to cycle through, each with its own markup and shell transcript — what drives the three tabs above. Leave it out and the engine animates whatever markup the <pre> was authored with.

Markup attributes

AttributeGoes onEffect
data-pasteany token span Inserts the whole value in one frame instead of typing it, then continues.
data-has-optionsany token span Comma-separated candidates to show in the autocomplete popover.
data-find-optionalongside the above The candidate it scrolls to and accepts. Must match the span's own text.
.command-inputa console line Marks a shell line to be typed. Every other line simply appears.

Where it fits

Anywhere a developer needs to understand something in four seconds.

Built for the moment someone decides to keep reading.

Product heroes

The first screen of a developer tool, showing the shortest path from install to result.

Quickstarts

Docs that demonstrate the happy path before asking anyone to copy anything.

Launch films

Screen-record the page at any resolution — the type is vector-sharp at 4K.

Conference talks

A slide that writes its own example while you talk over it, at a speed you set.

Onboarding tours

Walk a new user through the first API call without them touching a keyboard.

Changelogs

Show the diff behaving, not a still of it, next to the release note.

Colophon

This page wears the editor's theme. Every hue keeps the job it has in the code.

The palette isn't decoration — it's the syntax theme.

#6AE3B1Mode block, primary actions, accepted state
#FF6541Keywords, and exactly one headline word
#66D9EFOperators, shell prompts, section emphasis
#CA94FFNumbers, and every metric on the page
#E6DB74Strings and inline literals
#72C05DFunctions and healthy processes

Type is Archivo, driven along its width axis — headlines run expanded and heavy, body copy sits at normal width — with JetBrains Mono carrying every machine voice: labels, the gutter, the status bar and the shell.

Available for new work

I build the parts of a product people screenshot.

This engine started as one section of one client's homepage — a brief that said "like Stripe, but ours." It became a reusable piece of interface machinery, and it still runs everywhere it was installed. If you have a front-end that needs to feel alive — animation systems, product demos, design-led marketing sites, interfaces with real motion design behind them — that's the work I want.