Light Rays
spell-ui/light-raysFreeComponent
Animated light rays effect using WebGL shaders.
Live preview
live · rendered by the registry
Rendered by spell-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://spell.sh/r/light-rays.jsonSource
1"use client";23import { useRef, useEffect, useMemo, useState, type CSSProperties } from "react";4import * as THREE from "three";56interface AnimationConfig {7 animate: boolean;8 speed: number;9}1011interface SingleColorConfig {12 mode: "single";13 color: string;14}1516interface MultiColorConfig {17 mode: "multi";18 color1: string;19 color2: string;20}2122interface RandomColorConfig {23 mode: "random";24}2526type RaysColorConfig = SingleColorConfig | MultiColorConfig | RandomColorConfig;2728interface RaysProps {29 intensity?: number;30 rays?: number;31 reach?: number;32 position?: number;33 radius?: string;34 backgroundColor?: string;35 animation?: AnimationConfig;36 raysColor?: RaysColorConfig;37 style?: CSSProperties;38 className?: string;39}4041const RAY_Y_POSITION_1 = -0.4;42const RAY_Y_POSITION_2 = -0.5;4344export default function Rays({45 intensity = 13,46 rays = 32,47 reach = 16,48 position = 50,49 radius = "0px",50 backgroundColor = "#000",51 animation = { animate: true, speed: 10 },52 raysColor = { mode: "single", color: "#639AFF" },53 style,54 className,55}: RaysProps) {56 const containerRef = useRef<HTMLDivElement>(null);57 const meshRef = useRef<THREE.Mesh | null>(null);58 const frameIdRef = useRef<number | undefined>(undefined);59 const animationRef = useRef<AnimationConfig>(animation);6061 const [isMounted, setIsMounted] = useState(false);6263 useEffect(() => {64 setIsMounted(true);65 return () => setIsMounted(false);66 }, []);6768 useEffect(() => {69 animationRef.current = animation;70 }, [animation]);7172 const [randomColor1RGB, randomColor2RGB] = useMemo(() => {73 if (raysColor.mode === "random") {74 const h = Math.random() * 360;75 const s = 60 + Math.random() * 40;76 return [hslToRgb(h, s, 50), hslToRgb(h, s, 65)];77 }78 return [79 [1, 1, 1],80 [1, 1, 1],81 ] as [[number, number, number], [number, number, number]];82 }, [raysColor.mode]);8384 const [color1RGB, color2RGB] = useMemo((): [85 [number, number, number],86 [number, number, number],87 ] => {88 if (raysColor.mode === "random") {89 return [randomColor1RGB, randomColor2RGB] as [90 [number, number, number],91 [number, number, number],92 ];93 }9495 let color1 = "#fff";96 let color2 = "#fff";9798 if (raysColor.mode === "single") {99 color1 = raysColor.color;100 color2 = raysColor.color;101 } else if (raysColor.mode === "multi") {102 color1 = raysColor.color1;103 color2 = raysColor.color2;104 }105106// … truncated
What it pulls in
npm packages
Files it writes
More from spell-ui
All 33 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Checkboxanimated-checkbox | spell-ui | Components | Free | 1 dep | |
| Animated Gradientanimated-gradient | spell-ui | Components | Free | no deps | |
| Badgebadge | spell-ui | Components | Free | 2 deps | |
| Bars Spinnerbars-spinner | spell-ui | Components | Free | no deps | |
| Blur Revealblur-reveal | spell-ui | Components | Free | 1 dep | |
| Chartchart | spell-ui | Components | Free | no deps | |
| Color Selectorcolor-selector | spell-ui | Components | Free | no deps | |
| Copy Buttoncopy-button | spell-ui | Components | Free | 1 dep |
