PICKUP

A horror short · 4 parts · 3 endings

Dad is driving you home. Then Dad calls.

Where are you, son? I’m outside, waiting for you. The GPS is taking you into the woods. The doors are locked. You get three seconds to decide what to do.

  • 3:33 in total
  • One hidden ending
  • Drawn and scored in code
Playable right here. Sound on, about 90 seconds.

Watch

Start with Part 1. Then choose.

Part 1

The Ride

1:20

Practice is over and it’s pouring. Dad picks you up. Then your phone buzzes, and it’s Dad.

What do you do?

Each choice opens a different ending. Spoilers, so watch Part 1 first.

How it’s made

Every frame is drawn by code.

PICKUP is a single HTML file. About 1,500 lines of JavaScript draw every frame on a canvas: the rain on the windshield, the dashboard glow, the GPS screen and all 34 of the mimic’s teeth. There is no camera, no stock footage and no AI-generated art.

Every sound is generated live with the Web Audio API. The rain is filtered noise. The engine is two sawtooth waves a hair apart in pitch. Each voice is a string of short beeps, and the mimic’s beeps jump an octave at random. The four videos were rendered frame by frame from the same code.

// the mimic's grin: up to 17 teeth per row, top row hangs down, bottom row points up
const n = Math.round(lerp(5, 17, k));
for (let i = 0; i < n; i++){
  const u0 = i / n, u1 = (i + 1) / n, um = (i + .5) / n;
  const x0 = lerp(L, R, u0), x1 = lerp(L, R, u1), xm = lerp(L, R, um);
  c.beginPath(); c.moveTo(x0, qy(u0, top, cTop) - 3); c.lineTo(x1, qy(u1, top, cTop) - 3); c.lineTo(xm, qy(um, top, cTop) + h * .38); c.closePath(); c.fill(); c.stroke();
  c.beginPath(); c.moveTo(x0, qy(u0, top, cBot) + 3); c.lineTo(x1, qy(u1, top, cBot) + 3); c.lineTo(xm, qy(um, top, cBot) - h * .34); c.closePath(); c.fill(); c.stroke();
}
Lines of JavaScript
1,469
Shots
29
Running time
3:33
Video
1080 × 1920, 30 fps
Sound effects
19, synthesized
Voices
6, all beeps
Endings
3, one hidden