From d44b5af55c0277f8d829cb3bfe29764beb75e86c Mon Sep 17 00:00:00 2001 From: Exelo Date: Sat, 31 Jan 2026 02:06:53 +0100 Subject: [PATCH] feat: add docs --- docs/docs/architecture.rst | 195 +++++++++++++++++++++++++ docs/docs/client.rst | 143 ++++++++++++++++++ docs/docs/index.rst | 10 ++ docs/docs/server.rst | 173 ++++++++++++++++++++++ docs/docs/website.rst | 246 +++++++++++++++++++++++++++++++ docs/guides/contributing.rst | 249 ++++++++++++++++++++++++++++++++ docs/guides/getting-started.rst | 242 +++++++++++++++++++++++++++++++ docs/guides/index.rst | 8 + docs/index.rst | 24 +++ 9 files changed, 1290 insertions(+) create mode 100644 docs/docs/architecture.rst create mode 100644 docs/docs/client.rst create mode 100644 docs/docs/index.rst create mode 100644 docs/docs/server.rst create mode 100644 docs/docs/website.rst create mode 100644 docs/guides/contributing.rst create mode 100644 docs/guides/getting-started.rst create mode 100644 docs/guides/index.rst create mode 100644 docs/index.rst diff --git a/docs/docs/architecture.rst b/docs/docs/architecture.rst new file mode 100644 index 0000000..b8c5a85 --- /dev/null +++ b/docs/docs/architecture.rst @@ -0,0 +1,195 @@ +Architecture +============ + +Overview +-------- + +NanoForge Loader is a runtime system that serves and executes NanoForge game +engine projects. It provides two execution modes: + +- **Client mode**: Serves a web interface where users can load and play games + directly in the browser using WebGL. +- **Server mode**: Executes game server logic in a Node.js worker thread, + suitable for multiplayer game backends. + +Both loaders share a common architecture: they read game files from a directory, +generate a manifest of assets, and execute the game's ``main.js`` entry point. + +Technology Stack +---------------- + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - Component + - Technology + * - Language + - TypeScript (strict mode) + * - Runtime + - Bun (bundler and runtime) + * - Module Formats + - ESM + CJS (dual package) + * - Target + - Browser (client) / Node.js (server) + * - Package Manager + - pnpm 10.x + * - Node Version + - 25 + * - Linter + - ESLint 9.x + * - Formatter + - Prettier 3.x + * - CI/CD + - GitHub Actions + +Package Architecture +-------------------- + +The loader is organized as a monorepo with three packages: + +:: + + loader/ + +-- apps/ + | +-- client/ # Browser loader server + | | +-- src/ + | | | +-- server.ts # HTTP server entry point + | | | +-- env.ts # Environment configuration + | | | +-- files.ts # File utilities + | | | +-- manifest.ts # Manifest generation + | | | +-- watch.ts # File watcher for hot reload + | | +-- package.json + | +-- server/ # Node.js server loader + | | +-- src/ + | | | +-- server.ts # Bootstrap entry point + | | | +-- worker.ts # Worker thread implementation + | | | +-- env.ts # Environment configuration + | | | +-- files.ts # File utilities + | | | +-- watch.ts # File watcher for hot reload + | | +-- package.json + | +-- website/ # Web interface + | +-- src/ + | | +-- index.ts # Main entry point + | | +-- cache/ # Caching logic + | | +-- file-system/ # File system abstraction + | | +-- game/ # Game runner + | | +-- loader/ # Game file loader + | | +-- types/ # TypeScript types + | | +-- utils/ # Utility functions + | | +-- version/ # Version management + | +-- package.json + +-- package.json # Root workspace config + +-- pnpm-workspace.yaml # pnpm workspace definition + +-- turbo.json # Turbo build configuration + +Client Loader Flow +------------------ + +The client loader implements an HTTP server using Bun: + +1. **Server Initialization**: Starts an HTTP server on the configured port. + +2. **Route Handling**: + + - ``/`` - Serves the website ``index.html`` + - ``/*`` - Serves static website assets + - ``/manifest`` - Returns the game file manifest (JSON) + - ``/env`` - Returns public environment variables + - ``/game/*`` - Serves game files from the game directory + +3. **Manifest Generation**: On each ``/manifest`` request, scans the game + directory and builds a list of all game files with their paths. + +4. **Hot Reload** (optional): When ``WATCH=true``, starts a WebSocket server + that notifies the browser when game files change. + +.. code-block:: text + + Browser Client Loader Game Directory + | | | + |----GET /manifest-------->| | + | |---scan directory--------->| + | |<--file list---------------| + |<---JSON manifest---------| | + | | | + |----GET /game/main.js---->| | + | |---read file-------------->| + |<---JavaScript file-------| | + | | | + |====WebSocket (watch)=====| | + |<---file changed----------|<--fsnotify---------------| + +Server Loader Flow +------------------ + +The server loader executes game logic in a Node.js worker thread: + +1. **Bootstrap**: Reads the game directory and locates ``main.js``. + +2. **Worker Fork**: Spawns a child process that runs the worker script. + +3. **Game Execution**: The worker imports ``main.js`` and calls its ``main()`` + function with a file map containing all game assets. + +4. **Hot Reload** (optional): When watch mode is enabled, the worker process + is killed and restarted when files change. + +.. code-block:: text + + Server Loader Worker Thread Game Code + | | | + |---fork(worker.js)--------->| | + | |---import main.js-------->| + | |<--main function----------| + | |---call main()----------->| + | | | + [file change detected] | | + |---kill worker------------->| | + |---fork new worker--------->| | + +Website Architecture +-------------------- + +The website package provides the browser-side game loader: + +1. **Manifest Fetching**: Requests ``/manifest`` from the client server. + +2. **File Caching**: Downloads game files and stores them in browser storage + (IndexedDB via the file-system abstraction). + +3. **Version Checking**: Compares the manifest version with cached version + to determine if files need updating. + +4. **Game Loading**: Imports the main module and creates a file map for + the game to access assets. + +5. **Game Execution**: Calls the game's ``main()`` function with canvas + and file references. + +6. **Watch Integration**: Subscribes to the WebSocket for hot reload + notifications during development. + +Build Pipeline +-------------- + +The project uses Bun for building and bundling: + +.. code-block:: bash + + # Build all packages + pnpm run build + + # What happens internally: + # 1. website: bun build -> dist/index.html + assets + # 2. client: bun build -> dist/server.js + # 3. server: bun build -> dist/server.js + dist/worker.js + +Each package produces optimized bundles for its target environment: + +- **Website**: Browser bundle with HTML entry point +- **Client**: Bun-targeted server bundle +- **Server**: Node.js-targeted bundles for server and worker + +Turbo is used to orchestrate builds across packages with proper dependency +ordering (website must build before client). diff --git a/docs/docs/client.rst b/docs/docs/client.rst new file mode 100644 index 0000000..c454163 --- /dev/null +++ b/docs/docs/client.rst @@ -0,0 +1,143 @@ +client +============= + +**Package**: ``@nanoforge-dev/loader-client`` + +The client loader serves a web interface for loading and running NanoForge +games in the browser. It provides an HTTP server that serves the website +assets and game files. + +Overview +-------- + +The client loader is a Bun-based HTTP server that: + +- Serves the loader website interface +- Provides a manifest endpoint listing all game files +- Serves game files from a configured directory +- Optionall:white_check_mark: y enables hot reload via WebSocket + +Environment Variables +--------------------- + +.. list-table:: + :header-rows: 1 + :widths: 25 15 60 + + * - Variable + - Required + - Description + * - ``PORT`` + - Yes + - Port number for the HTTP server + * - ``GAME_DIR`` + - Yes + - Absolute path to the game directory + * - ``WATCH`` + - No + - Set to ``"true"`` to enable hot reload + * - ``WATCH_PORT`` + - No + - Port for the WebSocket watch server + * - ``WATCH_SERVER_GAME_DIR`` + - No + - Game directory for server-side watch + * - ``PUBLIC_*`` + - No + - Any variable prefixed with ``PUBLIC_`` is exposed to the client + +API Endpoints +------------- + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Endpoint + - Description + * - ``GET /`` + - Serves the main ``index.html`` page + * - ``GET /*`` + - Serves static website assets + * - ``GET /manifest`` + - Returns the game manifest as JSON + * - ``GET /env`` + - Returns public environment variables as JSON + * - ``GET /game/*`` + - Serves files from the game directory + +Manifest Format +--------------- + +The ``/manifest`` endpoint returns a JSON object: + +.. code-block:: typescript + + interface IManifest { + version: string; + files: { path: string }[]; + watch: { enable: false } | { enable: true; url: string }; + } + +Source Modules +-------------- + +server.ts +^^^^^^^^^ + +Main entry point that creates and configures the Bun HTTP server with all +route handlers. + +env.ts +^^^^^^ + +Environment variable accessors: + +.. code-block:: typescript + + function getPort(): string + function getGameDir(): string + function getWatch(): string | undefined + function getWatchPort(): string | undefined + function getWatchServerGameDir(): string | undefined + function getPublicEnv(): Record + +manifest.ts +^^^^^^^^^^^ + +Manifest generation: + +.. code-block:: typescript + + const MANIFEST: IManifest + function updateManifest(gameDir: string): Promise + +watch.ts +^^^^^^^^ + +File watching for hot reload: + +.. code-block:: typescript + + function startWatch( + gameDir: string, + watchPort: string | undefined, + watchServerGameDir: string | undefined + ): void + +Usage +----- + +.. code-block:: bash + + # Set required environment variables + export PORT=3000 + export GAME_DIR=/path/to/game + + # Start the client loader + pnpm --filter @nanoforge-dev/loader-client start + + # With hot reload + export WATCH=true + export WATCH_PORT=3001 + pnpm --filter @nanoforge-dev/loader-client start diff --git a/docs/docs/index.rst b/docs/docs/index.rst new file mode 100644 index 0000000..d997893 --- /dev/null +++ b/docs/docs/index.rst @@ -0,0 +1,10 @@ +Technical Documentation +====================== + +.. toctree:: + :maxdepth: 2 + + architecture + client + website + server diff --git a/docs/docs/server.rst b/docs/docs/server.rst new file mode 100644 index 0000000..f98ce97 --- /dev/null +++ b/docs/docs/server.rst @@ -0,0 +1,173 @@ +server +============= + +**Package**: ``@nanoforge-dev/loader-server`` + +The server loader executes NanoForge game server logic in a Node.js +environment. It runs the game's ``main.js`` in a worker thread with +file access and optional hot reload. + +Overview +-------- + +The server loader: + +- Scans the game directory for files +- Locates the ``main.js`` entry point +- Forks a worker process to execute game code +- Provides file paths to the game via a Map +- Optionally restarts on file changes + +Environment Variables +--------------------- + +.. list-table:: + :header-rows: 1 + :widths: 25 15 60 + + * - Variable + - Required + - Description + * - ``GAME_DIR`` + - Yes + - Absolute path to the game directory + * - ``WATCH`` + - No + - Set to any value to enable hot reload + +Game Entry Point +---------------- + +The server loader expects a ``main.js`` file in the game directory that +exports a ``main`` function: + +.. code-block:: typescript + + interface RunOptions { + files: Map; + } + + export async function main(options: RunOptions): Promise { + // Game server logic + const files = options.files; + // files.get("/assets/config.json") -> absolute path to file + } + +The ``files`` map contains all game files with their relative paths as keys +and absolute file system paths as values. + +Worker Thread +------------- + +The game code runs in a separate worker thread (child process), which: + +- Isolates game code from the loader process +- Enables clean restarts during hot reload +- Prevents game crashes from affecting the loader + +Source Modules +-------------- + +server.ts +^^^^^^^^^ + +Bootstrap entry point that: + +1. Reads the game directory +2. Locates ``main.js`` +3. Forks the worker process +4. Sets up file watching if enabled + +.. code-block:: typescript + + async function bootstrap(): Promise + +worker.ts +^^^^^^^^^ + +Worker thread implementation that: + +1. Receives the main path and file list via process arguments +2. Imports the game's main module using ``createRequire`` +3. Calls the ``main()`` function with the files map + +.. code-block:: typescript + + interface MainFunction { + main: (options: { files: Map }) => Promise; + } + +env.ts +^^^^^^ + +Environment variable accessors: + +.. code-block:: typescript + + function getGameDir(): string + function getWatch(): string | undefined + +files.ts +^^^^^^^^ + +File system utilities: + +.. code-block:: typescript + + function getFiles(gameDir: string): [string, string][] + +Returns an array of tuples containing ``[relativePath, absolutePath]`` for +all files in the game directory. + +watch.ts +^^^^^^^^ + +File watching for hot reload: + +.. code-block:: typescript + + function startWatch( + gameDir: string, + callback: () => Promise + ): void + +Calls the callback function when files change, allowing the server to +restart the worker process. + +Usage +----- + +.. code-block:: bash + + # Set required environment variables + export GAME_DIR=/path/to/game + + # Start the server loader + pnpm --filter @nanoforge-dev/loader-server start + + # With hot reload + export WATCH=1 + pnpm --filter @nanoforge-dev/loader-server start + +Example Game Server +------------------- + +.. code-block:: javascript + + // main.js + export async function main(options) { + const { files } = options; + + console.log("Server starting..."); + console.log("Available files:", [...files.keys()]); + + // Read a config file + const configPath = files.get("/config.json"); + if (configPath) { + const config = await import(configPath, { with: { type: "json" } }); + console.log("Config loaded:", config); + } + + // Your game server logic here + // e.g., start a WebSocket server, initialize game state, etc. + } diff --git a/docs/docs/website.rst b/docs/docs/website.rst new file mode 100644 index 0000000..a924cd5 --- /dev/null +++ b/docs/docs/website.rst @@ -0,0 +1,246 @@ +website +============== + +**Package**: ``@nanoforge-dev/loader-website`` + +The website package provides the browser-side interface for loading and +running NanoForge games. It handles manifest fetching, file caching, +and game initialization. + +Overview +-------- + +The website is a client-side application that: + +- Fetches the game manifest from the loader server +- Caches game files in browser storage +- Loads and executes the game's main module +- Provides a canvas and file access to the game +- Supports hot reload via WebSocket + +Modules +------- + +loader +^^^^^^ + +**Path**: ``src/loader/`` + +Loads game files from the manifest and prepares them for execution. + +.. code-block:: typescript + + async function loadGameFiles( + manifest: IExtendedManifest + ): Promise<[Map, any]> + +Returns a tuple containing: + +1. A map of file paths to local (cached) paths +2. The imported main module + +The loader: + +- Iterates through manifest files +- Caches each file locally +- Dynamically imports ``main.js`` +- Returns the main module's exports + +game +^^^^ + +**Path**: ``src/game/`` + +Handles game execution and window management. + +.. code-block:: typescript + + function runGame( + mainModule: any, + options: Omit + ): void + +- Switches the UI to game mode +- Gets the canvas element +- Calls the game's ``main()`` function with options + +cache +^^^^^ + +**Path**: ``src/cache/`` + +Manages browser-side caching of game files for offline support and +faster subsequent loads. + +file-system +^^^^^^^^^^^ + +**Path**: ``src/file-system/`` + +Provides a file system abstraction over browser storage APIs (IndexedDB): + +.. code-block:: typescript + + class FileSystemManager { + async getDirectory(path: string): Promise + async getFile(path: string): Promise + } + + class FileSystemDirectory { + async list(): Promise + async create(): Promise + } + + class FileSystemFile { + async read(): Promise + async write(data: Blob): Promise + async exists(): Promise + } + + class FileSystemHandler { + // Low-level storage interface + } + +manifest +^^^^^^^^ + +**Path**: ``src/manifest.ts`` + +Manifest fetching and validation: + +.. code-block:: typescript + + async function getManifest(): Promise + function isManifestUpToDate(manifest: IManifest): boolean + +version +^^^^^^^ + +**Path**: ``src/version/`` + +Manages version tracking for cache invalidation: + +.. code-block:: typescript + + function getVersion(): string | null + function setVersion(version: string): void + +watch +^^^^^ + +**Path**: ``src/watch.ts`` + +WebSocket connection for hot reload notifications. + +window +^^^^^^ + +**Path**: ``src/window.ts`` + +UI state management: + +.. code-block:: typescript + + function setLoadingStatus(status: string): void + function changeWindowToGame(): void + +utils +^^^^^ + +**Path**: ``src/utils/`` + +Utility functions: + +**logger.utils.ts** + +.. code-block:: typescript + + class Logger { + constructor(prefix: string) + info(...args: any[]): void + warn(...args: any[]): void + error(...args: any[]): void + } + +**document.utils.ts** + +.. code-block:: typescript + + function getElementById(id: string): HTMLElement + function addScript(src: string): void + +**delay.utils.ts** + +.. code-block:: typescript + + function delay(ms: number): Promise + +Types +----- + +IManifest +^^^^^^^^^ + +.. code-block:: typescript + + interface IManifest { + version: string; + files: IManifestFile[]; + watch: { enable: false } | { enable: true; url: string }; + } + +IManifestFile +^^^^^^^^^^^^^ + +.. code-block:: typescript + + interface IManifestFile { + path: string; + } + +IExtendedManifest +^^^^^^^^^^^^^^^^^ + +Extended manifest with local file paths after caching: + +.. code-block:: typescript + + interface IExtendedManifest { + files: IExtendedManifestFile[]; + } + +IExtendedManifestFile +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: typescript + + interface IExtendedManifestFile extends IManifestFile { + localPath: string; // Local cached path (blob URL or IndexedDB path) + } + +IGameOptions +^^^^^^^^^^^^ + +Options passed to the game's main function: + +.. code-block:: typescript + + interface IGameOptions { + canvas: HTMLCanvasElement; + files: Map; + } + +Build Output +------------ + +The website builds to static assets: + +:: + + dist/ + +-- index.html # Main HTML entry point + +-- index.js # Bundled JavaScript + +-- style.css # Styles + +-- assets/ # Static assets + +These files are served by the client loader and consumed by the browser. diff --git a/docs/guides/contributing.rst b/docs/guides/contributing.rst new file mode 100644 index 0000000..26d184a --- /dev/null +++ b/docs/guides/contributing.rst @@ -0,0 +1,249 @@ +Contributing +============ + +This guide explains how to contribute to the NanoForge Loader project. + +Prerequisites +------------- + +- `Node.js `_ version 25 +- `pnpm `_ 10.x +- `Bun `_ runtime + +Setup +----- + +1. **Fork and clone** the repository: + + .. code-block:: bash + + git clone https://github.com//Loader.git + cd Loader + +2. **Ensure you are on the main branch**: + + .. code-block:: bash + + git checkout main + +3. **Install dependencies**: + + .. code-block:: bash + + pnpm install --frozen-lockfile + + This also sets up Husky git hooks via the ``prepare`` script. + +4. **Create a feature branch**: + + .. code-block:: bash + + git checkout -b feat/my-feature + +Development Workflow +-------------------- + +1. Make your changes in the appropriate ``apps/`` package: + + - ``apps/client/`` - Client loader server + - ``apps/server/`` - Server loader + - ``apps/website/`` - Browser interface + +2. Run formatting and lint fixes: + + .. code-block:: bash + + pnpm format + +3. Build all packages to verify there are no errors: + + .. code-block:: bash + + pnpm build + +4. Run the full lint check: + + .. code-block:: bash + + pnpm lint + +Building Individual Packages +---------------------------- + +To build a specific package: + +.. code-block:: bash + + # Build website + pnpm --filter @nanoforge-dev/loader-website build + + # Build client + pnpm --filter @nanoforge-dev/loader-client build + + # Build server + pnpm --filter @nanoforge-dev/loader-server build + +.. note:: + + The client package depends on the website package. Build website first + when making changes to both. + +Commit Convention +----------------- + +This project uses `Conventional Commits `_. +Every commit message must follow this format: + +:: + + (): + + [optional body] + + [optional footer(s)] + +Valid types: + +.. list-table:: + :header-rows: 1 + :widths: 15 85 + + * - Type + - Purpose + * - ``feat`` + - A new feature + * - ``fix`` + - A bug fix + * - ``docs`` + - Documentation changes + * - ``chore`` + - Maintenance tasks (deps, CI, tooling) + * - ``refactor`` + - Code restructuring without behavior change + * - ``perf`` + - Performance improvements + * - ``test`` + - Adding or updating tests + * - ``style`` + - Code style changes (formatting, whitespace) + +Scopes for this project: + +.. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Scope + - Package + * - ``loader-client`` + - Client loader package + * - ``loader-server`` + - Server loader package + * - ``loader-website`` + - Website package + +Examples: + +.. code-block:: text + + feat(loader-client): add WebSocket reconnection logic + fix(loader-server): correct worker restart on file change + docs: update getting started guide + chore(deps): update bun to v1.2 + +Commit messages are validated by ``commitlint`` via a git hook. Commits that +do not follow the convention are rejected. + +Pull Request Process +-------------------- + +1. Push your branch to your fork: + + .. code-block:: bash + + git push origin feat/my-feature + +2. `Open a pull request `_ + against the ``main`` branch. + +3. Ensure the CI pipeline passes (lint checks, builds). + +4. Request a review from a maintainer. + +5. Once approved, the PR is merged into ``main``. + +Code Style +---------- + +The project enforces consistent code style through ESLint and Prettier. + +Naming conventions: + +- **Files**: kebab-case (``file-system-manager.ts``) +- **Classes**: PascalCase (``FileSystemManager``) +- **Functions**: camelCase (``loadGameFiles``) +- **Constants**: SCREAMING_SNAKE_CASE (``MANIFEST``) +- **Interfaces**: PascalCase with ``I`` prefix (``IManifest``) + +Import ordering (enforced by Prettier plugin): + +1. Node.js built-in modules (``node:path``, ``node:fs``) +2. External packages +3. Internal modules (relative imports) + +Project Structure +----------------- + +When adding code, follow the existing structure: + +- **Client**: HTTP server logic in ``apps/client/src/`` +- **Server**: Bootstrap and worker in ``apps/server/src/`` +- **Website**: Browser modules in ``apps/website/src/`` + +Each package has its own: + +- ``src/`` directory for source code +- ``package.json`` with package-specific scripts +- ``CHANGELOG.md`` for release notes + +Dependencies +------------ + +Dependencies are managed through pnpm workspace version catalogs defined in +``pnpm-workspace.yaml``. When adding or updating a dependency, use the catalog +reference rather than a direct version: + +.. code-block:: json + + { + "devDependencies": { + "typescript": "catalog:build", + "eslint": "catalog:lint" + } + } + +Release Process +--------------- + +Releases are managed using ``cliff-jumper``: + +.. code-block:: bash + + # Generate changelog and bump version + pnpm --filter @nanoforge-dev/loader-client release + pnpm --filter @nanoforge-dev/loader-server release + pnpm --filter @nanoforge-dev/loader-website release + +Each package maintains its own version and changelog. + +Reporting Issues +---------------- + +Report bugs and request features on the +`GitHub Issues `_ page. + +Security +-------- + +For security vulnerabilities, refer to the ``SECURITY.md`` file in the +repository root for the responsible disclosure process. diff --git a/docs/guides/getting-started.rst b/docs/guides/getting-started.rst new file mode 100644 index 0000000..13b9d66 --- /dev/null +++ b/docs/guides/getting-started.rst @@ -0,0 +1,242 @@ +Getting Started +=============== + +This guide explains how to use the NanoForge Loader packages to run +NanoForge game engine projects. + +Prerequisites +------------- + +- `Node.js `_ version 25 or later +- `Bun `_ runtime (for client loader) +- A package manager: npm, yarn, pnpm, or bun + +Installation +------------ + +Install the loader packages as dependencies in your project: + +.. code-block:: bash + + # npm + npm install @nanoforge-dev/loader-client @nanoforge-dev/loader-server + + # pnpm + pnpm add @nanoforge-dev/loader-client @nanoforge-dev/loader-server + + # yarn + yarn add @nanoforge-dev/loader-client @nanoforge-dev/loader-server + + # bun + bun add @nanoforge-dev/loader-client @nanoforge-dev/loader-server + +Running the Client Loader +------------------------- + +The client loader serves your game in a browser environment. + +Basic Usage +^^^^^^^^^^^ + +Set the required environment variables and start the loader: + +.. code-block:: bash + + export PORT=3000 + export GAME_DIR=/path/to/your/game + pnpm --filter @nanoforge-dev/loader-client start + +Open ``http://localhost:3000`` in your browser to load and play the game. + +With Hot Reload +^^^^^^^^^^^^^^^ + +Enable hot reload for development: + +.. code-block:: bash + + export PORT=3000 + export GAME_DIR=/path/to/your/game + export WATCH=true + export WATCH_PORT=3001 + pnpm --filter @nanoforge-dev/loader-client start + +The browser will automatically reload when game files change. + +Environment Variables +^^^^^^^^^^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + :widths: 25 75 + + * - Variable + - Description + * - ``PORT`` + - HTTP server port (required) + * - ``GAME_DIR`` + - Path to game directory (required) + * - ``WATCH`` + - Set to ``"true"`` to enable hot reload + * - ``WATCH_PORT`` + - WebSocket port for hot reload notifications + * - ``WATCH_SERVER_GAME_DIR`` + - Server game directory for watch coordination + * - ``PUBLIC_*`` + - Any ``PUBLIC_`` prefixed variable is exposed to the client + +Running the Server Loader +------------------------- + +The server loader executes your game's server-side logic. + +Basic Usage +^^^^^^^^^^^ + +Set the game directory and start the loader: + +.. code-block:: bash + + export GAME_DIR=/path/to/your/game + pnpm --filter @nanoforge-dev/loader-server start + +The server will locate ``main.js`` in your game directory and execute it +in a worker thread. + +With Hot Reload +^^^^^^^^^^^^^^^ + +Enable hot reload for development: + +.. code-block:: bash + + export GAME_DIR=/path/to/your/game + export WATCH=1 + pnpm --filter @nanoforge-dev/loader-server start + +The worker will restart when game files change. + +Game Entry Point +^^^^^^^^^^^^^^^^ + +Your game must have a ``main.js`` file that exports a ``main`` function: + +.. code-block:: javascript + + // main.js + export async function main(options) { + const files = options.files; + console.log("Server started with files:", [...files.keys()]); + + // Your game server logic here + } + +The ``options.files`` map contains all game files with their paths. + +Project Structure +----------------- + +A typical NanoForge game project structure: + +:: + + my-game/ + +-- main.js # Entry point (exports main function) + +-- assets/ + | +-- sprites/ + | +-- sounds/ + | +-- config.json + +-- components/ + +-- systems/ + +-- package.json + +The loader will include all files in the manifest and make them available +to your game code. + +Using with NanoForge CLI +------------------------ + +The loader is typically invoked through the NanoForge CLI rather than +directly: + +.. code-block:: bash + + # Run client (browser) game + nanoforge run --part client + + # Run server game + nanoforge run --part server + + # Development mode with hot reload + nanoforge dev + +The CLI handles environment variable setup and loader invocation. + +Typical Development Workflow +---------------------------- + +1. **Create a NanoForge project** using schematics: + + .. code-block:: bash + + schematics @nanoforge-dev/schematics:application my-game + +2. **Install dependencies**: + + .. code-block:: bash + + cd my-game + pnpm install + +3. **Generate client base code**: + + .. code-block:: bash + + schematics @nanoforge-dev/schematics:part-base my-game --part=client + +4. **Generate main entry point**: + + .. code-block:: bash + + schematics @nanoforge-dev/schematics:part-main my-game --part=client + +5. **Build your game**: + + .. code-block:: bash + + pnpm build + +6. **Run in development mode** with hot reload: + + .. code-block:: bash + + export PORT=3000 + export GAME_DIR=$(pwd)/dist/client + export WATCH=true + pnpm --filter @nanoforge-dev/loader-client start + +7. **Open the browser** at ``http://localhost:3000`` to play your game. + +Troubleshooting +--------------- + +Common issues and solutions: + +**"PORT env variable not found"** + Set the ``PORT`` environment variable before starting the client loader. + +**"GAME_DIR env variable not found"** + Set the ``GAME_DIR`` environment variable to your game's build output + directory. + +**"No main.js found"** + Ensure your game directory contains a ``main.js`` file that exports + a ``main`` function. + +**Game not loading in browser** + Check the browser console for errors. Ensure the game was built + correctly and all assets are present in the game directory. + +**Hot reload not working** + Verify ``WATCH=true`` is set and the ``WATCH_PORT`` is available. + Check that no firewall is blocking WebSocket connections. diff --git a/docs/guides/index.rst b/docs/guides/index.rst new file mode 100644 index 0000000..f5b5208 --- /dev/null +++ b/docs/guides/index.rst @@ -0,0 +1,8 @@ +Guides +====== + +.. toctree:: + :maxdepth: 2 + + getting-started + contributing diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..afac8c1 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,24 @@ +NanoForge Loader +================ + +``@nanoforge-dev/loader`` provides runtime loaders for the NanoForge game engine. +It enables serving, loading, and executing NanoForge games in both browser and +server environments with hot-reload support for development. + +The project consists of three packages: + +- **loader-client**: Browser-based loader with web interface +- **loader-server**: Server-side loader with worker thread support +- **loader-website**: Interactive web interface for game loading + +.. toctree:: + :maxdepth: 2 + :caption: Technical Documentation + + docs/index + +.. toctree:: + :maxdepth: 2 + :caption: Guides + + guides/index