Files
mintel.me/apps/web/src/components/bits/BitGlow.tsx
T
mmintelandClaude Opus 5.5 e89a248ca5 feat: binary glow effects, refined drawings and calls to action
Dark surfaces now carry light: frames glow along their edge and shed binary
digits (BitAura), dark sections open with a lit seam (BitSeam), the career
path is a line of light and "My work" became a dark stage. Buttons carry a
travelling light and a spot that follows the pointer (BitGlow).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 13:07:09 +02:00

50 lines
1.6 KiB
TypeScript

"use client";
import * as React from "react";
const SURFACE = "[data-glow]";
/**
* BitGlow: a light that follows the pointer across every `data-glow` surface.
* It only publishes the pointer position as `--gx` / `--gy` on those surfaces;
* the light itself is drawn in CSS by a `.bit-glow` child (see globals.css).
* Purely decorative, and off when reduced motion is requested.
*/
export const BitGlow: React.FC = () => {
React.useEffect(() => {
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
let frame = 0;
let latest: PointerEvent | null = null;
const publish = () => {
frame = 0;
if (!latest) return;
const { clientX, clientY, target } = latest;
let surface =
target instanceof Element ? target.closest<HTMLElement>(SURFACE) : null;
// Surfaces nest (a button inside a dark section): each one gets its own position.
while (surface) {
const rect = surface.getBoundingClientRect();
surface.style.setProperty("--gx", `${clientX - rect.left}px`);
surface.style.setProperty("--gy", `${clientY - rect.top}px`);
surface =
surface.parentElement?.closest<HTMLElement>(SURFACE) ?? null;
}
};
const onPointerMove = (event: PointerEvent) => {
latest = event;
if (frame === 0) frame = window.requestAnimationFrame(publish);
};
window.addEventListener("pointermove", onPointerMove, { passive: true });
return () => {
window.removeEventListener("pointermove", onPointerMove);
if (frame !== 0) window.cancelAnimationFrame(frame);
};
}, []);
return null;
};