Zero-runtime-dependency WebGPU engine for real-time MMD/PMX rendering — renderer, animation, IK, physics, and a multi-effect VFX system, all in TypeScript.
One piece of the Reze MMD family, covering the whole MMD workflow on the web:
| reze-engine | This repo — the WebGPU foundation, anime-character rendering and physics |
| reze-design | Scene design, rendering and sharing |
| reze-studio | Animation editing on a professional timeline and curve editor |
| MiKaPo | Real-time motion capture in the browser, exporting straight to VMD |
| reze-rig | Retarget FBX animations to MMD VMD format, Mixamo and Unity tested |
npm install reze-engineMMD fidelity
- PMX models, VMD motion with MMD's own bezier packing, IK with per-chain enable, append-inherit bones and fixed-axis twist bones, VMD export
- Vertex / group / bone / material morphs (multiply and add), vertex morphs on a GPU compute path
- MMD draw disciplines reproduced: author-order transparency with depth write, per-mesh interleaved outline hulls, the eyes-through-bangs stencil pass, sphere maps as graph nodes
- In-house sequential-impulse physics for PMX rigs — rigid bodies, joints, deterministic wind, a world floor
- Stages as environments, not characters: a stage PMX takes the same materials, graphs and style groups a character does, and keeps the bone and material morphs its author rigged for doors, lifts and colour switches — while skipping physics, IK and idle pose work, and owning the floor so the built-in ground steps aside
Rendering
- Shader-graph materials: every look is a Blender-style node graph compiled to WGSL; style groups bind any materials to any graph; ungrouped materials render a Principled BSDF default
- HDR pipeline end to end — bloom, 4× MSAA, three view transforms (Filmic, Standard, AgX from Blender's own LUT), bladed-bokeh depth of field
- Colour grading over the tonemapped image: ASC CDL slope / offset / power with contrast and saturation, uniforms-only so dragging a slider rebuilds no pipeline — and the background layer stays ungraded, so a grade shapes the scene without staining the sky behind it
- Two concentric shadow cascades: crisp contact shadows on the cast, coverage for a full stage
- Floor mirror: a planar reflection pass reusing the scene pipelines, with depth-proportional blur and the reflection composited as its own ground layer
- HDRI worlds (
.hdr): the sky renders through the same view transform as the scene and lights the cast via spherical-harmonic irradiance — the sun keeps the toon ramp - Positional lights, placed in the scene or emitted by effect shaders — stage rigs, firework bursts, a hand ribbon lighting the dancer as it passes
Effects
- N simultaneous scene effects, each one WGSL file declaring its mounts: fullscreen background/foreground, GPU particles, bone-trail ribbons, a persistent simulation grid, and lights
- Effects read the scene through data interfaces — the cast (bones, velocities, trail history), the audio analysis, MIDI notes,
.lrclyrics with their words rasterised for the shader to draw, and per-pixel object/material ids - Particles and ribbons are scene geometry: depth-tested, bloomed, and reflected in the mirror
- Install-time compile diagnostics per effect; a broken effect fails alone
Pipeline
- GPU frustum culling writing indirect draw arguments, replayed through render bundles — the CPU re-encodes only when scene structure changes
- Deterministic by construction: everything runs on the scene clock, so offline export (
renderFrameat any resolution) reproduces the live scene exactly - Camera: orbit, bone-follow, or a driven MMD camera VMD; GPU picking, gizmos, morph/material editing surfaces
- Every emitted shader is compiled on a real GPU device by the repo's validation tool (
engine/tools/validate-wgsl.mjs) before release
import { Engine } from "reze-engine"
const engine = new Engine(canvas)
await engine.init()
const model = await engine.loadModel("reze", "/models/reze/reze.pmx")
await engine.autoStyleGroups("reze")
await model.loadVmd("dance", "/animations/dance.vmd")
model.show("dance")
model.play()
engine.runRenderLoop()autoStyleGroups reads the model's own material names and gives each group a
shader graph, so hair, eyes and skin come out looking like MMD with no shading
code of your own.
One frame, top to bottom. The CPU describes the scene once and the GPU runs it: culling and effect simulation in compute, shadows and the floor mirror feeding a scene pass that draws MMD the way MMD artists expect — author order, outlines, the eye/hair stencil — then bloom, film tone mapping, and depth of field finish the image.
MIT
