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

anny-js

v0.0.3

Published

Live 3D body animation in the browser — FK + LBS for the Anny body model (Apache 2.0). Drives 163 bones from MediaPipe Pose at < 2 ms.

Readme

anny-js

Live 3D body animation entirely in the browser — powered by Anny (Naver, Apache 2.0).

No server. No Python. No native modules. Just a TypeScript library and a 1.4 MB binary.

FK + LBS on a 14 718-vertex / 163-bone parametric body in < 2 ms.
WebGL 4-view rendering at 30 fps on integrated GPU.

▶ Animation demo · 📷 Live pose demo


What is Anny?

Anny is Naver's open-source parametric 3D human body model — Apache 2.0, commercial use allowed. Think SMPL/SMPL-X but with a clean permissive license. Anny has:

  • 14 718 vertices, 163 bones, triangulated mesh
  • 11 semantic shape parameters (gender, height, weight, muscle, proportions…)
  • 256 local blendshapes for detailed shape control
  • Full LBS skinning with 8 influence bones per vertex
  • A Blender-compatible rig (bone rolls, parent hierarchy, A-pose)

anny-js exposes Anny's forward kinematics and linear blend skinning as a clean browser API, plus:

  • A MediaPipe Pose driver (33 landmarks → 163 bone deltas, parent-corrected)
  • A WebGL renderer (back-face culled, depth-tested, 4-camera multi-view)
  • An animation API to drive any bones with rotation matrices

Installation

npm install anny-js

CDN (no bundler):

<script type="module">
  import { loadAnnyModel, lbs, forwardKinematics }
    from 'https://cdn.jsdelivr.net/npm/anny-js/dist/index.js';
</script>

Quick start — custom animation

import {
  loadAnnyModel, buildBoneIndex,
  allocBoneTransforms, identityDeltas, setDeltas,
  lbs, allocVertexBuffer, rodriguesToMat3,
} from 'anny-js';

// 1. Load model once (~20 ms, 1.4 MB)
const model     = await loadAnnyModel('/anny_model.json', '/anny_model.bin');
const boneIndex = buildBoneIndex(model);

// Allocate reusable frame buffers
const boneXforms = allocBoneTransforms(model.boneCount);  // (163×16) Float32Array
const vertBuf    = allocVertexBuffer(model);              // (14718×3) Float32Array

// 2. Build a pose — both arms raised 90°
const deltas = identityDeltas(model.boneCount);
const up = rodriguesToMat3(new Float32Array([0, 0, 1]), Math.PI / 2);
setDeltas(deltas, model, [
  { bone: 'upperarm01.L', rot: up },
  { bone: 'upperarm01.R', rot: up },
]);

// 3. FK → LBS → raw vertex positions every frame
forwardKinematics(model, deltas, boneXforms);
const { vertices, faces } = lbs(model, boneXforms, vertBuf);
// vertices: Float32Array (V×3, Anny Z-up metres)
// faces:    Int32Array   (F×3)

Quick start — drive from MediaPipe Pose

import {
  loadAnnyModel, buildBoneIndex,
  allocBoneTransforms, lbs, allocVertexBuffer,
  landmarksToPoseDeltas, forwardKinematics,
} from 'anny-js';

const model     = await loadAnnyModel('/anny_model.json', '/anny_model.bin');
const boneIndex = buildBoneIndex(model);
const boneXf    = allocBoneTransforms(model.boneCount);
const vertBuf   = allocVertexBuffer(model);

// In your MediaPipe Pose detection loop:
function onLandmarks(landmarks) {         // 33 × {x,y,z,visibility}
  const deltas = landmarksToPoseDeltas(landmarks, model, boneIndex);
  forwardKinematics(model, deltas, boneXf);
  const { vertices, faces } = lbs(model, boneXf, vertBuf);
  // → feed into WebGL / Three.js / your renderer
}

See demo/live.html for the full 4-view WebGL demo with recording.


Demos

