feat: add ParticleOverlay component for tsParticles effects
This commit is contained in:
parent
a6e3ca6066
commit
e947e8e127
1 changed files with 75 additions and 0 deletions
75
client/src/components/ParticleOverlay.tsx
Normal file
75
client/src/components/ParticleOverlay.tsx
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import Particles, { initParticlesEngine } from "@tsparticles/react";
|
||||||
|
import { loadSlim } from "@tsparticles/slim";
|
||||||
|
import type { AtmosphereState } from "../lib/atmosphereTypes";
|
||||||
|
import { getFireConfig, getRainConfig, getEmbersConfig } from "../lib/particleConfigs";
|
||||||
|
|
||||||
|
// Module-level singleton so the engine is only initialised once
|
||||||
|
let enginePromise: Promise<void> | null = null;
|
||||||
|
function ensureEngine(): Promise<void> {
|
||||||
|
if (!enginePromise) {
|
||||||
|
enginePromise = initParticlesEngine(async (engine) => {
|
||||||
|
await loadSlim(engine);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return enginePromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const overlayStyle: React.CSSProperties = {
|
||||||
|
position: "fixed",
|
||||||
|
inset: 0,
|
||||||
|
zIndex: 9997,
|
||||||
|
pointerEvents: "none",
|
||||||
|
};
|
||||||
|
|
||||||
|
const instanceStyle: React.CSSProperties = {
|
||||||
|
position: "absolute",
|
||||||
|
inset: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ParticleOverlayProps {
|
||||||
|
atmosphere: AtmosphereState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ParticleOverlay({ atmosphere }: ParticleOverlayProps) {
|
||||||
|
const [ready, setReady] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ensureEngine().then(() => setReady(true));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!ready) return null;
|
||||||
|
|
||||||
|
const { fire, rain, embers } = atmosphere;
|
||||||
|
const anyActive = fire.active || rain.active || embers.active;
|
||||||
|
if (!anyActive) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={overlayStyle}>
|
||||||
|
{fire.active && (
|
||||||
|
<Particles
|
||||||
|
key={`fire-${fire.intensity}`}
|
||||||
|
id="particles-fire"
|
||||||
|
options={getFireConfig(fire.intensity)}
|
||||||
|
style={instanceStyle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{rain.active && (
|
||||||
|
<Particles
|
||||||
|
key={`rain-${rain.intensity}`}
|
||||||
|
id="particles-rain"
|
||||||
|
options={getRainConfig(rain.intensity)}
|
||||||
|
style={instanceStyle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{embers.active && (
|
||||||
|
<Particles
|
||||||
|
key={`embers-${embers.intensity}`}
|
||||||
|
id="particles-embers"
|
||||||
|
options={getEmbersConfig(embers.intensity)}
|
||||||
|
style={instanceStyle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue