Skip to content

Confetti

The confetti simulation creates customizable particle bursts. Unlike the other simulations, confetti does not auto-spawn — you trigger bursts manually using the fire() method.

Click anywhere

Examples

Click to fire

Click anywhere to fire a confetti burst from that position.

Click anywhere

<template>
    <div ref="containerRef" class="effect-demo effect-demo--clickable" @click="onClick">
        <canvas ref="canvasRef"></canvas>

        <span class="effect-demo__hint">Click anywhere</span>
    </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';

const canvasRef = ref<HTMLCanvasElement>();
const containerRef = ref<HTMLDivElement>();
let sim: { fire(config: Record<string, unknown>): void; destroy(): void } | null = null;

function onClick(evt: MouseEvent): void {
    if (!sim || !containerRef.value) {
        return;
    }

    const rect = containerRef.value.getBoundingClientRect();

    sim.fire({
        angle: 90,
        spread: 60,
        particles: 120,
        startVelocity: 45,
        x: (evt.clientX - rect.left) / rect.width,
        y: (evt.clientY - rect.top) / rect.height
    });
}

onMounted(async () => {
    const { ConfettiSimulation } = await import('@basmilius/sparkle');

    if (canvasRef.value) {
        sim = new ConfettiSimulation(canvasRef.value, {scale: 0.5});
    }
});

onUnmounted(() => {
    sim?.destroy();
    sim = null;
});
</script>

Directional bursts

Fire confetti from both sides of the screen simultaneously.

<template>
    <div class="effect-demo">
        <canvas ref="canvasRef"></canvas>

        <div class="effect-demo__controls">
            <button @click="celebrate">Celebrate!</button>
        </div>
    </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';

const canvasRef = ref<HTMLCanvasElement>();
let sim: { fire(config: Record<string, unknown>): void; destroy(): void } | null = null;

function celebrate(): void {
    if (!sim) {
        return;
    }

    sim.fire({
        angle: 45,
        spread: 50,
        particles: 80,
        startVelocity: 50,
        x: 0,
        y: 0.7
    });

    sim.fire({
        angle: 135,
        spread: 50,
        particles: 80,
        startVelocity: 50,
        x: 1,
        y: 0.7
    });
}

onMounted(async () => {
    const { ConfettiSimulation } = await import('@basmilius/sparkle');

    if (canvasRef.value) {
        sim = new ConfettiSimulation(canvasRef.value, {scale: 0.5});
    }
});

onUnmounted(() => {
    sim?.destroy();
    sim = null;
});
</script>

Custom Colors

Override the default color palette:

typescript
sim.fire({
    angle: 90,
    spread: 70,
    particles: 120,
    startVelocity: 40,
    colors: ['#ff0000', '#00ff00', '#0000ff'],
    x: 0.5,
    y: 0.5
});

Custom Shapes

Choose which particle shapes to use:

typescript
sim.fire({
    angle: 90,
    spread: 60,
    particles: 100,
    startVelocity: 45,
    shapes: ['star', 'circle'],
    x: 0.5,
    y: 0.5
});

Available shapes: circle, diamond, ribbon, square, star, triangle.

Physics Tuning

Adjust gravity and decay for different feels:

typescript
// Slow, floaty confetti
sim.fire({
    angle: 90,
    spread: 90,
    particles: 200,
    startVelocity: 30,
    gravity: 0.5,
    decay: 0.95,
    ticks: 400,
    x: 0.5,
    y: 0.5
});
typescript
// Fast, explosive confetti
sim.fire({
    angle: 90,
    spread: 120,
    particles: 250,
    startVelocity: 70,
    gravity: 2,
    decay: 0.85,
    ticks: 100,
    x: 0.5,
    y: 0.5
});