| | Demo | Description | |--|------|-------------| | 🎬 | demo/anim.html | No camera. Pose cycle (A-pose → T-pose → guard → wave…), 4 simultaneous camera views (front, back, 3/4, above), smooth blending between poses. Pure performance showcase. | | 📷 | demo/live.html | Webcam required. MediaPipe Pose drives all 163 bones live. 4-view WebGL, skeleton overlay, built-in WebM recorder (⏺ REC button). |

Run locally:

git clone https://github.com/datar-psa/anny-js
cd anny-js && bun install
bun run demo    # http://localhost:3000

API reference

Loading

loadAnnyModel(manifestUrl: string, binUrl: string): Promise<AnnyModel>

Fetches the binary model. ~20 ms cold, instant from browser cache. Call once.


Bone access

buildBoneIndex(model): Map<string, number>   // build once, reuse

Key bone names: spine01, neck01, head, upperarm01.L/R, lowerarm01.L/R, wrist.L/R, upperleg01.L/R, lowerleg01.L/R.


Posing

// Array of per-bone local delta rotations (3×3 Float32Array or null = identity)
identityDeltas(boneCount: number): PoseDeltas

// Single bone
setDelta(deltas, model, 'upperarm01.L', rot3x3Float32)

// Multiple at once
setDeltas(deltas, model, [{ bone: 'spine01', rot }, ...])

// From MediaPipe Pose landmarks (parent-corrected, XZ-projected for depth stability)
landmarksToPoseDeltas(
  landmarks: Landmark[],   // 33 × {x,y,z?,visibility?}
  model: AnnyModel,
  boneIndex: Map<string, number>,
  mirrorX?: boolean        // default false (standard front-facing webcam)
): PoseDeltas

Kinematics + skinning

// Forward kinematics — updates boneXforms in-place
forwardKinematics(model, deltas, boneXforms: Float32Array): void

// Linear blend skinning — returns posed vertices
lbs(model, boneXforms, outVertices?: Float32Array): SkinnedMesh
// SkinnedMesh: { vertices: Float32Array (V×3), faces: Int32Array (F×3) }

Both are zero-allocation when called with pre-allocated output buffers (see allocBoneTransforms / allocVertexBuffer). Call every frame without GC pressure.


Canvas 2D renderer

renderAnny(ctx: CanvasRenderingContext2D, mesh: SkinnedMesh, opts: RenderOptions): void

type RenderOptions = {
  cx: number;         // canvas X of body centre
  footY: number;      // canvas Y of feet
  scale: number;      // pixels per metre (body height ≈ 1.7 m)
  color: string;      // fill colour
  outlineColor?: string;
  flipX?: boolean;    // mirror for self-view (default false)
  viewRotY?: number;  // horizontal orbit angle (radians)
  viewRotX?: number;  // vertical tilt (negative = bird's-eye)
}

For production use the WebGL path in the demos (4 draw calls for 4 views).


Rotation helpers

rodriguesToMat3(axis: Float32Array, angle: number): Float32Array  // axis-angle → 3×3
rotFromTo(from: Float32Array, to: Float32Array):    Float32Array  // shortest arc rotation

Performance

Measured on Intel Iris Xe (integrated, 12th-gen laptop):

| Operation | Time | |-----------|------| | Model load | ~20 ms (cold), instant (cached) | | FK (163 bones) | ~0.4 ms | | LBS (14 718 verts, 8 weights/vert) | ~1.2 ms | | WebGL 4-view render | ~4 ms | | End-to-end (pose → render) | < 6 ms | | Frame rate | 30 fps (GPU-limited by MediaPipe) |


Regenerating the model binary

The included binary is the average Anny body (neutral parameters, A-pose). To rebake:

# Requires anny Python package (from vton-exp venv)
source /path/to/venv/bin/activate
python tools/extract_anny.py --out assets/ \
  --params '{"gender":0.5,"height":0.55,"weight":0.4}'

License

anny-js: Apache 2.0
Anny body model (Naver): Apache 2.0
assets/anny_model.bin is derived from Anny and inherits Apache 2.0.