Resident ready Static companion
kari_mikumao Lab

Systems

WMMD architecture: a hostable MMD runtime

Why the engine is split into layered Rust crates with hard dependency invariants, so the same code can drive an editor, an AR host, or an offline renderer.

  • wmmd
  • architecture
  • rust
  • mmd

WMMD is a hostable MikuMikuDance runtime and rendering backend written in Rust. “Hostable” is the whole design constraint: the same codebase drives a desktop editor today, and is meant to be embedded in VJ tools, AR and VR runtimes, game engines, mocap pipelines, and offline renderers. That only works if no layer secretly assumes it owns the window, the GPU, or the clock.

The layering

The workspace is a set of crates arranged so that dependencies point one way:

  • wmmd-clock — the transport clock, with zero external dependencies at all.
  • wmmd-runtime — the CPU-only simulation engine: scene data, skeletons, physics backends, the IK solver, and the frame update loop.
  • wmmd-asset — PMX/PMD parsing, VMD animation loading, texture analysis, and path resolution; it delegates material work to wmmd-material.
  • wmmd-render — the backend-agnostic render interface. It depends on glam and serde and nothing else.
  • wmmd-render-wgpu — the wgpu implementation of that interface, owning every GPU pass.
  • wmmd-host-winit — a desktop surface, and only a surface.
  • wmmd-session, wmmd-ui-egui, wmmd-audio, wmmd-export, wmmd-editor, wmmd-desktop, wmmd-tools — host-neutral session state, panels, audio, offline export, and the applications on top.

The invariants are the architecture

The dependency graph is enforced by a written list of invariants, and violating one is treated as a bug rather than a style question. The ones that shape everything else:

  • wmmd-render has zero GPU dependencies and zero runtime dependencies. GPU layout types like CameraUniform live in the wgpu crate; the abstract interface never references runtime commands.
  • wmmd-runtime never loads files. The host calls the asset crate and pushes an AddModel command carrying an already-parsed asset. The engine has no opinion about your filesystem.
  • wmmd-render-wgpu never owns the swapchain. The host acquires the frame, builds a render target, calls render(), and presents. That single rule is what lets an AR or headless host exist at all.
  • wmmd-render-wgpu is egui-free, and wmmd-host-winit is surface-only — the GPU context lives in the render crate so a host without winit can still create a device.
  • RenderRequest is the single interface point. Callers assemble camera, shadow center, lighting, debug flags, and frame, then hand it over.
  • wmmd-clock and wmmd-audio are standalone. Neither knows anything about scenes or rendering; the host wires them to the runtime.

Why this discipline pays

Every one of those rules is a refusal to take a shortcut that would have been easier in a desktop-only engine. The payoff is that adding a new surface — a Vision Pro host, a VJ plugin, an export job — is a matter of driving the existing interfaces rather than forking the renderer. The engine is also model-agnostic by rule: fixes are made at the system level and never branch on a particular MMD model, so a bug reproduced with one file is fixed for the whole space of valid PMX and VMD inputs.