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 burst() method.

Click anywhere

Examples

Click to fire

Click anywhere to fire a confetti burst from that position.

Click anywhere

<template>
    <EffectDemo
        ref="containerRef"
        clickable
        @click="onClick">
        <canvas ref="canvasRef"></canvas>

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

<script
    setup
    lang="ts">
    import { onMounted, onUnmounted, ref } from 'vue';
    import { createConfetti } from '@basmilius/sparkle';

    const canvasRef = ref<HTMLCanvasElement>();
    const containerRef = ref<HTMLDivElement>();
    let sim: ReturnType<typeof createConfetti> | null = null;

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

        const rect = containerRef.value.getBoundingClientRect();

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

    onMounted(() => {
        if (canvasRef.value) {
            sim = createConfetti();
            sim.mount(canvasRef.value).start();
        }
    });

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

Directional bursts

Fire confetti from both sides of the screen simultaneously.

<template>
    <EffectDemo>
        <canvas ref="canvasRef"></canvas>

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

<script
    setup
    lang="ts">
    import { onMounted, onUnmounted, ref } from 'vue';
    import { createConfetti } from '@basmilius/sparkle';

    const canvasRef = ref<HTMLCanvasElement>();
    let sim: ReturnType<typeof createConfetti> | null = null;

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

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

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

    onMounted(() => {
        if (canvasRef.value) {
            sim = createConfetti();
            sim.mount(canvasRef.value).start();
        }
    });

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

Color Palettes

Try different color palettes by clicking the buttons below, then click anywhere to fire.

Color palettes

Select a palette and click anywhere to compare the different color styles.

<template>
    <EffectDemo
        ref="containerRef"
        clickable
        @click="onClick">
        <canvas ref="canvasRef"></canvas>

        <div class="effect-demo__controls">
            <button
                v-for="(name, key) in paletteNames"
                :key="key"
                :style="buttonStyle(key)"
                @click.stop="onSelect(key, $event)">
                {{ name }}
            </button>
        </div>
    </EffectDemo>
</template>

<script
    setup
    lang="ts">
    import { onMounted, onUnmounted, ref } from 'vue';
    import type { Palette } from '@basmilius/sparkle';
    import { createConfetti } from '@basmilius/sparkle';

    const paletteNames: Record<Palette, string> = {
        classic: 'Classic',
        pastel: 'Soft Pastels',
        vibrant: 'Vibrant Modern',
        warm: 'Rich & Warm'
    };

    const canvasRef = ref<HTMLCanvasElement>();
    const containerRef = ref<HTMLDivElement>();
    const activePalette = ref<Palette>('vibrant');
    let sim: ReturnType<typeof createConfetti> | null = null;

    function buttonStyle(palette: Palette): Record<string, string> {
        if (palette !== activePalette.value) {
            return {};
        }

        return {
            background: 'rgba(255, 255, 255, .2)',
            borderColor: 'rgba(255, 255, 255, .3)',
            color: 'white'
        };
    }

    function onSelect(palette: Palette, evt: MouseEvent): void {
        activePalette.value = palette;

        if (!sim || !containerRef.value) {
            return;
        }

        const rect = containerRef.value.getBoundingClientRect();

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

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

        const rect = containerRef.value.getBoundingClientRect();

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

    onMounted(() => {
        if (canvasRef.value) {
            sim = createConfetti();
            sim.mount(canvasRef.value).start();
        }
    });

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

Use a built-in palette:

typescript
confetti.burst({
    palette: 'warm',
    particles: 120
});

Or provide custom colors to override the palette:

typescript
confetti.burst({
    colors: ['#ff0000', '#00ff00', '#0000ff'],
    particles: 120
});

Available palettes: classic, pastel, vibrant (default), warm.

Custom Shapes

Choose which particle shapes to use:

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

Available shapes: bowtie, circle, crescent, diamond, heart, hexagon, ribbon, ring, square, star, triangle.

Physics Tuning

Adjust gravity and decay for different feels:

typescript
// Slow, floaty confetti
confetti.burst({
    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
confetti.burst({
    angle: 90,
    spread: 120,
    particles: 250,
    startVelocity: 70,
    gravity: 2,
    decay: 0.85,
    ticks: 100,
    x: 0.5,
    y: 0.5
});