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

three-zoo

v0.13.0

Published

Some reusable bits for building things with Three.js

Readme

Installation

npm install three-zoo

Contents

  • IK - TwoBoneIK, AimChainIK
  • Instanced Mesh Pool - InstancedMeshPool, InstancedMeshInstance, InstancedMeshGroup
  • Lighting - Sun, SkyLight
  • Material Converters - Standard to Basic / Lambert / Phong / Toon / Physical, Basic to Physical
  • Miscellaneous - DualFovCamera, SceneTraversal, SceneSorter, SkinnedMeshBaker

IK

TwoBoneIK

Analytical two-bone IK solver. Chain: root -> middle -> end. Pole controls bend direction. Writes local quaternions to root and middle.

const twoBoneIK = new TwoBoneIK(upperArm, foreArm, hand, poleObject, targetObject);

// call after AnimationMixer.update() each frame
twoBoneIK.solve();

// tune pole twist per bone
twoBoneIK.rootPoleAxis.set(0, 1, 0);
twoBoneIK.middlePoleTwist = false;

AimChainIK

Distributes aim rotation across a bone chain according to per-bone weights.

const aimChainIK = new AimChainIK([spine1, spine2, spine3, head]);

aimChainIK.curve = [0.2, 0.5, 0.8, 1.0]; // root gets least, tip gets most
aimChainIK.weight = 0.8;                 // global blend

// sample directions before calling - mutates bone quaternions
aimChainIK.solve(currentForward, targetDirection);

Instanced Mesh Pool

Manages InstancedMesh instances keyed by geometry+material. Grows capacity automatically.

const pool = new InstancedMeshPool(scene, { initialCapacity: 32, capacityStep: 16 });

// allocate / update / release individual instances
const instance = new InstancedMeshInstance(pool, geometry, material);
instance.setPosition3f(1, 0, 0).setScale3f(2, 2, 2).flushTransform();
instance.destroy();

// group multiple instances under a shared Object3D transform
const group = new InstancedMeshGroup([instanceA, instanceB]);
scene.add(group);
group.position.set(10, 0, 0);
group.flushTransform(); // propagates group world matrix to all instances
group.destroy();

Lighting

Sun

DirectionalLight with spherical positioning and shadow auto-configuration.

const sun = new Sun();
sun.elevation = Math.PI / 4;
sun.azimuth = Math.PI / 2;
sun.distance = 100;

sun.configureShadowsForBoundingBox(sceneBounds);
sun.setDirectionFromHDRTexture(hdrTexture, 50);

SkyLight

HemisphereLight that extracts sky and ground colors from an HDR environment map.

const skyLight = new SkyLight();
skyLight.setColorsFromHDRTexture(hdrTexture, {
  skySampleCount: 100,
  groundSampleCount: 100,
});

Material Converters

All converters expose a single static convert(material, options?). Common options:

| Option | Default | Description | |------------------|---------|--------------------------------------| | preserveName | true | Copy .name to the new material | | copyUserData | true | Copy .userData | | disposeOriginal| false | Dispose source material after conversion |

// Standard -> unlit
const basicMaterial = StandardToBasicConverter.convert(standardMaterial, { brightnessFactor: 1.3, combineEmissive: true });

// Standard -> diffuse-only lit
const lambertMaterial  = StandardToLambertConverter.convert(standardMaterial);
const phongMaterial    = StandardToPhongConverter.convert(standardMaterial);
const toonMaterial     = StandardToToonConverter.convert(standardMaterial);

// Standard <-> Physical
const physicalMaterial  = StandardToPhysicalConverter.convert(standardMaterial);
const standardMaterial2 = BasicToPhysicalConverter.convert(basicMaterial);

Miscellaneous

DualFovCamera

PerspectiveCamera with independent horizontal and vertical FOV.

const camera = new DualFovCamera(90, 60);
camera.horizontalFov = 100;
camera.verticalFov = 70;

camera.fitVerticalFovToPoints(vertices);
camera.fitVerticalFovToBox(boundingBox);
camera.fitVerticalFovToMesh(skinnedMesh);
camera.lookAtMeshCenterOfMass(skinnedMesh);

SceneTraversal

Static helpers for depth-first scene graph traversal.

// find by name
const playerObject  = SceneTraversal.getObjectByName(scene, 'Player');
const metalMaterial = SceneTraversal.getMaterialByName(scene, 'Metal');

// filter by regex or predicate
const enemies         = SceneTraversal.filterObjects(scene, /^enemy_/);
const glassMaterials  = SceneTraversal.filterMaterials(scene, /glass/i);

// enumerate with callback
SceneTraversal.enumerateMaterials(scene, (material) => {
  material.needsUpdate = true;
});

// find meshes that use specific materials
const glassMeshes = SceneTraversal.findMaterialUsers(scene, glassMaterials);

SceneSorter

Assigns sequential renderOrder values sorted by distance to a point. Useful for transparent meshes.

// front-to-back
SceneSorter.sortByDistanceToPoint(object, cameraPosition, 0);

// back-to-front (transparent objects)
SceneSorter.sortByDistanceToPoint(object, cameraPosition, 0, true);

SkinnedMeshBaker

Bakes a SkinnedMesh to static geometry.

// current pose
const staticMesh = SkinnedMeshBaker.bakePose(skinnedMesh);

// specific animation frame
const frameMesh = SkinnedMeshBaker.bakeAnimationFrame(armature, skinnedMesh, 1.5, animationClip);

Requirements

  • three >=0.157.0 <0.180.0 (peer dependency)

License

MIT © jango