Magnetic Lattice Hero
A dark tech-grid hero whose lattice of nodes and lines bends towards the pointer like a magnet, sending out a ripple wave from wherever you click.
A full-bleed canvas draws a regular lattice of nodes joined by thin lines. As the pointer moves inside the section, nodes within the radius are pulled towards it, the lines bend with them, and nearby nodes and lines light up in a glowing neon accent. Click and a ripple spreads out from that point, pushing each node it passes 14px outward before it springs back with a brief flash. Every node returns to rest through spring integration, and a dark radial scrim behind the centred text keeps the headline readable however busy the lattice gets.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add magnetic-lattice-hero.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<MagneticLatticeHero/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/magnetic-lattice-hero.en.jsonOr, once registries are configured in components.json, install it as @webberui/magnetic-lattice-hero.
Usage
import { MagneticLatticeHero } from "@/components/ui/magnetic-lattice-hero";
<MagneticLatticeHero
eyebrow="格點雲 2.0 開發者預覽"
title="讓每一次部署都看得見"
subtitle="服務、佇列與資料庫的連線狀態畫成一張即時拓樸圖。"
primaryAction={{ label: "建立免費專案", href: "/signup" }}
secondaryAction={{ label: "閱讀文件", href: "/docs" }}
gap={36}
radius={160}
diagonal
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Main title (required) |
eyebrow | ReactNode | — | Small label above the title, shown as an accent pill |
subtitle | ReactNode | — | Subtitle below the title |
primaryAction | MagneticLatticeHeroAction | — | Primary CTA with an accent background and an arrow icon |
secondaryAction | MagneticLatticeHeroAction | — | Secondary CTA, outlined |
as | "h1" | "h2" | "h1" | Heading level; use "h2" when the page already has an h1 |
minHeight | number | 560 | Minimum section height (px) |
gap | number | 36 | Lattice spacing (px) |
radius | number | 160 | Magnetic radius around the pointer (px); nodes inside it are pulled towards the pointer |
strength | number | 24 | Maximum pull (px); the actual offset is (1 - d/r)² × strength |
ripple | boolean | true | Whether a press sends out a ripple from that point |
diagonal | boolean | false | Also draw diagonals, turning the grid into a triangle mesh |
surface | "dark" | "auto" | "dark" | dark is always dark; auto follows the site light/dark theme |
rippleSpeed | number | — | Ripple expansion speed (px/s), written to --wb-magnetic-lattice-hero-ripple-speed; falls back to the CSS variable (default 600) |
duration | number | — | Entrance duration (ms), written to --wb-magnetic-lattice-hero-duration; falls back to the CSS variable (default 600) |
onRipple | (point: MagneticLatticeHeroRipplePoint) => void | — | Called every time a ripple is spawned |
className | string | — | Merged into the root section |
MagneticLatticeHeroAction
| Field | Type | Default | Description |
|---|---|---|---|
label | string | — | Button label |
href | string | — | Renders an <a> when provided, otherwise a <button type="button"> |
onClick | (event: React.MouseEvent<HTMLElement>) => void | — | Click handler |
MagneticLatticeHeroRipplePoint
| Field | Type | Default | Description |
|---|---|---|---|
x | number | — | Horizontal coordinate of the ripple origin (relative to the root section, px) |
y | number | — | Vertical coordinate of the ripple origin (relative to the root section, px) |
source | "pointer" | "focus" | — | Triggered by a pointer press or by keyboard focus on a CTA |
How it works
- Every node has a rest position and a current position, and chases its target each frame through spring integration (stiffness 0.08, damping 0.82). Once everything is back at rest the loop stops on its own and wakes again on the next pointer move.
- Magnetism only responds to mouse and pen: nodes inside the radius move towards the pointer by (1 - d/r)² × strength, never further than their distance to it. Touch drags do not pull the lattice, but a tap still sends out a ripple.
- The ripple ring is 40px wide and expands at
--wb-magnetic-lattice-hero-ripple-speed(default600px/s) until it reaches the corner farthest from its origin. Up to 4 run at once; beyond that the oldest is dropped. - The glow (
shadowBlur) is only drawn on bright nodes and the whole lattice is stroked in one pass, keeping each frame cheap. Canvas DPR is capped at 2, a ResizeObserver rebuilds the lattice, an IntersectionObserver pauses it when scrolled out of view, and everything is cleaned up on unmount. - Overridable CSS variables:
--wb-magnetic-lattice-hero-accent(darkdefaults to#2dd4bf;autouses#0d9488in light and#2dd4bfin dark),--wb-magnetic-lattice-hero-ripple-speedand--wb-magnetic-lattice-hero-duration. Colours are read inside the effect and re-read on theme changes whensurface="auto". - Entrance order: eyebrow, title, subtitle and CTAs rise 16px and fade in, 80ms apart, easing
cubic-bezier(0.22,1,0.36,1).
Accessibility
- The root is a
<section aria-labelledby>pointing at the title'suseId. - The canvas and the radial scrim are both
aria-hiddenand purely decorative; the scrim behind the text keeps the headline contrasted against the lattice. - CTAs are
<a>elements ortype="button"buttons with a focus-visible ring; focusing a CTA from the keyboard fires one decorative ripple at the button. - With prefers-reduced-motion (reduce motion) enabled, only a static lattice is drawn — no pointer follow and no ripples — and the entrance becomes a 150ms fade with no stagger.
Skyline Scroll Hero
A scroll-driven React hero with a segmented city skyline — as you scroll the sky shifts from dusk to night, buildings light their windows section by section, the stage headline switches, and the moon rises in the last stage.
Sketchnote Pricing
A notebook-paper pricing section for React: hand-drawn borders and check marks stroke in, the recommended plan gets a sketched circle and note, and prices tween between monthly and yearly.