Beginner BrowserNodeBun @vulfram/engine

Getting Started

The first runnable flow in Vulfram: create a window, camera, light, and one model, then start the frame loop.

What You Will Explore

  • Transport selection per runtime (Browser, Node, Bun).
  • Window and world creation with a minimal scene graph.
  • Main loop with tick scheduling and deterministic updates.

Prerequisites

  • Node.js or Bun installed locally.
  • A basic TypeScript project scaffold.
  • For browser mode, an HTML canvas mounted in the page.

Related Docs

Transport

You are viewing: Browser (WASM) · Switch

1. Install packages

bash
npm i @vulfram/engine @vulfram/transport-browser

2. Prepare the canvas

In the browser, Vulfram needs a canvas. Use the id vulfram-canvas.

html
<canvas id="vulfram-canvas" class="w-full h-full"></canvas>

3. Boot and first frame

The snippet below creates the world, window, camera, light, and a cube. Then it starts the main loop.

ts
import {
  initEngine,
  Mount,
  World3D,
  createWindow,
  tick,
} from '@vulfram/engine';
import { initWasmTransport, transportWasm } from '@vulfram/transport-browser';


async function boot() {
  await initWasmTransport();
  initEngine({ transport: transportWasm });

  const worldId = World3D.create3DWorld();
  const { windowId } = createWindow({
    title: 'Hello Vulfram',
    size: [1024, 640],
    position: [0, 0],
    canvasId: 'vulfram-canvas',
  });
Mount.mountWorldToWindow(worldId, windowId);

  const camera = World3D.create3DEntity(worldId);
  World3D.update3DTransform(worldId, camera, {
    position: [0, 0, 10],
    rotation: [0, 0, 0, 1],
    scale: [1, 1, 1],
  });
  World3D.create3DCamera(worldId, camera, { kind: 'perspective', near: 0.1, far: 100.0 });

  const light = World3D.create3DEntity(worldId);
  World3D.update3DTransform(worldId, light, {
    position: [2, 4, 6],
    rotation: [0, 0, 0, 1],
    scale: [1, 1, 1],
  });
  World3D.create3DLight(worldId, light, { kind: 'point', intensity: 14, range: 25 });

  const geometryId = World3D.create3DGeometry(worldId, { type: 'primitive', shape: 'cube' });
  const materialId = World3D.create3DMaterial(worldId, {
    kind: 'standard',
    options: {
      type: 'standard',
      content: {
        baseColor: [1, 1, 1, 1],
        surfaceType: 'opaque',
        flags: 0,
      },
    },
  });

  const cube = World3D.create3DEntity(worldId);
  World3D.create3DModel(worldId, cube, { geometryId, materialId, castShadow: true, receiveShadow: true });

  let last = performance.now();
  function frame(now: number) {
    const delta = now - last;
    last = now;
    tick(now, delta);
    requestAnimationFrame(frame);
  }
  requestAnimationFrame(frame);
}

boot().catch(console.error);
Live demo canvas