npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

threejs-fauna

v0.1.0

Published

Procedural animals for three.js: fish schools, birds and wildlife that live in the right biomes

Readme

threejs-fauna

Procedural animals for three.js that live where they should. Fish schools swim in rivers and seas, matched to water type, temperature and depth. Bird flocks fly over the biomes they like. Bodies, colour patterns, swimming and wing beats are generated (TSL, no textures or models). Groups spawn deterministically in tiles around the camera and move as seeded, fixed-step boids that never leave their habitat. Built on a threejs-biomes World, part of threejs-worldgen.

npm i threejs-fauna threejs-biomes three
import { World } from 'threejs-biomes'
import { Fauna, Fish, FishSchools } from 'threejs-fauna'

const world = new World({ seed: 1 })
const fauna = await Fauna.create({ camera, scene, renderer, world, seed: 7 })   // fish + birds
fauna.set({ birds: { density: 8 }, fish: { species: { shark: { habitat: { weight: 0 } } } } })

const schools = await FishSchools.create({ camera, scene, renderer, world })   // or one kind on its own
schools.set({ predators: [{ object: camera, radius: 3 }] })                     // fish scatter from the camera

const nemo = await Fish.create({ scene, renderer, preset: 'clownfish', seed: 3 }) // one hero fish
nemo.set({ speed: 2, species: { pattern: { stripes: { count: 4 } } } })
import { Fauna, Fish, FishSchools, BirdFlocks } from 'threejs-fauna/react'

<Fauna world={world} birds={{ density: 6 }} />
<group position={[0, 1, 0]}><Fish preset="tang" speed={1.5} /></group>

| Export | What it does | |---|---| | Fish | One fish of any species, swimming in place. set({ preset, species, speed, turn, seed, states }). | | FishSchools | Schools streamed around the camera wherever there is water deep enough for the species. | | BirdFlocks | Flocks streamed around the camera over their biomes, in a height band above ground or water. | | Fauna | Every kind in FAUNA_KINDS at once, sharing seed, origin, states and predators. Set a kind to false to leave it out. | | FISH_SPECIES / BIRD_SPECIES | The built-in species as plain JSON. Pass edited or new ones through species. | | buildFishMesh(shape) / buildBirdMesh(shape) | The generators, as typed arrays (no three.js, so they run in workers and tests). | | Flock, GridEnvironment, spawnTile | The pure boids, habitat grid and per-tile placement the layers are built from. | | FaunaLayer | Base class for new kinds (land herds): implement species, habitat, mesh, material and animation. |

Fish (12 presets). Freshwater: trout, carp, perch and pike. Warm reef: clownfish, tang and parrotfish. Cold sea: cod, herring and mackerel. Large open water: tuna and shark. The body is lofted from superellipse cross-sections along a spine and is watertight. Parameters: depth, width, where it is deepest, nose shape, back/belly split, tail stalk and squareness. Fins are two-sided sheets: tail (forked, lunate, rounded or truncate, with optional shark asymmetry), dorsal and anal fins (any number), pectoral and pelvic fins. The mouth and eye are painted. The pattern is drawn in the shader: countershading, bars or lengthwise stripes (wavy, banded, outlined), spots, iridescence and a silver sheen. Each fish varies its size, girth, hue, brightness and pattern phase from the seed.

Swimming is vertex animation on one InstancedMesh per species. A travelling wave A(s)·sin(k·s − phase) grows toward the tail. Its frequency comes from the swimming speed, and the phase is integrated on the CPU, so speed changes never jump. Turning bends the body by the turn rate, and the paired fins flutter. Birds flap with the wing bending toward the tip, glide by turns, and bank into turns.

Placement samples the world: water depth is waterLevel − elevation. Fresh water means a river (river > water.riverStrength) or inland water (continentalness > water.inland). Species are then picked by water type, temperature and depth (birds by biome weights). Each group bakes a small, conservative grid of its band (bed to surface for fish, ground plus altitude for birds), and the boids treat everything outside it as a wall. They also keep margin plus each fish's own half-height and pitch from the bed and the surface, so no fin ever breaks the water. Everything comes from seed, the tile and the world (no Math.random). The tests check that every fish stays under the surface and above the bed against the real world.

Scale. Groups live in the world's local frame, which is re-centred on the camera on planets. Instance matrices are relative to an anchor near the camera, so GPU numbers stay small anywhere (set origin for a floating origin). World sampling is the expensive part (~0.2–0.6 ms a sample), so spawning is a generator capped at buildBudget ms per frame. Groups beyond simDistance are drawn but not simulated. Instance buffers are written in place each frame, with explicit bounding spheres.

Weathering. states: { wetness, snow, burn, damage } (0…1) matches the shared material-state layer of threejs-weathering. Fish mostly ignore it (burnt and damaged fish darken and dull). Birds darken when wet and whiten on top with snow.

Not done yet. Boids run on the CPU and are O(n²) per group: fine for hundreds of animals and fully deterministic. For thousands, the next step is a WebGPU compute pass, with positions and velocities in instancedArray storage buffers and a uniform-grid neighbour search. It would give up exact cross-machine determinism. There are no lakes yet, only sea and noise rivers (the World has no lake surface), and no land herds yet (FaunaLayer is the slot).

Full API docs: https://askalice.github.io/threejs-worldgen/docs/. Sandbox: npm run dev, then /fauna.html (species gallery) and /fauna.html?world.

License

Apache-2.0