Build your first web game.

This guide walks you through installing the CLI, scaffolding a project, writing game logic with the ECS architecture, and shipping to production - all in one place.

01

Prerequisites

NanoForge requires Node.js 25+ and a package manager. We recommend pnpm, but npm, yarn, and bun all work.

Node.js

≥ 25

LTS recommended

Package manager

pnpm / npm / yarn / bun

your choice

TypeScript

optional

highly recommended

Install the NanoForge CLI globally:

terminal
pnpm add -g @nanoforge-dev/cli
nf --version
02

Create a project with editor support

Pass --editor to nf new to scaffold a project that includes the editor entry points and save file at .nanoforge/.

terminal
nf new --editor

The --editor flag adds editor-specific dependencies and generates the .nanoforge/editor/ entry points alongside your regular client/ source.

03

Start the editor

Run nf editor from inside your project directory. The editor is a web app that opens at http://localhost:4000.

terminal
cd my-game
nf editor .

Load your project

The editor opens on the project loader page. You have two options:

Create new project

Opens a form asking for a project name and local path. The editor initialises a fresh save file.

Open project

Load a project already present on disk. The editor reads the save file and regenerates the editor entry point.

Recent projects are cached in the browser so you can reopen them with a single click.

04

Create and edit entities

Inside the workspace, use the scene hierarchy to spawn entities and the component inspector to attach data.

  1. 1

    In the hierarchy panel, click + New entity and choose a name. A blank entity appears.

  2. 2

    Select the entity. In the inspector on the right, click Add component and pick Position. Set x: 400, y: 300.

  3. 3

    Add a second component: Velocity. Set vx: 120, vy: 0.

  4. 4

    The editor writes automaticaly modifications in .nanoforge/client.save.json.

.nanoforge/client.save.json
// .nanoforge/client.save.json - written by the editor on File › Save
{
  "entities": [
    {
      "id": "entity_42",
      "components": [
        { "type": "Position", "x": 400, "y": 300 },
        { "type": "Velocity", "vx": 120, "vy": 0 }
      ]
    }
  ]
}
05

Generate & run

Then let's build and start the game. nf dev generate the entry point, builds and serves the client - the game reflects your latest editor changes:

terminal
nf dev --generate --editor

Run editor

nf editor . - the editor UI

Run project in dev mode

nf dev --generate --editor - generate, build and serves the game

06

Deploy with project manager

When you're ready to share your game, push it to GitHub and connect it to the Project Manager. It handles builds, versioning, and hosting so your players always get the latest version.

1

Push to GitHub

Commit your project and push it to a GitHub repository. The Project Manager reads directly from your repo.

2

Create a project

In the Project Manager, create a new project and link it to your GitHub repository.

3

Build

Trigger a build from the Project Manager dashboard. It pulls your latest commit, installs dependencies, and compiles the game.

4

Deploy

Once the build succeeds, deploy with one click. Your game is live at a shareable URL — no install required.

NanoForge games are served as a URL — no client install, no plugins. Your players open a link and the game runs.

01

Prerequisites

NanoForge requires Node.js 25+ and a package manager. We recommend pnpm, but npm, yarn, and bun all work.

Node.js

≥ 25

LTS recommended

Package manager

pnpm / npm / yarn / bun

your choice

TypeScript

optional

highly recommended

Install the NanoForge CLI globally:

terminal
pnpm add -g @nanoforge-dev/cli
nf --version
02

Create a project

Run nf new to scaffold a new project. The interactive wizard will ask you a few questions about your setup.

terminal
nf new

You can also pass flags to skip the wizard:

terminal
nf new --name my-game --language ts --server --no-docker
03

Project structure

nf new generates the following layout. All your game logic lives in client/ (browser) and optionally server/ (for multiplayer).

project layout
my-game/
├── client/                  # browser-side entry point
│   └── main.ts
├── server/                  # node.js server (multiplayer)
│   └── main.ts
├── nanoforge.config.json    # build & runtime config
├── package.json
└── tsconfig.json

The generated client/main.ts exports a main() function that NanoForge calls to boot your game:

