Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .idea/codeStyles/codeStyleConfig.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 79 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,112 @@
<div align="center">
<br />
<p>
<a href="https://github.com/NanoForge-dev"><img src="https://github.com/NanoForge-dev/Loader/blob/main/.github/logo.png" width="546" alt="NanoForge" /></a>
</p>
<br />
<p>
<a href="https://github.com/NanoForge-dev/Loader/actions/workflows/tests.yml"><img src="https://github.com/NanoForge-dev/Loader/actions/workflows/tests.yml/badge.svg" alt="Tests status" /></a>
<a href="https://github.com/NanoForge-dev"><img src="https://github.com/NanoForge-dev/Loader/blob/main/.github/logo.png" width="546" alt="NanoForge" /></a>
</p>
<br />
<p>
<a href="https://github.com/NanoForge-dev/Loader/actions/workflows/tests.yml"><img src="https://github.com/NanoForge-dev/Loader/actions/workflows/tests.yml/badge.svg" alt="Tests status" /></a>
<a href="https://github.com/NanoForge-dev/Loader/actions/workflows/push-docs.yml"><img src="https://github.com/NanoForge-dev/Loader/actions/workflows/push-docs.yml/badge.svg" alt="Documentation status" /></a>
<a href="https://github.com/NanoForge-dev/Loader/commits/main"><img src="https://img.shields.io/github/last-commit/NanoForge-dev/Loader.svg?logo=github&logoColor=ffffff" alt="Last commit" /></a>
<a href="https://github.com/NanoForge-dev/Loader/graphs/contributors"><img src="https://img.shields.io/github/contributors/NanoForge-dev/Loader.svg?maxAge=3600&logo=github&logoColor=fff&color=00c7be" alt="Contributors" /></a>
</p>
<a href="https://github.com/NanoForge-dev/Loader/graphs/contributors"><img src="https://img.shields.io/github/contributors/NanoForge-dev/Loader.svg?maxAge=3600&logo=github&logoColor=fff&color=00c7be" alt="Contributors" /></a>
</p>
</div>

## About

This repository contains the Loader of NanoForge. Check [releases][github-releases] to see versions of the Loader. Nanoforge is a powerful game engine for web browser.
This repository contains the Loader of NanoForge. Check [releases][github-releases] to see versions of the Loader. NanoForge is a powerful game engine for web browsers.

The Loader is the runtime layer invoked by the [NanoForge CLI][cli-source] when you run `nf start`. It handles both sides of a NanoForge project simultaneously: the **client side** served to the browser and the **server side** running in Node.js.

## Usage

To use Nanoforge Loader, please refer to the [CLI documentation][cli-source] !
To use the NanoForge Loader, please refer to the [CLI documentation][cli-source]!

First, install the CLI :
First, install the CLI:

```bash
npm install -g @nanoforge-dev/cli
```

Create a new project :
Create a new project:

```bash
nf new
```

And then build and start it :
Then build and start it:

```bash
cd <path_to_my_project>
nf build
nf start
```

## Packages

This monorepo provides three packages, each fulfilling a distinct role at runtime.

- `loader-client` : Bun HTTP server that serves the browser loader UI and the compiled client game files. The entry point for everything the browser sees.
- `loader-server` : Node.js process that runs the compiled server game files in an isolated worker. The entry point for the server-side game logic.
- `loader-website` : Browser application bundled as a static asset. Displays the loading screen, caches game files in the browser and bootstraps the game.

### `@nanoforge-dev/loader-client`

The client loader is a Bun HTTP server that bridges the browser and the compiled game client. It:

- Serves the `loader-website` frontend at `/`
- Exposes the game file manifest at `/manifest`
- Serves compiled game files at `/game/*`
- Exposes `NANOFORGE_*` environment variables at `/env`
- Supports HTTPS/TLS via `--cert` and `--key`
- Supports hot-reload via WebSocket watch mode (`--watch`)

| Option | Default | Description |
| -------------------------- | ------------------- | ---------------------------------------------- |
| `-p, --port <port>` | `3000` | Port the HTTP server listens on |
| `-d, --dir <dir>` | `.nanoforge/client` | Directory of compiled client game files |
| `--watch` | `false` | Enable file watcher and browser hot-reload |
| `--watch-port <port>` | auto | Port for the WebSocket watch server |
| `--watch-server-dir <dir>` | — | Also watch a server game directory for changes |
| `--cert <file>` | — | TLS certificate file (enables HTTPS) |
| `--key <file>` | — | TLS private key file (enables HTTPS) |

