# Symbols effect

A live halftone that rebuilds a clip from small tinted symbols, one per brightness band. Live at https://design.how/vault#sandbox.

Install the skill, which carries the template, the brief and a check script:

```sh
npx skills add https://design.how/vault/sandbox
```

## What it is

A short clip, a running cat, beetles, flowers, blocky letters spelling hi, plays rebuilt from little marks. The frame is split into a grid of square cells about 8 pixels wide on a 600 pixel card, and each cell shows one small symbol, a dot, a ring, a square, a triangle, a cross, tinted in one of four colours. Dark parts of the picture get one symbol and colour, the light parts another, so the image reads from a distance and dissolves into pattern up close. Every two seconds the card moves to a new clip with its own palette and symbols.

It is one fragment shader on one full-frame quad. Each pixel snaps to the centre of its cell and samples the source there, so a whole cell reads one colour, and the luminance of that sample picks a band from four ranges, 0 to 25%, to 50, to 75 and to 100 by default. The band's symbol, a 32 by 32 canvas drawn from paths, tiles once per cell and is multiplied by the band's colour over a white ground; the empty symbol leaves paper. The source is cover-cropped so the grid always fills the frame, and the cell size scales with the card's width so a phone sees the same density as a desktop.

A video is a three.js VideoTexture, preloaded for every preset so a switch never decodes from cold, and the new clip only replaces the old one after its first frame has really been decoded, which avoids a black flash. Switching looks inside the playground crossfades colours and symbols on a spring. The playground also takes an image or a clip of your own, entirely in the browser, and saves a PNG or records the canvas to WebM.

## How it works

- Draw a full-frame quad with one ShaderMaterial; pass the source, the cell size, four band colours, four band ranges and four glyph textures as uniforms.
- In the fragment shader, snap the pixel to its cell centre, cover-crop and sample the source, and take its luminance.
- Find the band whose range holds that luminance, tile the band's glyph once per cell, and tint it with the band colour over white.
- Scale the cell with the card's width against a 600 pixel reference, so the number of cells across stays constant.
- Keep a pool of preloaded videos and swap the texture only after the new clip has presented a decoded frame.
- Pause the clip and the cycle off screen and on a hidden tab; stop on webglcontextlost; on destroy dispose the textures, the material and the geometry, then renderer.dispose() and renderer.forceContextLoss().
- Under reduced motion, hold the first look on a decoded frame of its clip.

## What you can change

- `PRESETS` (seven looks): Each clip with its four band colours, four symbols and zoom.
- `GLYPHS` (twenty-four symbols): The symbols a band can stamp, drawn as canvas paths.
- `CELL` (8): The cell size in pixels at a 600 pixel wide card.
- `CYCLE_MS` (2000): How long the card holds each look.
- `bandStops` (0, 0.25, 0.5, 0.75, 1): Where the four brightness bands split.

Last updated: 2026-11-02
