@hdcodedev/snowfall 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/dist/index.d.mts +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +433 -169
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +433 -170
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Snowfall.tsx","../src/SnowfallProvider.tsx","../src/utils/snowfall/constants.ts","../src/utils/snowfall/dom.ts","../src/utils/snowfall/physics.ts","../src/utils/snowfall/draw.ts"],"sourcesContent":["'use client';\n\nexport { default as Snowfall } from './Snowfall';\nexport { SnowfallProvider, useSnowfall, DEFAULT_PHYSICS } from './SnowfallProvider';\nexport type { PhysicsConfig } from './SnowfallProvider';\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useSnowfall } from './SnowfallProvider';\nimport { Snowflake, SnowAccumulation } from './utils/snowfall/types';\nimport { getElementRects } from './utils/snowfall/dom';\nimport { createSnowflake, initializeAccumulation, meltAndSmoothAccumulation, updateSnowflakes } from './utils/snowfall/physics';\nimport { drawAccumulations, drawSideAccumulations, drawSnowflake } from './utils/snowfall/draw';\n\nexport default function Snowfall() {\n const { isEnabled, physicsConfig } = useSnowfall();\n const isEnabledRef = useRef(isEnabled);\n const physicsConfigRef = useRef(physicsConfig);\n const [isMounted, setIsMounted] = useState(false);\n const [isVisible, setIsVisible] = useState(false);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const fixedCanvasRef = useRef<HTMLCanvasElement>(null);\n const snowflakesRef = useRef<Snowflake[]>([]);\n const accumulationRef = useRef<Map<Element, SnowAccumulation>>(new Map());\n const animationIdRef = useRef<number>(0);\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n useEffect(() => {\n isEnabledRef.current = isEnabled;\n }, [isEnabled]);\n\n useEffect(() => {\n physicsConfigRef.current = physicsConfig;\n }, [physicsConfig]);\n\n useEffect(() => {\n if (!isMounted) return;\n\n const canvas = canvasRef.current;\n const fixedCanvas = fixedCanvasRef.current;\n if (!canvas || !fixedCanvas) return;\n\n const ctx = canvas.getContext('2d');\n const fixedCtx = fixedCanvas.getContext('2d');\n if (!ctx || !fixedCtx) return;\n\n const resizeCanvas = () => {\n if (canvasRef.current && fixedCanvasRef.current) {\n const newHeight = Math.max(document.documentElement.scrollHeight, window.innerHeight);\n const newWidth = Math.max(document.documentElement.scrollWidth, window.innerWidth);\n\n if (canvasRef.current.height !== newHeight || canvasRef.current.width !== newWidth) {\n canvasRef.current.width = newWidth;\n canvasRef.current.height = newHeight;\n }\n\n // Fixed canvas matches viewport\n if (fixedCanvasRef.current.width !== window.innerWidth || fixedCanvasRef.current.height !== window.innerHeight) {\n fixedCanvasRef.current.width = window.innerWidth;\n fixedCanvasRef.current.height = window.innerHeight;\n }\n }\n };\n resizeCanvas();\n\n const resizeObserver = new ResizeObserver(() => {\n resizeCanvas();\n });\n resizeObserver.observe(document.body);\n\n snowflakesRef.current = [];\n\n const initAccumulationWrapper = () => {\n initializeAccumulation(accumulationRef.current, physicsConfigRef.current);\n };\n initAccumulationWrapper();\n\n setIsVisible(true);\n\n let lastTime = 0;\n\n const animate = (currentTime: number) => {\n if (lastTime === 0) {\n lastTime = currentTime;\n animationIdRef.current = requestAnimationFrame(animate);\n return;\n }\n\n const deltaTime = Math.min(currentTime - lastTime, 50);\n lastTime = currentTime;\n const dt = deltaTime / 16.67;\n\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n fixedCtx.clearRect(0, 0, fixedCanvas.width, fixedCanvas.height);\n\n const snowflakes = snowflakesRef.current;\n const elementRects = getElementRects(accumulationRef.current);\n\n // Physics Update: Melt and Smooth\n meltAndSmoothAccumulation(elementRects, physicsConfigRef.current, dt);\n\n // Physics Update: Snowflakes & Collisions\n updateSnowflakes(snowflakes, elementRects, physicsConfigRef.current, dt, canvas.width, canvas.height);\n\n // Draw Snowflakes\n for (const flake of snowflakes) {\n drawSnowflake(ctx, flake);\n }\n\n // Spawn new snowflakes\n if (isEnabledRef.current && snowflakes.length < physicsConfigRef.current.MAX_FLAKES) {\n const isBackground = Math.random() < 0.4;\n snowflakes.push(createSnowflake(canvas.width, physicsConfigRef.current, isBackground));\n }\n\n // Draw Accumulation\n drawAccumulations(ctx, fixedCtx, elementRects);\n drawSideAccumulations(ctx, fixedCtx, elementRects);\n\n animationIdRef.current = requestAnimationFrame(animate);\n };\n\n animationIdRef.current = requestAnimationFrame(animate);\n\n const handleResize = () => {\n resizeCanvas();\n accumulationRef.current.clear();\n initAccumulationWrapper();\n };\n\n window.addEventListener('resize', handleResize);\n const checkInterval = setInterval(initAccumulationWrapper, 3000);\n\n return () => {\n cancelAnimationFrame(animationIdRef.current);\n window.removeEventListener('resize', handleResize);\n clearInterval(checkInterval);\n resizeObserver.disconnect();\n };\n }, [isMounted]);\n\n if (!isMounted) return null;\n\n return (\n <>\n <canvas\n ref={canvasRef}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n pointerEvents: 'none',\n zIndex: 9999,\n opacity: isVisible ? 1 : 0,\n transition: 'opacity 0.3s ease-in',\n }}\n aria-hidden=\"true\"\n />\n <canvas\n ref={fixedCanvasRef}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n pointerEvents: 'none',\n zIndex: 9999,\n opacity: isVisible ? 1 : 0,\n transition: 'opacity 0.3s ease-in',\n }}\n aria-hidden=\"true\"\n />\n </>\n );\n}\n","'use client';\n\nimport React, { createContext, useContext, useState, ReactNode } from 'react';\n\nexport interface PhysicsConfig {\n MAX_FLAKES: number;\n MELT_SPEED: number;\n WIND_STRENGTH: number;\n ACCUMULATION: {\n SIDE_RATE: number;\n TOP_RATE: number;\n BOTTOM_RATE: number;\n };\n MAX_DEPTH: {\n TOP: number;\n BOTTOM: number;\n SIDE: number;\n };\n FLAKE_SIZE: {\n MIN: number;\n MAX: number;\n };\n}\n\nexport const DEFAULT_PHYSICS: PhysicsConfig = {\n MAX_FLAKES: 1000,\n MELT_SPEED: 0.00001,\n WIND_STRENGTH: 1.5,\n ACCUMULATION: {\n SIDE_RATE: 1,\n TOP_RATE: 5,\n BOTTOM_RATE: 5.0,\n },\n MAX_DEPTH: {\n TOP: 100,\n BOTTOM: 50,\n SIDE: 20,\n },\n FLAKE_SIZE: {\n MIN: 0.5,\n MAX: 1.6,\n }\n};\n\ninterface SnowfallContextType {\n isEnabled: boolean;\n toggleSnow: () => void;\n physicsConfig: PhysicsConfig;\n updatePhysicsConfig: (config: Partial<PhysicsConfig>) => void;\n resetPhysics: () => void;\n}\n\nconst SnowfallContext = createContext<SnowfallContextType | undefined>(undefined);\n\nexport function SnowfallProvider({ children }: { children: ReactNode }) {\n const [isEnabled, setIsEnabled] = useState(true);\n const [physicsConfig, setPhysicsConfig] = useState<PhysicsConfig>(DEFAULT_PHYSICS);\n\n const toggleSnow = () => {\n setIsEnabled((prev) => !prev);\n };\n\n const updatePhysicsConfig = (config: Partial<PhysicsConfig>) => {\n setPhysicsConfig((prev) => ({\n ...prev,\n ...config,\n ACCUMULATION: {\n ...prev.ACCUMULATION,\n ...(config.ACCUMULATION || {}),\n },\n MAX_DEPTH: {\n ...prev.MAX_DEPTH,\n ...(config.MAX_DEPTH || {}),\n },\n FLAKE_SIZE: {\n ...prev.FLAKE_SIZE,\n ...(config.FLAKE_SIZE || {}),\n },\n }));\n };\n\n const resetPhysics = () => {\n setPhysicsConfig(DEFAULT_PHYSICS);\n };\n\n return (\n <SnowfallContext.Provider value={{\n isEnabled,\n toggleSnow,\n physicsConfig,\n updatePhysicsConfig,\n resetPhysics\n }}>\n {children}\n </SnowfallContext.Provider>\n );\n}\n\nexport function useSnowfall() {\n const context = useContext(SnowfallContext);\n if (context === undefined) {\n throw new Error('useSnowfall must be used within a SnowfallProvider');\n }\n return context;\n}\n","export const ATTR_SNOWFALL = 'data-snowfall';\n\nexport const VAL_IGNORE = 'ignore';\nexport const VAL_TOP = 'top';\nexport const VAL_BOTTOM = 'bottom';\n\nexport const TAG_HEADER = 'header';\nexport const TAG_FOOTER = 'footer';\n\nexport const ROLE_BANNER = 'banner';\nexport const ROLE_CONTENTINFO = 'contentinfo';\n","import { SnowAccumulation, ElementSurface, SnowfallSurface } from './types';\nimport {\n ATTR_SNOWFALL, VAL_IGNORE, VAL_TOP, VAL_BOTTOM,\n TAG_HEADER, TAG_FOOTER, ROLE_BANNER, ROLE_CONTENTINFO\n} from './constants';\n\n// Headers: snow accumulates on BOTTOM edge\n// Footers: default to TOP surface (snow piles on top)\n// Use data-snowfall attributes to override this behavior\nconst BOTTOM_TAGS = [TAG_HEADER];\nconst BOTTOM_ROLES = [ROLE_BANNER];\n\nconst AUTO_DETECT_TAGS = ['header', 'footer', 'article', 'section', 'aside', 'nav'];\nconst AUTO_DETECT_ROLES = ['[role=\"banner\"]', '[role=\"contentinfo\"]', '[role=\"main\"]'];\nconst AUTO_DETECT_CLASSES = [\n '.card', '[class*=\"card\"]', '[class*=\"Card\"]',\n '[class*=\"bg-\"]', '[class*=\"shadow-\"]', '[class*=\"rounded-\"]'\n];\n\nexport const getElementType = (el: Element): SnowfallSurface => {\n const tagName = el.tagName.toLowerCase();\n if (BOTTOM_TAGS.includes(tagName)) return VAL_BOTTOM;\n\n const role = el.getAttribute('role');\n if (role && BOTTOM_ROLES.includes(role)) return VAL_BOTTOM;\n\n // Default: snow accumulates on top of elements (natural physics)\n return VAL_TOP;\n};\n\nconst shouldAccumulate = (el: Element): boolean => {\n // Explicit opt-out\n if (el.getAttribute(ATTR_SNOWFALL) === VAL_IGNORE) return false;\n\n // Explicit opt-in\n if (el.hasAttribute(ATTR_SNOWFALL)) return true;\n\n // Heuristics\n const styles = window.getComputedStyle(el);\n const rect = el.getBoundingClientRect();\n\n const isVisible = styles.display !== 'none' &&\n styles.visibility !== 'hidden' &&\n parseFloat(styles.opacity) > 0.1;\n if (!isVisible) return false;\n\n // Check for visual prominence\n const bgColor = styles.backgroundColor;\n const hasBackground = bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent';\n const hasBorder = parseFloat(styles.borderWidth) > 0 || styles.borderStyle !== 'none';\n const hasBoxShadow = styles.boxShadow !== 'none';\n const hasBorderRadius = parseFloat(styles.borderRadius) > 0;\n\n return hasBackground || hasBorder || hasBoxShadow || hasBorderRadius;\n};\n\nexport const getAccumulationSurfaces = (): { el: Element; type: SnowfallSurface; isFixed: boolean }[] => {\n const surfaces: { el: Element; type: SnowfallSurface; isFixed: boolean }[] = [];\n const seen = new Set<Element>();\n\n const candidates = document.querySelectorAll(\n [\n `[${ATTR_SNOWFALL}]`,\n ...AUTO_DETECT_TAGS,\n ...AUTO_DETECT_ROLES,\n ...AUTO_DETECT_CLASSES\n ].join(', ')\n );\n\n candidates.forEach(el => {\n if (seen.has(el)) return;\n\n const rect = el.getBoundingClientRect();\n\n // Manual override check first\n const manualOverride = el.getAttribute(ATTR_SNOWFALL);\n if (manualOverride === VAL_IGNORE) return;\n\n // If manually opted in, skip some heuristic checks but keep basic visibility/size sanity\n const isManuallyIncluded = manualOverride !== null;\n\n const styles = window.getComputedStyle(el);\n const isVisible = styles.display !== 'none' &&\n styles.visibility !== 'hidden' &&\n parseFloat(styles.opacity) > 0.1;\n\n if (!isVisible && !isManuallyIncluded) return;\n\n // Skip really small elements unless manually forced\n const hasSize = rect.width >= 100 && rect.height >= 50;\n if (!hasSize && !isManuallyIncluded) return;\n\n // HEURISTIC: Skip full-page wrappers\n const isFullPageWrapper = rect.top <= 10 && rect.height >= window.innerHeight * 0.9;\n\n\n const isBottomTag = BOTTOM_TAGS.includes(el.tagName.toLowerCase());\n const isBottomRole = BOTTOM_ROLES.includes(el.getAttribute('role') || '');\n const isBottomSurface = isBottomTag || isBottomRole ||\n manualOverride === VAL_BOTTOM;\n\n if (isFullPageWrapper && !isBottomSurface && !isManuallyIncluded) return;\n\n let isFixed = false;\n let currentEl: Element | null = el;\n while (currentEl && currentEl !== document.body) {\n const style = window.getComputedStyle(currentEl);\n if (style.position === 'fixed' || style.position === 'sticky') {\n isFixed = true;\n break;\n }\n currentEl = currentEl.parentElement;\n }\n\n if (shouldAccumulate(el)) {\n // Determine type: manual override takes precedence\n let type: SnowfallSurface = getElementType(el);\n\n if (manualOverride === VAL_BOTTOM) {\n type = VAL_BOTTOM;\n } else if (manualOverride === VAL_TOP) {\n type = VAL_TOP;\n }\n\n surfaces.push({ el, type, isFixed });\n seen.add(el);\n }\n });\n\n console.log(`[Snowfall] Auto-detection found ${surfaces.length} surfaces`);\n return surfaces;\n};\n\nexport const getElementRects = (accumulationMap: Map<Element, SnowAccumulation>): ElementSurface[] => {\n const elementRects: ElementSurface[] = [];\n\n for (const [el, acc] of accumulationMap.entries()) {\n if (!el.isConnected) continue;\n const rect = el.getBoundingClientRect();\n // Convert viewport coordinates to absolute page coordinates\n const absoluteRect = {\n left: rect.left + window.scrollX,\n right: rect.right + window.scrollX,\n top: rect.top + window.scrollY,\n bottom: rect.bottom + window.scrollY,\n width: rect.width,\n height: rect.height,\n x: rect.x, // Note: these are strictly viewport relative in DOMRect usually, \n // but we just need consistent absolute coords for physics\n y: rect.y,\n toJSON: rect.toJSON\n };\n // We cast because we constructed a compatible object, though strictly DOMRect has readonly properties\n elementRects.push({ el, rect: absoluteRect as unknown as DOMRect, acc });\n }\n return elementRects;\n};\n","import { PhysicsConfig } from '../../SnowfallProvider';\nimport { Snowflake, SnowAccumulation, ElementSurface } from './types';\nimport { getAccumulationSurfaces } from './dom';\nimport { VAL_BOTTOM } from './constants';\n\nexport const createSnowflake = (\n canvasWidth: number,\n config: PhysicsConfig,\n isBackground: boolean = false\n): Snowflake => {\n if (isBackground) {\n const sizeRatio = Math.random();\n const radius = config.FLAKE_SIZE.MIN * 0.6 + sizeRatio * (config.FLAKE_SIZE.MAX - config.FLAKE_SIZE.MIN) * 0.4;\n return {\n x: Math.random() * canvasWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.3 + Math.random() * 0.2 + 0.2,\n wind: (Math.random() - 0.5) * (config.WIND_STRENGTH * 0.625),\n opacity: Math.random() * 0.2 + 0.2,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.015 + 0.005,\n sizeRatio,\n isBackground: true\n };\n } else {\n const sizeRatio = Math.random();\n const radius = config.FLAKE_SIZE.MIN + sizeRatio * (config.FLAKE_SIZE.MAX - config.FLAKE_SIZE.MIN);\n return {\n x: Math.random() * canvasWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.5 + Math.random() * 0.3 + 0.5,\n wind: (Math.random() - 0.5) * config.WIND_STRENGTH,\n opacity: Math.random() * 0.3 + 0.5,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.02 + 0.01,\n sizeRatio,\n isBackground: false\n };\n }\n};\n\nexport const initializeAccumulation = (\n accumulationMap: Map<Element, SnowAccumulation>,\n config: PhysicsConfig\n) => {\n const elements = getAccumulationSurfaces();\n // Prune disconnected elements\n for (const [el] of accumulationMap.entries()) {\n if (!el.isConnected) {\n accumulationMap.delete(el);\n }\n }\n\n elements.forEach(({ el, type, isFixed }) => {\n const existing = accumulationMap.get(el);\n const rect = el.getBoundingClientRect();\n const width = Math.ceil(rect.width);\n const isBottom = type === VAL_BOTTOM;\n\n if (existing && existing.heights.length === width) {\n existing.type = type;\n existing.isFixed = isFixed;\n if (existing.borderRadius !== undefined) {\n const styleBuffer = window.getComputedStyle(el); // Potentially slow in loop, strictly necessary?\n existing.borderRadius = parseFloat(styleBuffer.borderTopLeftRadius) || 0;\n }\n return;\n }\n\n const height = Math.ceil(rect.height);\n const baseMax = isBottom ? config.MAX_DEPTH.BOTTOM : config.MAX_DEPTH.TOP;\n\n const styles = window.getComputedStyle(el);\n const borderRadius = parseFloat(styles.borderTopLeftRadius) || 0;\n\n let maxHeights = new Array(width);\n for (let i = 0; i < width; i++) {\n let edgeFactor = 1.0;\n if (!isBottom && borderRadius > 0) {\n if (i < borderRadius) {\n edgeFactor = Math.pow(i / borderRadius, 1.2);\n } else if (i > width - borderRadius) {\n edgeFactor = Math.pow((width - i) / borderRadius, 1.2);\n }\n }\n maxHeights[i] = baseMax * edgeFactor * (0.85 + Math.random() * 0.15);\n }\n\n // Smooth maxHeights\n const smoothPasses = 4;\n for (let p = 0; p < smoothPasses; p++) {\n const smoothed = [...maxHeights];\n for (let i = 1; i < width - 1; i++) {\n smoothed[i] = (maxHeights[i - 1] + maxHeights[i] + maxHeights[i + 1]) / 3;\n }\n maxHeights = smoothed;\n }\n\n accumulationMap.set(el, {\n heights: existing?.heights.length === width ? existing.heights : new Array(width).fill(0),\n maxHeights,\n leftSide: existing?.leftSide.length === height ? existing.leftSide : new Array(height).fill(0),\n rightSide: existing?.rightSide.length === height ? existing.rightSide : new Array(height).fill(0),\n maxSideHeight: isBottom ? 0 : config.MAX_DEPTH.SIDE,\n borderRadius,\n type,\n isFixed,\n });\n });\n};\n\nconst accumulateSide = (\n sideArray: number[],\n rectHeight: number,\n localY: number,\n maxSideHeight: number,\n borderRadius: number,\n config: PhysicsConfig\n) => {\n const spread = 4;\n const addHeight = config.ACCUMULATION.SIDE_RATE * (0.8 + Math.random() * 0.4);\n\n for (let dy = -spread; dy <= spread; dy++) {\n const y = localY + dy;\n if (y >= 0 && y < sideArray.length) {\n const inTop = y < borderRadius;\n const inBottom = y > rectHeight - borderRadius;\n if (borderRadius > 0 && (inTop || inBottom)) continue;\n\n const normalizedDist = Math.abs(dy) / spread;\n const falloff = (Math.cos(normalizedDist * Math.PI) + 1) / 2;\n sideArray[y] = Math.min(maxSideHeight, sideArray[y] + addHeight * falloff);\n }\n }\n};\n\nexport const updateSnowflakes = (\n snowflakes: Snowflake[],\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number,\n canvasWidth: number,\n canvasHeight: number\n) => {\n for (let i = snowflakes.length - 1; i >= 0; i--) {\n const flake = snowflakes[i];\n\n flake.wobble += flake.wobbleSpeed * dt;\n flake.x += (flake.wind + Math.sin(flake.wobble) * 0.5) * dt;\n flake.y += (flake.speed + Math.cos(flake.wobble * 0.5) * 0.1) * dt;\n\n let landed = false;\n\n for (const { rect, acc } of elementRects) {\n const isBottom = acc.type === VAL_BOTTOM;\n\n // Side collisions\n if (!landed && acc.maxSideHeight > 0 && !isBottom) {\n const isInVerticalBounds = flake.y >= rect.top && flake.y <= rect.bottom;\n\n if (isInVerticalBounds) {\n const localY = Math.floor(flake.y - rect.top);\n const borderRadius = acc.borderRadius;\n\n const isInTopCorner = localY < borderRadius;\n const isInBottomCorner = localY > rect.height - borderRadius;\n const isCorner = borderRadius > 0 && (isInTopCorner || isInBottomCorner);\n\n if (flake.x >= rect.left - 5 && flake.x < rect.left + 3) {\n if (!isCorner) {\n accumulateSide(acc.leftSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (!landed && flake.x > rect.right - 3 && flake.x <= rect.right + 5) {\n if (!isCorner) {\n accumulateSide(acc.rightSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (landed) break;\n }\n }\n\n // Top accumulation\n if (flake.x >= rect.left && flake.x <= rect.right) {\n const localX = Math.floor(flake.x - rect.left);\n const currentHeight = acc.heights[localX] || 0;\n const maxHeight = acc.maxHeights[localX] || 5;\n\n const surfaceY = isBottom ? rect.bottom - currentHeight : rect.top - currentHeight;\n\n if (flake.y >= surfaceY && flake.y < surfaceY + 10 && currentHeight < maxHeight) {\n const shouldAccumulate = isBottom ? Math.random() < 0.15 : true;\n\n if (shouldAccumulate) {\n const baseSpread = Math.ceil(flake.radius);\n const spread = baseSpread + Math.floor(Math.random() * 2);\n const accumRate = isBottom ? config.ACCUMULATION.BOTTOM_RATE : config.ACCUMULATION.TOP_RATE;\n const centerOffset = Math.floor(Math.random() * 3) - 1;\n\n for (let dx = -spread; dx <= spread; dx++) {\n if (Math.random() < 0.15) continue;\n const idx = localX + dx + centerOffset;\n if (idx >= 0 && idx < acc.heights.length) {\n const dist = Math.abs(dx);\n const pixelMax = acc.maxHeights[idx] || 5;\n\n const normDist = dist / spread;\n const falloff = (Math.cos(normDist * Math.PI) + 1) / 2;\n const baseAdd = 0.3 * falloff;\n\n const randomFactor = 0.8 + Math.random() * 0.4;\n const addHeight = baseAdd * randomFactor * accumRate;\n\n if (acc.heights[idx] < pixelMax && addHeight > 0) {\n acc.heights[idx] = Math.min(pixelMax, acc.heights[idx] + addHeight);\n }\n }\n }\n\n if (isBottom) {\n landed = true;\n break;\n }\n }\n\n if (!isBottom) {\n landed = true;\n break;\n }\n }\n }\n }\n\n if (landed || flake.y > canvasHeight + 10 || flake.x < -20 || flake.x > canvasWidth + 20) {\n snowflakes.splice(i, 1);\n }\n }\n};\n\nexport const meltAndSmoothAccumulation = (\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number\n) => {\n for (const { acc } of elementRects) {\n const meltRate = config.MELT_SPEED * dt;\n const len = acc.heights.length;\n\n // Smooth\n if (len > 2) {\n for (let i = 1; i < len - 1; i++) {\n if (acc.heights[i] > 0.05) {\n const avg = (acc.heights[i - 1] + acc.heights[i + 1]) / 2;\n acc.heights[i] = acc.heights[i] * 0.99 + avg * 0.01;\n }\n }\n }\n\n // Melt\n for (let i = 0; i < acc.heights.length; i++) {\n if (acc.heights[i] > 0) acc.heights[i] = Math.max(0, acc.heights[i] - meltRate);\n }\n for (let i = 0; i < acc.leftSide.length; i++) {\n if (acc.leftSide[i] > 0) acc.leftSide[i] = Math.max(0, acc.leftSide[i] - meltRate);\n if (acc.rightSide[i] > 0) acc.rightSide[i] = Math.max(0, acc.rightSide[i] - meltRate);\n }\n }\n};\n","import { Snowflake, ElementSurface } from './types';\nimport { VAL_BOTTOM } from './constants';\n\nexport const drawSnowflake = (ctx: CanvasRenderingContext2D, flake: Snowflake) => {\n ctx.beginPath();\n ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI * 2);\n ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity})`;\n ctx.fill();\n\n ctx.beginPath();\n ctx.arc(flake.x, flake.y, flake.radius * 1.5, 0, Math.PI * 2);\n ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity * 0.2})`;\n ctx.fill();\n};\n\nexport const drawAccumulations = (\n ctx: CanvasRenderingContext2D,\n fixedCtx: CanvasRenderingContext2D | null,\n elementRects: ElementSurface[]\n) => {\n // Setup styles for both contexts\n const setupCtx = (c: CanvasRenderingContext2D) => {\n c.fillStyle = 'rgba(255, 255, 255, 0.95)';\n c.shadowColor = 'rgba(200, 230, 255, 0.6)';\n c.shadowBlur = 4;\n c.shadowOffsetY = -1;\n };\n setupCtx(ctx);\n if (fixedCtx) setupCtx(fixedCtx);\n\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n\n for (const { rect, acc } of elementRects) {\n if (!acc.heights.some(h => h > 0.1)) continue;\n\n const useFixed = acc.isFixed && fixedCtx;\n const targetCtx = useFixed ? fixedCtx! : ctx;\n\n // If using fixed context, we need to convert absolute coordinates (rect) back to viewport coordinates\n const dx = useFixed ? -scrollX : 0;\n const dy = useFixed ? -scrollY : 0;\n\n const isBottom = acc.type === VAL_BOTTOM;\n const baseY = isBottom ? rect.bottom - 1 : rect.top + 1;\n const borderRadius = acc.borderRadius;\n\n const getCurveOffset = (xPos: number) => {\n if (borderRadius <= 0 || isBottom) return 0;\n let offset = 0;\n if (xPos < borderRadius) {\n const dist = borderRadius - xPos;\n offset = borderRadius - Math.sqrt(Math.max(0, borderRadius * borderRadius - dist * dist));\n } else if (xPos > rect.width - borderRadius) {\n const dist = xPos - (rect.width - borderRadius);\n offset = borderRadius - Math.sqrt(Math.max(0, borderRadius * borderRadius - dist * dist));\n }\n return offset;\n };\n\n targetCtx.beginPath();\n let first = true;\n const step = 2;\n const len = acc.heights.length;\n\n for (let x = 0; x < len; x += step) {\n const height = acc.heights[x] || 0;\n const px = rect.left + x + dx;\n const py = baseY - height + getCurveOffset(x) + dy;\n if (first) {\n targetCtx.moveTo(px, py);\n first = false;\n } else {\n targetCtx.lineTo(px, py);\n }\n }\n\n if ((len - 1) % step !== 0) {\n const x = len - 1;\n const height = acc.heights[x] || 0;\n const px = rect.left + x + dx;\n const py = baseY - height + getCurveOffset(x) + dy;\n targetCtx.lineTo(px, py);\n }\n\n for (let x = len - 1; x >= 0; x -= step) {\n const px = rect.left + x + dx;\n const py = baseY + getCurveOffset(x) + dy;\n targetCtx.lineTo(px, py);\n }\n\n const startX = 0;\n const startPx = rect.left + startX + dx;\n const startPy = baseY + getCurveOffset(startX) + dy;\n targetCtx.lineTo(startPx, startPy);\n\n targetCtx.closePath();\n targetCtx.fill();\n }\n\n ctx.shadowBlur = 0;\n ctx.shadowOffsetY = 0;\n if (fixedCtx) {\n fixedCtx.shadowBlur = 0;\n fixedCtx.shadowOffsetY = 0;\n }\n};\n\nexport const drawSideAccumulations = (\n ctx: CanvasRenderingContext2D,\n fixedCtx: CanvasRenderingContext2D | null,\n elementRects: ElementSurface[]\n) => {\n const setupCtx = (c: CanvasRenderingContext2D) => {\n c.fillStyle = 'rgba(255, 255, 255, 0.95)';\n c.shadowColor = 'rgba(200, 230, 255, 0.6)';\n c.shadowBlur = 3;\n };\n setupCtx(ctx);\n if (fixedCtx) setupCtx(fixedCtx);\n\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n\n for (const { rect, acc } of elementRects) {\n if (acc.maxSideHeight === 0) continue;\n\n const hasLeftSnow = acc.leftSide.some(h => h > 0.3);\n const hasRightSnow = acc.rightSide.some(h => h > 0.3);\n\n if (!hasLeftSnow && !hasRightSnow) continue;\n\n const useFixed = acc.isFixed && fixedCtx;\n const targetCtx = useFixed ? fixedCtx! : ctx;\n const dx = useFixed ? -scrollX : 0;\n const dy = useFixed ? -scrollY : 0;\n\n const drawSide = (sideArray: number[], isLeft: boolean) => {\n targetCtx.beginPath();\n const baseX = isLeft ? rect.left : rect.right;\n\n // Start at the top of the element\n targetCtx.moveTo(baseX + dx, rect.top + dy);\n\n for (let y = 0; y < sideArray.length; y += 2) {\n const width = sideArray[y] || 0;\n const nextY = Math.min(y + 2, sideArray.length - 1);\n const nextWidth = sideArray[nextY] || 0;\n\n // Apply gravity influence: snow accumulates more towards the bottom\n // Quadratic falloff makes accumulation stronger at the bottom\n const heightRatio = y / sideArray.length;\n const gravityMultiplier = Math.pow(heightRatio, 1.5); // Heavy bias towards bottom\n\n const py = rect.top + y + dy;\n const px = (isLeft ? baseX - (width * gravityMultiplier) : baseX + (width * gravityMultiplier)) + dx;\n const ny = rect.top + nextY + dy;\n const nRatio = nextY / sideArray.length;\n const nGravityMultiplier = Math.pow(nRatio, 1.5);\n const nx = (isLeft ? baseX - (nextWidth * nGravityMultiplier) : baseX + (nextWidth * nGravityMultiplier)) + dx;\n\n targetCtx.lineTo(px, py);\n targetCtx.lineTo(nx, ny);\n }\n\n // Close at the bottom\n targetCtx.lineTo(baseX + dx, rect.bottom + dy);\n targetCtx.closePath();\n targetCtx.fill();\n };\n\n if (hasLeftSnow) drawSide(acc.leftSide, true);\n if (hasRightSnow) drawSide(acc.rightSide, false);\n }\n\n ctx.shadowBlur = 0;\n if (fixedCtx) fixedCtx.shadowBlur = 0;\n};\n"],"mappings":"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","names":["import_react","shouldAccumulate","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Snowfall.tsx","../src/SnowfallProvider.tsx","../src/utils/snowfall/constants.ts","../src/utils/snowfall/dom.ts","../src/utils/snowfall/physics.ts","../src/utils/snowfall/draw.ts","../src/DebugPanel.tsx"],"sourcesContent":["'use client';\n\n// Main components\nexport { default as Snowfall } from './Snowfall';\nexport { SnowfallProvider, useSnowfall, DEFAULT_PHYSICS } from './SnowfallProvider';\nexport { default as DebugPanel } from './DebugPanel';\n\n// Types\nexport type { PhysicsConfig, PerformanceMetrics } from './SnowfallProvider';\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useSnowfall } from './SnowfallProvider';\nimport { Snowflake, SnowAccumulation } from './utils/snowfall/types';\nimport { getElementRects } from './utils/snowfall/dom';\nimport { createSnowflake, initializeAccumulation, meltAndSmoothAccumulation, updateSnowflakes } from './utils/snowfall/physics';\nimport { drawAccumulations, drawSideAccumulations, drawSnowflake } from './utils/snowfall/draw';\n\nexport default function Snowfall() {\n const { isEnabled, physicsConfig, setMetrics } = useSnowfall();\n const isEnabledRef = useRef(isEnabled);\n const physicsConfigRef = useRef(physicsConfig);\n const setMetricsRef = useRef(setMetrics);\n const [isMounted, setIsMounted] = useState(false);\n const [isVisible, setIsVisible] = useState(false);\n\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const snowflakesRef = useRef<Snowflake[]>([]);\n const accumulationRef = useRef<Map<Element, SnowAccumulation>>(new Map());\n const animationIdRef = useRef<number>(0);\n\n // Performance metrics tracking\n const fpsFrames = useRef<number[]>([]);\n const metricsRef = useRef({\n scanTime: 0,\n rectUpdateTime: 0,\n frameTime: 0,\n rafGap: 0,\n clearTime: 0,\n physicsTime: 0,\n drawTime: 0,\n });\n\n useEffect(() => {\n setIsMounted(true);\n }, []);\n\n useEffect(() => {\n isEnabledRef.current = isEnabled;\n }, [isEnabled]);\n\n useEffect(() => {\n physicsConfigRef.current = physicsConfig;\n }, [physicsConfig]);\n\n useEffect(() => {\n setMetricsRef.current = setMetrics;\n }, [setMetrics]);\n\n useEffect(() => {\n if (!isMounted) return;\n\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const resizeCanvas = () => {\n if (canvasRef.current) {\n // Use viewport dimensions for fixed canvas\n const newWidth = window.innerWidth;\n const newHeight = window.innerHeight;\n\n // Handle high DPI displays\n const dpr = window.devicePixelRatio || 1;\n canvasRef.current.width = newWidth * dpr;\n canvasRef.current.height = newHeight * dpr;\n\n // Set CSS size\n canvasRef.current.style.width = `${newWidth}px`;\n canvasRef.current.style.height = `${newHeight}px`;\n }\n };\n resizeCanvas();\n\n const windowResizeObserver = new ResizeObserver(() => {\n resizeCanvas();\n });\n windowResizeObserver.observe(document.body);\n\n // Separate observer for snow accumulation surfaces\n const surfaceObserver = new ResizeObserver((entries) => {\n // Check if any accumulation element actually changed size\n let needsUpdate = false;\n for (const entry of entries) {\n if (entry.target.isConnected) {\n needsUpdate = true;\n break;\n }\n }\n if (needsUpdate) {\n // Re-run initialization to adapt to new sizes\n // We do NOT want to infinitely recurse, so initAccumulationWrapper\n // must be careful about disconnection if called from here.\n // Actually, we don't need to disconnect/reconnect here if the set of elements hasn't changed,\n // but getAccumulationSurfaces (called by init) might find new ones or drop old ones.\n // For simplicity, we just trigger the scan.\n initAccumulationWrapper();\n }\n });\n\n snowflakesRef.current = [];\n\n const initAccumulationWrapper = () => {\n const scanStart = performance.now();\n initializeAccumulation(accumulationRef.current, physicsConfigRef.current);\n\n // Sync observer with current surfaces\n surfaceObserver.disconnect();\n for (const [el] of accumulationRef.current) {\n surfaceObserver.observe(el);\n }\n\n metricsRef.current.scanTime = performance.now() - scanStart;\n };\n initAccumulationWrapper();\n\n setIsVisible(true);\n\n let lastTime = 0;\n let lastMetricsUpdate = 0;\n // Holds current frame's element positions\n let elementRects: ReturnType<typeof getElementRects> = [];\n\n const animate = (currentTime: number) => {\n if (lastTime === 0) {\n lastTime = currentTime;\n animationIdRef.current = requestAnimationFrame(animate);\n return;\n }\n\n\n const deltaTime = Math.min(currentTime - lastTime, 50);\n\n // Always track FPS so we have data when panel opens\n const now = performance.now();\n fpsFrames.current.push(now);\n fpsFrames.current = fpsFrames.current.filter(t => now - t < 1000);\n\n // Track detailed performance metrics\n metricsRef.current.rafGap = currentTime - lastTime;\n\n lastTime = currentTime;\n const dt = deltaTime / 16.67;\n\n const frameStartTime = performance.now();\n\n // Time canvas clear\n const clearStart = performance.now();\n\n // Reset transform to clear the entire viewport-sized canvas\n // We use the dpr scaling, so we clear the logical width/height\n const dpr = window.devicePixelRatio || 1;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr);\n\n // Translate the context to Simulate Scrolling\n // We move the 'world' up by scrollY, so absolute coordinates draw in the correct place relative to viewport\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n ctx.translate(-scrollX, -scrollY);\n\n metricsRef.current.clearTime = performance.now() - clearStart;\n\n const snowflakes = snowflakesRef.current;\n\n // PERFORMANCE: Update element rects EVERY FRAME to track layout changes and animations\n // getBoundingClientRect() is necessary to handle moving/animating elements\n // getBoundingClientRect() is fast enough for the accumulation targets (< 50 elements)\n const rectStart = performance.now();\n elementRects = getElementRects(accumulationRef.current);\n metricsRef.current.rectUpdateTime = performance.now() - rectStart;\n\n // Time physics\n const physicsStart = performance.now();\n meltAndSmoothAccumulation(elementRects, physicsConfigRef.current, dt);\n updateSnowflakes(\n snowflakes,\n elementRects,\n physicsConfigRef.current,\n dt,\n document.documentElement.scrollWidth,\n document.documentElement.scrollHeight\n );\n metricsRef.current.physicsTime = performance.now() - physicsStart;\n\n // Draw Snowflakes\n const drawStart = performance.now();\n for (const flake of snowflakes) {\n drawSnowflake(ctx, flake);\n }\n\n // Spawn new snowflakes\n if (isEnabledRef.current && snowflakes.length < physicsConfigRef.current.MAX_FLAKES) {\n const isBackground = Math.random() < 0.4;\n // createSnowflake uses window.scrollY, so it creates flakes in world space\n snowflakes.push(createSnowflake(document.documentElement.scrollWidth, physicsConfigRef.current, isBackground));\n }\n\n // Draw Accumulation\n // We draw accumulations in World Space (by adding scroll offset in draw.ts)\n // This aligns perfectly with the translated context and world-space snowflakes.\n drawAccumulations(ctx, elementRects);\n drawSideAccumulations(ctx, elementRects);\n\n metricsRef.current.drawTime = performance.now() - drawStart;\n metricsRef.current.frameTime = performance.now() - frameStartTime;\n\n // Update metrics every 500ms\n if (currentTime - lastMetricsUpdate > 500) {\n setMetricsRef.current({\n fps: fpsFrames.current.length,\n frameTime: metricsRef.current.frameTime,\n scanTime: metricsRef.current.scanTime,\n rectUpdateTime: metricsRef.current.rectUpdateTime,\n surfaceCount: accumulationRef.current.size,\n flakeCount: snowflakes.length,\n maxFlakes: physicsConfigRef.current.MAX_FLAKES,\n rafGap: metricsRef.current.rafGap,\n clearTime: metricsRef.current.clearTime,\n physicsTime: metricsRef.current.physicsTime,\n drawTime: metricsRef.current.drawTime,\n });\n lastMetricsUpdate = currentTime;\n }\n\n animationIdRef.current = requestAnimationFrame(animate);\n };\n\n animationIdRef.current = requestAnimationFrame(animate);\n\n const handleResize = () => {\n resizeCanvas();\n accumulationRef.current.clear();\n initAccumulationWrapper();\n };\n\n window.addEventListener('resize', handleResize);\n\n // Periodic surface scan every 5 seconds to detect DOM changes\n const checkInterval = setInterval(initAccumulationWrapper, 5000);\n\n return () => {\n cancelAnimationFrame(animationIdRef.current);\n window.removeEventListener('resize', handleResize);\n clearInterval(checkInterval);\n windowResizeObserver.disconnect();\n surfaceObserver.disconnect();\n };\n }, [isMounted]);\n\n if (!isMounted) return null;\n\n return (\n <>\n <canvas\n ref={canvasRef}\n style={{\n position: 'fixed', // FIXED position to eliminate scroll jitter\n top: 0,\n left: 0,\n pointerEvents: 'none',\n zIndex: 9999,\n opacity: isVisible ? 1 : 0,\n transition: 'opacity 0.3s ease-in',\n willChange: 'transform',\n }}\n aria-hidden=\"true\"\n />\n\n </>\n );\n}\n","'use client';\n\nimport React, { createContext, useContext, useState, ReactNode } from 'react';\n\nexport interface PhysicsConfig {\n MAX_FLAKES: number;\n MELT_SPEED: number;\n WIND_STRENGTH: number;\n ACCUMULATION: {\n SIDE_RATE: number;\n TOP_RATE: number;\n BOTTOM_RATE: number;\n };\n MAX_DEPTH: {\n TOP: number;\n BOTTOM: number;\n SIDE: number;\n };\n FLAKE_SIZE: {\n MIN: number;\n MAX: number;\n };\n MAX_SURFACES: number;\n}\n\nexport const DEFAULT_PHYSICS: PhysicsConfig = {\n MAX_FLAKES: 1000,\n MELT_SPEED: 0.00001,\n WIND_STRENGTH: 1.5,\n ACCUMULATION: {\n SIDE_RATE: 1,\n TOP_RATE: 5,\n BOTTOM_RATE: 5.0,\n },\n MAX_DEPTH: {\n TOP: 100,\n BOTTOM: 50,\n SIDE: 20,\n },\n FLAKE_SIZE: {\n MIN: 0.5,\n MAX: 1.6,\n },\n MAX_SURFACES: 15\n};\n\nexport interface PerformanceMetrics {\n fps: number;\n frameTime: number;\n scanTime: number;\n rectUpdateTime: number;\n surfaceCount: number;\n flakeCount: number;\n maxFlakes: number;\n // Detailed metrics\n rafGap: number; // Time between requestAnimationFrame calls\n clearTime: number; // Time to clear canvas\n physicsTime: number; // Time for physics updates\n drawTime: number; // Time to draw snowflakes and accumulation\n}\n\ninterface SnowfallContextType {\n isEnabled: boolean;\n toggleSnow: () => void;\n physicsConfig: PhysicsConfig;\n updatePhysicsConfig: (config: Partial<PhysicsConfig>) => void;\n resetPhysics: () => void;\n debugMode: boolean;\n toggleDebug: () => void;\n metrics: PerformanceMetrics | null;\n setMetrics: (metrics: PerformanceMetrics) => void;\n}\n\nconst SnowfallContext = createContext<SnowfallContextType | undefined>(undefined);\n\nexport function SnowfallProvider({ children, initialDebug = false }: { children: ReactNode; initialDebug?: boolean }) {\n const [isEnabled, setIsEnabled] = useState(true);\n const [physicsConfig, setPhysicsConfig] = useState<PhysicsConfig>(DEFAULT_PHYSICS);\n const [debugMode, setDebugMode] = useState(initialDebug);\n const [metrics, setMetrics] = useState<PerformanceMetrics | null>(null);\n\n const toggleSnow = () => {\n setIsEnabled((prev) => !prev);\n };\n\n const toggleDebug = () => {\n setDebugMode((prev) => !prev);\n };\n\n const updatePhysicsConfig = (config: Partial<PhysicsConfig>) => {\n setPhysicsConfig((prev) => ({\n ...prev,\n ...config,\n ACCUMULATION: {\n ...prev.ACCUMULATION,\n ...(config.ACCUMULATION || {}),\n },\n MAX_DEPTH: {\n ...prev.MAX_DEPTH,\n ...(config.MAX_DEPTH || {}),\n },\n FLAKE_SIZE: {\n ...prev.FLAKE_SIZE,\n ...(config.FLAKE_SIZE || {}),\n },\n }));\n };\n\n const resetPhysics = () => {\n setPhysicsConfig(DEFAULT_PHYSICS);\n };\n\n return (\n <SnowfallContext.Provider value={{\n isEnabled,\n toggleSnow,\n physicsConfig,\n updatePhysicsConfig,\n resetPhysics,\n debugMode,\n toggleDebug,\n metrics,\n setMetrics,\n }}>\n {children}\n </SnowfallContext.Provider>\n );\n}\n\nexport function useSnowfall() {\n const context = useContext(SnowfallContext);\n if (context === undefined) {\n throw new Error('useSnowfall must be used within a SnowfallProvider');\n }\n return context;\n}\n","export const ATTR_SNOWFALL = 'data-snowfall';\n\nexport const VAL_IGNORE = 'ignore';\nexport const VAL_TOP = 'top';\nexport const VAL_BOTTOM = 'bottom';\n\nexport const TAG_HEADER = 'header';\nexport const TAG_FOOTER = 'footer';\n\nexport const ROLE_BANNER = 'banner';\nexport const ROLE_CONTENTINFO = 'contentinfo';\n","import { SnowAccumulation, ElementSurface, SnowfallSurface } from './types';\nimport {\n ATTR_SNOWFALL, VAL_IGNORE, VAL_TOP, VAL_BOTTOM,\n TAG_HEADER, TAG_FOOTER, ROLE_BANNER, ROLE_CONTENTINFO\n} from './constants';\n\n// Headers: snow accumulates on BOTTOM edge\n// Footers: default to TOP surface (snow piles on top)\n// Use data-snowfall attributes to override this behavior\nconst BOTTOM_TAGS = [TAG_HEADER];\nconst BOTTOM_ROLES = [ROLE_BANNER];\n\nconst AUTO_DETECT_TAGS = [TAG_HEADER, TAG_FOOTER, 'article', 'section', 'aside', 'nav'];\nconst AUTO_DETECT_ROLES = [`[role=\"${ROLE_BANNER}\"]`, `[role=\"${ROLE_CONTENTINFO}\"]`, '[role=\"main\"]'];\nconst AUTO_DETECT_CLASSES = [\n '.card', '[class*=\"card\"]', '[class*=\"Card\"]',\n '[class*=\"bg-\"]', '[class*=\"shadow-\"]', '[class*=\"rounded-\"]'\n];\n\n// Helper to get element type (Top vs Bottom surface) based on tags/roles\n// This is used to determine if snow should sit ON TOP or hang from the BOTTOM.\n\nexport const getElementType = (el: Element): SnowfallSurface => {\n const tagName = el.tagName.toLowerCase();\n if (BOTTOM_TAGS.includes(tagName)) return VAL_BOTTOM;\n\n const role = el.getAttribute('role');\n if (role && BOTTOM_ROLES.includes(role)) return VAL_BOTTOM;\n\n // Default: snow accumulates on top of elements (natural physics)\n return VAL_TOP;\n};\n\nconst shouldAccumulate = (el: Element, precomputedStyle?: CSSStyleDeclaration): boolean => {\n if (el.getAttribute(ATTR_SNOWFALL) === VAL_IGNORE) return false;\n // Explicit opt-in\n if (el.hasAttribute(ATTR_SNOWFALL)) return true;\n\n const styles = precomputedStyle || window.getComputedStyle(el);\n const isVisible = styles.display !== 'none' &&\n styles.visibility !== 'hidden' &&\n parseFloat(styles.opacity) > 0.1;\n if (!isVisible) return false;\n\n // Check for visual prominence\n const bgColor = styles.backgroundColor;\n const hasBackground = bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent';\n const hasBorder = (parseFloat(styles.borderWidth) > 0 && styles.borderColor !== 'transparent' && styles.borderColor !== 'rgba(0, 0, 0, 0)') && styles.borderStyle !== 'none';\n const hasBoxShadow = styles.boxShadow !== 'none';\n const hasFilter = styles.filter !== 'none' && styles.filter.includes('drop-shadow');\n const hasBackdropFilter = styles.backdropFilter !== 'none';\n\n return hasBackground || hasBorder || hasBoxShadow || hasFilter || hasBackdropFilter;\n};\n\nexport const getAccumulationSurfaces = (maxSurfaces: number = 5): { el: Element; type: SnowfallSurface }[] => {\n // No explicit clearing needed as we don't cache styles persistently anymore.\n const surfaces: { el: Element; type: SnowfallSurface }[] = [];\n const seen = new Set<Element>();\n\n const candidates = document.querySelectorAll(\n [\n `[${ATTR_SNOWFALL}]`,\n ...AUTO_DETECT_TAGS,\n ...AUTO_DETECT_ROLES,\n ...AUTO_DETECT_CLASSES\n ].join(', ')\n );\n\n for (const el of candidates) {\n if (surfaces.length >= maxSurfaces) break;\n if (seen.has(el)) continue;\n\n // Manual override check first\n const manualOverride = el.getAttribute(ATTR_SNOWFALL);\n if (manualOverride === VAL_IGNORE) continue;\n\n // If manually opted in, skip some heuristic checks but keep basic visibility/size sanity\n const isManuallyIncluded = manualOverride !== null;\n const styles = window.getComputedStyle(el);\n\n // Visibility Check: Must be visible and opaque enough\n const isVisible = styles.display !== 'none' && styles.visibility !== 'hidden' && parseFloat(styles.opacity) > 0.1;\n\n if (!isVisible && !isManuallyIncluded) continue;\n\n const rect = el.getBoundingClientRect();\n const hasSize = rect.width >= 100 && rect.height >= 50;\n if (!hasSize && !isManuallyIncluded) continue;\n\n const isFullPageWrapper = rect.top <= 10 && rect.height >= window.innerHeight * 0.9;\n const isBottomTag = BOTTOM_TAGS.includes(el.tagName.toLowerCase());\n const isBottomRole = BOTTOM_ROLES.includes(el.getAttribute('role') || '');\n const isBottomSurface = isBottomTag || isBottomRole || manualOverride === VAL_BOTTOM;\n\n if (isFullPageWrapper && !isBottomSurface && !isManuallyIncluded) continue;\n\n if (shouldAccumulate(el, styles)) {\n let type: SnowfallSurface = getElementType(el);\n if (manualOverride === VAL_BOTTOM) type = VAL_BOTTOM;\n else if (manualOverride === VAL_TOP) type = VAL_TOP;\n\n surfaces.push({ el, type });\n seen.add(el);\n }\n }\n\n return surfaces;\n};\n\nexport const getElementRects = (accumulationMap: Map<Element, SnowAccumulation>): ElementSurface[] => {\n const elementRects: ElementSurface[] = [];\n for (const [el, acc] of accumulationMap.entries()) {\n if (!el.isConnected) continue;\n // PURE VIEWPORT RECT. No scroll math.\n const rect = el.getBoundingClientRect();\n elementRects.push({ el, rect, acc });\n }\n return elementRects;\n};\n","import { PhysicsConfig } from '../../SnowfallProvider';\nimport { Snowflake, SnowAccumulation, ElementSurface } from './types';\nimport { getAccumulationSurfaces } from './dom';\nimport { VAL_BOTTOM } from './constants';\n\nexport const createSnowflake = (\n worldWidth: number,\n config: PhysicsConfig,\n isBackground: boolean = false\n): Snowflake => {\n // Background flakes are smaller, slower, and have lower opacity to create depth (parallax feel).\n if (isBackground) {\n const sizeRatio = Math.random();\n const radius = config.FLAKE_SIZE.MIN * 0.6 + sizeRatio * (config.FLAKE_SIZE.MAX - config.FLAKE_SIZE.MIN) * 0.4;\n return {\n x: Math.random() * worldWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.3 + Math.random() * 0.2 + 0.2,\n wind: (Math.random() - 0.5) * (config.WIND_STRENGTH * 0.625),\n opacity: Math.random() * 0.2 + 0.2,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.015 + 0.005,\n sizeRatio,\n isBackground: true\n };\n } else {\n const sizeRatio = Math.random();\n const radius = config.FLAKE_SIZE.MIN + sizeRatio * (config.FLAKE_SIZE.MAX - config.FLAKE_SIZE.MIN);\n return {\n x: Math.random() * worldWidth,\n y: window.scrollY - 5,\n radius,\n speed: radius * 0.5 + Math.random() * 0.3 + 0.5,\n wind: (Math.random() - 0.5) * config.WIND_STRENGTH,\n opacity: Math.random() * 0.3 + 0.5,\n wobble: Math.random() * Math.PI * 2,\n wobbleSpeed: Math.random() * 0.02 + 0.01,\n sizeRatio,\n isBackground: false\n };\n }\n};\n\nexport const initializeAccumulation = (\n accumulationMap: Map<Element, SnowAccumulation>,\n config: PhysicsConfig\n) => {\n // Scan DOM for new valid surfaces\n const elements = getAccumulationSurfaces(config.MAX_SURFACES);\n // Prune disconnected elements\n for (const [el] of accumulationMap.entries()) {\n if (!el.isConnected) {\n accumulationMap.delete(el);\n }\n }\n\n elements.forEach(({ el, type }) => {\n const existing = accumulationMap.get(el);\n const rect = el.getBoundingClientRect();\n const width = Math.ceil(rect.width);\n const isBottom = type === VAL_BOTTOM;\n\n if (existing && existing.heights.length === width) {\n existing.type = type;\n if (existing.borderRadius !== undefined) {\n const styleBuffer = window.getComputedStyle(el);\n existing.borderRadius = parseFloat(styleBuffer.borderTopLeftRadius) || 0;\n }\n return;\n }\n\n const height = Math.ceil(rect.height);\n const baseMax = isBottom ? config.MAX_DEPTH.BOTTOM : config.MAX_DEPTH.TOP;\n\n const styles = window.getComputedStyle(el);\n const borderRadius = parseFloat(styles.borderTopLeftRadius) || 0;\n\n let maxHeights = new Array(width);\n for (let i = 0; i < width; i++) {\n let edgeFactor = 1.0;\n if (!isBottom && borderRadius > 0) {\n if (i < borderRadius) {\n edgeFactor = Math.pow(i / borderRadius, 1.2);\n } else if (i > width - borderRadius) {\n edgeFactor = Math.pow((width - i) / borderRadius, 1.2);\n }\n }\n maxHeights[i] = baseMax * edgeFactor * (0.85 + Math.random() * 0.15);\n }\n\n const smoothPasses = 4;\n for (let p = 0; p < smoothPasses; p++) {\n const smoothed = [...maxHeights];\n for (let i = 1; i < width - 1; i++) {\n smoothed[i] = (maxHeights[i - 1] + maxHeights[i] + maxHeights[i + 1]) / 3;\n }\n maxHeights = smoothed;\n }\n\n accumulationMap.set(el, {\n heights: existing?.heights.length === width ? existing.heights : new Array(width).fill(0),\n maxHeights,\n leftSide: existing?.leftSide.length === height ? existing.leftSide : new Array(height).fill(0),\n rightSide: existing?.rightSide.length === height ? existing.rightSide : new Array(height).fill(0),\n maxSideHeight: isBottom ? 0 : config.MAX_DEPTH.SIDE,\n borderRadius,\n type\n });\n });\n};\n\nconst accumulateSide = (\n sideArray: number[],\n rectHeight: number,\n localY: number,\n maxSideHeight: number,\n borderRadius: number,\n config: PhysicsConfig\n) => {\n const spread = 4;\n const addHeight = config.ACCUMULATION.SIDE_RATE * (0.8 + Math.random() * 0.4);\n\n for (let dy = -spread; dy <= spread; dy++) {\n const y = localY + dy;\n if (y >= 0 && y < sideArray.length) {\n const inTop = y < borderRadius;\n const inBottom = y > rectHeight - borderRadius;\n if (borderRadius > 0 && (inTop || inBottom)) continue;\n\n const normalizedDist = Math.abs(dy) / spread;\n const falloff = (Math.cos(normalizedDist * Math.PI) + 1) / 2;\n sideArray[y] = Math.min(maxSideHeight, sideArray[y] + addHeight * falloff);\n }\n }\n};\n\nexport const updateSnowflakes = (\n snowflakes: Snowflake[],\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number,\n worldWidth: number,\n worldHeight: number\n) => {\n // Scroll used for World -> Viewport mapping for collision\n // Flakes are in World Space.\n // DOM Rects are in Viewport Space (relative to the window).\n // To check collision, we subtract scrollX/Y from Flake coordinates to get their Viewport position.\n const scrollX = window.scrollX;\n const scrollY = window.scrollY;\n\n for (let i = snowflakes.length - 1; i >= 0; i--) {\n const flake = snowflakes[i];\n\n flake.wobble += flake.wobbleSpeed * dt;\n flake.x += (flake.wind + Math.sin(flake.wobble) * 0.5) * dt;\n flake.y += (flake.speed + Math.cos(flake.wobble * 0.5) * 0.1) * dt;\n\n let landed = false;\n\n for (const item of elementRects) {\n const { rect, acc } = item;\n const isBottom = acc.type === VAL_BOTTOM;\n\n // Flake is World Space. Rect is Viewport Space.\n // Map Flake to Viewport Relative for collision check vs Rect\n const flakeViewportX = flake.x - scrollX;\n const flakeViewportY = flake.y - scrollY;\n\n // Simple Collision Check\n const isInVerticalBounds = flakeViewportY >= rect.top && flakeViewportY <= rect.bottom;\n\n // Side collisions\n // Check if flake hits the left or right edge of the element\n if (!landed && acc.maxSideHeight > 0 && !isBottom) {\n if (isInVerticalBounds) {\n const localY = Math.floor(flakeViewportY - rect.top);\n const borderRadius = acc.borderRadius;\n\n const isInTopCorner = localY < borderRadius;\n const isInBottomCorner = localY > rect.height - borderRadius;\n const isCorner = borderRadius > 0 && (isInTopCorner || isInBottomCorner);\n\n if (flakeViewportX >= rect.left - 5 && flakeViewportX < rect.left + 3) {\n if (!isCorner) {\n accumulateSide(acc.leftSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (!landed && flakeViewportX > rect.right - 3 && flakeViewportX <= rect.right + 5) {\n if (!isCorner) {\n accumulateSide(acc.rightSide, rect.height, localY, acc.maxSideHeight, borderRadius, config);\n landed = true;\n }\n }\n\n if (landed) break;\n }\n }\n\n // Top/Bottom accumulation\n // Check if flake hits the primary horizontal surface\n if (flakeViewportX >= rect.left && flakeViewportX <= rect.right) {\n const localX = Math.floor(flakeViewportX - rect.left);\n const currentHeight = acc.heights[localX] || 0;\n const maxHeight = acc.maxHeights[localX] || 5;\n\n const surfaceY = isBottom ? rect.bottom - currentHeight : rect.top - currentHeight;\n\n if (flakeViewportY >= surfaceY && flakeViewportY < surfaceY + 10 && currentHeight < maxHeight) {\n const shouldAccumulate = isBottom ? Math.random() < 0.15 : true;\n\n if (shouldAccumulate) {\n const baseSpread = Math.ceil(flake.radius);\n const spread = baseSpread + Math.floor(Math.random() * 2);\n const accumRate = isBottom ? config.ACCUMULATION.BOTTOM_RATE : config.ACCUMULATION.TOP_RATE;\n const centerOffset = Math.floor(Math.random() * 3) - 1;\n\n for (let dx = -spread; dx <= spread; dx++) {\n if (Math.random() < 0.15) continue;\n const idx = localX + dx + centerOffset;\n if (idx >= 0 && idx < acc.heights.length) {\n const dist = Math.abs(dx);\n const pixelMax = acc.maxHeights[idx] || 5;\n\n const normDist = dist / spread;\n const falloff = (Math.cos(normDist * Math.PI) + 1) / 2;\n const baseAdd = 0.3 * falloff;\n\n const randomFactor = 0.8 + Math.random() * 0.4;\n const addHeight = baseAdd * randomFactor * accumRate;\n\n if (acc.heights[idx] < pixelMax && addHeight > 0) {\n acc.heights[idx] = Math.min(pixelMax, acc.heights[idx] + addHeight);\n }\n }\n }\n\n if (isBottom) {\n landed = true;\n break;\n }\n }\n\n if (!isBottom) {\n landed = true;\n break;\n }\n }\n }\n }\n\n if (landed || flake.y > worldHeight + 10 || flake.x < -20 || flake.x > worldWidth + 20) {\n snowflakes.splice(i, 1);\n }\n }\n};\n\nexport const meltAndSmoothAccumulation = (\n elementRects: ElementSurface[],\n config: PhysicsConfig,\n dt: number\n) => {\n for (const { acc } of elementRects) {\n const meltRate = config.MELT_SPEED * dt;\n const len = acc.heights.length;\n\n // Smooth\n if (len > 2) {\n for (let i = 1; i < len - 1; i++) {\n if (acc.heights[i] > 0.05) {\n const avg = (acc.heights[i - 1] + acc.heights[i + 1]) / 2;\n acc.heights[i] = acc.heights[i] * 0.99 + avg * 0.01;\n }\n }\n }\n\n // Melt\n for (let i = 0; i < acc.heights.length; i++) {\n if (acc.heights[i] > 0) acc.heights[i] = Math.max(0, acc.heights[i] - meltRate);\n }\n for (let i = 0; i < acc.leftSide.length; i++) {\n if (acc.leftSide[i] > 0) acc.leftSide[i] = Math.max(0, acc.leftSide[i] - meltRate);\n if (acc.rightSide[i] > 0) acc.rightSide[i] = Math.max(0, acc.rightSide[i] - meltRate);\n }\n }\n};\n","import { Snowflake, ElementSurface } from './types';\nimport { VAL_BOTTOM } from './constants';\n\nexport const drawSnowflake = (ctx: CanvasRenderingContext2D, flake: Snowflake) => {\n // Flakes are tracked in World Space.\n // The Canvas Context is translated by (-scrollX, -scrollY), effectively viewing the World.\n // So we can draw flakes directly at their World (x, y) coordinates.\n ctx.beginPath();\n ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI * 2);\n ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity})`;\n ctx.fill();\n\n // Glow effect\n ctx.beginPath();\n ctx.arc(flake.x, flake.y, flake.radius * 1.5, 0, Math.PI * 2);\n ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity * 0.2})`;\n ctx.fill();\n};\n\nexport const drawAccumulations = (\n ctx: CanvasRenderingContext2D,\n elementRects: ElementSurface[]\n) => {\n const setupCtx = (c: CanvasRenderingContext2D) => {\n c.fillStyle = 'rgba(255, 255, 255, 0.95)';\n c.shadowColor = 'rgba(200, 230, 255, 0.6)';\n c.shadowBlur = 4;\n c.shadowOffsetY = -1;\n };\n setupCtx(ctx);\n\n const currentScrollX = window.scrollX;\n const currentScrollY = window.scrollY;\n\n for (const item of elementRects) {\n const { rect, acc } = item;\n\n if (!acc.heights.some(h => h > 0.1)) continue;\n\n // Convert Viewport Rect to World Space for Drawing (match Context)\n // The Canvas Context is translated by (-scrollX, -scrollY) to simulate a camera.\n // We need to draw in World coordinates.\n // Element Rects are in Viewport Coordinates (from getBoundingClientRect).\n // World Coordinate = Viewport Coordinate + Scroll Offset.\n const dx = currentScrollX;\n const dy = currentScrollY;\n\n const isBottom = acc.type === VAL_BOTTOM;\n const baseY = isBottom ? rect.bottom - 1 : rect.top + 1;\n const borderRadius = acc.borderRadius;\n\n const getCurveOffset = (xPos: number) => {\n if (borderRadius <= 0 || isBottom) return 0;\n let offset = 0;\n if (xPos < borderRadius) {\n const dist = borderRadius - xPos;\n offset = borderRadius - Math.sqrt(Math.max(0, borderRadius * borderRadius - dist * dist));\n } else if (xPos > rect.width - borderRadius) {\n const dist = xPos - (rect.width - borderRadius);\n offset = borderRadius - Math.sqrt(Math.max(0, borderRadius * borderRadius - dist * dist));\n }\n return offset;\n };\n\n ctx.beginPath();\n let first = true;\n const step = 2;\n const len = acc.heights.length;\n\n for (let x = 0; x < len; x += step) {\n const height = acc.heights[x] || 0;\n const px = rect.left + x + dx;\n const py = baseY - height + getCurveOffset(x) + dy;\n if (first) {\n ctx.moveTo(px, py);\n first = false;\n } else {\n ctx.lineTo(px, py);\n }\n }\n\n if ((len - 1) % step !== 0) {\n const x = len - 1;\n const height = acc.heights[x] || 0;\n const px = rect.left + x + dx;\n const py = baseY - height + getCurveOffset(x) + dy;\n ctx.lineTo(px, py);\n }\n\n for (let x = len - 1; x >= 0; x -= step) {\n const px = rect.left + x + dx;\n const py = baseY + getCurveOffset(x) + dy;\n ctx.lineTo(px, py);\n }\n\n const startX = 0;\n const startPx = rect.left + startX + dx;\n const startPy = baseY + getCurveOffset(startX) + dy;\n ctx.lineTo(startPx, startPy);\n\n ctx.closePath();\n ctx.fill();\n }\n\n ctx.shadowBlur = 0;\n ctx.shadowOffsetY = 0;\n};\n\nexport const drawSideAccumulations = (\n ctx: CanvasRenderingContext2D,\n elementRects: ElementSurface[]\n) => {\n const setupCtx = (c: CanvasRenderingContext2D) => {\n c.fillStyle = 'rgba(255, 255, 255, 0.95)';\n c.shadowColor = 'rgba(200, 230, 255, 0.6)';\n c.shadowBlur = 3;\n };\n setupCtx(ctx);\n\n const currentScrollX = window.scrollX;\n const currentScrollY = window.scrollY;\n\n for (const item of elementRects) {\n const { rect, acc } = item;\n\n if (acc.maxSideHeight === 0) continue;\n\n const hasLeftSnow = acc.leftSide.some(h => h > 0.3);\n const hasRightSnow = acc.rightSide.some(h => h > 0.3);\n\n if (!hasLeftSnow && !hasRightSnow) continue;\n\n const dx = currentScrollX;\n const dy = currentScrollY;\n\n const drawSide = (sideArray: number[], isLeft: boolean) => {\n ctx.beginPath();\n const baseX = isLeft ? rect.left : rect.right;\n\n ctx.moveTo(baseX + dx, rect.top + dy);\n\n for (let y = 0; y < sideArray.length; y += 2) {\n const width = sideArray[y] || 0;\n const nextY = Math.min(y + 2, sideArray.length - 1);\n const nextWidth = sideArray[nextY] || 0;\n\n const heightRatio = y / sideArray.length;\n const gravityMultiplier = Math.pow(heightRatio, 1.5);\n\n const py = rect.top + y + dy;\n const px = (isLeft ? baseX - (width * gravityMultiplier) : baseX + (width * gravityMultiplier)) + dx;\n const ny = rect.top + nextY + dy;\n const nRatio = nextY / sideArray.length;\n const nGravityMultiplier = Math.pow(nRatio, 1.5);\n const nx = (isLeft ? baseX - (nextWidth * nGravityMultiplier) : baseX + (nextWidth * nGravityMultiplier)) + dx;\n\n ctx.lineTo(px, py);\n ctx.lineTo(nx, ny);\n }\n\n // Close at the bottom\n ctx.lineTo(baseX + dx, rect.bottom + dy);\n ctx.closePath();\n ctx.fill();\n };\n\n if (hasLeftSnow) drawSide(acc.leftSide, true);\n if (hasRightSnow) drawSide(acc.rightSide, false);\n }\n\n ctx.shadowBlur = 0;\n};\n","'use client';\n\nimport { useSnowfall } from './SnowfallProvider';\nimport { useEffect, useState } from 'react';\n\nexport default function DebugPanel({ defaultOpen = true }: { defaultOpen?: boolean }) {\n const { debugMode, toggleDebug, metrics } = useSnowfall();\n const [isMinimized, setIsMinimized] = useState(!defaultOpen);\n const [copied, setCopied] = useState(false);\n\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.shiftKey && e.key === 'D') {\n toggleDebug();\n }\n };\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [toggleDebug]);\n\n const copyToClipboard = () => {\n if (metrics) {\n const data = {\n ...metrics,\n timestamp: new Date().toISOString(),\n userAgent: navigator.userAgent,\n canvasSize: {\n width: window.innerWidth,\n height: window.innerHeight,\n },\n };\n navigator.clipboard.writeText(JSON.stringify(data, null, 2));\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n };\n\n if (!debugMode) return null;\n\n return (\n <div\n data-snowfall=\"top\"\n style={{\n position: 'fixed',\n bottom: '80px',\n left: '24px',\n backgroundColor: 'rgba(15, 23, 42, 0.75)',\n backdropFilter: 'blur(16px)',\n WebkitBackdropFilter: 'blur(16px)',\n color: '#e2e8f0',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',\n fontSize: '12px',\n padding: isMinimized ? '12px' : '20px',\n borderRadius: '16px',\n zIndex: 10000,\n minWidth: isMinimized ? 'auto' : '300px',\n maxWidth: '100%',\n border: '1px solid rgba(255, 255, 255, 0.1)',\n boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.2), 0 8px 10px -6px rgba(0, 0, 0, 0.2)',\n transition: 'all 0.2s ease',\n }}>\n <div style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: isMinimized ? 0 : '16px',\n gap: '16px'\n }}>\n <div style={{ fontWeight: '600', color: '#fff', display: 'flex', alignItems: 'center', gap: '8px' }}>\n <span style={{ fontSize: '14px' }}>❄️</span>\n <span style={{\n background: 'linear-gradient(to right, #60a5fa, #22d3ee)',\n WebkitBackgroundClip: 'text',\n WebkitTextFillColor: 'transparent',\n fontWeight: '700'\n }}>DEBUG</span>\n </div>\n <div style={{ display: 'flex', gap: '8px' }}>\n <button\n onClick={() => setIsMinimized(!isMinimized)}\n style={{\n background: 'rgba(255, 255, 255, 0.1)',\n border: '1px solid rgba(255, 255, 255, 0.1)',\n color: '#fff',\n cursor: 'pointer',\n width: '24px',\n height: '24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '6px',\n fontSize: '10px',\n }}\n >\n {isMinimized ? '▲' : '▼'}\n </button>\n <button\n onClick={toggleDebug}\n style={{\n background: 'rgba(239, 68, 68, 0.15)',\n border: '1px solid rgba(239, 68, 68, 0.2)',\n color: '#f87171',\n cursor: 'pointer',\n width: '24px',\n height: '24px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '6px',\n fontSize: '12px',\n }}\n >\n ✕\n </button>\n </div>\n </div>\n\n {!isMinimized && metrics && (\n <>\n <div style={{ marginBottom: '12px', paddingBottom: '12px', borderBottom: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ color: '#94a3b8', marginBottom: '8px', fontSize: '11px', fontWeight: '600', letterSpacing: '0.5px', textTransform: 'uppercase' }}>\n Performance\n </div>\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>\n <span>FPS</span>\n <span style={{ fontWeight: 'bold', color: metrics.fps < 30 ? '#f87171' : metrics.fps < 50 ? '#facc15' : '#4ade80' }}>\n {metrics.fps.toFixed(1)}\n </span>\n </div>\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>\n <span>Frame Time</span>\n <span style={{ fontFamily: 'monospace' }}>{metrics.frameTime.toFixed(2)}ms</span>\n </div>\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\n <span style={{ color: metrics.rafGap && metrics.rafGap > 20 ? '#fbbf24' : 'inherit' }}>rAF Gap</span>\n <span style={{ fontFamily: 'monospace' }}>{metrics.rafGap?.toFixed(1) || 0}ms</span>\n </div>\n </div>\n\n <div style={{ marginBottom: '12px', paddingBottom: '12px', borderBottom: '1px solid rgba(255,255,255,0.08)' }}>\n <div style={{ color: '#94a3b8', marginBottom: '8px', fontSize: '11px', fontWeight: '600', letterSpacing: '0.5px', textTransform: 'uppercase' }}>\n Detailed Timings\n </div>\n <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '4px 12px' }}>\n <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>Clear</span> <span style={{ fontFamily: 'monospace' }}>{metrics.clearTime?.toFixed(2) || 0}ms</span></div>\n <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>Physics</span> <span style={{ fontFamily: 'monospace' }}>{metrics.physicsTime?.toFixed(2) || 0}ms</span></div>\n <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>Draw</span> <span style={{ fontFamily: 'monospace' }}>{metrics.drawTime?.toFixed(2) || 0}ms</span></div>\n <div style={{ display: 'flex', justifyContent: 'space-between' }}><span>Scan</span> <span style={{ fontFamily: 'monospace' }}>{metrics.scanTime.toFixed(2)}ms</span></div>\n <div style={{ display: 'flex', justifyContent: 'space-between', gridColumn: 'span 2' }}><span>Rect Update</span> <span style={{ fontFamily: 'monospace' }}>{metrics.rectUpdateTime.toFixed(2)}ms</span></div>\n </div>\n </div>\n\n <div style={{ marginBottom: '16px' }}>\n <div style={{ color: '#94a3b8', marginBottom: '8px', fontSize: '11px', fontWeight: '600', letterSpacing: '0.5px', textTransform: 'uppercase' }}>\n Counts\n </div>\n <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>\n <span>Snowflakes</span>\n <span style={{ fontFamily: 'monospace' }}>{metrics.flakeCount} / {metrics.maxFlakes}</span>\n </div>\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\n <span>Surfaces</span>\n <span style={{ fontFamily: 'monospace' }}>{metrics.surfaceCount}</span>\n </div>\n </div>\n\n <button\n onClick={copyToClipboard}\n style={{\n width: '100%',\n padding: '10px',\n background: copied ? 'rgba(34, 197, 94, 0.2)' : 'rgba(255, 255, 255, 0.05)',\n border: copied ? '1px solid rgba(34, 197, 94, 0.5)' : '1px solid rgba(255, 255, 255, 0.1)',\n color: copied ? '#4ade80' : '#fff',\n cursor: 'pointer',\n borderRadius: '8px',\n fontSize: '11px',\n fontWeight: '600',\n transition: 'all 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '6px'\n }}\n >\n {copied ? '✓ COPIED' : '📋 COPY METRICS'}\n </button>\n\n <div style={{ marginTop: '12px', fontSize: '10px', color: '#64748b', textAlign: 'center' }}>\n Shift+D to toggle\n </div>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","shouldAccumulate","import_jsx_runtime","import_react","import_jsx_runtime"]}
|