WebGL

three.quarks Particle System Configuration Guide

December 4, 2025
8 min read

Creating stunning visual effects in WebGL applications requires powerful particle systems. three.quarks is a flexible JavaScript library built on Three.js that simplifies particle effect creation with a modular, configuration-driven approach. This guide covers everything you need to configure particle systems, from emitter shapes to render modes and practical examples.

What is three.quarks?

three.quarks is a powerful particle system library for Three.js that provides a comprehensive framework for creating visual effects like fire, explosions, smoke, rain, and magical auras. Unlike basic particle implementations, three.quarks offers sophisticated controls over emission patterns, particle behavior, and rendering techniques.

A particle system in three.quarks consists of four key components: the emitter shape (where particles spawn), emission settings (how and when they're emitted), particle initialization (starting properties like size and color), and behaviors (how particles change over their lifetime).

Basic Structure

Every particle system starts with a configuration object passed to the ParticleSystem constructor. Here's a minimal example:

import { ParticleSystem, BatchedRenderer } from 'three.quarks';

const particleSystem = new ParticleSystem({
    duration: 5,
    looping: true,

    shape: new SphereEmitter({ radius: 1 }),

    startLife: new ConstantValue(2),
    startSpeed: new IntervalValue(5, 10),
    startSize: new ConstantValue(1),
    startColor: new ConstantColor(new Vector4(1, 1, 1, 1)),

    material: new MeshBasicMaterial({ map: texture }),
    renderMode: RenderMode.BillBoard,

    behaviors: [
        new SizeOverLife(...),
        new ColorOverLife(...),
    ]
});

// Add to scene
const batchRenderer = new BatchedRenderer();
scene.add(batchRenderer);
batchRenderer.addSystem(particleSystem);
scene.add(particleSystem.emitter);

This creates a basic particle system that emits from a sphere, runs for 5 seconds, and loops continuously. The particles live for 2 seconds each, move at varying speeds, and appear as billboards always facing the camera.

Emitter Shapes

Emitter shapes define where and how particles spawn. three.quarks provides multiple shape types to match different effect requirements.

PointEmitter

The simplest emitter spawns all particles from a single point in space. Perfect for explosions, fireworks origins, or focused beams:

shape: new PointEmitter()

SphereEmitter

Spherical emission creates omnidirectional effects. Control whether particles spawn from the entire volume or just the surface:

// Full sphere volume explosion
shape: new SphereEmitter({
    radius: 5,
    thickness: 1,      // 1 = full volume
    mode: EmitterMode.Random
})

// Hollow sphere surface only (aura effect)
shape: new SphereEmitter({
    radius: 3,
    thickness: 0,      // 0 = surface only
    mode: EmitterMode.Random
})

ConeEmitter

Cone-shaped emission creates directional effects. Essential for jets, rockets, and spray patterns:

// Wide cone (30 degree angle)
shape: new ConeEmitter({
    radius: 1,
    angle: Math.PI / 6,     // 30° cone
    thickness: 1,
    mode: EmitterMode.Random
})

// Narrow laser beam
shape: new ConeEmitter({
    radius: 0.5,
    angle: Math.PI / 18,    // ~10° cone
    thickness: 0.2,
    mode: EmitterMode.Random
})

CircleEmitter

Circular disc emission works well for ground impacts and ring explosions:

// Full circular disc
shape: new CircleEmitter({
    radius: 3,
    thickness: 1,
    mode: EmitterMode.Random
})

// Ring (edge only)
shape: new CircleEmitter({
    radius: 2,
    thickness: 0,
    mode: EmitterMode.Random
})

Emission Settings

Control when and how many particles are emitted using continuous emission or burst patterns.

Continuous Emission

The emissionOverTime parameter controls steady particle flow measured in particles per second:

// Fixed rate: 30 particles per second
{
    emissionOverTime: new ConstantValue(30)
}

// Variable rate: random 20-50 per second
{
    emissionOverTime: new IntervalValue(20, 50)
}

Burst Emission

Bursts emit batches of particles at specific times. Perfect for explosions and timed effects:

// Single burst at start
{
    emissionBursts: [{
        time: 0,
        count: new ConstantValue(100),
        cycle: 1,
        interval: 0,
        probability: 1
    }]
}

// Repeating bursts every 0.2 seconds
{
    emissionBursts: [{
        time: 0,
        count: new ConstantValue(30),
        cycle: 1,
        interval: 0.2,
        probability: 1
    }]
}

Particle Initialization

Initialization properties define particle characteristics when spawned.

Lifetime and Speed

The startLife parameter controls how long particles exist, while startSpeed sets their initial velocity:

// All particles live exactly 2 seconds
startLife: new ConstantValue(2)

// Random lifetime between 1-3 seconds
startLife: new IntervalValue(1, 3)

// Fixed speed
startSpeed: new ConstantValue(5)

// Random speed (3-10 units/sec)
startSpeed: new IntervalValue(3, 10)

Size and Color

Set initial particle appearance with size and color generators:

// Fixed size
startSize: new ConstantValue(0.5)

// Random size variation
startSize: new IntervalValue(0.3, 0.8)

// White particles
startColor: new ConstantColor(new Vector4(1, 1, 1, 1))

// Orange glow
startColor: new ConstantColor(new Vector4(1, 0.5, 0, 1))

// Random color between yellow and red
startColor: new ColorRange(
    new Vector4(1, 1, 0, 1),    // Yellow
    new Vector4(1, 0, 0, 1)     // Red
)

Value Generators

Value generators control how properties are assigned and vary. Understanding these is crucial for creating dynamic effects.

ConstantValue

Returns the same fixed value for all particles:

new ConstantValue(5)  // Always returns 5

IntervalValue

Generates a random value between min and max for each particle at spawn time:

new IntervalValue(1, 10)  // Random 1-10 per particle

PiecewiseBezier

Creates smooth curves over particle lifetime using Bezier interpolation. Essential for animations:

// Linear fade: 0 → 1
new PiecewiseBezier([[new Bezier(0, 0.33, 0.67, 1), 0]])

// Ease in-out: 0 → peak → 0
new PiecewiseBezier([[new Bezier(0, 1, 1, 0), 0]])

// Complex multi-segment curve
new PiecewiseBezier([
    [new Bezier(0, 0.5, 1, 1), 0],      // 0-50%
    [new Bezier(1, 1, 0.5, 0), 0.5]     // 50-100%
])

Render Modes

Render modes determine how particles appear visually. Choose based on your effect requirements and performance needs.

BillBoard Mode

The most common mode renders flat sprites always facing the camera. Best performance and suitable for most effects:

{
    renderMode: RenderMode.BillBoard,
    material: new MeshBasicMaterial({
        map: texture,
        transparent: true,
        blending: AdditiveBlending,
        depthWrite: false
    })
}

StretchedBillBoard Mode

Stretches particles along their direction of movement, creating motion blur effects:

{
    renderMode: RenderMode.StretchedBillBoard,
    rendererEmitterSettings: {
        speedFactor: 0.1,    // Stretch based on velocity
        lengthFactor: 2.0    // Base stretch amount
    }
}

Mesh Mode

Renders full 3D geometry for each particle. Lower performance but more realistic:

{
    renderMode: RenderMode.Mesh,
    instancingGeometry: new BoxGeometry(1, 1, 1),
    rendererEmitterSettings: {
        startRotationX: new ConstantValue(0),
        startRotationY: new ConstantValue(0),
        startRotationZ: new ConstantValue(0)
    }
}

Complete Example: Fire Effect

Putting it all together, here's a complete fire effect with upward-rising flames and color transitions:

const fire = new ParticleSystem({
    duration: 5,
    looping: true,
    prewarm: true,

    shape: new ConeEmitter({
        radius: 0.5,
        angle: Math.PI / 6,
        thickness: 0.3
    }),

    startLife: new IntervalValue(0.8, 1.5),
    startSpeed: new IntervalValue(3, 6),
    startSize: new IntervalValue(0.5, 1),
    startColor: new ConstantColor(new Vector4(1, 1, 1, 1)),

    emissionOverTime: new ConstantValue(50),

    material: new MeshBasicMaterial({
        map: fireTexture,
        transparent: true,
        blending: AdditiveBlending,
        depthWrite: false
    }),

    renderMode: RenderMode.BillBoard,

    behaviors: [
        new SizeOverLife(
            new PiecewiseBezier([[new Bezier(1, 1.5, 2, 2.5), 0]])
        ),
        new ColorOverLife(new Gradient(
            [
                [new Vector3(1, 1, 0.5), 0],    // Yellow
                [new Vector3(1, 0.5, 0), 0.5],  // Orange
                [new Vector3(0.3, 0, 0), 1]     // Dark red
            ],
            [[1, 0], [0.8, 0.3], [0, 1]]
        )),
        new ApplyForce(new Vector3(0, 1, 0), new ConstantValue(2)),
        new Noise(new ConstantValue(1), new ConstantValue(3))
    ]
});

This fire effect emits 50 particles per second from a cone shape, grows in size over its lifetime, transitions from yellow to orange to dark red, rises upward due to applied force, and has noise for organic movement.

Complete Example: Explosion

A quick burst explosion expanding outward from a point:

const explosion = new ParticleSystem({
    duration: 1,
    looping: false,
    autoDestroy: true,

    shape: new SphereEmitter({
        radius: 0.1,
        thickness: 0,
        mode: EmitterMode.Burst
    }),

    startLife: new IntervalValue(0.8, 1.2),
    startSpeed: new IntervalValue(10, 20),
    startSize: new IntervalValue(0.5, 1.5),
    startColor: new ColorRange(
        new Vector4(1, 1, 0.5, 1),
        new Vector4(1, 0.5, 0, 1)
    ),

    emissionBursts: [{
        time: 0,
        count: new ConstantValue(200),
        cycle: 1
    }],

    material: new MeshBasicMaterial({
        transparent: true,
        blending: AdditiveBlending,
        depthWrite: false
    }),

    renderMode: RenderMode.BillBoard,

    behaviors: [
        new SizeOverLife(
            new PiecewiseBezier([[new Bezier(1, 2, 2, 0), 0]])
        ),
        new ApplyForce(new Vector3(0, -5, 0), new ConstantValue(1))
    ]
});

Best Practices

Follow these guidelines for optimal performance and quality:

  • Start simple: Begin with PointEmitter and BillBoard mode, add complexity gradually
  • Limit particle count: More particles mean more GPU work. Start conservative and increase as needed
  • Use batching: The BatchedRenderer groups similar particle systems for efficiency
  • Disable depthWrite: Set depthWrite: false for transparent particles to improve blending
  • Choose appropriate blending: Use AdditiveBlending for fire and energy effects, NormalBlending for smoke
  • Use texture atlases: Sprite sheets are more efficient than individual textures
  • Test on target hardware: Mobile devices handle fewer particles than desktops

Blending Mode Reference

Choose the right blending mode for your effect type:

  • AdditiveBlending: Fire, explosions, energy effects, glows - creates bright, glowing appearance
  • NormalBlending: Smoke, clouds, standard particles - standard alpha blending
  • MultiplyBlending: Dark effects, shadows - darkens underlying colors

Conclusion

three.quarks provides a comprehensive framework for creating stunning WebGL particle effects. By understanding emitter shapes, emission patterns, value generators, and render modes, you can craft sophisticated visual effects from fire and explosions to magical auras and weather systems.

Start with simple configurations and gradually add complexity. Pay attention to performance on your target hardware, and don't hesitate to experiment with different combinations of emitters, behaviors, and materials to achieve your desired effect.

For more advanced features, explore the official documentation at quarks.art/runtime/docs and experiment with the visual editor at quarks.art/create.