Perspective Grid
rivelle/perspective-gridFreeComponent
A pointer-reactive perspective horizon grid without canvas or WebGL.
Install it
npx shadcn@latest add https://rivelle.dev/r/perspective-grid.jsonSource
1"use client";23import * as React from "react";45import { cn } from "@/lib/utils";67type PerspectiveGridProps = React.ComponentProps<"div"> & {8 fade?: boolean;9};1011function PerspectiveGrid({12 children,13 className,14 fade = true,15 onPointerLeave,16 onPointerMove,17 style,18 ...props19}: PerspectiveGridProps) {20 return (21 <div22 className={cn(23 "relative isolate overflow-hidden rounded-[2.25rem] border border-foreground/10 bg-foreground text-background",24 className,25 )}26 data-slot="perspective-grid"27 onPointerLeave={(event) => {28 event.currentTarget.style.setProperty("--grid-rx", "58deg");29 event.currentTarget.style.setProperty("--grid-rz", "0deg");30 onPointerLeave?.(event);31 }}32 onPointerMove={(event) => {33 if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches) {34 const bounds = event.currentTarget.getBoundingClientRect();35 const x = (event.clientX - bounds.left) / bounds.width - 0.5;36 const y = (event.clientY - bounds.top) / bounds.height - 0.5;37 event.currentTarget.style.setProperty(38 "--grid-rx",39 `${58 - y * 24}deg`,40 );41 event.currentTarget.style.setProperty("--grid-rz", `${x * 16}deg`);42 }43 onPointerMove?.(event);44 }}45 style={46 {47 "--grid-rx": "58deg",48 "--grid-rz": "0deg",49 ...style,50 } as React.CSSProperties51 }52 {...props}53 >54 <div55 aria-hidden="true"56 className="absolute inset-x-[-35%] bottom-[-32%] h-[88%] origin-bottom transition-transform duration-200 ease-out will-change-transform [backface-visibility:hidden] [transform:perspective(520px)_rotateX(var(--grid-rx))_rotateZ(var(--grid-rz))] motion-reduce:transition-none"57 style={{58 backgroundImage:59 "linear-gradient(color-mix(in oklch, var(--primary) 44%, transparent) 1px, transparent 1px), linear-gradient(90deg, color-mix(in oklch, var(--primary) 44%, transparent) 1px, transparent 1px)",60 backgroundSize: "56px 56px",61 }}62 />63 <div64 aria-hidden="true"65 className="absolute bottom-[26%] left-1/2 h-px w-[70%] -translate-x-1/2 bg-primary/70 shadow-[0_0_40px_8px_color-mix(in_oklch,var(--primary)_45%,transparent)]"66 />67 {fade ? (68 <div69 aria-hidden="true"70// … truncated
What it pulls in
Other registry items
Files it writes
More from rivelle
All 83 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | rivelle | Components | Free | 2 deps | |
| Alertalert | rivelle | Components | Free | 1 dep | |
| Alert Dialogalert-dialog | rivelle | Components | Free | 1 dep | |
| Aspect Ratioaspect-ratio | rivelle | Components | Free | 1 dep | |
| Avataravatar | rivelle | Components | Free | 1 dep | |
| Badgebadge | rivelle | Components | Free | 2 deps | |
| Breadcrumbbreadcrumb | rivelle | Components | Free | 2 deps | |
| Buttonbutton | rivelle | Components | Free | 2 deps |
