The layer behind everything
5 sheets
Grids, dots, rings, hatch, mesh, noise, travelling beams. Every one of them is currentColor and alpha on your own theme tokens — no hex, nothing to re-theme — and every one is shown here over real copy at section size, because a thumbnail of a background tells you nothing about the background.
<section className="relative isolate overflow-hidden py-24">
<Backdrop /> {/* or GridBeams, or whatever you installed */}
<h1>…</h1> {/* your content, unchanged */}
</section>relative gives the layer a box to fill; isolate gives it a stacking context, without which the negative z-index escapes upward and the pattern paints behind an ancestor's background instead of behind your content. That is the whole integration — the rest is on each sheet.
Backdrop
A static pattern layer for the space behind a hero or a section: grid, dots, rings, mesh, noise or hatch, built from theme tokens and masked at the edges.
Every environment, one deploy log
Preview, staging and production read from the same manifest, so a rollback is one commit and not an afternoon. Pattern: grid.
The default. 1px token lines at a 32px pitch, faded at all four edges by two intersected mask ramps — no hard cut-off anywhere along the border.
Every environment, one deploy log
Preview, staging and production read from the same manifest, so a rollback is one commit and not an afternoon. Pattern: dots.
A tighter 20px pitch. The pitch is clamped to a floor per pattern, so a caller passing size={2} gets a legible grain instead of a moiré smear.
Every environment, one deploy log
Preview, staging and production read from the same manifest, so a rollback is one commit and not an afternoon. Pattern: rings.
Concentric rings off-centred above the text block, so the densest part of the pattern sits where the copy is not. Radial fade keeps the ring count ambiguous.
Every environment, one deploy log
Preview, staging and production read from the same manifest, so a rollback is one commit and not an afternoon. Pattern: hatch.
45-degree lines at an 8px pitch — the densest pattern here, and the one that most needs the fade. Shown bottom-faded, which is how a hero hands off to the section under it.
Every environment, one deploy log
Preview, staging and production read from the same manifest, so a rollback is one commit and not an afternoon. Pattern: mesh.
Four soft radials of the text colour at different weights. No hue is named anywhere, so it stays a neutral field on neutral tokens and picks up chroma only if the client's foreground has some.
fade="edges"fade="radial"fade="top"fade="bottom"The four masks on one pattern. Look at where each panel stops carrying pattern: edges dissolves on all four sides, radial pools in the middle, top and bottom hand off to the next section.
Body copy at this density, on the surface it will actually ship on.
subtleBody copy at this density, on the surface it will actually ship on.
normalBody copy at this density, on the surface it will actually ship on.
strongSide by side on purpose: density is the variable, so it can only be judged against its neighbours. Noise reads it most clearly. Body text stays above 4.5:1 at every step.
Grid Beams
A grid with light travelling along its lines — the atmosphere layer for a hero, with every beam's line, phase and resting frame derived from the beam count and the grid pitch.
Light that follows the lines
The grid is @automindz/backdrop. This item adds the travel and nothing else — one alpha table, one pattern, one dissolve at the edges.
Five streaks, alternating down column lines and across row lines, each one exactly on a 1px grid line rather than near it. Watch a beam leave the frame: the next one is already a fifth of a lap behind it, because the phases are (i + ½)/n and the delays are negative.
Declared in cells, not in pixels
A percentage pitch is what lets a beam sit on a line by arithmetic — no ref, no ResizeObserver, no client boundary behind a background.
The rate cap doing its job: ten beams over the asked-for 7s would arrive at 1.43Hz, so the lap is left alone — ask for 3s and it stretches to 6.667s instead of flickering. The 16 × 9 pitch makes the cells square in a wide frame.
currentColor and alpha, never a hex
Give it any colour utility and both halves follow. The per-theme alphas are Backdrop's, so this grid and every other grid in the app agree about how dark a hairline is.
text-primary on the layer tints the grid and the streak together, because the nested Backdrop is handed text-inherit rather than its own text-foreground. One beam parks dead centre at rest — never off-screen, which is what the half-step in the phase buys.
Never blank, at any intensity
Drop the stylesheet and the picture is the same one, minus the travel. There is no state in which this renders an empty box.
beams={0} is the empty state and it is a complete backdrop, not a gap: the grid renders on its own. This is also what a reduced-motion visitor sees, except that their beams are still there, parked at the frame the animation holds at t = 0.
Glyph Matrix
A field of characters behind a hero that changes under the pointer and keeps what you leave behind, with a readability clearing and an opt-in glitch that tears two bands.
It keeps what you leave behind
A cell entering the pointer's reach rolls to a different character and that becomes its character. The glyph array is the field's only state, so there is nothing to spring back to.
The characters under the cursor change, and they stay: sweep an area, move away, and the glyphs you left behind are the new ones. Watch the edge of the pool — every cell's reach is jittered across 0.55×–1.25× of the nominal, so the boundary is ragged rather than a disc sliding under the mouse. The whole layer is a canvas, so there is nothing here to select and nothing for Ctrl+F to find.
clearing={1} — the default
Muted metadata is the hard case: it starts at 4.74:1 on bare background, so any texture under it drops below 4.5:1.
clearing={0}
Muted metadata is the hard case: it starts at 4.74:1 on bare background, so any texture under it drops below 4.5:1.
clearing thins the field where the copy is instead of dimming it everywhere: a flat elliptical core over the middle, ramping out before the sides, so the edges and corners keep full texture. Its floor is not a look — it is an ink ceiling of 0.012, half the alpha at which text-muted-foreground (4.74:1 on bare background, a quarter of a point of headroom) crosses 4.5:1, halved because two neighbouring glyphs' antialiased edges composite. A heavier intensity therefore gets a deeper clearing on its own. Sampled off the canvas behind this copy: muted measures 4.6:1 in light and 7.5:1 in dark. The lower panel is the same strong field with clearing={0} — 2.2:1, which is what the muted line has to survive without it.
cellSize is a length in px, not a column count, so the field is the same texture in a 360px card and a 2560px hero — it simply has more of it. 14 is the default and what the published implementations use; 28 is the coarse terminal this item used to be limited to. The pitch is floored at 6px and the cell count capped at 20 000, so a cellSize of 1 gets a legible field instead of a locked tab.
A tear, not a filter
Only the row mid-cut is redrawn, and only on the four frames its offset actually changes — the other 96% of a band's lap costs nothing at all.
glitch tears two bands: a little over half of a row slips sideways and churns its characters in three hard cuts, then lands back in alignment carrying the new ones. A band tears once every nine seconds here and glyphMatrixTearCycle() will not let it go under two — a sixth of WCAG 2.3.1's threshold — and it is gone entirely under prefers-reduced-motion.
mutation is a rate in Hz — how often one cell changes character — so 0.1 is a slow drift and 0.45 is the default. The third tile asks for 6Hz and gets 1.5, half the WCAG flash threshold; the cap is arithmetic in glyphMatrixRate(), not a line in the docs. A frame costs the cells that changed, so the rate is also the per-frame budget.
Bring your own alphabet
Latin letters are left out of all three sets: a field of them reads as words the eye keeps trying to finish, which is the alphabet-soup failure this item exists to avoid.
glyphs is a string; GLYPH_SETS ships terminal, katakana and binary. There is no colour prop and no hex: the glyphs are painted in the layer's computed color, so text-primary is the whole API and the field follows the consumer's theme in both schemes. The mono face is read off the element too, so your font stack draws it.
Interactive Grid
A tiled grid of real cells for the space behind a hero — square or honeycomb at a fixed cell size, flat or receding to a horizon and slanted across it on two degree props, inert, breathing on a deterministic hash, or lighting up under the pointer and taking a full second to let go, in pure CSS.
Real cells, no client boundary
Per-cell :hover needs no pointer coordinates, so there is no listener and no state — this renders in a server component, like every other backdrop here.
Sweep the pointer across it rather than parking on one cell. A cell lights in 100ms and goes out over 1000ms, so you leave a wake of cells still fading behind you — the falloff is in time, not in space, because CSS cannot name the cell below the one you are on. The fill is flat currentColor at 0.145 of the layer's alpha, which renders at the same lightness the published implementations reach; there is no gradient, no scale and no rim, because all three read as busy next to theirs. Zoom in on one lit cell: the block is flat all the way to its edge and every line around it is the same weight. It stops half a hairline short of the outline to stay that way — a pattern clips half of every line into the cell it borders, and a fill that reached it composited darker there than in the middle of the same cell.
The far edge has no line to end on
The mask is applied in the plane's own box, before the transform, so its ramp comes out as a horizon rather than as a fade at the top of the section.
A real rotateX under a perspective, so the cells foreshorten and the columns converge on a vanishing point; a skew would slant them without either. Sweep near the bottom — hit-testing follows the transformed shape, so the cell that lights is the one you are on, lying in the plane. Cells are still square in their own plane: the tilt is a transform on the field, never a change to the tiling.
Both lattices turn together, or neither does
The lines and the cells sit in one group and share one rotation, so a slant cannot put the lit cells out of phase with the outlines they belong to.
Two props, both plain degrees: tilt={50} is how far the plane leans away, rotate={-14} is how far the lattice turns inside it. The rows now run diagonally and converge off to the upper right instead of straight up the box — two vanishing points rather than one — while the horizon stays level and the near edge stays pinned flat along the bottom, because the turn is applied inside the SVG and never to the element. Sweep down near the front: the lit cells lie in the turned plane and fade along the row you just crossed.
CSS has no randomness
So the scatter is arithmetic. Each cell's phase and whether it breathes at all are two independent draws from one hash — sharing one would make the quiet cells exactly the late ones.
shape, behaviour and tilt are three orthogonal props, so this costs nothing extra: a hexagon of width 48 has circumradius 48 ÷ √3 and stays regular at any tilt. Roughly a third of the cells breathe, scattered by a hash of their position rather than by Math.random() — the same field on the server, in the browser and on every reload, with no ResizeObserver and no hydration mismatch.
2200px of container, one <rect> of lines
Scroll right to the end: the grid is still there. The lines are an SVG pattern filling 100% × 100% at a fixed pitch, so coverage does not depend on the cell counts or on the cell cap — an earlier build stopped after 1600px and left 799px of bare background on a 2400px hero.
wide — 40px cells
tall — the same 40px cells
One size={40}, two containers of opposite proportions, and the cells are identical in both — measure them. The SVG carries no viewBox, so a user unit is a CSS pixel and nothing is fitted to anything, and the lines run into all four corners because the default has no mask to take them away again.
default — clipped by the container
fade="edges"
Left is the default: the grid runs into the container's corners and the container clips it. Right is fade="edges", for a grid bleeding into other content rather than into a boundary — compare where the first line falls on each. behaviour="static" renders the pattern and nothing else, two nodes and no cells, which is also what you get with no stylesheet, on a touch device, and under reduced motion for pulse.
Flickering Grid
A field of squares flickering behind a hero on a canvas, drawn in the container's own computed colour, capped at 1.5Hz and stopped when it scrolls off screen.
Every environment, one deploy log
Preview, staging and production read from the same manifest, so a rollback is one commit and not an afternoon. defaults
The defaults: 4px squares on a 10px pitch, each square re-rolling about once every three seconds. Watch it for ten seconds — nothing about it repeats, and the button is clickable, because the whole layer is pointer-events: none.
Every environment, one deploy log
Preview, staging and production read from the same manifest, so a rollback is one commit and not an afternoon. flickerChance={0}
flickerChance={0} holds the picture three other renders show: the server's, the canvas's first frame, and prefers-reduced-motion. It is an even field at half maxOpacity — the moving field's own mean — so the flicker emerges out of it rather than cutting to it.
14 / 64 / 61 / 2The two dials that change what the field is: a coarse mosaic, the default weave, and a fine grain. The pitch is floored at 3px and the square count capped at 120 000, so a squareSize of a fraction gets a legible field instead of a locked tab.
0.1Hz0.3Hzasked 6Hz → 1.5HzflickerChance is a rate in Hz — how often one square changes — so 0.1 is a slow shimmer and 0.3 is the default. The third tile asks for 6Hz and gets 1.5, half the WCAG flash threshold; the cap is arithmetic, not a line in the docs.
text-foregroundtext-primarymaxOpacity={0.8}No colour prop: the squares are drawn in the container's computed color, so a utility class is the whole API and the item follows the consumer's theme in both schemes. maxOpacity is the ceiling a square can reach, and the layer carries a per-theme multiplier so dark is not a cage.
