# DBS Games Browser ports of the **Diamond Bullet Studios** back catalogue, rebuilt from the original project sources recovered off the studio's old drives, plus the untouched source archive each port was converted from. ``` npm install npm start # http://localhost:8123/ ``` The root page is the library: every game under `games/` that has a `game.json` appears there with its box art, and clicking one plays it. Nothing is built or bundled — the games are plain ES modules and every server route is a static file. ## Layout ``` index.html the library page site/ the library page's own CSS/JS/icon — nothing game-specific library.json generated card data (npm run library); serve.mjs also serves it live games// one self-contained port per game game.json title, year, box art, status — the only file the library reads index.html the game page src/ assets/ the port and its converted content vendor/ pinned third-party runtime (e.g. three.js) tools/ the converters that produced this game's assets/ docs/ provenance, engine notes, conversion reports for this game boxart.png shipped marketplace art, when it survived README.md what was ported, what deviates, and why archive// the original snapshot the port was made from — read-only reference tools/ converters shared across games (FBX→glTF, glTF validation) ``` Everything about one game lives in that game's folder; nothing in `games/` reaches sideways into another game. ## The library | Game | Year | Original platform | Status | |---|---|---|---| | [Mower](games/mower/) | 2010 | Xbox Live Indie Games (XNA 3.1) | Playable | | [Contention: Orion IV](games/contention/) | 2010 | Windows (Blitz3D) | In progress | | [Catalyst 2012](games/catalyst/) | 2012 | Xbox Live Indie Games (XNA 4.0) | In progress | ## Adding a converted game 1. `mkdir games/` and put the playable page at `games//index.html`. 2. Drop the original snapshot in `archive//` and leave it read-only. 3. Write `games//game.json` (copy `games/mower/game.json`; `title`, `year` and `status` are all that is required — `status` is `playable`, `in-progress` or `planned`, and only `playable` ones count as converted). 4. Add `boxart.png` if the original art survived; without it the card falls back to a lettered placeholder. 5. `npm run library` — or just reload, since `serve.mjs` rebuilds `/library.json` from the folder on every request. ## Shared tools | | | |---|---| | `tools/fbx6_to_gltf.py` | ASCII FBX 6100 (Blender 2.49 "FBX for XNA") → glTF 2.0, with skinning and takes | | `tools/validate_gltf.py` | structural validation of the converted glTF | | `tools/three_check.mjs` | loads every converted model through three.js and reports what it sees | | `tools/preview_model.py` | three orthographic views of a converted model, for checking how it is oriented | | `tools/build_library.mjs` | builds `library.json` from `games/*/game.json` | Game-specific converters and test harnesses stay with their game, in `games//tools/`. How a port is done and verified is in [`docs/workflow.md`](docs/workflow.md). ## Deploy No GitHub, no CI. There is no bundler either, so there is nothing to build but `library.json` — the deployed site *is* this tree, minus the archive. ```bash cp deploy.env.example deploy.env # fill in SSH_HOST and REMOTE_DIR npm run deploy ``` Target is `helium:/home/helium/dbs-games`, served at **dbs-games.maverickmd.dev**. Server side there is **no system Caddy** — ports 80/443 belong to the `catalyst-tools` compose project's caddy container, which acts as the edge proxy for the box. So this site is a block in `/home/helium/catalyst-tools/Caddyfile`, and `REMOTE_DIR` is bind-mounted into that container as `/srv/dbs-games`. See [`Caddyfile.snippet`](Caddyfile.snippet). Caddy gets the TLS cert itself, once DNS points at 23.238.64.244. What is and is not pushed is `scripts/deploy.rsync-filter`, and it is **deliberately not derived from `.gitignore`**. The two rules disagree on purpose: * `archive/` is *in* the repo's world but never deployed — 809 MB of evidence that nothing at runtime may load from. * `games/catalyst/assets/video/` and `games/contention/assets/cinematics/` are gitignored but **must** deploy, or the intros and credits 404. `deploy.sh` refuses to push if they are missing locally, because a fresh clone has the code and not the media, and the resulting site fails quietly. Cache headers follow from having no build step: without content hashing, a filename cannot tell you whether it is stale, so only `vendor/` (pinned per game and never edited in place) and `assets/` get a long max-age. Everything else is `no-cache`, or a deploy never reaches anyone. Four content types are set explicitly in the Caddy block because the defaults are wrong for this tree, and `serve.mjs` has the same table for the same reasons: `.wasm` (`instantiateStreaming` rejects anything else, so Jolt will not start), `.md` (as `text/plain`, so doc links open instead of downloading), `.gltf`, and `.m4a`. **Never edit helium's `Caddyfile` with `sed -i` or any editor that writes a new file.** Docker bind-mounts a *single file* by inode, so replacing the file orphans the container's view and it silently keeps serving the old config — `caddy reload` will report success while changing nothing. Append with `>>`, overwrite with `cat >`, or recreate the container to re-bind.