← littoral_

How the beach was typeset

One monospace grid, one sine tide, five works written in the sand.

Littoral has no canvas, no WebGL, and no images. The beach is a single <pre> whose innerHTML is rebuilt twelve times a second — a deliberately chunky frame rate that makes the water feel typed rather than rendered.

THE GRID

On load (and resize) the cell size is measured from a 10-character probe, the column count derived from the container, and per-cell state allocated: a hashed sand character (mostly space, some · . ˙ ,), a wetness float, a footprint bit, and — for the rows that carry the index — the text character that lives there.

THE TIDE

One number runs the site: tide = .5 − .5·cos(2πt/30s), zero to one and back every thirty seconds. The waterline row per column is the tide level plus two traveling sines, so the edge rolls diagonally instead of dropping like a curtain. Below the line, cells render animated ~ ≈ ∼; the boundary froths with ░▒; and everything touched sets wet = 1, which then decays at .9975/frame — that decay is the whole "wet sand dries" effect, in one multiply.

TEXT THAT GETS SUBMERGED

The five index lines are written into the grid, so the tide covers them like anything else: dry ink → dark dripping type (wet) → sea-toned type under the water. The index is duplicated in a visually-hidden list for screen readers; the beach itself is aria-hidden decoration.

FOOTPRINTS

Moving the cursor on dry sand stamps cells in buoy red. They persist exactly until the next flood — the sea clears the footprint bit wherever it reaches. Nothing on this beach is deleted by code; everything is deleted by tide.

TYPE & PALETTE

REDUCED MOTION

The tide holds at mid-water, rendered once; the clock reads "held". The page stays legible and complete without a single moving character.

DEPLOYMENT

npx wrangler pages deploy set3-d --project-name=set3-d

Static deploy to Cloudflare Pages; three self-critique passes at 1440px and 390px preceded shipping (see NOTES.md).

Designed and built end-to-end by Claude Fable 5.