Skip to content
WANCRAFT

E.112Backgrounds & Effects

Bokeh Field

Out-of-focus lights drifting at different depths, with pointer parallax and a circle or hexagon aperture.

NewReactCanvasTailwindintermediate

Overview

Bokeh Field fills its container with soft out-of-focus lights. Each light has a depth that sets its size, blur, opacity, drift speed and how far it shifts with the pointer parallax, so the field reads as layered space even when still. All blur is pre-rendered: one sprite per colour and blur level is drawn once with shadowBlur (a brighter rim, like real lens highlights, in a circle or hexagonal aperture), and every frame is a batch of scaled drawImage calls — no per-frame filters. Dark themes blend additively for glow; light themes deepen pale colours so the circles stay visible. The canvas is DPR-aware, pauses offscreen and in hidden tabs, and reduced motion renders a still frame.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/bokeh-field.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/bokeh-field.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/bokeh-field.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { BokehField } from "@/components/ui/bokeh-field";

export function BokehFieldExample() {
  return (
    <div className="relative h-80 w-full overflow-hidden rounded-xl">
      <BokehField />
    </div>
  );
}

03Props

PropTypeDefaultDescription
countnumber40Number of lights.
palette"ember" | "mint" | "dusk" | "mono""ember"Named palette; mono uses the inherited text colour.
colorsstring[]—Custom colours (any CSS colours); overrides palette.
speednumber1Drift speed multiplier; 0 holds the lights still.
sizenumber120Diameter of the nearest lights in px; the farthest are about a third of this.
blurnumber0.6Defocus of near lights, 0–1 (baked into sprites).
aperture"circle" | "hexagon""circle"Lens aperture shape of every light.
parallaxbooleantrueLayers shift by depth (up to 36px) as a mouse or pen pointer moves.
childrenReactNode—Optional content layered above the field.
...propsHTMLAttributes<HTMLDivElement>—Forwarded to the root, which is absolute inset-0 — place it inside a positioned parent.

04Features

  • 01Depth drives size, blur, opacity, drift speed and parallax
  • 02Pre-rendered sprites per colour × blur level (shadowBlur, works in every browser) — no per-frame filters
  • 03Bright-rimmed circle or hexagonal aperture, like real lens bokeh
  • 04Additive glow on dark themes; pale colours deepened on light themes
  • 05Gentle twinkle and sideways sway; resizing rescales positions instead of reshuffling
  • 06DPR-aware canvas (capped at 2), ResizeObserver, pauses offscreen and in hidden tabs
motion · continuousinput · pointerinput · viewport

05Accessibility

  • The canvas is aria-hidden and ignores pointer events; layered content stays fully interactive.
  • prefers-reduced-motion renders a single still frame with no drift, twinkle or parallax.
  • Parallax follows mouse and pen pointers only, so touch scrolling never moves the lights.