### `@nanoforge-dev/loader-server`

The server loader is a Node.js process that runs the server-side game code. It:

- Scans the game server directory for compiled files
- Forks an isolated worker that requires `/main.js` and calls its exported `main()` function
- Passes all game files and `NANOFORGE_*` environment variables to the game
- Restarts the worker on file changes when `--watch` is enabled

| Option | Default | Description |
| ----------------- | ------------------- | ------------------------------------------------ |
| `-d, --dir <dir>` | `.nanoforge/server` | Directory of compiled server game files |
| `--watch` | `false` | Enable file watcher and worker restart on change |

### `@nanoforge-dev/loader-website`

The website loader is a browser application bundled as a static asset and served by `loader-client`. It:

- Displays a loading screen with a progress bar and status messages
- Fetches the manifest from `/manifest` to get the list of game files and the version
- Downloads each game file and stores it locally using the browser's Origin Private File System (OPFS)
- Dynamically imports `/main.js` and calls its exported `main()` function
- Passes the game files map and environment to the game inside a container `<div>`
- Connects to the WebSocket watch server when enabled and reloads the page on `update`
- Catches unhandled errors and displays them on screen

## Environment Variables

Both `loader-client` and `loader-server` collect environment variables prefixed with `NANOFORGE_` and forward them to the game with the prefix stripped:

```
NANOFORGE_MY_VAR=hello → { MY_VAR: "hello" }
```

The browser game receives these via the `/env` endpoint. The server game receives them directly as a plain object passed to `main()`.

## Contributing

Please read through our [contribution guidelines][contributing] before starting a pull request. We welcome contributions of all kinds, not just code! If you're stuck for ideas, look for the [good first issue][good-first-issue] label on issues in the repository. If you have any questions about the project, feel free to ask them on [Discussions][discussions]. Before creating your own issue or pull request, always check to see if one already exists! Don't rush contributions, take your time and ensure you're doing it correctly.
Expand Down
47 changes: 42 additions & 5 deletions apps/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,68 @@

## About

This repository contains the Loader Client of NanoForge. Check [releases][github-releases] to see versions of the Loader. Nanoforge is a powerful game engine for web browser.
This package contains the Client Loader of NanoForge. It is part of the [NanoForge Loader][loader-source] monorepo. Check [releases][github-releases] to see versions. NanoForge is a powerful game engine for web browsers.

The client loader is a Bun HTTP server that serves the browser-facing side of a NanoForge project. It delivers the loader UI, the compiled game files and the game environment to the browser, and optionally streams live-reload events via WebSocket.

## Usage

To use Nanoforge Loader, please refer to the [CLI documentation][cli-source] !
To use the NanoForge Loader, please refer to the [CLI documentation][cli-source]!

First, install the CLI :
First, install the CLI:

```bash
npm install -g @nanoforge-dev/cli
```

Create a new project :
Create a new project:

```bash
nf new
```

And then build and start it :
Then build and start it:

```bash
cd <path_to_my_project>
nf build
nf start
```

## Routes

The client loader exposes the following HTTP routes:

| Route | Description |
| --------------- | --------------------------------------------------------------------- |
| `GET /` | Serves the `loader-website` HTML application |
| `GET /*` | Serves static assets bundled with `loader-website` |
| `GET /manifest` | Returns the list of game files and the current version as JSON |
| `GET /env` | Returns `NANOFORGE_*` environment variables (prefix stripped) as JSON |
| `GET /game/*` | Serves compiled game client files from the configured game directory |

## Options

| Option | Default | Description |
| -------------------------- | ------------------- | ---------------------------------------------- |
| `-p, --port <port>` | `3000` | Port the HTTP server listens on |
| `-d, --dir <dir>` | `.nanoforge/client` | Directory of compiled client game files |
| `--watch` | `false` | Enable file watcher and browser hot-reload |
| `--watch-port <port>` | auto | Port for the WebSocket watch server |
| `--watch-server-dir <dir>` | — | Also watch a server game directory for changes |
| `--cert <file>` | — | TLS certificate file (enables HTTPS) |
| `--key <file>` | — | TLS private key file (enables HTTPS) |

## Watch Mode

