Skip to content

Warp Grid

Show a line grid that sags toward the pointer like mass bending space.

import { WarpGrid } 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 where the idea is weight, gravity or structure: infrastructure, finance, anything that should feel like a surface under load. It is the one grid that never goes fully still, because with nobody there the well rests in the middle and breathes slowly. Keep it to one per page.

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

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

export function WeightedHero() {
  return (
    <section className="relative isolate min-h-[560px]">
      <WarpGrid />
      <p className="relative text-5xl font-semibold">Space bends around what matters</p>
    </section>
  )
}

The well follows the pointer with the same smoothing as the other backgrounds. When the pointer leaves, it glides back to the middle of the field and shallows to 40% of its depth. A press deepens it for a moment, which is what makes it respond on touch screens.

Reference

Propscolors, intensity, speed… (8)

Props

WarpGrid props
PropType
colors[lines: string, well: string]

[lines, well] CSS colors. Default: --color-fg-subtle lines that take --color-accent near the well.

–
intensitynumber

Line opacity, 0–1.5.

default 1

1
speednumber

Clock multiplier for the idle breathing and the pulse a press leaves.

default 1

1
spacingnumber

Grid pitch in CSS px.

default 26

26
depthnumber

How far the well pulls the grid, 0–2.

default 1

1
radiusnumber

Reach of the well in CSS px.

default 240

240
interactiveboolean

Pointer reactivity; a press deepens the well for a moment.

default true

true
classNamestring–
PerformanceCanvas 2D; one path plus a few for the lit lines

Performance

It's drawn with Canvas 2D, not WebGL. Every line is sampled every 8 pixels and each sample is one inverse-square evaluation, so the whole grid is the base path plus five alpha-bucketed paths for the lit segments. The canvas renders at a device-pixel ratio capped at 2. On the low motion-budget tier the lines are sampled 60% more coarsely and the loop runs at 30 fps. The loop pauses when the grid is offscreen or the tab is hidden, and it stops and cleans up on unmount. If the browser can't create a 2D context, it falls back to a static CSS wash of the accent color.

MotionWell position, breathing, press pulse · reduced motion

Motion

Motion tokens
MomentTokens
Well positionblends from the middle to the pointer by pointer strength
no token

smoothed per frame

smoothed per frame
Idle breathingthe well deepens and eases about 6% while nobody is there
no token

speed ÷ time scale

speed ÷ time scale
Press pulsethe well deepens by half, then decays
no token

about 0.3 s half-life

about 0.3 s half-life

Reduced motion

Draws one still grid sagging toward the middle: the same composition every time. There's no breathing and no pointer response, and it redraws only when the size, the props or the theme change.

Reduced motion

The grid sags toward the middle at its resting depth, so it's the same on every visit and in every screenshot. The lines and the lit accent keep their colors. Only the breathing and the pointer response are gone. Switch on Reduced motion in any preview above to compare.

AccessibilityARIA

Accessibility

  • It's decorative: the element is aria-hidden and ignores pointer events.
  • Lines cross whatever sits above them. Keep a quiet pool of canvas behind the copy, as the hero preview does, or lower intensity, and check your text's contrast there.
  • The idle breathing is slow and stops offscreen. Under reduced motion the grid doesn't move at all.