Files
OpenFlare/frontend/components/ui/snow-effect.tsx
T
ryan 63cd906cfc refactor(repo): consolidate openflare-server to root and move subprojects to internal/apps
- Merge all files inside openflare-server to the repository root directory.
- Relocate agent, relay, and flared subprojects from internal/ to internal/apps/.
- Combine docker-compose files and update build context paths to root.
- Update GitHub workflows and Dockerfiles to refer to new directories and package names.
- Rewrite Go package imports across all files.
- Resolve database renew test race condition and clean up docs.
2026-06-19 14:23:29 +08:00

97 lines
2.2 KiB
TypeScript

"use client"
import {useEffect, useRef} from "react"
interface Snowflake {
x: number
y: number
radius: number
speed: number
opacity: number
drift: number
}
export function SnowEffect() {
const canvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
const canvas = canvasRef.current
if (!canvas) return
const ctx = canvas.getContext("2d")
if (!ctx) return
let animationFrameId: number
let snowflakes: Snowflake[] = []
const resizeCanvas = () => {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
}
const createSnowflakes = () => {
const count = Math.floor(window.innerWidth / 4)
snowflakes = []
for (let i = 0; i < count; i++) {
snowflakes.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
radius: Math.random() * 3 + 1,
speed: Math.random() * 2 + 0.5,
opacity: Math.random() * 0.5 + 0.3,
drift: Math.random() * 1 - 0.5
})
}
}
const drawSnowflakes = () => {
if (!ctx || !canvas) return
ctx.clearRect(0, 0, canvas.width, canvas.height)
snowflakes.forEach((flake) => {
ctx.beginPath()
ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI * 2)
ctx.fillStyle = `rgba(255, 255, 255, ${ flake.opacity })`
ctx.fill()
flake.y += flake.speed
flake.x += flake.drift
if (flake.y > canvas.height) {
flake.y = -flake.radius
flake.x = Math.random() * canvas.width
}
if (flake.x > canvas.width) {
flake.x = 0
} else if (flake.x < 0) {
flake.x = canvas.width
}
})
animationFrameId = requestAnimationFrame(drawSnowflakes)
}
resizeCanvas()
createSnowflakes()
drawSnowflakes()
window.addEventListener("resize", () => {
resizeCanvas()
createSnowflakes()
})
return () => {
cancelAnimationFrame(animationFrameId)
window.removeEventListener("resize", resizeCanvas)
}
}, [])
return (
<canvas
ref={canvasRef}
className="fixed inset-0 pointer-events-none z-50"
style={{ background: "transparent" }}
/>
)
}