When `--watch` is enabled, the client loader starts a WebSocket server on `--watch-port` (or a random free port). Any file change in the game directory causes the server to broadcast an `update` message. The `loader-website` frontend listens for this message and reloads the page automatically.

You can also pass `--watch-server-dir` to trigger a reload when the server game directory changes — useful when both sides are compiled simultaneously.

## HTTPS / TLS

Pass `--cert` and `--key` to enable HTTPS. The `loader-website` frontend will detect TLS and communicate this to the game via the `/env` response (`tlsEnabled: true`). HTTPS is required when the browser's secure context is enforced (e.g. to use the Origin Private File System).

## Contributing

Please read through our [contribution guidelines][contributing] before starting a pull request. We welcome contributions of all kinds, not just code! If you're stuck for ideas, look for the [good first issue][good-first-issue] label on issues in the repository. If you have any questions about the project, feel free to ask them on [Discussions][discussions]. Before creating your own issue or pull request, always check to see if one already exists! Don't rush contributions, take your time and ensure you're doing it correctly.
Expand All @@ -53,5 +89,6 @@ If you don't understand something in the documentation, you are experiencing pro
[contributing]: https://github.com/NanoForge-dev/Loader/blob/main/.github/CONTRIBUTING.md
[discussions]: https://github.com/NanoForge-dev/Loader/discussions
[cli-source]: https://github.com/NanoForge-dev/CLI
[loader-source]: https://github.com/NanoForge-dev/Loader
[github-releases]: https://github.com/NanoForge-dev/Loader/releases
[good-first-issue]: https://github.com/NanoForge-dev/Loader/contribute
7 changes: 6 additions & 1 deletion apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,18 @@
"prettier": "catalog:lint",
"typescript": "catalog:build"
},
"packageManager": "pnpm@10.22.0",
"packageManager": "pnpm@11.5.1",
"engines": {
"node": "25"
},
"publishConfig": {
"access": "public"
},
"pnpm": {
"allowBuilds": {
"bun": true
}
},
"lint-staged": {
"**": [
"prettier --ignore-unknown --write"
Expand Down
3 changes: 3 additions & 0 deletions apps/client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["bun"]
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"]
}
41 changes: 36 additions & 5 deletions apps/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,62 @@

## About

This repository contains the Loader Server of NanoForge. Check [releases][github-releases] to see versions of the Loader. Nanoforge is a powerful game engine for web browser.
This package contains the Server Loader of NanoForge. It is part of the [NanoForge Loader][loader-source] monorepo. Check [releases][github-releases] to see versions. NanoForge is a powerful game engine for web browsers.

The server loader is a Node.js process that runs the server-side game code of a NanoForge project. It scans a compiled game directory, then forks an isolated worker process that loads `main.js` and calls its exported `main()` function.

## Usage

To use Nanoforge Loader, please refer to the [CLI documentation][cli-source] !
To use the NanoForge Loader, please refer to the [CLI documentation][cli-source]!

First, install the CLI :
First, install the CLI:

```bash
npm install -g @nanoforge-dev/cli
```

Create a new project :
Create a new project:

```bash
nf new
```

And then build and start it :
Then build and start it:

```bash
cd <path_to_my_project>
nf build
nf start
```

## How It Works

The server loader runs in two processes:

1. **Server** (`server.js`) — the entry point. It scans the game directory, locates `/main.js`, and forks the worker. In `--watch` mode it restarts the worker whenever a file changes.
2. **Worker** (`worker.js`) — the isolated child process. It requires the game's `main.js` and calls `main({ files, env })`, where `files` is a map of all game file paths and `env` contains the forwarded environment variables.

## Options

| Option | Default | Description |
| ----------------- | ------------------- | ------------------------------------------------ |
| `-d, --dir <dir>` | `.nanoforge/server` | Directory of compiled server game files |
| `--watch` | `false` | Enable file watcher and worker restart on change |

## Watch Mode

When `--watch` is enabled, the loader watches the game directory recursively. On any file change, the running worker is killed and a new worker is immediately forked with a fresh state. Changes are debounced to 100 ms to avoid redundant restarts during bulk builds.

## Environment Variables

The server loader reads all environment variables prefixed with `NANOFORGE_`, strips the prefix, and passes them to the game as a plain object:

```
NANOFORGE_MY_VAR=hello → { MY_VAR: "hello" }
```

These variables are available inside the game via the `env` field of the `main()` options.

## Contributing

Please read through our [contribution guidelines][contributing] before starting a pull request. We welcome contributions of all kinds, not just code! If you're stuck for ideas, look for the [good first issue][good-first-issue] label on issues in the repository. If you have any questions about the project, feel free to ask them on [Discussions][discussions]. Before creating your own issue or pull request, always check to see if one already exists! Don't rush contributions, take your time and ensure you're doing it correctly.
Expand All @@ -53,5 +83,6 @@ If you don't understand something in the documentation, you are experiencing pro
[contributing]: https://github.com/NanoForge-dev/Loader/blob/main/.github/CONTRIBUTING.md
[discussions]: https://github.com/NanoForge-dev/Loader/discussions
[cli-source]: https://github.com/NanoForge-dev/CLI
[loader-source]: https://github.com/NanoForge-dev/Loader
[github-releases]: https://github.com/NanoForge-dev/Loader/releases
[good-first-issue]: https://github.com/NanoForge-dev/Loader/contribute
2 changes: 1 addition & 1 deletion apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"prettier": "catalog:lint",
"typescript": "catalog:build"
},
"packageManager": "pnpm@10.22.0",
"packageManager": "pnpm@11.5.1",
"engines": {
"node": "25"
},
Expand Down
33 changes: 28 additions & 5 deletions apps/website/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,54 @@

