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

reze-engine

v0.10.0

Published

A lightweight WebGPU engine for real-time 3D MMD/PMX model rendering

Readme

Reze Engine

A minimal-dependency WebGPU engine for real-time MMD/PMX rendering. Only external dependency is Ammo.js for physics.

Install

npm install reze-engine

Features

  • Blinn-Phong shading, alpha blending, rim lighting, outlines, MSAA 4x
  • VMD animation with IK solver and Bullet physics
  • Orbit camera with bone-follow mode
  • GPU picking (double-click/tap)
  • Ground plane with PCF shadow mapping, grid lines, and frosted texture
  • Multi-model support

Quick Start

import { Engine, Vec3 } from "reze-engine"

const engine = new Engine(canvas, {
  ambientColor: new Vec3(0.88, 0.92, 0.99),
  cameraDistance: 31.5, // MMD units (1 unit = 8 cm)
})
await engine.init()

const model = await engine.loadModel("hero", "/models/hero/hero.pmx")
await model.loadAnimation("idle", "/animations/idle.vmd")
model.show("idle")
model.play()

engine.setCameraFollow(model, "センター", new Vec3(0, 3.5, 0))
engine.addGround({ width: 160, height: 160 })
engine.runRenderLoop()

API

Engine

| Method | Description | |--------|-------------| | new Engine(canvas, options?) | Create engine with optional config | | engine.init() | Initialize WebGPU device and context | | engine.loadModel(path) | Load PMX model (auto-named) | | engine.loadModel(name, path) | Load PMX model with name | | engine.getModel(name) | Get model by name | | engine.getModelNames() | List all model names | | engine.removeModel(name) | Remove model | | engine.setMaterialVisible(model, mat, visible) | Show/hide material | | engine.toggleMaterialVisible(model, mat) | Toggle material visibility | | engine.setIKEnabled(enabled) | Enable/disable IK globally | | engine.setPhysicsEnabled(enabled) | Enable/disable physics globally | | engine.setCameraFollow(model, bone?, offset?) | Orbit center tracks a bone | | engine.setCameraTarget(vec3) | Static camera target | | engine.setCameraDistance(d) | Set orbit radius | | engine.setCameraAlpha(a) | Set horizontal orbit angle | | engine.setCameraBeta(b) | Set vertical orbit angle | | engine.addGround(options?) | Add ground plane with shadows | | engine.runRenderLoop(callback?) | Start render loop | | engine.stopRenderLoop() | Stop render loop | | engine.getStats() | Returns { fps, frameTime } | | engine.dispose() | Clean up all resources |

Model

| Method | Description | |--------|-------------| | model.loadAnimation(name, url) | Load VMD animation | | model.loadAnimation(name, clip) | Load/replace animation clip directly | | model.show(name) | Set pose at time 0 (resets bones and morphs first) | | model.play(name?) | Play animation (queued if busy; named play resets bones/morphs first) | | model.play(name, { priority?, loop? }) | Priority-aware play; loop wraps at end (0 default/lowest priority) | | model.pause() | Pause playback | | model.stop() | Stop playback | | model.seek(time) | Seek to time | | model.getAnimationProgress() | { current, duration, percentage, animationName, looping, playing, paused }current/duration are seconds | | model.getAnimationClip(name) | Get loaded clip by name | | model.rotateBones(rotations, ms?) | Tween bone rotations | | model.moveBones(translations, ms?) | Tween bone translations | | model.setMorphWeight(name, weight, ms?) | Tween morph weight | | model.resetAllBones() | Reset to bind pose | | model.resetAllMorphs() | Reset all morph weights | | model.getBoneWorldPosition(name) | World position of bone |

AnimationClip is frame-based: frameCount is the last keyframe frame index, keyframes store frame. Engine playback uses fixed 30 FPS. Looping is controlled via play(name, { loop: true }), not on the clip.

Engine Options

{
  ambientColor: Vec3,
  directionalLightIntensity: number,
  minSpecularIntensity: number,
  rimLightIntensity: number,
  cameraDistance: number,
  cameraTarget: Vec3,
  cameraFov: number,
  onRaycast: (modelName, material, screenX, screenY) => void,
  shadowLightDirection: Vec3,
  physicsOptions: {
    constraintSolverKeywords: string[],
  },
}

shadowLightDirection — direction of the shadow-only light, independent of the visible directional light. Default (0.12, -1, 0.16) casts a near-top-down shadow with a slight offset so extended limbs still project visible shadows.

constraintSolverKeywords — joints whose name contains any keyword use the Bullet 2.75 constraint solver; all others keep the stable Ammo 2.82+ default. See babylon-mmd: Fix Constraint Behavior for details.

Ground Options

engine.addGround({
  width: 100,            // ground plane width
  height: 100,           // ground plane depth
  diffuseColor: Vec3,    // base color (default: 0.8, 0.1, 1.0)
  fadeStart: 5.0,        // distance where edge fade begins
  fadeEnd: 60.0,         // distance where ground fully fades out
  shadowMapSize: 4096,   // shadow map resolution
  shadowStrength: 1.0,   // shadow darkness
  gridSpacing: 5.0,      // world-space distance between grid lines
  gridLineWidth: 0.012,  // thickness of grid lines
  gridLineOpacity: 0.4,  // grid line visibility (0–1)
  gridLineColor: Vec3,   // grid line color (default: 0.8, 0.8, 0.8)
  noiseStrength: 0.08,   // frosted/matte micro-texture intensity
})

Projects Using This Engine

  • MiKaPo — Real-time motion capture for MMD
  • Popo — LLM-generated MMD poses
  • MPL — Motion programming language for MMD
  • Mixamo-MMD — Retarget Mixamo FBX to VMD

Tutorial

How to Render an Anime Character with WebGPU