# Migrating a three.js scene to Net Forge

> Net Forge renders with three.js, so a three.js game moves over by splitting it in two: rules go into a declarative src/game.ts that runs on the server and the client, and drawing stays in the template's three.js client.

Net Forge, the open-source multiplayer browser game engine built for AI coding agents, is published on npm under `@netforge` with source at https://github.com/netnetdev/net-forge.

Source: https://forge.netnet.capital/docs/migrate/from-threejs-scene  
Last updated: 2026-10-24. Checked against @netforge/engine 0.2.0.

Net Forge renders with three.js (`three` 0.186.1, `WebGPURenderer` with a WebGL2 fallback), so moving a three.js game over is mostly a split: the rules go into `src/game.ts`, which the room host and the browser both run, and the drawing stays in a three.js client. Start from the template nearest your game and port one thing at a time.

```sh
npm create netforge@latest my-game -- --template survivor --yes
cd my-game
npm run play
```

## What maps to what

| In your three.js game | In Net Forge |
|---|---|
| `requestAnimationFrame` loop that moves things | The simulation's fixed tick (30 or 60 Hz, set by the template); the client renders between ticks |
| `Mesh` per enemy | A prefab with a library model id, drawn as an instanced crowd |
| Your collision checks | Rapier bodies, triggers and raycasts in `@netforge/engine-sim` |
| `GLTFLoader` with file paths | Library asset ids such as `"style.lowpoly.bat"` (glTF, meshopt and KTX2 under the hood) |
| `EffectComposer` passes | `game({ look })`: preset, bloom, fog, vignette, tint |
| Screen shake and hit effects by hand | `prefab({ feel })` and `weapon({ feel })` |

## 1. Pick a template and play it

The template gives you the renderer, camera, input, netcode and HUD. Play it once so you know what you are changing.

```sh
npm create netforge@latest my-game -- --template survivor --yes
```

## 2. Move one enemy

```ts title=src/game.ts
import { prefab } from "@netforge/engine";

prefab("wisp", {
  model: "style.lowpoly.bat",
  health: 8,
  speed: 5,
  radius: 0.25,
  damage: 4,
  ai: "chase",
  feel: { particles: "magic", color: "#7ad7ff", shake: 0.1 },
});
```

Add it to the director's `pool` in the same file so it spawns. A model id the library does not have fails the build with one line that says so.

## 3. Bring your own drawing only where you need it

Scene code lives in the template's browser client, not in `src/game.ts`. If you need custom drawing, fork the template package and work in its `client/` folder with `@netforge/engine/runtime` (`createRenderStack`, `FeelKit`, `InstancedCrowd`, `CameraRig`). If you want the simulation under a scene you already have, `@netforge/engine-sim` has no rendering dependency; see [Net Forge and three.js](https://forge.netnet.capital/docs/compare/threejs.md). The runnable example [`packages/engine/examples/threejs-scene`](https://github.com/netnetdev/net-forge/tree/main/packages/engine/examples/threejs-scene) is exactly that: a plain three.js scene whose keys become input commands for an authoritative room stepping `@netforge/engine-sim`. Run it from a clone of the public repository after `pnpm install` and `pnpm build`:

```sh
pnpm --filter @netforge/engine example:threejs
```

[How to add authoritative multiplayer to a three.js game](https://forge.netnet.capital/docs/guides/threejs-authoritative-multiplayer.md#run-the-example) walks through it.

## 4. Test it

```sh
npm test
```

## FAQ

### Do I have to throw away my three.js code?

Not the knowledge, and not shaders or effects you move into a forked template client. Game rules move into `src/game.ts`, because that file is what runs on the server.

### Can src/game.ts import three?

No. It may import only `@netforge/engine`, which keeps the game something the room can run and replay without a renderer.

### Can I use my own models?

Games reference models by library id. The library has CC0 models in six art styles; see [Assets and art styles](https://forge.netnet.capital/docs/concepts/assets-art-styles.md).

### Does my game get multiplayer for free?

Yes, once its rules are in `src/game.ts`: every template is already an authoritative multiplayer game. Open the play link in a second tab to join the same room.