client/main.ts
import { type IRunOptions } from '@nanoforge-dev/common';
import { NanoforgeFactory } from '@nanoforge-dev/core';

export async function main(options: IRunOptions) {
  const app = NanoforgeFactory.createClient();

  // register libraries, then init and run
  await app.init(options);
  await app.run();
}
04

Core concepts

NanoForge uses an Entity-Component-System (ECS) architecture. Everything in your game — players, projectiles, tiles — is an entity made of components, processed by systems.

E

Entity

A unique ID in the world. Has no data of its own — it is the sum of its components.

player, bullet, tile

C

Component

Plain data attached to an entity. A Position, a Velocity, a Health value.

Position, Velocity, Health

S

System

A function that runs every tick, queries entities with specific components, and transforms them.

moveSystem, drawSystem

Systems never know about each other. They only query the components they care about. This makes it easy to add, remove, or replace behaviour without touching unrelated code.

05

First game logic

Let's build a moving square. First, define two components to describe an entity's position and velocity:

client/components.ts
export class Position {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

export class Velocity {
  constructor(
    public vx: number = 0,
    public vy: number = 0,
  ) {}
}

Then write a system that reads those components and moves entities each tick. The getZipper call returns only entities that have all the listed components:

client/systems/move.system.ts
import type { Registry, Context } from '@nanoforge-dev/ecs-client';
import { Position, Velocity } from '../components';

export function moveSystem(registry: Registry, ctx: Context) {
  const entities = registry.getZipper([Position, Velocity]);

  for (const entity of entities) {
    entity.Position.x += entity.Velocity.vx * ctx.deltaTime;
    entity.Position.y += entity.Velocity.vy * ctx.deltaTime;
  }
}

Register the ECS library, then spawn an entity and attach components in your main() function. The registry is the entry point for all entity and system management:

client/main.ts
import { ECSClientLibrary } from '@nanoforge-dev/ecs-client';
// ... other imports

export async function main(options: IRunOptions) {
  const app = NanoforgeFactory.createClient();
  const ecs = new ECSClientLibrary();
  app.useComponentSystem(ecs);

  await app.init(options);

  const registry = ecs.registry;

  const player = registry.spawnEntity();
  registry.addComponent(player, new Position(400, 300));
  registry.addComponent(player, new Velocity(120, 0));
  registry.addSystem(moveSystem);

  await app.run();
}

To render the entity, add a draw system using the @nanoforge-dev/graphics-2d library:

client/systems/draw.system.ts
import { Graphics2DLibrary, Rect } from '@nanoforge-dev/graphics-2d';
import type { Registry, Context } from '@nanoforge-dev/ecs-client';
import { Position } from '../components';

export function drawSystem(registry: Registry, ctx: Context) {
  const graphics = ctx.libs.getGraphics<Graphics2DLibrary>();
  const entities = registry.getZipper([Position]);

  for (const entity of entities) {
    const rect = new Rect({
      x: entity.Position.x,
      y: entity.Position.y,
      width: 32,
      height: 32,
      fill: '#7c3aed',
    });
    graphics.stage.add(rect);
  }
}
06

Run in dev mode

nf dev compiles your project, starts both client and server, and watches for changes with hot reload.

terminal
cd my-game
nf dev

Hot reload

Save a file and the engine recompiles and reloads without losing entity state.

Dev tools

Inspect entities and tweak components live with the built-in visual editor.

07

Install packages

The NanoForge Registry hosts ready-to-use components, systems, and templates. Install them with nf install:

terminal
nf install nf/position-2d
nf install --server nf/position-2d
nf install --lib @nanoforge-dev/input

Once installed, packages are imported like any TypeScript module. The CLI also generates stubs for components and systems so you can start using them immediately.

nf/position-2d
nf/move-2d
nf/drawable-circle-2d
nf/velocity-2d
Browse all
08

Build & deploy

When you're ready to ship, build your project and start the production server:

terminal
nf build
nf start
nf start --port 8080 --cert cert.pem --key key.pem

You can also manage deployments directly from the Project Manager — a web dashboard where you can monitor builds, manage multiple projects, and invite collaborators.

NanoForge games are served as a URL — no client install, no plugins. Your players open a link and the game runs.

Next steps