Skip to content
Dethink Components

ComponentsMagneticBeamsBackground

MagneticBeamsBackground

Add grid beams that follow the pointer.

On this page

Use this component from the local workspace package. Follow the setup guide first. A public npm package and registry are not available yet.

View registry files

Import the component into your page or component file.

Usage
import { MagneticBeamsBackground } from "@dethink/components";

Try the examples, then open the code to use them in your app. The background fills its container; these previews bound it with a height utility.

Hero composition

Move the pointer over the preview: beams converge toward it along their rails, and resume their traversal from that point when the pointer leaves.

Move your pointer

A hero that leans in when you do

The beams spring toward your pointer while it hovers, then pick their traversal back up from wherever they are when it leaves.

Show sourceexamples/magnetic-beams-background/basic.tsx
examples/magnetic-beams-background/basic.tsx
"use client";

import { Badge, Button, MagneticBeamsBackground } from "@dethink/components";

export function MagneticBeamsBackgroundBasic() {
  return (
    <MagneticBeamsBackground
      className="border-border h-[24rem] rounded-lg border"
      tone="primary"
    >
      <div className="flex h-[24rem] flex-col items-center justify-center gap-4 px-6 text-center">
        <Badge tone="primary" variant="soft">
          Move your pointer
        </Badge>
        <h2 className="text-foreground max-w-xl text-3xl font-semibold tracking-tight">
          A hero that leans in when you do
        </h2>
        <p className="text-muted-foreground max-w-md text-sm leading-6">
          The beams spring toward your pointer while it hovers, then pick their
          traversal back up from wherever they are when it leaves.
        </p>
        <div className="flex gap-3">
          <Button>Get started</Button>
          <Button variant="outline">View docs</Button>
        </div>
      </div>
    </MagneticBeamsBackground>
  );
}

Modes, variants, and interactive={false}

Every visual axis is a literal token-backed variant. mode switches how beams approach the pointer: magnetic springs onto it, follow travels there at the normal loop speed. interactive={false} keeps the plain traversal loop.

tone="foreground" · dense · fast · magnetic
mode="follow" · beams travel to the pointer at loop speed
interactive={false} · plain traversal
tone="primary" · sparse · bold · slow
Show sourceexamples/magnetic-beams-background/variants.tsx
examples/magnetic-beams-background/variants.tsx
"use client";

import { MagneticBeamsBackground } from "@dethink/components";

export function MagneticBeamsBackgroundVariants() {
  return (
    <div className="grid gap-4 sm:grid-cols-2">
      <MagneticBeamsBackground
        className="border-border h-48 rounded-lg border"
        density="dense"
        seed={3}
        speed="fast"
        tone="foreground"
      >
        <div className="flex h-48 items-end p-4">
          <span className="text-muted-foreground text-xs font-medium">
            tone=&quot;foreground&quot; · dense · fast · magnetic
          </span>
        </div>
      </MagneticBeamsBackground>
      <MagneticBeamsBackground
        className="border-border h-48 rounded-lg border"
        mode="follow"
        seed={7}
        tone="primary"
      >
        <div className="flex h-48 items-end p-4">
          <span className="text-muted-foreground text-xs font-medium">
            mode=&quot;follow&quot; · beams travel to the pointer at loop speed
          </span>
        </div>
      </MagneticBeamsBackground>
      <MagneticBeamsBackground
        className="border-border h-48 rounded-lg border"
        interactive={false}
        seed={5}
        tone="muted"
      >
        <div className="flex h-48 items-end p-4">
          <span className="text-muted-foreground text-xs font-medium">
            interactive=&#123;false&#125; · plain traversal
          </span>
        </div>
      </MagneticBeamsBackground>
      <MagneticBeamsBackground
        className="border-border h-48 rounded-lg border"
        density="sparse"
        intensity="bold"
        seed={9}
        speed="slow"
        tone="primary"
      >
        <div className="flex h-48 items-end p-4">
          <span className="text-muted-foreground text-xs font-medium">
            tone=&quot;primary&quot; · sparse · bold · slow
          </span>
        </div>
      </MagneticBeamsBackground>
    </div>
  );
}

Static frame

animate={false} — and any user with a reduced-motion preference — gets this composition: no loops or attraction mounted, still designed.

Designed at rest

animate={false} renders the same frame reduced-motion users see: the grid plus two frozen beam segments, no loops or pointer attraction mounted.

Show sourceexamples/magnetic-beams-background/static.tsx
examples/magnetic-beams-background/static.tsx
"use client";

import { MagneticBeamsBackground } from "@dethink/components";

export function MagneticBeamsBackgroundStatic() {
  return (
    <MagneticBeamsBackground
      animate={false}
      className="border-border h-56 rounded-lg border"
      tone="primary"
    >
      <div className="flex h-56 flex-col items-center justify-center gap-2 px-6 text-center">
        <h3 className="text-foreground text-xl font-semibold">
          Designed at rest
        </h3>
        <p className="text-muted-foreground max-w-sm text-sm leading-6">
          animate={"{false}"} renders the same frame reduced-motion users see:
          the grid plus two frozen beam segments, no loops or pointer
          attraction mounted.
        </p>
      </div>
    </MagneticBeamsBackground>
  );
}

MagneticBeamsBackground accepts div props plus the shared background contract — animate, density, intensity, speed, tone, and seed — and adds interactive and mode for the pointer attraction.

MagneticBeamsBackground props
PropWhat it doesDefault
animatebooleanSet to false to force the static composition regardless of OS motion preference: the grid plus two frozen beam segments, with no animation loops or pointer attraction mounted.true
interactivebooleanEnables pointer attraction: while the pointer hovers the component, each beam springs along its rail toward the pointer (horizontal beams track x, vertical beams track y); on leave, each beam resumes its traversal from its current position. Set to false to keep the plain traversal loop.true
mode"magnetic" | "follow"How beams approach the pointer. magnetic springs each beam onto the pointer's projection with velocity-preserving physics; follow travels there linearly at the beam's normal traversal speed, so the chase reads as steady motion instead of a snap."magnetic"
density"sparse" | "normal" | "dense"Grid cell size (96/56/32px) and beam count (3/5/7). Denser grids suit tighter, more technical compositions."normal"
intensity"faint" | "subtle" | "bold"Opacity tier for the grid pattern. Keep faint or subtle under body copy; bold is for short hero statements."subtle"
speed"slow" | "normal" | "fast"Beam traversal duration (9/6/3.5s per sweep), also used when a beam finishes its pass after the pointer leaves. Loops pause automatically while the background is offscreen."normal"
tone"foreground" | "muted" | "primary"Semantic token driving the grid and beam color via currentColor, so light and dark mode adapt automatically."muted"
seednumberDrives all pseudo-random beam placement deterministically. The same seed renders the same layout on the server and every client, so markup is SSR-stable; change it to reshuffle the beams.1
childrenReactNodeHero content rendered in the content slot above the aria-hidden decorative layer. The layer is pointer-events-none, so children stay fully interactive while pointer moves are tracked on the root.Not set
getMagneticBeamsBackgroundMotionConfig / getMagneticBeamsBackgroundGeometry / getMagneticBeamsBackgroundPointerProgress / getMagneticBeamsBackgroundFollowDuration / *ClassNames helpers(speed, reducedMotion) => config, (seed, density) => beams, (pointerFraction) => progress, (current, target, beamDuration) => seconds, ({ className }) => stringOpen-code escape hatches: read the resolved loop and attraction transitions, reuse the seeded beam geometry, map a pointer position to a beam's pass progress, or apply the root, layer, and content class recipes to custom elements.Not set