Skip to content

Dot Matrix Wave

Add a dot-grid background that ripples on hover and click.

import { DotMatrixWave } from '@youj/motion/backgrounds'

Experimental: what this label means

Installation & usage

npm i @youj/motion

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use it for products that sell precision: design tools, developer platforms, anything about pixels and grids. It's also a good "listening" state, because its idle pulses read as something waiting for input. Don't use it behind long text or dense UI, and don't pair it with another animated background on the same page.

The matrix fills its nearest positioned ancestor and paints behind your content, so make the container relative and isolate.

import { DotMatrixWave } from '@youj/motion/backgrounds'

export function PrecisionHero() {
  return (
    <section className="relative isolate min-h-[560px]">
      <DotMatrixWave />
      <p className="relative text-5xl font-semibold">Built to the last pixel</p>
    </section>
  )
}

Every dot is a single anti-aliased disc on a grid snapped to device pixels, evaluated at its center, so the lattice stays crisp at any pixel ratio. Untouched, the matrix breathes with a slow, low swell. Dots grow and brighten toward the excited color as a wave passes through them.

Reference

Propscolors, intensity, speed… (7)

Props

DotMatrixWave props
PropType
colors[dots: string, excited: string]

[dots, excited] CSS colors. Default: --color-fg dots that heat to --color-accent.

–
intensitynumber

Dot contrast, 0–1.5.

default 1

1
speednumber

Clock multiplier for the idle swell and ripple travel.

default 1

1
spacingnumber

Grid pitch in CSS px.

default 22

22
interactiveboolean

Pointer raises a lens of dots and leaves a wake; clicks send a ripple.

default true

true
ambientboolean

A pulse every few seconds while nobody is interacting, each from the next point of a fixed, evenly spread sequence across the middle of the field.

default true

true
classNamestring–
PerformanceIt's one WebGL2 fragment shader on a single full-screen triangle,…

Performance

It's one WebGL2 fragment shader on a single full-screen triangle, rendered at a device-pixel ratio capped at 2. It tracks at most eight rings at a time, and the oldest gives way to a new one. The loop pauses when the matrix is offscreen or the tab is hidden, recovers from a lost GL context, and releases the context on unmount. Without WebGL2, it falls back to a static CSS dot pattern at the same spacing.

MotionSwell, rings, pointer lens · reduced motion

Motion

Motion tokens
MomentTokens
Swellidle breathing of the whole lattice
no token

speed ÷ time scale

speed ÷ time scale
Ringsclicks, the pointer wake and ambient pulses
no token

380 px per clock second

380 px per clock second
Pointer lensfollows the pointer, fades in and out
no token

smoothed per frame

smoothed per frame

Reduced motion

Draws one still frame with a single ring frozen mid-flight, so the matrix still reads as something that responds. There's no lens, no wake and no ambient pulse.

Ring travel is measured in the matrix's own clock, so it slows with the Speed control like everything else.

Reduced motion

The matrix holds one composed frame, with a single ring frozen in the middle of the field. There's no swell, no lens and no pulse, but the lattice and its colors stay the same, and the frozen ring still hints at what the matrix does. Switch on Reduced motion in any preview above to compare.

AccessibilityARIA

Accessibility

  • It's decorative: the element is aria-hidden and ignores pointer events, so presses pass through to the content above it.
  • A ring is visual feedback only. If a press does something, like sending a test event, confirm it in text as well. The Pointer and clicks story does this with a status message.
  • Keep a quiet pool of canvas behind the copy, and check your text's contrast over the brightest rings.