@ppmpreetham/three-boids
v1.0.4
Published
Readme
Three Boids
A boid simulation library written in TSL (Three Shading Language) and wrapped in a React Three Fiber component: <BoidsSystem />.
Installation
# npm
npm install @ppmpreetham/three-boids three @react-three/fiber
# pnpm
pnpm add @ppmpreetham/three-boids three @react-three/fiber
# yarn
yarn add @ppmpreetham/three-boids three @react-three/fiber[!NOTE]
Requires WebGPU support. Ensure your Three.js canvas is initialized withTHREE.WebGPURenderer.
Quick Start (React Three Fiber)
import React, { useMemo, useRef } from "react"
import * as THREE from "three/webgpu"
import { Canvas, useFrame } from "@react-three/fiber"
import { BoidsSystem, BoidRuleType, BoidRulesetType, BoidState } from "@ppmpreetham/three-boids"
function Scene() {
const goalRef = useRef<THREE.Object3D>(null)
useFrame(({ clock }) => {
if (!goalRef.current) return
const t = clock.getElapsedTime() * 0.5
goalRef.current.position.set(Math.cos(t) * 15, 6 + Math.sin(t * 1.5) * 3, Math.sin(t) * 15)
})
// flock behavior state
const states: BoidState[] = useMemo(
() => [
{
name: "Fly",
ruleset: BoidRulesetType.Fuzzy,
fuzziness: 0.5,
rules: [
{ type: BoidRuleType.Separate },
{
type: BoidRuleType.AvoidCollision,
lookAhead: 2,
withBoids: true,
withDeflectors: true,
},
{ type: BoidRuleType.Goal, object: 0, predict: true },
{ type: BoidRuleType.Flock },
{ type: BoidRuleType.AverageSpeed, speed: 0.6, wander: 0.2, level: 0.4 },
],
},
],
[],
)
// collision obstacles
const deflectors = useMemo(
() => [
{
type: "plane" as const,
point: new THREE.Vector3(0, 0, 0),
normal: new THREE.Vector3(0, 1, 0),
},
{ type: "sphere" as const, center: new THREE.Vector3(0, 4, 0), radius: 4 },
],
[],
)
return (
<>
<ambientLight intensity={0.6} />
<directionalLight position={[20, 30, 20]} intensity={1.5} />
{/* Target object */}
<mesh ref={goalRef}>
<sphereGeometry args={[0.4, 16, 16]} />
<meshBasicMaterial color="#ffcc00" />
</mesh>
{/* Obstacle */}
<mesh position={[0, 4, 0]}>
<sphereGeometry args={[4, 32, 32]} />
<meshStandardMaterial color="#444444" />
</mesh>
{/* Ground plane */}
<mesh rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[100, 100]} />
<meshStandardMaterial color="#222222" />
</mesh>
{/* Boid Flock */}
<BoidsSystem
count={1000}
color="#44aaff"
states={states}
targets={goalRef.current ? [{ object: goalRef.current }] : []}
deflectors={deflectors}
settings={{
allowFlight: true,
airMaxSpeed: 8,
airMinSpeed: 2,
airMaxAcc: 0.5,
airPersonalSpace: 1.2,
banking: 1.2,
pitch: 1.0,
}}
turbulence={{
enabled: true,
strength: 0.5,
scale: 0.2,
speed: 0.1,
}}
spawn={{
center: new THREE.Vector3(0, 10, 0),
box: new THREE.Vector3(10, 4, 10),
speed: [2, 5],
}}
/>
</>
)
}Battle & Interactions
Flocks can target and fight each other using the relations prop and BoidsSystemHandle refs:
import {
BoidsSystem,
BoidsSystemHandle,
BoidRuleType,
BoidRulesetType,
} from "@ppmpreetham/three-boids"
function BattleScene() {
const redRef = useRef<BoidsSystemHandle>(null)
const blueRef = useRef<BoidsSystemHandle>(null)
const redStates = useMemo(
() => [
{
name: "Attack",
ruleset: BoidRulesetType.Prioritized,
rules: [
{ type: BoidRuleType.Separate },
{ type: BoidRuleType.Fight, distance: 30, fleeDistance: 40 },
{ type: BoidRuleType.Flock },
],
},
],
[],
)
return (
<>
<BoidsSystem
ref={redRef}
count={500}
color="#ff4444"
states={redStates}
settings={{ health: 1.0, strength: 0.2, aggression: 1.5 }}
relations={blueRef.current ? [{ system: blueRef.current, mode: "enemy" }] : []}
/>
<BoidsSystem
ref={blueRef}
count={500}
color="#4488ff"
states={redStates}
settings={{ health: 1.0, strength: 0.15, aggression: 1.0 }}
relations={redRef.current ? [{ system: redRef.current, mode: "enemy" }] : []}
/>
</>
)
}Rules & Ruleset Types
Rulesets (BoidRulesetType)
BoidRulesetType.Fuzzy(Default): Randomly evaluates rules based on fuzziness weighting for lifelike organic variation.BoidRulesetType.Prioritized: Evaluates rules in sequential order and executes the first rule that triggers.BoidRulesetType.Average: Computes a weighted average vector of all matching active rules.
Rule Types (BoidRuleType)
| Rule | Description | Key Parameters |
| ---------------- | --------------------------------------------------------------------------- | ------------------------------------------ |
| Separate | Keeps boids from crowding nearby flockmates. | — |
| Flock | Standard alignment and cohesion toward flock centroid. | — |
| AvoidCollision | Casts forward rays to steer away from boids and deflectors. | lookAhead, withBoids, withDeflectors |
| Goal | Seeks toward a target object index with optional lead prediction. | object, predict |
| Avoid | Flees away from a predator or danger object index. | object, predict, fearFactor |
| FollowLeader | Follows a specific leader object or queues behind prior boids in the flock. | distance, useLine, queueSize |
| AverageSpeed | Maintains cruising speed with random wander orientation. | speed, wander, level |
| Fight | Attacks enemy flocks or flees when outnumbered. | distance, fleeDistance |
<BoidsSystem /> Props
| Prop | Type | Default | Description |
| ------------ | --------------------------- | ------------------------ | ------------------------------------------------------------- |
| count | number | 1000 | Number of simulated boids. |
| settings | Partial<BoidSettings> | {} | Physics, movement, agility, and battle parameters. |
| states | BoidState[] | Default Fly State | Behavior state machine configurations. |
| targets | BoidTargetInput[] | [] | External THREE.Object3D targets for Goal / Avoid rules. |
| deflectors | BoidDeflectorInput[] | [] | Obstacle deflectors (plane or sphere). |
| relations | BoidRelationInput[] | [] | Inter-flock interactions (enemy, friend, neutral). |
| turbulence | BoidTurbulence | { enabled: false } | Divergence-free 3D curl noise turbulence field. |
| spawn | BoidSpawn | Center box | Initial spawn volume (box or mesh surface sampling). |
| gravity | number | -9.81 | Gravitational acceleration along Y. |
| groundY | number | 0 | Default ground level for landing and walking. |
| color | THREE.ColorRepresentation | "#ffffff" | Instanced mesh color tint. |
| geometry | THREE.BufferGeometry | Cone geometry | Custom geometry for boid instances. |
| material | THREE.Material | MeshStandardNodeMaterial | Custom TSL-compatible material. |
| ref | Ref<BoidsSystemHandle> | — | Access underlying GPU buffers and uniforms imperatively. |
Vanilla Three.js / GPGPU API
For projects without React, you can use the pure TypeGPU/TSL GPGPU factory:
import * as THREE from "three/webgpu"
import { createBoidGPU, syncBoidUniforms, resolveSpawn } from "@ppmpreetham/three-boids"
const spawn = resolveSpawn({
center: new THREE.Vector3(0, 5, 0),
box: new THREE.Vector3(10, 2, 10),
})
const boidGPU = createBoidGPU(1000, settings, spawn, 0)
const initCompute = boidGPU.initNode
const simCompute = boidGPU.simulationNode([], states)
// in your render loop:
renderer.compute(simCompute)
renderer.render(scene, camera)