A lightweight engine built with WebGPU and TypeScript for real-time 3D anime character MMD model rendering.
- Blinn-Phong lighting
- Alpha blending
- Post alpha eye rendering (the see-through eyes)
- Rim lighting
- Outlines
- MSAA 4x anti-aliasing
- Bone and morph API
- VMD animation
- IK solver
- Ammo/Bullet physics
export default function Scene() {
const canvasRef = useRef < HTMLCanvasElement > null
const engineRef = useRef < Engine > null
const initEngine = useCallback(async () => {
if (canvasRef.current) {
try {
const engine = new Engine(canvasRef.current, {})
engineRef.current = engine
await engine.init()
await engine.loadModel("/models/reze/reze.pmx")
engine.runRenderLoop(() => {})
} catch (error) {
console.error(error)
}
}
}, [])
useEffect(() => {
void (async () => {
initEngine()
})()
return () => {
if (engineRef.current) {
engineRef.current.dispose()
}
}
}, [initEngine])
return <canvas ref={canvasRef} className="w-full h-full" />
}Engine options
const DEFAULT_ENGINE_OPTIONS: RequiredEngineOptions = {
ambientColor: new Vec3(0.82, 0.82, 0.82),
directionalLightIntensity: 0.2,
minSpecularIntensity: 0.3,
rimLightIntensity: 0.4,
cameraDistance: 26.6,
cameraTarget: new Vec3(0, 12.5, 0),
cameraFov: Math.PI / 4,
onRaycast: undefined,
}Load and play VMD animation files.
await engine.loadAnimation("/animations/dance.vmd")
engine.playAnimation()
engine.pauseAnimation()
engine.stopAnimation()
engine.seekAnimation(2.5) // seek to 2.5 seconds
const { current, duration, percentage } = engine.getAnimationProgress()Load animation from structured keyframe data directly — for animation editors or programmatic animation creation. The engine handles interpolation and playback natively.
import type { AnimationData } from "reze-engine"
const data: AnimationData = {
boneTracks: {
"首": [
{ frame: 0, rotation: new Quat(0, 0, 0, 1), translation: new Vec3(0, 0, 0), interpolation: new Uint8Array(64) },
{ frame: 30, rotation: neckQuat, translation: new Vec3(0, 0, 0), interpolation: new Uint8Array(64) },
],
},
morphTracks: {
"まばたき": [
{ frame: 0, weight: 0 },
{ frame: 15, weight: 1 },
{ frame: 30, weight: 0 },
],
},
}
engine.loadAnimationData(data)
engine.playAnimation()
const data = engine.getAnimationData() // retrieve current animation dataRotate and move bones with optional tween duration. Translations are VMD-style (relative to bind pose world position).
engine.rotateBones({ "首": neckQuat, "頭": headQuat }, 300)
engine.moveBones({ "センター": centerVec }, 300)
engine.setMorphWeight("まばたき", 1.0, 300)
engine.resetAllBones()
engine.resetAllMorphs()- MiKaPo - Online real-time motion capture for MMD using webcam and MediaPipe
- Popo - Fine-tuned LLM that generates MMD poses from natural language descriptions
- MPL - Semantic motion programming language for scripting MMD animations with intuitive syntax
- Mixamo-MMD - Retarget Mixamo FBX animation to VMD in one click
Learn WebGPU from scratch by building an anime character renderer in incremental steps. The tutorial covers the complete rendering pipeline from a simple triangle to fully textured, skeletal-animated characters.
