Integrazione Svelte
Il pacchetto @tsparticles/svelte fornisce un componente Svelte nativo per tsParticles. Questa guida copre Svelte (con Vite) e SvelteKit, incluse opzioni reattive, gestione eventi e istanze multiple.
Installazione
npm install @tsparticles/svelte @tsparticles/enginePer il bundle completo o preset:
npm install tsparticles
npm install @tsparticles/preset-snow
npm install @tsparticles/preset-stars
npm install @tsparticles/preset-confetti
npm install @tsparticles/preset-fireworksUtilizzo Base
<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import type { Engine, ISourceOptions } from "@tsparticles/engine";
let engineInitialised = false;
const particlesInit = async (engine: Engine): Promise<void> => {
await loadFull(engine);
engineInitialised = true;
};
const options: ISourceOptions = {
background: {
color: "#0d47a1",
},
fpsLimit: 120,
particles: {
number: {
value: 80,
},
color: {
value: "#ffffff",
},
shape: {
type: "circle",
},
opacity: {
value: 0.5,
},
size: {
value: { min: 1, max: 5 },
},
links: {
enable: true,
distance: 150,
color: "#ffffff",
opacity: 0.4,
width: 1,
},
move: {
enable: true,
speed: 2,
outModes: "out",
},
},
};
</script>
<Particles
id="tsparticles"
options={options}
on:init={particlesInit}
/>Inizializzazione del Motore
Passa un gestore di eventi on:init per caricare i plugin e i preset necessari alla tua app:
<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import type { Engine } from "@tsparticles/engine";
const handleInit = async (event: CustomEvent<Engine>) => {
const engine = event.detail;
await loadFull(engine);
};
</script>
<Particles
id="tsparticles"
options={options}
on:init={handleInit}
/>In alternativa, usa l'utilità initParticlesEngine prima del montaggio:
<script lang="ts">
import Particles, { initParticlesEngine } from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import { onMount } from "svelte";
let ready = false;
onMount(async () => {
await initParticlesEngine(async (engine) => {
await loadFull(engine);
});
ready = true;
});
</script>
{#if ready}
<Particles id="tsparticles" options={options} />
{/if}Effetto Neve
npm install @tsparticles/preset-snow<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadSnowPreset } from "@tsparticles/preset-snow";
import type { Engine, ISourceOptions } from "@tsparticles/engine";
const handleInit = async (event: CustomEvent<Engine>) => {
await loadSnowPreset(event.detail);
};
const options: ISourceOptions = {
preset: "snow",
background: {
color: "#1a1a2e",
},
};
</script>
<Particles
id="snow"
{options}
on:init={handleInit}
/>Personalizza il comportamento del preset unendo opzioni aggiuntive:
<script lang="ts">
const options: ISourceOptions = {
preset: "snow",
background: { color: "#0f0f23" },
particles: {
move: {
speed: 1.5, // nevicata più lenta
},
opacity: {
value: 0.8, // fiocchi più visibili
},
},
};
</script>Effetto Stelle
npm install @tsparticles/preset-stars<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadStarsPreset } from "@tsparticles/preset-stars";
import type { Engine, ISourceOptions } from "@tsparticles/engine";
const handleInit = async (event: CustomEvent<Engine>) => {
await loadStarsPreset(event.detail);
};
const options: ISourceOptions = {
preset: "stars",
background: {
color: "#000000",
},
};
</script>
<Particles
id="stars"
{options}
on:init={handleInit}
/>Particelle Interattive
Aggiungi interattività al passaggio del mouse e al click:
<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import type { Engine, ISourceOptions } from "@tsparticles/engine";
const handleInit = async (event: CustomEvent<Engine>) => {
await loadFull(event.detail);
};
const options: ISourceOptions = {
background: {
color: "#0d0d0d",
},
particles: {
number: { value: 100 },
color: { value: "#00d8ff" },
shape: { type: "circle" },
opacity: { value: 0.6 },
size: { value: { min: 1, max: 4 } },
links: {
enable: true,
distance: 120,
color: "#00d8ff",
opacity: 0.3,
width: 1,
},
move: {
enable: true,
speed: 3,
},
},
interactivity: {
events: {
onHover: {
enable: true,
mode: "grab",
},
onClick: {
enable: true,
mode: "push",
},
},
modes: {
grab: {
distance: 180,
links: { opacity: 0.5 },
},
push: {
quantity: 4,
},
},
},
};
</script>
<Particles
id="interactive"
{options}
on:init={handleInit}
/>Gestione Eventi
<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import type { Container, Engine } from "@tsparticles/engine";
let container: Container;
const handleInit = async (event: CustomEvent<Engine>) => {
await loadFull(event.detail);
};
const handleLoaded = (event: CustomEvent<Container>) => {
container = event.detail;
console.log("Container caricato", container);
};
const pause = () => container?.pause();
const resume = () => container?.play();
const destroy = () => container?.destroy();
</script>
<div>
<button on:click={pause}>Pausa</button>
<button on:click={resume}>Riprendi</button>
<button on:click={destroy}>Distruggi</button>
</div>
<Particles
id="tsparticles"
options={options}
on:init={handleInit}
on:particlesLoaded={handleLoaded}
/>| Evento | Dettaglio | Viene attivato |
|---|---|---|
on:init | Engine | Dopo che il motore è inizializzato |
on:particlesLoaded | Container | Dopo che il container è completamente pronto |
Esempio TypeScript
Componente tipizzato completo:
<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import type {
Container,
Engine,
ISourceOptions,
} from "@tsparticles/engine";
let particlesContainer: Container | undefined;
const options: ISourceOptions = {
background: {
color: "#1e1e2e",
},
fpsLimit: 60,
particles: {
color: {
value: "#cdd6f4",
},
links: {
color: "#cdd6f4",
distance: 150,
enable: true,
opacity: 0.3,
width: 1,
},
move: {
enable: true,
speed: 1.5,
},
number: {
value: 60,
},
opacity: {
value: 0.6,
},
size: {
value: { min: 1, max: 3 },
},
},
interactivity: {
events: {
onHover: {
enable: true,
mode: "repulse",
},
},
modes: {
repulse: {
distance: 100,
},
},
},
detectRetina: true,
};
const handleInit = async (event: CustomEvent<Engine>) => {
await loadFull(event.detail);
};
const handleLoaded = (event: CustomEvent<Container>) => {
particlesContainer = event.detail;
};
</script>
<Particles
id="tsparticles"
{options}
on:init={handleInit}
on:particlesLoaded={handleLoaded}
/>Opzioni Dinamiche
Le opzioni reattive aggiornano le particelle senza ricreare l'istanza:
<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import type { Engine, ISourceOptions } from "@tsparticles/engine";
let color = "#ff0000";
const handleInit = async (event: CustomEvent<Engine>) => {
await loadFull(event.detail);
};
$: options = {
background: {
color: "#000000",
},
particles: {
color: {
value: color,
},
links: {
color: color,
enable: true,
distance: 150,
},
number: {
value: 60,
},
move: {
enable: true,
speed: 2,
},
size: {
value: { min: 1, max: 3 },
},
},
} satisfies ISourceOptions;
</script>
<div>
<label>
Colore Particelle:
<input type="color" bind:value={color} />
</label>
</div>
<Particles
id="dynamic"
{options}
on:init={handleInit}
/>La dichiarazione reattiva $: ricalcola options ogni volta che color cambia, e il componente Particles recepisce automaticamente la nuova configurazione.
Istanze Multiple
Renderizza diversi sistemi di particelle indipendenti sulla stessa pagina:
<script lang="ts">
import Particles from "@tsparticles/svelte";
import { loadFull } from "tsparticles";
import type { Engine, ISourceOptions } from "@tsparticles/engine";
const handleInit = async (event: CustomEvent<Engine>) => {
await loadFull(event.detail);
};
const fireOptions: ISourceOptions = {
background: { color: "#1a0000" },
particles: {
color: { value: "#ff4500" },
number: { value: 40 },
move: { enable: true, speed: 1 },
size: { value: { min: 2, max: 6 } },
opacity: { value: 0.8 },
},
};
const waterOptions: ISourceOptions = {
background: { color: "#000d1a" },
particles: {
color: { value: "#00bfff" },
number: { value: 60 },
move: { enable: true, speed: 0.5, direction: "top" },
size: { value: { min: 1, max: 3 } },
opacity: { value: 0.5 },
},
};
</script>
<div style="display: grid; grid-template-columns: 1fr 1fr; height: 100vh;">
<div style="position: relative;">
<Particles id="fire" options={fireOptions} on:init={handleInit} />
</div>
<div style="position: relative;">
<Particles id="water" options={waterOptions} on:init={handleInit} />
</div>
</div>Ogni componente <Particles> ha il proprio id, canvas e contesto del motore.
Utilizzo con SvelteKit
In SvelteKit, il canvas richiede l'ambiente browser. Disabilita SSR per il componente:
<script lang="ts">
import { browser } from "$app/environment";
import { onMount } from "svelte";
let Component: typeof import("@tsparticles/svelte").default;
onMount(async () => {
if (browser) {
const module = await import("@tsparticles/svelte");
Component = module.default;
}
});
</script>
{#if Component}
<svelte:component this={Component} id="tsparticles" options={options} />
{/if}Oppure avvolgi l'import in un componente solo client. Per SvelteKit 2+, puoi anche usare le esclusioni SSR di vite-plugin-svelte.
Riferimento API
| Prop | Tipo | Default | Descrizione |
|---|---|---|---|
id | string | "tsparticles" | ID dell'elemento canvas |
options | ISourceOptions | {} | Oggetto di configurazione particelle |
url | string | — | URL per una configurazione JSON remota |
theme | string | — | Theme name (requires @tsparticles/plugin-themes; safe no-op otherwise). |
| Evento | Dettaglio | Descrizione |
|---|---|---|
on:init | Engine | Viene attivato quando il motore è inizializzato (usa per caricare plugin) |
on:particlesLoaded | Container | Viene attivato quando il container è completamente pronto |
Risoluzione dei Problemi
- Canvas non visibile — Assicurati che il contenitore padre abbia dimensioni esplicite (
height: 100%,height: 100vho un valore fisso in pixel). loadFull is not a function— Verifica chetsparticlessia installato e che stai importandoloadFulldatsparticles(non da@tsparticles/engine).- Reattività non funzionante — Assicurati che
optionssia una variabile reattiva ($:oletcollegata a una fonte reattiva). Valoriconstpuri non si aggiorneranno. - SvelteKit schermata bianca — Importa
@tsparticles/sveltedinamicamente o usa la protezionebrowsercome mostrato nella sezione SvelteKit sopra. - Errori TypeScript per
event.detail— Usa i tipiCustomEvent<Engine>eCustomEvent<Container>per i gestori di eventi.
