Dual Sparks
scrollxui/dualsparksFreeComponent
Corner-based spark waves that radiate inward and outward with smooth motion.
Live preview
live · rendered by the registry
Rendered by scrollxui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://scrollxui.dev/registry/dualsparks.jsonSource
1"use client";23import React, { useEffect, useRef, useCallback } from "react";4import { cn } from "@/lib/utils";56interface DualSparksProps {7 sparkColor?: string;8 sparkColorDark?: string;9 sparkSize?: number;10 sparkCount?: number;11 duration?: number;12 easing?: "linear" | "ease-in" | "ease-out" | "ease-in-out";13 waveInterval?: number;14 maxRadius?: number;15 ringsPerWave?: number;16 ringSpacing?: number;17 enableInward?: boolean;18 corners?: "both" | "left" | "right";19 backgroundColor?: string;20 backgroundColorDark?: string;21 clearBackground?: boolean;22 backgroundOpacity?: number;23 className?: string;24 children?: React.ReactNode;25 forceDarkMode?: boolean;26}2728interface Spark {29 x: number;30 y: number;31 angle: number;32 radius: number;33 startTime: number;34 waveId: number;35 ringIndex: number;36 direction: "outward" | "inward";37 corner: "left" | "right";38}3940export const DualSparks: React.FC<DualSparksProps> = ({41 sparkColor = "#000000",42 sparkColorDark = "#ffffff",43 sparkSize = 10,44 sparkCount = 24,45 duration = 3500,46 easing = "ease-out",47 waveInterval = 1400,48 maxRadius = 800,49 ringsPerWave = 5,50 ringSpacing = 40,51 enableInward = true,52 corners = "both",53 backgroundColor = "rgba(240, 240, 250, 0.15)",54 backgroundColorDark = "rgba(0, 0, 0, 0.15)",55 clearBackground = true,56 backgroundOpacity = 0.15,57 className = "",58 children,59 forceDarkMode,60}) => {61 const canvasRef = useRef<HTMLCanvasElement>(null);62 const sparksRef = useRef<Spark[]>([]);63 const lastWaveTimeRef = useRef<number>(0);64 const lastInwardWaveTimeRef = useRef<number>(700);65 const waveIdRef = useRef<number>(0);66 const containerWidthRef = useRef<number>(0);67 const containerHeightRef = useRef<number>(0);68 const animationIdRef = useRef<number>(0);6970 const isDarkMode = useCallback(() => {71 if (forceDarkMode !== undefined) return forceDarkMode;72 if (typeof document === "undefined") return false;73 return document.documentElement.classList.contains("dark");74 }, [forceDarkMode]);7576 const getSparkColor = useCallback(() => {77 return isDarkMode() ? sparkColorDark : sparkColor;78 }, [isDarkMode, sparkColor, sparkColorDark]);7980 const getBackgroundColor = useCallback(() => {81 const baseColor = isDarkMode() ? backgroundColorDark : backgroundColor;8283 if (backgroundOpacity !== undefined && backgroundOpacity !== 0.15) {84 const match = baseColor.match(85 /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/86 );87 if (match) {88// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from scrollxui
All 180 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | scrollxui | Components | Free | 4 deps | |
| Alert Dialogalert-dialog | scrollxui | Components | Free | 7 deps | |
| Animated Buttonanimated-button | scrollxui | Components | Free | 4 deps | |
| Animated Tabsanimated-tabs | scrollxui | Components | Free | 1 dep | |
| Animated Testimonialsanimated-testimonials | scrollxui | Components | Free | 2 deps | |
| Animated TextGenerateanimated-textgenerate | scrollxui | Components | Free | 3 deps | |
| Announcementannouncement | scrollxui | Components | Free | 5 deps | |
| Aspect Ratioaspect-ratio | scrollxui | Components | Free | 1 dep |
