TruchetMaze

Quarter-circle tiles flipped at random in a square lattice, joining into one continuous maze that breathes along a diagonal.

the maze breathes along a diagonal

Paste into Claude Code, Cursor or any agent. Pinned to a tag, so it will not change under you.

Options

ground #0b0a18

css colour

The ground the maze is drawn on. Near-black with a trace of violet in it rather than a true black, so the darkest part of the ramp still has somewhere to go.

near #6d2fd1

css colour

Line colour at the near end of the ramp.

mid #e04b9e

css colour

Line colour through the middle. This is the stop that matters: between two colours you get one hue and a tint of it, and passing through a third is what makes a ramp read as light falling across something rather than as a fade.

far #ff9a4a

css colour

Line colour at the far end.

cells 9

3 to 30, good: 6 to 14

Tiles across the short edge of the frame. Few and large reads as architecture; many and small reads as a textile, and past about twenty the curves are too short to follow and it becomes a texture rather than a maze.

thickness 0.17

0.02 to 0.5, good: 0.1 to 0.25

Line width as a fraction of a cell, so it holds when the cell count changes. At 0.5 neighbouring arcs meet and the maze fills in solid, which is a different and also usable look.

rotation 0

0 to 90, good: 0 to 45

Rotation of the lattice in degrees. Only ninety are worth having: a square lattice of symmetric tiles is unchanged by a quarter turn.

softness 0.04

0 to 1, good: 0 to 0.2

Softness of the line edge, on top of the one pixel of antialiasing that is always there. At 0 the line is as crisp as the display allows; high values turn the maze into a glow of itself.

seed 3

0 to 999

Which tiles are flipped. Changes the maze and nothing else, and every value is as good as every other, which is the pleasant thing about a Truchet tiling.

breathe 0.42

0 to 0.9, good: 0.2 to 0.6

How much the line weight swells and thins as the wave passes. At 0 the maze is a still image, which is a legitimate way to use this and costs nothing to draw.

wave 7

2 to 24, good: 5 to 12

Cells between one crest of the breathing wave and the next. Short wavelengths make neighbouring tiles disagree and read as noise; long ones move the whole frame together and read as a tide.

tilt 0.35

0 to 1

Direction of the colour ramp. 0 runs it up the frame, 1 runs it across, and between the two it runs on a diagonal, which is where it crosses the most curves.

period 12

6 to 60 s, good: 10 to 24

Seconds for one cycle of the breathing wave. The loop closes exactly on it, because the phase advances a whole turn in that time.

What it needs

Category
Backdrops, an effect
Dependencies
None at all
Browser
WEBGL2
Frame budget
~0.2 ms · 1 context
Pinned to
v0.13.0
  • The arcs are distance fields rather than drawn strokes. Distance to a circle is one length() and a subtraction, so a tile is two of those and a minimum, and the stroke is a band around the zero set. Line width is therefore a number rather than a resolution, and nothing aliases as the cells get small
  • fwidth measures one pixel in lattice units, which is what keeps the edge the same softness at every cell count and every rotation. A constant would be a different number of pixels each time the lattice is scaled
  • The tile hash is the multiply-and-stir kind rather than fract(sin(x) * 43758.0). The argument is a cell index that grows without bound as the lattice is rotated or the cell count raised, and the sine of a large number is a different value on a different driver
  • One hash, two length() calls, a minimum and a smoothstep per pixel. No noise, no loops, no textures and no render targets: this is among the cheapest effects in the library and it is meant to be, because a backdrop that costs a tenth of a frame is a backdrop that still works on a machine already doing something else
  • Measured with pnpm gputime rather than by timing the draw call, which returns as soon as the command is queued and says nothing about what the GPU then does

Concept credit: The parameter set: cells, thickness, rotation, softness and seed turned out to be the right five knobs for a quarter-circle Truchet tiling, and there was no reason to invent different ones. The tiling itself is Sebastien Truchet's, from 1704. The code here is this repo's own., by Shader Effects Inc.. The implementation here is written from scratch.