feat: add snow atmosphere effect
tsParticles snow — 60–300 flakes depending on intensity, size variation for depth, gentle drift via random speed + curved paths. Appears in atmosphere panel between Rain and Embers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
97954de110
commit
a923e1b226
4 changed files with 45 additions and 2 deletions
|
|
@ -8,6 +8,7 @@ const EFFECTS: { key: EffectKey; emoji: string; label: string }[] = [
|
|||
{ key: "fog", emoji: "🌫", label: "Fog" },
|
||||
{ key: "fire", emoji: "🔥", label: "Fire" },
|
||||
{ key: "rain", emoji: "🌧", label: "Rain" },
|
||||
{ key: "snow", emoji: "❄️", label: "Snow" },
|
||||
{ key: "embers", emoji: "✨", label: "Embers" },
|
||||
];
|
||||
|
||||
|
|
@ -26,6 +27,7 @@ export default function AtmospherePanel({
|
|||
fog: atmosphere.fog.intensity,
|
||||
fire: atmosphere.fire.intensity,
|
||||
rain: atmosphere.rain.intensity,
|
||||
snow: atmosphere.snow.intensity,
|
||||
embers: atmosphere.embers.intensity,
|
||||
});
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
|
@ -48,6 +50,7 @@ export default function AtmospherePanel({
|
|||
fog: atmosphere.fog.intensity,
|
||||
fire: atmosphere.fire.intensity,
|
||||
rain: atmosphere.rain.intensity,
|
||||
snow: atmosphere.snow.intensity,
|
||||
embers: atmosphere.embers.intensity,
|
||||
});
|
||||
}, [atmosphere]);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
|||
import Particles, { initParticlesEngine } from "@tsparticles/react";
|
||||
import { loadSlim } from "@tsparticles/slim";
|
||||
import type { AtmosphereState } from "../lib/atmosphereTypes";
|
||||
import { getRainConfig, getEmbersConfig } from "../lib/particleConfigs";
|
||||
import { getRainConfig, getSnowConfig, getEmbersConfig } from "../lib/particleConfigs";
|
||||
|
||||
// Module-level singleton so the engine is only initialised once
|
||||
let enginePromise: Promise<void> | null = null;
|
||||
|
|
@ -28,7 +28,7 @@ export default function ParticleOverlay({ atmosphere }: ParticleOverlayProps) {
|
|||
|
||||
if (!ready) return null;
|
||||
|
||||
const { rain, embers } = atmosphere;
|
||||
const { rain, snow, embers } = atmosphere;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -39,6 +39,13 @@ export default function ParticleOverlay({ atmosphere }: ParticleOverlayProps) {
|
|||
options={getRainConfig(rain.intensity)}
|
||||
/>
|
||||
)}
|
||||
{snow.active && (
|
||||
<Particles
|
||||
key={`snow-${snow.intensity}`}
|
||||
id="particles-snow"
|
||||
options={getSnowConfig(snow.intensity)}
|
||||
/>
|
||||
)}
|
||||
{embers.active && (
|
||||
<Particles
|
||||
key={`embers-${embers.intensity}`}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export interface AtmosphereState {
|
|||
fog: EffectState;
|
||||
fire: EffectState;
|
||||
rain: EffectState;
|
||||
snow: EffectState;
|
||||
embers: EffectState;
|
||||
}
|
||||
|
||||
|
|
@ -14,5 +15,6 @@ export const defaultAtmosphere: AtmosphereState = {
|
|||
fog: { active: false, intensity: 50 },
|
||||
fire: { active: false, intensity: 50 },
|
||||
rain: { active: false, intensity: 50 },
|
||||
snow: { active: false, intensity: 50 },
|
||||
embers: { active: false, intensity: 50 },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,6 +29,37 @@ export function getRainConfig(intensity: number): ISourceOptions {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Snow — intensity 0–100 → count 60–300, speed 1–3.5
|
||||
* Gentle falling flakes with wobble drift. Size varies for depth illusion.
|
||||
*/
|
||||
export function getSnowConfig(intensity: number): ISourceOptions {
|
||||
const count = Math.round(60 + (intensity / 100) * 240);
|
||||
const speed = 1 + (intensity / 100) * 2.5;
|
||||
return {
|
||||
fullScreen: { enable: true, zIndex: 9997 },
|
||||
particles: {
|
||||
number: { value: count, density: { enable: false } },
|
||||
color: { value: ["#ffffff", "#ddeeff", "#eef6ff"] },
|
||||
shape: { type: "circle" },
|
||||
opacity: {
|
||||
value: { min: 0.25, max: 0.75 },
|
||||
animation: { enable: true, speed: 0.3, sync: false, startValue: "random" },
|
||||
},
|
||||
size: { value: { min: 1, max: 5 } },
|
||||
move: {
|
||||
enable: true,
|
||||
speed: speed,
|
||||
direction: "bottom",
|
||||
random: true,
|
||||
straight: false,
|
||||
outModes: { default: "out" },
|
||||
},
|
||||
},
|
||||
interactivity: { events: { onClick: { enable: false }, onHover: { enable: false } } },
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Embers — intensity 0–100 → count 50–150, speed 0.5–2
|
||||
* Smaller, more numerous slow-drifting sparks. Flickering opacity.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue