Vanilla Vite + TypeScript + Three.js + Rapier starter for Web Hammer runtime.
bun install
bun run dev
bun run build- plain Vite app
- modular game runtime shell
- scene registry in
src/scenes - animation bundle registry in
src/animations - scene-local runtime manifests and assets
- animation-local graph/artifact manifests and assets
- starter capsule controller driven by runtime camera/player settings
- static collision extraction from runtime physics definitions
- scene-level
systems,mount, andgotoScene(...)hooks - Rapier runtime initialization
- gameplay-runtime bootstrap
- Run the app and move around in the included starter scene.
- Replace
src/scenes/main/scene.runtime.jsonwith your exported runtime scene when ready. - If your scene has assets, place them under
src/scenes/main/assets/. - Export animation bundles from the animation editor and unpack them into
src/animations/<animation-name>/. - Inspect
src/scenes/arena/for a second scene and thegotoScene(...)transition pattern. - Add custom scene logic in
src/scenes/main/index.tsand custom animation wiring in your own gameplay code.
@ggez/three-runtime@ggez/runtime-format@ggez/gameplay-runtime@ggez/runtime-physics-rapier@ggez/anim-runtime@ggez/anim-three@ggez/anim-exporter
The scaffold is intentionally vanilla, but it is structured as a real game app rather than a preview playground.
Animation bundles are intentionally low-level. The starter exposes discovery and loading helpers, but your game code still owns character loading, controller logic, parameter updates, and when to instantiate an animator.
Expected animation export layout:
src/animations/player-locomotion/
animation.bundle.json
graph.animation.json
assets/
hero.glb
jump-start.glb
run-forward.glb
Typical usage:
import { createAnimatorInstance } from "@ggez/anim-runtime";
import { animations } from "./animations";
const locomotionBundle = await animations["player-locomotion"].source.load();
const character = await locomotionBundle.loadCharacterAsset();
if (!character) {
throw new Error("Animation bundle is missing its exported character asset.");
}
const clips = await locomotionBundle.loadGraphClipAssets(character.skeleton);
const animator = createAnimatorInstance({
rig: character.rig,
graph: locomotionBundle.artifact.graph,
clips
});
animator.setFloat("speed", 1);
animator.setBool("grounded", true);