# VHS Camcorder Look (1987 Home Video) — `vhs-camcorder@1.0.0`

Makes any animation look like a 1980s camcorder tape: soft picture, bleeding colour, tracking noise, a shaky hand and the red-orange date stamp in the corner.

The home-video look behind this autumn's 80s AI trend. Everything you draw is put through a simulated VHS tape: detail goes soft, colour smears to the right of bright things, highlights trail, lines wobble, a band of tracking noise rolls up the frame, white dropouts flick past and the bottom edge tears where the video heads switch. On top comes the camcorder's own display, burned into the picture: a blocky dot-matrix date and time, a blinking REC dot or PLAY and a tape counter. A helper adds the camcorder operator too: handheld drift, a slow zoom creep and the autofocus hunting once. Type your own date, pick the colour cast (warm tungsten, natural or faded old tape) and how worn the tape is. The demo films a spring-break sunset on the beach or a birthday cake with its candles lit; the same code degrades your own canvas, 3D scene or video frame.

- Kind: effect; status: published; digest sha256:b7f58d49eb84005ac19aea7801e303b01cdadbf51f83a6669a6430698a176930
- Role: Full-frame finishing effect (Canvas 2D) plus a camcorder date-stamp overlay and handheld camera move.
- Implementation: canvas2d; entry `src/vhs-camcorder.js`
- Files: https://aipixelwizard.com/registry/vhs-camcorder/1.0.0/<path> (`LICENSE`, `asset.json`, `demo.js`, `index.html`, `src/vhs-camcorder.js`)
- Manifest JSON: https://aipixelwizard.com/api/v1/visuals/vhs-camcorder/versions/1.0.0
- Runnable demo: https://aipixelwizard.com/registry/vhs-camcorder/1.0.0/index.html (open over http; it imports sibling packages by relative path)
- Dependencies (exact): `apw-runtime@1.0.0` (demo) — Demo harness and seeded random numbers. src/vhs-camcorder.js has no dependencies.

