making movies in the terminal

2 min read

A terminal can do a lot with a few words and a pause. A line appears, hesitates, and corrects itself. You read the correction differently because you watched it happen.

I made featurette, a TypeScript library for short films in the terminal. You write scenes as async functions, deciding what appears and when. It handles drawing and playback.

write a scene

Here's a small intermission. The message starts out confident about when it'll be back:

intermission
The words “back in five minutes.” appear, pause, and change to “back in a little while.”

This is the code behind it:

import { defineFilm, play } from 'featurette';

const film = defineFilm({
  title: 'Intermission',
  minSize: { columns: 40, rows: 10 },
});

film.scene('intermission', async ($) => {
  await $.type('back in five minutes.', {
    at: $.center(),
  });
  await $.beat(1200);
  await $.backspace('five minutes.'.length);
  await $.type('a little while.');
  await $.beat(1600);
});

await play(film);

Save it as film.mjs. Use Node.js 20.19 or newer and a terminal at least 40 columns wide and 10 rows tall:

npm install featurette
node film.mjs

The $ object gives the scene its drawing, timing, and input controls. Each await lets the current action finish before the next one begins; beat(1200) holds the sentence for 1.2 seconds.

Try shortening that pause. Then make it much longer. The words stay the same, but the correction starts to feel different.

more than a line of text

A film's scenes play in order. Voices give characters their own color and typing speed. Layers let dialogue share a screen with a starfield, a glitch, or whatever you draw.

Some effects borrow from the terminal itself: you can stage a test run, stream fictional logs, or act out a merge conflict. A keypress can skip to the next scene, and even Ctrl+C can have a scripted goodbye. The usage guide covers those pieces.

leave the terminal as you found it

Playback temporarily takes over the terminal. When playback ends, featurette restores the cursor and input mode so you can carry on using the shell.

Resize policies include cropping, letterboxing, and switching to a transcript. It also supports reduced motion and automatically writes a plain-text transcript when output goes to a file or pipe.

something to watch

I made pidling with featurette. Open a terminal and run:

npx pidling

← all posts