Blend
A blob using mix-blend-mode: difference, so it inverts the colours underneath it instead of drawing over them. The most striking variant, and the most sensitive to the page around it.
Live props — bound to the real component
Install
npx shadcn@latest add @pointerui/blend# Copy three folders out of the repo
src/lib/engine/ -> lib/pointerui/engine/
src/registry/provider/ -> components/pointerui/provider/
src/registry/variants/blend/ -> components/pointerui/blend/
# 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);
});
// Blend's own layer setup is the same call with its own options.Usage
import { CursorProvider } from "@/components/pointerui/provider";
import { Blend } from "@/components/pointerui/blend";
export default function Page() {
return (
<CursorProvider>
<Blend />
<button data-cursor="grow">Hover me</button>
</CursorProvider>
);
}Props
Generated from blend/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 |
|---|---|---|---|
| size | number | 58 | Blob diameter in px. |
| color | string | "#ffffff" | Any CSS colour. Defaults to white, and this is the one variant that must not default to `--cursor-color`.
|
| growScale | number | 1.6 | Scale applied over a |
| lag | number | 0.45 | Follow duration in seconds. |
| blendMode | string | "difference" |
|
| ease | string | "power3" | 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="blend"
- Scales the blob up over the target.
- data-cursor="grow"
- Same scale-up, for pages already using `grow`.
- data-cursor="hide"
- Fades the blob out.
Notes & caveats
- This variant defaults to white, not
--cursor-color.differencesubtracts channel by channel, so only a white blob inverts what it crosses — a near-black one leaves a light page essentially unchanged. - Any ancestor that creates a stacking context traps the blend. A parent with
transform,filter,opacitybelow 1,isolation: isolate, orwill-changewill confine the inversion to that subtree. In development the variant warns in the console when it finds one.