## Exports
- `createVHS({ softness?, bleed?, sharpen?, smear?, noise?, wear?, headSwitch?, scanlines?, look?, seed? }) => { apply(ctx, width, height, info) }` — The tape. apply() reads the 2D canvas, degrades it in place (soft luma, bleeding chroma, wobble, tracking band, dropouts, head-switch tear, colour cast) and writes it back.
- `drawCamcorderOSD(ctx, width, height, info, { date?, clock?, mode?, blinkDate?, color?, scale?, counterStart? })` — The camcorder display: dot-matrix date and time bottom right, REC (blinking dot) or PLAY with a tape counter top left. Draw before apply() so it is burned in.
- `camcorderMove(info, { shake?, zoomCreep?, focusHunt?, focusAt?, size?, seed? }) => { x, y, angle, zoom, focusBlur }` — Handheld drift and tremor, a slow zoom creep and one autofocus hunt, as numbers to apply to your scene.
- `drawDotText(ctx, text, x, y, { dot?, color?, shadow?, tracking? }) => width` — Draws any text in the built-in 5×7 dot-matrix camcorder font (A–Z, 0–9, : . - / ' !).

## Parameters
- `scene` (select one of beach | party, default "beach") — Demo picture: What the demo films. Your own project can put anything through the tape.
- `date` (text, default "JUL 12 1987") — Date stamp: Shown bottom right in the camcorder font. Letters, numbers, spaces and : . - / ' ! work.
- `clock` (text, default "6:48 PM") — Time stamp: Shown above the date. Leave empty to hide it.
- `mode` (select one of rec | play | none, default "rec") — Camera display
- `blinkDate` (boolean, default true) — Blink the date
- `stampColor` (color, default "#ff6a1f") — Date stamp colour
- `look` (select one of warm | natural | faded, default "warm") — Colour cast
- `wear` (number 0–1, default 0.35) — Tape wear: Wobble, rolling tracking noise and white dropouts. 0 is a fresh tape.
- `bleed` (number 0–1.5, default 0.8) — Colour bleed: How far colour smears to the right of bright things.
- `softness` (number 0–1.5, default 0.8) — Softness: How much fine detail the tape loses.
- `noise` (number 0–1, default 0.4) — Grain
- `headSwitch` (boolean, default true) — Torn bottom edge: The noisy strip where the video heads switch.
- `shake` (number 0–2, default 1) — Handheld shake
- `zoomCreep` (number 0–0.3, default 0.08) — Zoom creep: How far the camera slowly zooms in over the clip.
- `focusHunt` (boolean, default true) — Autofocus hunts: The picture blurs and snaps back sharp once near the start.
- `seed` (integer 1–9999, default 3) — Variation: Changes the shake, the noise and the details of the demo picture.

## Composition
- Inputs: Canvas 2D context, width, height and the frame info ({ frame, time, duration }). apply() takes whatever is already drawn on the canvas.
- Outputs: apply() replaces the frame with the taped version (opaque). drawCamcorderOSD draws on top without clearing.
- Coordinates: Pixels. Effect sizes are tuned at 1080 wide and scale with the canvas. The display sits 7.5% in from the edges.
- Lighting: None of its own. The colour cast (warm, natural, faded) is applied after decoding the tape.
- Timing: Pure function of info.frame and info.time: noise changes every frame, the tracking band drifts up, REC blinks once a second.
- Works with: kinetic-title, stop-motion-feel, gradient-background, orbit-camera, chrome-orbit
- Draw the date stamp before apply() so it softens and bleeds with the picture, as a real camcorder burned it into the tape. Draw it after apply() for a crisp overlay.
- apply() reads pixels back, so the canvas must be same-origin (no tainted canvas). For three.js, draw the WebGL canvas onto a 2D canvas first, then apply.
- The date and time are plain text you choose; nothing reads the real clock, so renders stay repeatable.

## Output and loop
- 1080×1080, 30 fps, 8 s, procedural
- Seamless loop: no — A continuous handheld take with a zoom creep; it does not loop.
- Verified 2026-10-04 in Chrome 154.0.8037.97 headless on Linux 7.0.0-38-generic (x64), Node 22.14.0 (Canvas 2D); deterministic: yes

## Use it
New project: Create the tape once with createVHS(options). Each frame: draw your scene (optionally transformed by camcorderMove(info)), call drawCamcorderOSD(ctx, width, height, info, { date }), then vhs.apply(ctx, width, height, info).

Existing project: Copy src/vhs-camcorder.js. At the end of your 2D frame call vhs.apply(ctx, width, height, info); add drawCamcorderOSD just before it for the date stamp. For WebGL, copy the WebGL canvas onto a 2D canvas each frame and apply there.

Reuse ideas:
- Make the 80s AI photo trend move: draw your restyled 1985 portrait (or each frame of the AI clip) on a canvas, let camcorderMove drift and zoom it, add drawCamcorderOSD with your own date, then apply().
- Put Kinetic Title Reveal through the tape for a retro title card or end slate, with mode 'play' and the counter running.
- Combine with Stop-Motion Feel for a home-made claymation clip that looks like it was found on an old cassette.

## Limitations
- It degrades what it is given: it cannot add 80s hair, clothes or rooms to footage. Pair it with an AI restyle for that.
- The display font covers capital letters, digits and a few symbols only; there are no accented letters.
- Square and widescreen frames are fine, but it does not crop to the 4:3 shape of real tape.

## License
MIT. Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.

Provenance: Original code written for AI Pixel Wizard on 2026-10-04 by an automated agent (the daily trend routine), inspired by the 80s AI photo trend and its 'A Day in 1987' VHS home-video versions (see content/trends/2026-10-04-vhs-camcorder.md). The list of tells to reproduce (blinking red-orange date stamp lower right, chroma bleed, tracking noise along the bottom, handheld shake, zoom creep, autofocus hunting) follows https://www.getstarrd.app/blog/how-to-make-80s-ai-video. Separating brightness and colour (YIQ) and blurring colour more than brightness is the standard description of how VHS records video; the code, the dot-matrix font and the demo pictures were all written for this package. No code, images, fonts or shaders were copied.

