pixel-canvas
componentry/pixel-canvasFreeComponent
An interactive pixel grid with smooth trailing effects that lights up on hover and decays over time.
Live preview
live · rendered by the registry
Rendered by componentry on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://componentry.dev/r/pixel-canvas.jsonSource
1"use client";23import React, { useEffect, useRef, useCallback } from "react";4import { cn } from "@/lib/utils";56interface PixelCanvasProps extends React.HTMLAttributes<HTMLDivElement> {7 /** Size of each pixel cell in pixels */8 gap?: number;9 /** Speed of the trailing decay (higher = faster fade) */10 speed?: number;11 /** Array of colors for pixels - will interpolate through them as trail fades */12 colors?: string[];13 /** Disable mouse tracking */14 noFocus?: boolean;15 /** Variant style */16 variant?: "default" | "trail" | "glow";17}1819interface Pixel {20 x: number;21 y: number;22 size: number;23 intensity: number;24 targetIntensity: number;25 colorPhase: number;26}2728// Helper to interpolate between two hex colors29function lerpColor(color1: string, color2: string, t: number): string {30 const c1 = hexToRgb(color1);31 const c2 = hexToRgb(color2);32 if (!c1 || !c2) return color1;3334 const r = Math.round(c1.r + (c2.r - c1.r) * t);35 const g = Math.round(c1.g + (c2.g - c1.g) * t);36 const b = Math.round(c1.b + (c2.b - c1.b) * t);3738 return `rgb(${r}, ${g}, ${b})`;39}4041function hexToRgb(hex: string): { r: number; g: number; b: number } | null {42 const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);43 return result44 ? {45 r: parseInt(result[1]!, 16),46 g: parseInt(result[2]!, 16),47 b: parseInt(result[3]!, 16),48 }49 : null;50}5152export function PixelCanvas({53 className,54 gap = 6,55 speed = 0.02,56 colors = ["#e879f9", "#a78bfa", "#38bdf8", "#22d3ee"],57 noFocus = false,58 variant = "default",59 ...props60}: PixelCanvasProps) {61 const canvasRef = useRef<HTMLCanvasElement>(null);62 const containerRef = useRef<HTMLDivElement>(null);63 const pixelsRef = useRef<Pixel[][]>([]);64 const mouseRef = useRef({ x: -1000, y: -1000 });65 const animationRef = useRef<number>(0);66 const lastTimeRef = useRef<number>(0);6768 const getColorFromIntensity = useCallback((intensity: number, phase: number) => {69 if (colors.length === 0) return "#ffffff";70 if (colors.length === 1) return colors[0]!;7172 // Use phase + intensity to create a shifting color effect73 const t = (phase + intensity) % 1;74 const index = Math.floor(t * (colors.length - 1));75 const nextIndex = Math.min(index + 1, colors.length - 1);76 const localT = (t * (colors.length - 1)) % 1;7778 const color1 = colors[index];79// … truncated
More from componentry
All 59 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Gradientanimated-gradient | componentry | Components | Free | no deps | |
| ASCII Effectascii-effect | componentry | Components | Free | no deps | |
| Aurora Flowaurora-flow | componentry | Components | Free | no deps | |
| auth-modalauth-modal | componentry | Components | Free | no deps | |
| border-beamborder-beam | componentry | Components | Free | no deps | |
| circuit-boardcircuit-board | componentry | Components | Free | no deps | |
| closing-plasmaclosing-plasma | componentry | Components | Free | no deps | |
| collection-surfercollection-surfer | componentry | Components | Free | no deps |
