Mischief

70 / Scenes

Constellation Field

Drifting points joined by lines when they come close, brightening and swelling around the pointer.

Move your pointer across it

The points nearest the pointer brighten and swell. Everything else keeps drifting.

Installation

Copy the source into your project, or keep it behind a package.

npx shadcn@latest add Tinkerers-Labs/mischief-ui/constellation-field
import { ConstellationField } from "mischief-ui/constellation-field"

Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.

registry/default/constellation-field/constellation-field.tsx
"use client" import * as React from "react"import {  RenderSurface,  useThemeColors,  type SurfaceColor,} from "@/registry/default/render-surface/render-surface"import { cn } from "@/lib/utils" export type ConstellationFieldProps = React.HTMLAttributes<HTMLDivElement> & {  /** Points per 10,000 CSS pixels of area, so the density survives a resize. */  density?: number  speed?: number

Usage

export function Backdrop() {
  return (
    <ConstellationField className="rounded-xl border">
      <div className="px-8 py-16 text-center">
        <h2>Move your pointer across it</h2>
      </div>
    </ConstellationField>
  )
}

Density, not count

A fixed number of points looks crowded in a narrow column and empty across a wide hero. Density is given per unit of area instead, so the field is rebuilt with the right number of points whenever the box changes and looks the same at every width.

Where the time goes

Linking compares every pair of points, so the work grows with the square of the count. At the default density a panel of ordinary size holds a few dozen points and the comparison is not worth optimising. A full page backdrop at high density is a different matter, and the honest fix there is to lower the density rather than to make the loop cleverer.

Setting pointerRadius to zero removes the reaction and lets the field sit behind content that should receive the pointer instead.

API

densitynumberPoints per ten thousand square pixels, so the field looks the same after a resize. Defaults to 5.
speednumberMultiplies the drift. Defaults to 1.
linkDistancenumberPoints closer together than this are joined. Defaults to 120.
pointerRadiusnumberHow far the pointer reaches, in pixels. Zero turns the reaction off. Defaults to 160.
colorstringA theme custom property or a CSS colour for the points and lines. Defaults to "--foreground".
pausedbooleanHolds the field still.

Accessibility

Decoration, hidden from assistive technology, and behind its children on its own layer. Under reduced motion the points are painted once where they started and the drift never begins, so the pattern remains without any movement.