Skip to Content
Quarks

Behaviors

Behaviors are components that control how particles evolve over time in the three.quarks particle system. They modify particle properties such as position, velocity, color, size, and rotation throughout the particle’s lifetime, allowing you to create complex and realistic effects.

Overview

In three.quarks, behaviors are modular components that you add to a particle system. Each behavior focuses on a specific aspect of particle animation, and multiple behaviors can be combined to create sophisticated effects.

Using Behaviors

Behaviors are added to a particle system through the behaviors array in the ParticleSystem constructor:

const particleSystem = new ParticleSystem({ // ... other particle system properties behaviors: [ new SizeOverLife(new PiecewiseBezier([[new Bezier(1, 1.5, 0.5, 0), 0]])), new ColorOverLife( new Gradient([ [new Vector3(1, 0.5, 0.1), 0], [new Vector3(0.1, 0.1, 0.1), 1], ]), ), new ApplyForce(new Vector3(0, 5, 0), new ConstantValue(1)), ], });

Behavior Categories

Behaviors in three.quarks can be grouped into three main categories:

Movement Behaviors

These behaviors affect the position, velocity, or rotation of particles.

BehaviorDescription
ApplyForceApplies a constant force to particles
GravityForceApplies gravitational force toward a point
OrbitOverLifeMakes particles orbit around an axis
SpeedOverLifeControls particle speed throughout lifetime
LimitSpeedOverLifeCaps particle speed throughout lifetime
TurbulenceFieldApplies realistic turbulence to particle movement
NoiseAdds random noise to position and rotation
ForceOverLifeApplies a varying force based on lifetime
ApplyCollisionHandles collisions with objects or surfaces

Visual Behaviors

These behaviors affect the appearance of particles.

BehaviorDescription
ColorOverLifeChanges particle color throughout lifetime
ColorBySpeedChanges particle color based on speed
SizeOverLifeChanges particle size throughout lifetime
SizeBySpeedChanges particle size based on speed
RotationOverLifeControls particle rotation throughout lifetime
Rotation3DOverLifeControls 3D particle rotation throughout lifetime
RotationBySpeedControls particle rotation based on speed
FrameOverLifeAnimates sprite sheets throughout lifetime
WidthOverLengthControls the width of particle trails over their length

Advanced Behaviors

These behaviors offer more complex functionality.

BehaviorDescription
EmitSubParticleSystemEmits child particle systems from parent particles
ChangeEmitDirectionModifies the emission direction of particles
ApplySequencesControls sequences of particle movements

Detailed Behavior Documentation

Movement Behaviors

ApplyForce

Applies a constant force to particles, affecting their velocity over time.

new ApplyForce( direction, // Vector3: Direction of the force magnitude, // ValueGenerator: Magnitude of the force );

Example:

// Apply an upward force new ApplyForce(new Vector3(0, 1, 0), new ConstantValue(5));

GravityForce

Applies a gravitational force that pulls particles toward a central point.

new GravityForce( center, // Vector3: The point particles are attracted to magnitude, // number: Strength of the gravity );

Example:

// Create a gravitational pull toward the origin new GravityForce(new Vector3(0, 0, 0), 10);

OrbitOverLife

Makes particles orbit around an axis.

new OrbitOverLife( orbitSpeed, // ValueGenerator or FunctionValueGenerator: Speed of orbit axis, // Vector3: Axis to orbit around (default is y-axis) );

Example:

// Make particles orbit around the y-axis new OrbitOverLife( new ConstantValue(Math.PI / 2), // Half a rotation per second new Vector3(0, 1, 0), );

SpeedOverLife

Controls particle speed throughout their lifetime.

new SpeedOverLife( speed, // FunctionValueGenerator: Speed multiplier over lifetime );

Example:

// Particles start fast and slow down over time new SpeedOverLife(new PiecewiseBezier([[new Bezier(1, 0.8, 0.4, 0), 0]]));

LimitSpeedOverLife

Caps particle speed throughout their lifetime.

new LimitSpeedOverLife( speed, // FunctionValueGenerator: Maximum speed over lifetime dampen, // number: Damping factor (0-1) );

Example:

// Limit particle speed with increasing restriction over time new LimitSpeedOverLife( new PiecewiseBezier([[new Bezier(10, 8, 5, 2), 0]]), 0.5, );

TurbulenceField

Applies realistic turbulence to particle movement, creating natural flowing motion.

new TurbulenceField( scale, // Vector3: Scale of the turbulence field octaves, // number: Number of noise octaves (detail level) velocityMultiplier, // Vector3: Strength of turbulence per axis timeScale, // Vector3: Speed of turbulence change per axis );

Example:

// Create realistic air turbulence new TurbulenceField( new Vector3(2, 2, 2), 3, new Vector3(1, 2, 1), new Vector3(0.1, 0.1, 0.1), );

Noise

Adds random noise to particle position and rotation.

new Noise( frequency, // ValueGenerator: Noise frequency power, // ValueGenerator: Noise strength positionAmount, // ValueGenerator: Amount to affect position (0-1) rotationAmount, // ValueGenerator: Amount to affect rotation (0-1) );

Example:

// Add gentle noise to particle position new Noise( new ConstantValue(1), new ConstantValue(0.5), new ConstantValue(0.3), new ConstantValue(0), );

ForceOverLife

Applies a force that varies based on particle lifetime.

new ForceOverLife( x, // FunctionValueGenerator: X-axis force over lifetime y, // FunctionValueGenerator: Y-axis force over lifetime z, // FunctionValueGenerator: Z-axis force over lifetime );

Example:

// Force that varies over lifetime new ForceOverLife( new PiecewiseBezier([[new Bezier(0, 0.5, -0.5, 0), 0]]), new PiecewiseBezier([[new Bezier(0, 1, 1, 0), 0]]), new ConstantValue(0), );

ApplyCollision

Handles collisions with objects or surfaces, with bounce effects.

new ApplyCollision( resolver, // PhysicsResolver: Object that detects collisions bounce, // number: Bounciness factor (0-1) );

Example:

// Resolve collisions with ground plane with medium bounce const resolver = { resolve: (pos, normal) => { // Simple ground plane collision if (pos.y < 0) { normal.set(0, 1, 0); return true; } return false; }, }; new ApplyCollision(resolver, 0.7);

Visual Behaviors

ColorOverLife

Changes particle color throughout lifetime.

new ColorOverLife( color, // FunctionColorGenerator: Color gradient over lifetime );

Example:

// Particles fade from yellow to red to black new ColorOverLife( new Gradient( [ [new Vector3(1, 0.8, 0.2), 0], // Yellow [new Vector3(1, 0.2, 0.1), 0.5], // Red [new Vector3(0.1, 0.1, 0.1), 1], // Black ], [ [1, 0], // Fully opaque [0.8, 0.5], // Slightly transparent [0, 1], // Fully transparent ], ), );

ColorBySpeed

Changes particle color based on their speed.

new ColorBySpeed( color, // FunctionColorGenerator: Color gradient based on speed speedRange, // IntervalValue: Min and max speed range );

Example:

// Particles change color based on speed new ColorBySpeed( new Gradient([ [new Vector3(0, 0, 1), 0], // Blue (slow) [new Vector3(0, 1, 0), 0.5], // Green (medium) [new Vector3(1, 0, 0), 1], // Red (fast) ]), new IntervalValue(0, 10), // Speed range 0-10 );

SizeOverLife

Changes particle size throughout lifetime.

new SizeOverLife( size, // FunctionValueGenerator or Vector3Generator: Size over lifetime );

Example:

// Particles grow then shrink new SizeOverLife(new PiecewiseBezier([[new Bezier(0.5, 1, 1, 0), 0]]));

For different scaling per axis:

// Non-uniform scaling over lifetime new SizeOverLife( new Vector3Function( new PiecewiseBezier([[new Bezier(1, 1.5, 1, 0.5), 0]]), // X axis new PiecewiseBezier([[new Bezier(1, 0.5, 1.5, 1), 0]]), // Y axis new ConstantValue(1), // Z axis ), );

SizeBySpeed

Changes particle size based on their speed.

new SizeBySpeed( size, // FunctionValueGenerator or Vector3Generator: Size based on speed speedRange, // IntervalValue: Min and max speed range );

Example:

// Faster particles are larger new SizeBySpeed( new PiecewiseBezier([[new Bezier(0.5, 1, 1.5, 2), 0]]), new IntervalValue(0, 10), // Speed range 0-10 );

RotationOverLife

Controls 2D particle rotation throughout lifetime.

new RotationOverLife( angularVelocity, // ValueGenerator or FunctionValueGenerator: Rotation speed );

Example:

// Particles rotate at constant speed new RotationOverLife( new ConstantValue(Math.PI), // Half rotation per second );

Rotation3DOverLife

Controls 3D particle rotation throughout lifetime. Works with mesh particles.

new Rotation3DOverLife( angularVelocity, // RotationGenerator: 3D rotation control );

Example:

// Particles rotate around the y-axis new Rotation3DOverLife( new AxisAngleGenerator(new Vector3(0, 1, 0), new ConstantValue(Math.PI)), );

RotationBySpeed

Controls particle rotation based on speed.

new RotationBySpeed( angularVelocity, // ValueGenerator or FunctionValueGenerator: Rotation speed speedRange, // IntervalValue: Min and max speed range );

Example:

// Faster particles rotate more quickly new RotationBySpeed( new PiecewiseBezier([[new Bezier(0, Math.PI / 2, Math.PI, Math.PI * 2), 0]]), new IntervalValue(0, 10), // Speed range 0-10 );

FrameOverLife

Animates sprite sheets throughout particle lifetime.

new FrameOverLife( frame, // FunctionValueGenerator: Frame index over lifetime );

Example:

// Animate through a 4x4 sprite sheet new FrameOverLife(new PiecewiseBezier([[new Bezier(0, 5, 10, 15), 0]]));

WidthOverLength

Controls the width of particle trails over their length. Only works with TrailParticle.

new WidthOverLength( width, // FunctionValueGenerator: Width over trail length );

Example:

// Trail width tapers off new WidthOverLength(new PiecewiseBezier([[new Bezier(1, 0.8, 0.4, 0), 0]]));

Advanced Behaviors

EmitSubParticleSystem

Emits child particle systems from parent particles.

new EmitSubParticleSystem( particleSystem, // IParticleSystem: Parent particle system useVelocityAsBasis, // boolean: Whether to align with particle velocity subParticleSystem, // IEmitter: Child particle system to emit mode, // SubParticleEmitMode: When to emit (Death, Birth, Frame) emitProbability, // number: Probability of emission (0-1) );

Example:

// Emit explosion sub-system when particles die new EmitSubParticleSystem( particleSystem, true, explosionSystem.emitter, SubParticleEmitMode.Death, 1, );

ChangeEmitDirection

Modifies the emission direction of particles.

new ChangeEmitDirection( angle, // ValueGenerator: Angle to change direction by );

Example:

// Randomize emission direction within a cone new ChangeEmitDirection( new IntervalValue(0, Math.PI / 6), // 0-30 degrees );

ApplySequences

Controls sequences of particle movements, useful for complex motion paths.

new ApplySequences( delayBetweenParticles, // number: Delay between particle sequence starts );

Example creating a text sequence:

const sequence = new ApplySequences(0.05); // Add a sequence where particles form text sequence.appendSequencer( new IntervalValue(0, 2), // Time range new TextureSequencer(10, 10, new Vector3(0, 0, 0)), ); // Add the sequence behavior particleSystem.behaviors.push(sequence);

Combining Behaviors

Multiple behaviors can be combined to create complex effects. Behaviors are processed in the order they appear in the array:

// Create a fire effect with multiple behaviors const particleSystem = new ParticleSystem({ // ... other properties behaviors: [ // Size change over lifetime new SizeOverLife(new PiecewiseBezier([[new Bezier(0.5, 1, 1, 0), 0]])), // Color change over lifetime new ColorOverLife( new Gradient( [ [new Vector3(1, 0.8, 0.2), 0], // Yellow [new Vector3(1, 0.2, 0.1), 0.5], // Red [new Vector3(0.1, 0.1, 0.1), 1], // Black ], [ [1, 0], [0.8, 0.5], [0, 1], ], ), ), // Upward force new ApplyForce(new Vector3(0, 5, 0), new ConstantValue(1)), // Random rotation new RotationOverLife(new IntervalValue(-Math.PI, Math.PI)), // Natural turbulence new TurbulenceField( new Vector3(2, 2, 2), 2, new Vector3(1, 2, 1), new Vector3(0.1, 0.1, 0.1), ), ], });

Creating Custom Behaviors

You can create custom behaviors by implementing the Behavior interface:

class MyCustomBehavior { // Type identifier for the behavior type = "MyCustomBehavior"; // Constructor for your behavior constructor(param1, param2) { this.param1 = param1; this.param2 = param2; } // Called once when a particle is created initialize(particle, particleSystem) { // Initialize particle properties } // Called every frame for each particle update(particle, delta) { // Update particle properties based on delta time } // Called once per frame before updating particles frameUpdate(delta) { // Update behavior state before processing particles } // Called when you want to reset behavior state reset() { // Reset internal state } // For serialization toJSON() { return { type: this.type, param1: this.param1, param2: this.param2, }; } // Create a new instance of this behavior clone() { return new MyCustomBehavior(this.param1, this.param2); } } // Use your custom behavior particleSystem.behaviors.push(new MyCustomBehavior(10, "custom"));

Performance Considerations

  1. Behavior Complexity: Some behaviors (like TurbulenceField) are more computationally expensive than others. Use them judiciously.

  2. Order Matters: Behaviors are processed in the order they appear in the array. Put more important or prerequisite behaviors earlier.

  3. Batch Similar Systems: If you have multiple particle systems with identical behaviors, consider using a single system with more particles.

  4. Balance Quantity vs. Quality: For mobile or performance-critical applications, reduce the number of behaviors per particle system.

Next Steps

Last updated on