Skip to content

Layering Effects ​

Sparkle supports combining multiple effects on a single canvas using Scene. Each effect is an independent layer that can be stacked on top of others.

How It Works ​

Every effect class (e.g. Aurora, Stars, Rain) can be used standalone or as a layer inside a Scene. Effects contain the simulation logic without owning a canvas — they render onto whatever context they are given. Scene manages a single canvas and drives all layers with the same frame loop.

Scene (canvas + RAF loop)
  ├── Aurora    (draws first — background)
  ├── Stars     (draws on top)
  └── Rain      (draws on top)

Basic Usage ​

typescript
import { createAurora, createScene, createStars } from '@basmilius/sparkle';

const canvas = document.getElementById('canvas') as HTMLCanvasElement;

createScene()
    .mount(canvas)
    .layer(createAurora())
    .layer(createStars({ mode: 'shooting' }))
    .start();

The layer() method is chainable:

typescript
createScene()
    .mount(canvas)
    .layer(createAurora({ bands: 6 }))
    .layer(createStars({ mode: 'shooting', shootingInterval: [200, 500] }))
    .start();

Layer Ordering ​

Layers are drawn in the order they are added — the first layer draws first (bottom) and the last layer draws on top. Place background layers (like Aurora, Waves) first and particle effects on top.

Configuration ​

Each layer accepts the same config options as when used standalone:

typescript
createAurora({
    bands: 7,
    colors: ['#ff22aa', '#aa00ff']
})

createRain({
    variant: 'drizzle'
})

createLightning({
    branches: true,
    frequency: 0.5,
    color: '#ffcc88'
})

Example Combinations ​

Aurora Night Sky

Aurora with shooting stars layered on top.

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

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

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

    onMounted(() => {
        if (canvasRef.value) {
            sim = createScene()
                .mount(canvasRef.value)
                .layer(createAurora())
                .layer(createStars({mode: 'both'}).withFade({bottom: [0.3, 0.5]}));
            sim.start();
        }
    });

    onUnmounted(() => {
        sim?.destroy();
        sim = null;
    });
</script>
typescript
createScene()
    .mount(canvas)
    .layer(createAurora())
    .layer(createStars({ mode: 'both' }).withFade({ bottom: 0.4 }))
    .start();

Thunderstorm

Heavy rain with separate lightning layer for full control.

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

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

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

    onMounted(() => {
        if (canvasRef.value) {
            sim = createScene()
                .mount(canvasRef.value)
                .layer(createRain({variant: 'downpour'}))
                .layer(createLightning({branches: true, frequency: 0.4}));
            sim.start();
        }
    });

    onUnmounted(() => {
        sim?.destroy();
        sim = null;
    });
</script>
typescript
createScene()
    .mount(canvas)
    .layer(createRain({ variant: 'downpour' }))
    .layer(createLightning({ branches: true, frequency: 0.4 }))
    .start();

Festive Scene

Snow falling past festive balloons.

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

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

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

    onMounted(() => {
        if (canvasRef.value) {
            sim = createScene()
                .mount(canvasRef.value)
                .layer(createSnow())
                .layer(createBalloons({count: 8}));
            sim.start();
        }
    });

    onUnmounted(() => {
        sim?.destroy();
        sim = null;
    });
</script>
typescript
createScene()
    .mount(canvas)
    .layer(createSnow())
    .layer(createBalloons({ count: 8 }))
    .start();

Interactive Layers ​

Layers with mouse or click interaction (bubbles, donuts, particles, sparklers) attach their event listeners to the Scene canvas automatically:

typescript
createScene()
    .mount(canvas)
    .layer(createParticles({mouseMode: 'connect'}))
    .layer(createSparklers({hoverMode: true}))
    .start();