Lines Spotlight
Full-bleed layout rules that sit quiet until a cursor spotlight reveals them. Ships the screen-line utilities it measures — the same ones ruling this page.
npx shadcn@latest add https://www.obuseklearns.dev/r/lines-spotlight.jsonmove the cursor over the grid
Usage
lines-spotlight-demo.tsx
"use client";
import { useRef, useState } from "react";
/**
* Scoped restatement of the real effect. `LayoutSpotlight` measures the whole
* document and is already mounted once in the root layout, so a preview can't
* mount a second copy — this draws the same masked-duplicate trick inside a
* single stage instead.
*/
const SPOT_MASK = {
maskImage:
"radial-gradient(120px circle at var(--spot-x, -999px) var(--spot-y, -999px), black, transparent 70%)",
WebkitMaskImage:
"radial-gradient(120px circle at var(--spot-x, -999px) var(--spot-y, -999px), black, transparent 70%)",
} as const;
/** Quarter-height rows and rails inset by a fifth, as percentages of the stage. */
const HORIZONTALS = ["25%", "50%", "75%"];
const VERTICALS = ["20%", "80%"];
function Lines({ className }: { className: string }) {
return (
<>
{HORIZONTALS.map((offset) => (
<span
key={`h-${offset}`}
className={`absolute inset-x-0 h-px ${className}`}
style={{ top: `calc(${offset} - 1px)` }}
/>
))}
{VERTICALS.map((offset) => (
<span
key={`v-${offset}`}
className={`absolute inset-y-0 w-px ${className}`}
style={{ left: `calc(${offset} - 1px)` }}
/>
))}
</>
);
}
export function LinesSpotlightDemo() {
const stageRef = useRef<HTMLDivElement>(null);
const [active, setActive] = useState(false);
const track = (event: React.PointerEvent<HTMLDivElement>) => {
const stage = stageRef.current;
if (!stage || event.pointerType === "touch") {
return;
}
const rect = stage.getBoundingClientRect();
stage.style.setProperty("--spot-x", `${event.clientX - rect.left}px`);
stage.style.setProperty("--spot-y", `${event.clientY - rect.top}px`);
setActive(true);
};
return (
<div className="flex w-full flex-col items-center gap-4">
<div
ref={stageRef}
onPointerMove={track}
onPointerLeave={() => setActive(false)}
className="screen-line-top screen-line-bottom screen-line-left screen-line-right relative h-56 w-full max-w-sm overflow-hidden"
>
<Lines className="bg-line" />
<div
aria-hidden
className="pointer-events-none absolute inset-0 motion-reduce:hidden"
style={SPOT_MASK}
>
<Lines className="bg-foreground/70" />
</div>
</div>
{/* Pointer tracking is skipped on touch, so the prompt is too. */}
<p className="hidden font-mono text-xs text-muted-foreground pointer-fine:block">
{active ? "tracking pointer" : "move the cursor over the grid"}
</p>
</div>
);
}