three.quarks Particle Behaviors: Complete Animation Reference
Behaviors are the building blocks of particle effects in three.quarks. They're modular components that modify particle properties during their lifetime, enabling you to create everything from realistic smoke and fire to magical energy effects and complex physics simulations. This guide covers all essential behaviors and how to combine them effectively.
What Are Particle Behaviors?
Behaviors modify specific particle properties over time. While emitters and initial values determine where and how particles spawn, behaviors control what happens next—how particles move, change color, grow or shrink, rotate, and interact with forces. Each behavior focuses on a specific aspect, and multiple behaviors combine to create sophisticated effects.
Behaviors operate through three lifecycle phases: initialization (called once when a particle spawns), update (called every frame for each particle), and frame update (called once per frame for shared state). This architecture enables both per-particle customization and efficient batch operations.
Adding Behaviors
Adding behaviors to a particle system is straightforward. Create your system, then use addBehavior() to attach modular behaviors:
const ps = new ParticleSystem(config);
// Add behaviors
ps.addBehavior(new SizeOverLife(
new PiecewiseBezier([[new Bezier(1, 0.95, 0.75, 0), 0]])
));
ps.addBehavior(new ColorOverLife(
new ColorRange(startColor, endColor)
));
ps.addBehavior(new ApplyForce(
new Vector3(0, -9.8, 0),
new ConstantValue(1)
));
Behaviors execute in the order you add them, which matters when one behavior depends on another's output. For instance, apply forces before limiting speed, then use the final speed for color calculations.
Force & Motion Behaviors
These behaviors control particle movement through physics and forces.
ApplyForce: Directional Forces
Applies a constant directional force like wind, gravity, or magnetic fields. The force affects all particles equally regardless of position.
// Wind blowing particles to the right
ps.addBehavior(new ApplyForce(
new Vector3(1, 0, 0), // Direction
new ConstantValue(5) // Strength
));
// Simple gravity
ps.addBehavior(new ApplyForce(
new Vector3(0, -1, 0),
new ConstantValue(9.8) // Earth gravity
));
Use cases: Wind effects, directional explosions, water currents, uniform acceleration. Combine with Noise for more organic movement patterns.
GravityForce: Point Attraction
Simulates gravitational attraction toward a specific point using inverse-square law physics. Particles closer to the center experience stronger force.
// Particles attracted to origin
ps.addBehavior(new GravityForce(
new Vector3(0, 0, 0), // Center point
100 // Gravitational strength
));
// Multiple gravity wells
ps.addBehavior(new GravityForce(new Vector3(-5, 0, 0), 50));
ps.addBehavior(new GravityForce(new Vector3(5, 0, 0), 50));
Use cases: Black hole effects, orbital motion, magnetic attraction, vortex formations. Force increases dramatically as particles approach the center.
Noise: Organic Turbulence
Adds natural-looking randomness using Simplex noise. Creates organic, flowing motion essential for realistic fire, smoke, and fluid effects.
// Gentle smoke drift
ps.addBehavior(new Noise(
new ConstantValue(0.5), // Low frequency: slow changes
new ConstantValue(2), // Moderate power
new ConstantValue(1), // Full position effect
new ConstantValue(0) // No rotation
));
// Chaotic magical energy
ps.addBehavior(new Noise(
new ConstantValue(3), // High frequency: rapid changes
new ConstantValue(5), // Strong power
new ConstantValue(1),
new ConstantValue(0.5) // Some rotation
));
Performance note: CPU-intensive as it calculates per particle per frame. Reduce particle count if experiencing performance issues. Each particle uses a unique noise generator for natural variation.
OrbitOverLife: Circular Motion
Makes particles orbit around a specified axis, creating swirling or spiraling effects.
// Spiral upward around Y axis
ps.addBehavior(new OrbitOverLife(
new ConstantValue(Math.PI), // 180° per second
new Vector3(0, 1, 0) // Y axis
));
// Variable orbit speed over lifetime
ps.addBehavior(new OrbitOverLife(
new PiecewiseBezier([[new Bezier(0, Math.PI, Math.PI * 2, Math.PI), 0]]),
new Vector3(0, 1, 0)
));
Use cases: Tornado effects, orbital magic circles, spiraling projectiles, vortex formations, DNA helix patterns. Combine with upward force for tornado effects.
LimitSpeedOverLife: Speed Capping
Caps particle velocity to a maximum speed with smooth damping, simulating air resistance or terminal velocity.
// Particles slow down over time
ps.addBehavior(new LimitSpeedOverLife(
new PiecewiseBezier([[new Bezier(20, 15, 10, 5), 0]]), // Decreasing limit
0.5 // Moderate damping
));
// Hard speed cap
ps.addBehavior(new LimitSpeedOverLife(
new ConstantValue(10), // Constant limit
0.9 // Strong damping
));
The damping parameter controls how aggressively speed is reduced: 0 means no damping, 0.5 is moderate, and 1.0 creates an instant hard cap (not recommended as it can look jerky).
Visual Property Behaviors
These behaviors modify particle appearance—size, color, and rotation.
SizeOverLife: Size Animation
Changes particle size during its lifetime. Essential for expansion, shrinkage, and pulsing effects.
// Particles grow then fade to nothing
ps.addBehavior(new SizeOverLife(
new PiecewiseBezier([[new Bezier(1, 2, 2, 0), 0]]) // 1x → 2x → 0x
));
// Constant growth
ps.addBehavior(new SizeOverLife(
new PiecewiseBezier([[new Bezier(0.1, 0.5, 1, 2), 0]]) // 0.1x → 2x
));
Size values multiply with startSize rather than replacing it. Use Bezier curves for smooth transitions. Combine with ColorOverLife for coordinated fade effects.
ColorOverLife: Color Transitions
Changes particle color and alpha during lifetime. Critical for realistic fire, fades, and energy transitions.
// Fire color transition: yellow → orange → dark red
ps.addBehavior(new ColorOverLife(
new Gradient(
[
[new Vector3(1, 1, 0.5), 0], // Start: bright yellow
[new Vector3(1, 0.5, 0), 0.5], // Middle: orange
[new Vector3(0.5, 0, 0), 1] // End: dark red
],
[[1, 0], [0.8, 0.5], [0, 1]] // Alpha: fade out
)
));
// Simple fade to black
ps.addBehavior(new ColorOverLife(
new ColorRange(
new Vector4(1, 1, 1, 1), // Start: white, opaque
new Vector4(0, 0, 0, 0) // End: black, transparent
)
));
Colors multiply with startColor, so use white for pure behavior colors. Gradient supports multiple color stops and independent alpha control.
RotationOverLife: Sprite Rotation
Rotates 2D billboard particles over their lifetime. For 3D mesh rotation, use Rotation3DOverLife.
// Constant rotation
ps.addBehavior(new RotationOverLife(
new ConstantValue(Math.PI) // 180° per second
));
// Random rotation per particle
ps.addBehavior(new RotationOverLife(
new IntervalValue(-Math.PI * 2, Math.PI * 2) // -360° to +360°/sec
));
// Accelerating spin
ps.addBehavior(new RotationOverLife(
new PiecewiseBezier([[new Bezier(0, Math.PI, Math.PI * 2, Math.PI * 4), 0]])
));
Positive values rotate counter-clockwise, negative values clockwise. Use radians: Math.PI = 180°, Math.PI * 2 = 360°.
SpeedOverLife: Velocity Scaling
Modifies particle velocity magnitude over lifetime, creating acceleration or deceleration effects.
// Slow down over time (drag/friction)
ps.addBehavior(new SpeedOverLife(
new PiecewiseBezier([[new Bezier(1, 0.75, 0.5, 0.25), 0]]) // 100% → 25%
));
// Come to a complete stop
ps.addBehavior(new SpeedOverLife(
new PiecewiseBezier([[new Bezier(1, 0.5, 0.1, 0), 0]])
));
Multiplies velocity magnitude while preserving direction. Value of 0 stops particles, 1 maintains original speed, values >1 accelerate.
Animation Behaviors
FrameOverLife: Texture Atlas Animation
Animates through sprite sheet frames during particle lifetime, essential for fire sequences, explosions, and animated symbols.
// Animate through 16 frames
ps.addBehavior(new FrameOverLife(
new PiecewiseBezier([[new Bezier(0, 5.33, 10.67, 16), 0]])
));
// Configure atlas in ParticleSystem
const ps = new ParticleSystem({
// ...other config
uTileCount: 4, // 4 columns
vTileCount: 4, // 4 rows (16 frames)
startTileIndex: new ConstantValue(0), // Start at frame 0
blendTiles: true // Smooth frame blending
});
Frames are indexed left-to-right, top-to-bottom starting at 0. Enable blendTiles for smooth transitions between frames.
WidthOverLength: Trail Tapering
Changes trail width based on distance from start. Only works with RenderMode.Trail.
// Trail tapers to a point
ps.addBehavior(new WidthOverLength(
new PiecewiseBezier([[new Bezier(1, 0.75, 0.5, 0), 0]]) // Full → 0
));
// Bulge in middle
ps.addBehavior(new WidthOverLength(
new PiecewiseBezier([[new Bezier(0.5, 1.5, 1.5, 0.5), 0]])
));
Advanced: Sub-Particle Systems
EmitSubParticleSystem spawns secondary particle systems from parent particles, enabling fireworks, bullet impacts, and chain reactions.
// Create parent and child systems
const rocket = new ParticleSystem(rocketConfig);
const explosion = new ParticleSystem(explosionConfig);
// Emit explosion when rocket dies
rocket.addBehavior(new EmitSubParticleSystem(
rocket, // Parent reference
true, // Use velocity as basis
explosion.emitter, // Child emitter
SubParticleEmitMode.Death, // Emit on death
1.0 // 100% probability
));
// Add both to scene
batchRenderer.addSystem(rocket);
batchRenderer.addSystem(explosion);
scene.add(rocket.emitter);
scene.add(explosion.emitter);
Emit modes: Birth (spawn with parent), Death (spawn when parent dies), Frame (continuous emission). Use probability less than 1.0 for performance optimization.
Performance warning: Each sub-particle creates additional particles, potentially causing exponential growth. Use short lifetimes, limit maxParticle counts, and consider emission probability for control.
Combining Behaviors
Real effects require multiple behaviors working together. Here's realistic smoke:
const smoke = new ParticleSystem(smokeConfig);
// Size: grows over time
smoke.addBehavior(new SizeOverLife(
new PiecewiseBezier([[new Bezier(0.5, 1, 1.5, 2), 0]])
));
// Color: fades from gray to dark
smoke.addBehavior(new ColorOverLife(
new Gradient(
[[new Vector3(0.8, 0.8, 0.8), 0], [new Vector3(0.3, 0.3, 0.3), 1]],
[[0.8, 0], [0, 1]] // Fade out
)
));
// Motion: rises upward
smoke.addBehavior(new ApplyForce(
new Vector3(0, 1, 0),
new ConstantValue(2)
));
// Turbulence: organic movement
smoke.addBehavior(new Noise(
new ConstantValue(1),
new ConstantValue(2)
));
// Drag: slows down over time
smoke.addBehavior(new SpeedOverLife(
new PiecewiseBezier([[new Bezier(1, 0.7, 0.5, 0.3), 0]])
));
Performance Considerations
Follow these guidelines for optimal performance:
- Limit particle counts: More particles mean more behavior calculations per frame
- Avoid expensive behaviors:
NoiseandTurbulenceFieldare CPU-intensive - Use batching:
BatchedRenderergroups similar systems efficiently - Optimize curves: Simple Bezier curves perform better than complex multi-segment curves
- Order matters: Execute dependent behaviors in sequence (force → limit → color by speed)
- Test on target hardware: Mobile devices handle significantly fewer particles than desktops
Behavior Quick Reference
Here's a quick overview of behavior costs and uses:
- ApplyForce (Low cost) - Directional forces, wind, gravity
- GravityForce (Low cost) - Point attraction, black holes, vortexes
- Noise (High cost) - Organic turbulence, fire/smoke motion
- TurbulenceField (Very High cost) - Volumetric turbulence, atmospheric effects
- OrbitOverLife (Low cost) - Circular motion, spirals, tornadoes
- LimitSpeedOverLife (Low cost) - Terminal velocity, air resistance
- SizeOverLife (Low cost) - Size animation, growth/shrinkage
- ColorOverLife (Low cost) - Color transitions, fades
- RotationOverLife (Low cost) - 2D sprite rotation
- SpeedOverLife (Low cost) - Velocity scaling, drag
- FrameOverLife (Low cost) - Texture atlas animation
- EmitSubParticleSystem (Medium-High cost) - Secondary emissions, chain reactions
Conclusion
Behaviors transform static particle emissions into dynamic, lifelike effects. By understanding force and motion behaviors, visual property modifiers, animation techniques, and advanced features like sub-emitters, you can create everything from realistic fire and smoke to magical energy effects and complex physics simulations.
Start with simple behavior combinations and add complexity gradually. Pay attention to performance costs—especially with Noise and TurbulenceField—and always test on your target hardware. The key to compelling effects lies in combining multiple behaviors thoughtfully, each contributing to the overall visual story.
For more advanced techniques and complete examples, check out the official three.quarks documentation and experiment with the visual editor.