Skip to content

moureau-dev/murow

Repository files navigation

Murow

Monorepo for the murow game engine — a lightweight TypeScript framework for server-authoritative multiplayer games with WebGPU rendering.

Packages

  • murow — Core game engine (ECS, networking, protocol, game loop)
  • murow/webgpu — WebGPU 2D/3D renderer (bundled with murow)
  • murow/netcode — Opinionated multiplayer layer: snapshot sync, prediction with rollback, interest management (bundled with murow)

Installation

npm install murow

The WebGPU renderer and netcode layer are included by default:

import { GameLoop, PrefabBucket, World, defineComponent } from 'murow';
import { WebGPU2DRenderer, WebGPU3DRenderer, d } from 'murow/webgpu';
import { GameServer, GameClient, defineIntents } from 'murow/netcode';

Quick Examples

3D glTF Models with Animation
import { GameLoop, PrefabBucket } from 'murow';
import { WebGPU3DRenderer } from 'murow/webgpu';

// Declare every spawnable thing up-front. Typed ids, parallel load.
const prefabs = new PrefabBucket('3d')
  .add({
    type: 'gltf',
    id: 'hero',
    src: '/character.glb',
    animations: ['Idle', 'Run'],
    metadata: { scale: 0.01 },
  });

await prefabs.load();

// Renderer self-sizes from the bucket — no magic numbers.
const renderer = new WebGPU3DRenderer(canvas, { prefabs, maxInstances: 100 });
await renderer.init();

const hero = prefabs.get('hero');           // typed as GltfPrefab
const instance = renderer.addInstance({
  model: hero,
  position: [0, 0, 0],
  scale: hero.metadata.scale,
});

instance.play?.(hero.animations.Idle, { loop: true });   // typed clip name

renderer.camera.setPosition(3, 1, 3);
renderer.camera.setTarget(0, 0, 0);

const loop = new GameLoop({ tickRate: 20, type: 'client' });
loop.events.on('render', ({ alpha }) => renderer.render(alpha));
loop.start();
GPU Compute + Zero-Copy Rendering
import { WebGPU2DRenderer, d, std } from 'murow/webgpu';

const renderer = new WebGPU2DRenderer(canvas);
await renderer.init();

const Particle = d.struct({
  posX: d.f32, posY: d.f32,
  velX: d.f32, velY: d.f32,
  life: d.f32
});

// Physics runs on GPU
const compute = renderer
  .createCompute('physics', { workgroupSize: 256 })
  .buffers({
    particles: { storage: d.arrayOf(Particle, 10000), readwrite: true },
    config: { uniform: d.struct({ deltaTime: d.f32, gravity: d.f32 }) }
  })
  .shader(({ particles, config }, { globalId }) => {
    const p = particles[globalId.x];
    p.velY = p.velY + config.gravity * config.deltaTime;
    p.posY = p.posY + p.velY * config.deltaTime;
  })
  .build();

// Render directly from compute buffer (zero-copy)
const render = renderer
  .createGeometry('particles', { maxInstances: 10000, geometry: 'quad' })
  .instanceLayout({ dynamic: { posX: d.f32, posY: d.f32, velX: d.f32, velY: d.f32, life: d.f32 } })
  .fromCompute(compute, 'particles')
  .build();

compute.dispatch(10000);
render.render(); // GPU → GPU, no CPU overhead

Full example: benchmarks/renderer/programs/gpu-particles.ts

Documentation

Development

# Install dependencies
bun install

# Build all packages
bun run build

# Run tests
bun run test

# Publish (runs tests + builds)
bun run pub

License

MIT

About

Overpowered modular, high-performance, deterministic multiplayer-first TypeScript engine with data-oriented architecture and GPU-native rendering.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages