@hdcodedev/snowfall 1.0.3 → 1.0.5
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 +53 -17
- package/dist/index.d.mts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +288 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +288 -61
- 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\nconst BOTTOM_TAGS = [TAG_HEADER, TAG_FOOTER];\nconst BOTTOM_ROLES = [ROLE_BANNER, ROLE_CONTENTINFO];\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 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 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 const py = rect.top + y + dy;\n const px = (isLeft ? baseX - width : baseX + width) + dx;\n const ny = rect.top + nextY + dy;\n const nx = (isLeft ? baseX - nextWidth : baseX + nextWidth) + dx;\n\n targetCtx.lineTo(px, py);\n targetCtx.lineTo(nx, ny);\n }\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 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 };\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 const scanStart = performance.now();\n initializeAccumulation(accumulationRef.current, physicsConfigRef.current);\n metricsRef.current.scanTime = performance.now() - scanStart;\n };\n initAccumulationWrapper();\n\n setIsVisible(true);\n\n let lastTime = 0;\n let lastRectUpdate = 0;\n let lastMetricsUpdate = 0;\n let cachedElementRects: 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 ctx.clearRect(0, 0, canvas.width, canvas.height);\n metricsRef.current.clearTime = performance.now() - clearStart;\n\n const snowflakes = snowflakesRef.current;\n\n // PERFORMANCE: Only update element rects every 100ms instead of every frame\n // getBoundingClientRect() is expensive, especially on Safari\n if (currentTime - lastRectUpdate > 100) {\n const rectStart = performance.now();\n cachedElementRects = getElementRects(accumulationRef.current);\n metricsRef.current.rectUpdateTime = performance.now() - rectStart;\n lastRectUpdate = currentTime;\n }\n\n // Time physics\n const physicsStart = performance.now();\n meltAndSmoothAccumulation(cachedElementRects, physicsConfigRef.current, dt);\n updateSnowflakes(snowflakes, cachedElementRects, physicsConfigRef.current, dt, canvas.width, canvas.height);\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 snowflakes.push(createSnowflake(canvas.width, physicsConfigRef.current, isBackground));\n }\n\n // Draw Accumulation\n drawAccumulations(ctx, ctx, cachedElementRects);\n drawSideAccumulations(ctx, ctx, cachedElementRects);\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 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 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}\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\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 }: { children: ReactNode }) {\n const [isEnabled, setIsEnabled] = useState(true);\n const [physicsConfig, setPhysicsConfig] = useState<PhysicsConfig>(DEFAULT_PHYSICS);\n const [debugMode, setDebugMode] = useState(false);\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 = ['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\n// Performance optimization: Cache computed styles to avoid repeated getComputedStyle calls\n// Using Map instead of WeakMap to allow cache invalidation when styles change\n// Cache is cleared on each surface scan to prevent stale data after dynamic changes\nlet styleCache = new Map<Element, CSSStyleDeclaration>();\n\nconst getCachedStyle = (el: Element): CSSStyleDeclaration => {\n let cached = styleCache.get(el);\n if (!cached) {\n cached = window.getComputedStyle(el);\n styleCache.set(el, cached);\n }\n return cached;\n};\n\n/**\n * Clear the computed style cache. Called before re-scanning surfaces\n * to ensure fresh style data after dynamic changes (e.g., CSS class changes, media queries).\n */\nexport const clearStyleCache = (): void => {\n styleCache.clear();\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 // Clear style cache to ensure fresh computed styles after any dynamic changes\n clearStyleCache();\n\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 // 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 // OPTIMIZATION: Use cached styles and check visibility FIRST before expensive operations\n const styles = getCachedStyle(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 // Now get rect only if element is visible\n const rect = el.getBoundingClientRect();\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 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 // OPTIMIZATION: Check position using cached styles\n let isFixed = false;\n let currentEl: Element | null = el;\n while (currentEl && currentEl !== document.body) {\n const style = getCachedStyle(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 console.log('[Snowfall] ✅ Using OPTIMIZED version with Map-based caching & 5s intervals');\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 // 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 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","'use client';\n\nimport { useSnowfall } from './SnowfallProvider';\nimport { useEffect, useState } from 'react';\n\nexport default function DebugPanel() {\n const { debugMode, toggleDebug, metrics } = useSnowfall();\n const [isMinimized, setIsMinimized] = useState(false);\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 style={{\n position: 'fixed',\n bottom: '20px',\n left: '20px',\n backgroundColor: 'rgba(0, 0, 0, 0.9)',\n color: '#0f0',\n fontFamily: 'monospace',\n fontSize: '12px',\n padding: isMinimized ? '10px' : '15px',\n borderRadius: '8px',\n zIndex: 10000,\n minWidth: isMinimized ? 'auto' : '320px',\n maxWidth: '400px',\n border: '1px solid #0f0',\n boxShadow: '0 4px 20px rgba(0, 255, 0, 0.3)',\n }}>\n <div style={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: isMinimized ? 0 : '10px'\n }}>\n <div style={{ fontWeight: 'bold', color: '#0ff' }}>\n ❄️ SNOWFALL DEBUG\n </div>\n <div style={{ display: 'flex', gap: '10px' }}>\n <button\n onClick={() => setIsMinimized(!isMinimized)}\n style={{\n background: 'none',\n border: '1px solid #0f0',\n color: '#0f0',\n cursor: 'pointer',\n padding: '2px 8px',\n borderRadius: '4px',\n fontSize: '10px',\n }}\n >\n {isMinimized ? '▲' : '▼'}\n </button>\n <button\n onClick={toggleDebug}\n style={{\n background: 'none',\n border: '1px solid #f00',\n color: '#f00',\n cursor: 'pointer',\n padding: '2px 8px',\n borderRadius: '4px',\n fontSize: '10px',\n }}\n >\n ✕\n </button>\n </div>\n </div>\n\n {!isMinimized && metrics && (\n <>\n <div style={{ marginBottom: '10px', paddingBottom: '10px', borderBottom: '1px solid #333' }}>\n <div style={{ color: '#ff0', marginBottom: '5px', fontWeight: 'bold' }}>\n ⚡ PERFORMANCE\n </div>\n <div>FPS: <span style={{ color: metrics.fps < 30 ? '#f00' : metrics.fps < 50 ? '#ff0' : '#0f0' }}>{metrics.fps.toFixed(1)}</span></div>\n <div>Frame Time: {metrics.frameTime.toFixed(2)}ms</div>\n <div style={{ color: '#f80' }}>rAF Gap: {metrics.rafGap?.toFixed(1) || 0}ms {metrics.rafGap && metrics.rafGap > 20 ? '⚠️ THROTTLED!' : ''}</div>\n </div>\n\n <div style={{ marginBottom: '10px', paddingBottom: '10px', borderBottom: '1px solid #333' }}>\n <div style={{ color: '#ff0', marginBottom: '5px', fontWeight: 'bold' }}>\n 🔬 DETAILED TIMINGS\n </div>\n <div>Clear: {metrics.clearTime?.toFixed(2) || 0}ms</div>\n <div>Physics: {metrics.physicsTime?.toFixed(2) || 0}ms</div>\n <div>Draw: {metrics.drawTime?.toFixed(2) || 0}ms</div>\n <div>Scan: {metrics.scanTime.toFixed(2)}ms</div>\n <div>Rect Update: {metrics.rectUpdateTime.toFixed(2)}ms</div>\n </div>\n\n <div style={{ marginBottom: '10px', paddingBottom: '10px', borderBottom: '1px solid #333' }}>\n <div style={{ color: '#ff0', marginBottom: '5px', fontWeight: 'bold' }}>\n 📊 COUNTS\n </div>\n <div>Snowflakes: {metrics.flakeCount} / {metrics.maxFlakes}</div>\n <div>Surfaces: {metrics.surfaceCount}</div>\n </div>\n\n <button\n onClick={copyToClipboard}\n style={{\n width: '100%',\n padding: '8px',\n background: copied ? '#0a0' : '#000',\n border: copied ? '1px solid #0f0' : '1px solid #555',\n color: '#0f0',\n cursor: 'pointer',\n borderRadius: '4px',\n fontSize: '11px',\n fontFamily: 'monospace',\n }}\n >\n {copied ? '✓ COPIED!' : '📋 COPY METRICS'}\n </button>\n\n <div style={{ marginTop: '8px', fontSize: '10px', color: '#666', 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"]}
|