## About

This repository contains the Loader Website of NanoForge. Check [releases][github-releases] to see versions of the Loader. Nanoforge is a powerful game engine for web browser.
This package contains the Website Loader of NanoForge. It is part of the [NanoForge Loader][loader-source] monorepo. Check [releases][github-releases] to see versions. NanoForge is a powerful game engine for web browsers.

The website loader is a browser application (HTML + TypeScript) bundled as static assets and served by `loader-client`. It is the loading screen the player sees before the game starts: it downloads the game files, caches them locally in the browser and then bootstraps the game.

## Usage

To use Nanoforge Loader, please refer to the [CLI documentation][cli-source] !
To use the NanoForge Loader, please refer to the [CLI documentation][cli-source]!

First, install the CLI :
First, install the CLI:

```bash
npm install -g @nanoforge-dev/cli
```

Create a new project :
Create a new project:

```bash
nf new
```

And then build and start it :
Then build and start it:

```bash
cd <path_to_my_project>
nf build
nf start
```

## Loading Sequence

When the browser opens the loader URL, the following steps happen in order:

1. **Fetch manifest** — requests `/manifest` to get the game version and the list of files.
2. **Verify cache** — checks whether the game files from the previous session are still present in the browser's Origin Private File System (OPFS).
3. **Download files** — if the cache is stale or missing, downloads each game file from `/game/*` and writes it into OPFS, showing a progress bar and the current file name.
4. **Fetch environment** — requests `/env` to get the `NANOFORGE_*` variables forwarded by the server.
5. **Bootstrap game** — dynamically imports `/main.js` from the local cache, calls its exported `main({ files, env, container })` and hides the loading screen.

If any step fails, the error message is displayed on screen instead of a blank page.

## Watch Mode

When the server enables watch mode, the manifest includes a WebSocket URL. The website loader connects to this URL and reloads the page automatically whenever it receives an `update` message — enabling live-reload during development.

## Requirements

The loader requires a **secure context** (HTTPS or `localhost`) because it uses the browser's Origin Private File System API to cache game files locally. Starting the client loader with `--cert` and `--key` satisfies this requirement in production.

## Contributing

Please read through our [contribution guidelines][contributing] before starting a pull request. We welcome contributions of all kinds, not just code! If you're stuck for ideas, look for the [good first issue][good-first-issue] label on issues in the repository. If you have any questions about the project, feel free to ask them on [Discussions][discussions]. Before creating your own issue or pull request, always check to see if one already exists! Don't rush contributions, take your time and ensure you're doing it correctly.
Expand All @@ -53,5 +75,6 @@ If you don't understand something in the documentation, you are experiencing pro
[contributing]: https://github.com/NanoForge-dev/Loader/blob/main/.github/CONTRIBUTING.md
[discussions]: https://github.com/NanoForge-dev/Loader/discussions
[cli-source]: https://github.com/NanoForge-dev/CLI
[loader-source]: https://github.com/NanoForge-dev/Loader
[github-releases]: https://github.com/NanoForge-dev/Loader/releases
[good-first-issue]: https://github.com/NanoForge-dev/Loader/contribute
Loading
Loading