← All components

Trail canvas

A continuous smear drawn on one canvas from a fixed particle pool. The pool is allocated at mount and the render loop only mutates it, so there is nothing for the garbage collector to reclaim mid-drag.

Live props — bound to the real component

24
0.9
11
0.32

Install

npx shadcn@latest add @pointerui/trail-canvas

Usage

app/page.tsx
import { CursorProvider } from "@/components/pointerui/provider";
import { TrailCanvas } from "@/components/pointerui/trail-canvas";

export default function Page() {
  return (
    <CursorProvider>
      <TrailCanvas />

      <button data-cursor="grow">Hover me</button>
    </CursorProvider>
  );
}

Props

Generated from trail-canvas/types.ts and the component's own defaults, so this table cannot drift from the code you are about to copy.

PropTypeDefaultDescription
countnumber24

Particle pool size. Allocated once at mount — the render loop never creates an object, so there is nothing for the GC to collect mid-drag.

decaynumber0.92

Per-frame life multiplier, 0–1. Lower decays the trail faster.

radiusnumber11

Radius of a particle at full life, in px.

colorstring"var(--cursor-color, currentColor)"

Any CSS colour. Defaults to --cursor-color, falling back to currentColor — never hardcode a hex.

blendModeGlobalCompositeOperation"lighter"

Canvas compositing mode, and the one prop you must set for light backgrounds.

lighter adds colour, which reads as a gooey glow on dark surfaces and is invisible on white — adding to white stays white. On light backgrounds use source-over with a dark color and a lower alpha so particles darken instead of brightening.

alphanumber0.55

Peak particle alpha. Light backgrounds usually want this higher.

Data attributes

Mark any element with one of these and this variant responds when the pointer enters it. Values it does not understand are ignored.

data-cursor="hide"
Fades the canvas out.

Notes & caveats

  • blendMode is the one prop you must set for light backgrounds. lighter adds colour, which glows on dark surfaces and is invisible on white — adding to white stays white.
  • The backing store is sized to devicePixelRatio. Skipping that is the usual reason a canvas trail looks soft on a retina display.