Dot + ring
A small dot pinned to the pointer with a larger ring chasing it. The gap between the two follow durations is the whole effect — there is no spring physics, just 0.15s against 0.6s.
Live props — bound to the real component
Install
npx shadcn@latest add @pointerui/dot-ring# Copy three folders out of the repo
src/lib/engine/ -> lib/pointerui/engine/
src/registry/provider/ -> components/pointerui/provider/
src/registry/variants/dot-ring/ -> components/pointerui/dot-ring/
# Then fix the two aliases the CLI would have rewritten
# @/lib/engine -> @/lib/pointerui/engine
# ../../provider -> @/components/pointerui/providerimport { createEngine } from "./lib/pointerui/engine";
// The engine has no React imports at all, so it runs anywhere.
const engine = createEngine();
const el = document.createElement("div");
document.body.append(el);
const layer = engine.registerLayer(el, { duration: 0.15, ease: "power3" });
const stop = engine.onTick((state) => {
layer.setX(state.x);
layer.setY(state.y);
});
// DotRing's own layer setup is the same call with its own options.Usage
import { CursorProvider } from "@/components/pointerui/provider";
import { DotRing } from "@/components/pointerui/dot-ring";
export default function Page() {
return (
<CursorProvider>
<DotRing />
<button data-cursor="grow">Hover me</button>
</CursorProvider>
);
}Props
Generated from dot-ring/types.ts and the component's own defaults, so this table cannot drift from the code you are about to copy.
| Prop | Type | Default | Description |
|---|---|---|---|
| dotSize | number | 8 | Diameter of the leading dot, in px. |
| ringSize | number | 36 | Diameter of the trailing ring, in px. |
| ringWidth | number | 1.5 | Ring stroke width, in px. |
| ringAlpha | number | 0.4 | Ring stroke alpha, 0–1. The ring reads as a soft halo rather than a second hard outline, so it sits below the dot in visual weight. Applied with |
| color | string | "var(--cursor-color, currentColor)" | Any CSS colour. Defaults to the |
| lag | number | 0.6 | Ring follow duration in seconds. The gap between this and the dot's fixed 0.15s *is* the lag effect — there is no separate spring. |
| growScale | number | 2.5 | Ring scale while over a |
| pressScale | number | 0.85 | Ring scale while the pointer is held down. |
| ease | string | "power4" | GSAP ease for the follow tween. Any ease string GSAP understands works — This is the shape of the lag, where |
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="grow"
- Scales the ring up while over the target.
- data-cursor="hide"
- Fades both layers out.
Notes & caveats
- The dot and ring durations must stay different. Matching them removes the lag, which is the effect.
- Ring alpha is applied with
color-mix, not the element'sopacity— the reveal andhidetweens already own that property, and setting both makes them fight.