# Project Research Summary

**Project:** REBNO — Rebuild BN Online
**Domain:** Reverse-engineered rebuild of a 2000s-era GameMaker 5.3a real-time multiplayer 2D game on a modern Node+TS / Phaser-or-PixiJS / Fly.io stack
**Researched:** 2026-05-01
**Confidence:** HIGH (overall) — verified against `decomp/wiki/` evidence, `npm view` package versions, current ecosystem docs, and project-internal `CONCERNS.md`

## Executive Summary

REBNO is **three projects glued together by shared TypeScript types**, not one. There is an offline reverse-engineering / extraction pipeline (Stages 1-3) that turns a GameMaker 5.3a `.gmd` blob into structured documentation; a runtime pipeline (Stages 4-7) that is a textbook server-authoritative web multiplayer game (Node 22 + Colyseus 0.17 + Phaser 3.90 + WSS binary frames over Fly.io); and an asset pipeline that converts BMP/MIDI/font assets to web-native formats. The seam between server and client is a single shared `protocol` package; the seam between client prediction and server authority is a shared pure-functional `game-logic` package. Get those two seams right and Stages 6/7 become additive rather than restructuring.

The recommended approach skips the temptation to hand-roll the equivalent of 39dll: **use Colyseus + `@colyseus/schema`** and let the framework handle rooms, state delta sync, matchmaking, and reconnection — the exact set of problems the original BNO server hand-built in GML. For the client, **Phaser 3.90 "Tsugumi"** is the default (closest paradigm match to GameMaker rooms/sprites/tilemaps), with PixiJS as the fallback decided at end of Stage 2. Persistence is **`better-sqlite3` + Litestream to a Tigris bucket** — Postgres is wrong for <50 CCU on a single Fly machine. Auth is **Better-Auth + argon2id** (Lucia is officially deprecated as of March 2025). The MVP gate (two players moving + chatting in one room) needs ~6 message types and a single room implementation; everything else is a breadth expansion onto the same architecture.

The dominant risks are not technical — they are **process**: (1) reaching for modern decompilers (UTMT, Altar.NET) that cannot read 5.3a's no-`FORM`-header XOR+ZLIB layered binary; (2) trying to reverse the 39dll wire protocol from packet captures rather than from the GML `write*` call order which **is** the schema; (3) parsing `.bno`/`.bnb`/`.bnu` save data without first extracting the GML loader's `file_bin_read_*` call sequence; (4) IP/legal exposure from publishing Capcom-derived assets before legal prep is done; and (5) solo-developer burnout across a 7-stage arc. Each is preventable with a documented runbook, but none are forgiving if skipped. The CONCERNS.md plaintext-credentials archive (~298 accounts in `localList.txt`) and the original "Ctrl+E run clipboard as superuser" admin model must NOT be ported faithfully.

## Key Findings

### Recommended Stack

Node 22 LTS server with Colyseus 0.17.10 on top of `ws`, sharing `@colyseus/schema` 4.0.21 binary delta state with a Phaser 3.90 client built by Vite 8 — both halves consuming a `packages/protocol` and `packages/game-logic` workspace via pnpm. Persistence is `better-sqlite3` 12.9 with Litestream replicating to a Tigris S3-compatible bucket on Fly.io. Auth is Better-Auth 1.6.9 + argon2id. See STACK.md for full version pins, alternatives matrix, and Fly.io-specific gotchas.

**Core technologies:**
- **Node 22 LTS + TypeScript 5.6+** — single language across server, client, tools
- **Colyseus 0.17.10 + @colyseus/schema 4.0.21** — subsumes the room/state-sync/matchmaking layer the original 39dll server hand-rolled; saves 6-10 weeks
- **Phaser 3.90 "Tsugumi"** (NOT v4 yet) — closest paradigm match to GameMaker; re-evaluate at Stage 6 start
- **better-sqlite3 12.9 + Litestream** — synchronous API maps to single-tick game loop; near-zero RPO via WAL streaming to Tigris
- **Better-Auth 1.6.9 + argon2id** — Lucia is deprecated March 2025; argon2id is OWASP 2026 #1
- **pnpm workspaces alone** (no Turborepo for 3-package repo)
- **msgpackr 1.11.10** — for ad-hoc messages outside Colyseus schema (chat, RPC)
- **Fly.io single machine + persistent volume + Tigris bucket** — explicit fit for stateful WS server at <50 CCU

**Locked anti-choices:** Socket.IO, Lucia, plain bcrypt for new hashes, Postgres for v1, uWebSockets.js for v1, JSON over WS.

### Expected Features

**Must have (table stakes — MVP gate, P1):** account creation + login with session-token-authenticated WS; movement sync with client-side prediction (local) + entity interpolation (remote) + server reconciliation, server-authoritative validation; room/local chat; single room model with per-player nameplate; disconnect/reconnect handling with grace window; sane error UX.

**Should have (P2, before public access):** account migration with silent argon2 re-hash on first login + weak-password upgrade prompt; multi-room transitions; chat rate limiting (5/5s token bucket); ignore/block; report mechanism; friends list + presence; whispers; account recovery; modernized admin tools (web UI for kick/mute/ban — replacing the original RCE-style server console); wordlist profanity filter; chat history rolling buffer.

**Defer (P3, blocked on Stage 3) / Out:** Defer — full `.bnu` character persistence (schema unknown until Stage 3); message board; emotes; offline DM delivery. Out — voice chat, mobile native, ML anti-cheat, monetization, modding API, 3D/VR, public username changes, AI profanity filter, federation.

### Architecture Approach

REBNO is **three independent pipelines that share a typed contract**: an offline extraction pipeline (`tools/extract-gmd` → `.extracted/` → `docs/extracted-engine` + `docs/extracted-server`); an offline asset pipeline (`tools/asset-pipeline` → `dist/assets/` with content-hashed manifest); and the runtime pipeline (`apps/server` ↔ `apps/client` over WSS binary frames). The shared `packages/protocol` (wire types + codec) and `packages/game-logic` (pure simulation, zero I/O) are the load-bearing seams.

**Major components:**
1. **`tools/extract-gmd`** — TS Node CLI; sequential block parser per `decomp/wiki/03-gmd-format.md`; emits one-file-per-resource trees diffable in git
2. **`tools/asset-pipeline`** — BMP→PNG atlas (sharp), MIDI→OGG (ffmpeg + soundfont), BMP/TTF→WOFF2; content-hashed manifest
3. **`packages/protocol`** — TS message types + binary codec (opcode envelope + msgpack payload); `PROTOCOL_VERSION` constant
4. **`packages/game-logic`** — pure deterministic `step(state, inputs, dt) → state`; runnable in Node and browser identically
5. **`apps/server`** — Node 22 + Colyseus + Fastify; 20Hz fixed-tick per-room loop; Drizzle + better-sqlite3 + Litestream
6. **`apps/client`** — Vite + Phaser/Pixi; loads asset manifest at boot; reconciles when server diff disagrees with prediction
7. **Single-process room model on one Fly machine** — sharding triggers documented (CCU >200, hot room >50, tick >5ms blocking)

### Critical Pitfalls

1. **A1 — Reaching for UTMT/Altar.NET first** (Stage 1) — GM 5.3a has no `FORM` header. Hard-code era-appropriate tool list (GM Decompiler v2.1, GMD-Recovery in WinXP VM, LateralGM) in `decomp/TOOLS.md` at Stage 1 kickoff.
2. **A4 — Reading 39dll wire protocol from packet captures** (Stage 3) — There is no schema; "packet structure = read/write call order" in GML. Procedure: grep every `sendmessage`/`receivemessage` in extracted Master `.gmd`, trace the `clearbuffer; writebyte; writedouble; writestring` sequence — that **is** the packet.
3. **A5 — Treating `.bno`/`.bnu`/`.bnb` as parseable formats** (Stage 3) — Same pattern: meaning lives in GML loader's `file_bin_read_*` call sequence. Do NOT write parsers until Stage 3 produces a documented schema.
4. **B1 + plaintext-password port** (Stage 4 security) — Hard rule: client sends intent, server emits state. NEVER faithfully port plaintext password storage; argon2id from packet 1 with the two-state migration from B5.
5. **B7 — Persistence loss on Fly.io machine restart** (Stage 4 + 5) — Required: SQLite WAL mode, atomic writes, Litestream replication, SIGTERM grace handler. Test with `kill -9` mid-tick on staging.
6. **C7 — "Parity" scope explosion** (Stage 7) — "Parity" must be a closed checklist built from Stage 2/3 outputs and closed at end of Stage 3. Anything not on the list is Stage 8 wishlist.
7. **D4 — IP/legal exposure** — BNO is Capcom-derived. Repo stays private through Stage 7. Verify `legacy/` never pushed; cracked software deleted; deployment URL has no Capcom IP names.

## Implications for Roadmap

The 7-stage plan in `PROJECT.md` is essentially correct and architecturally well-shaped. Research **validates** the staging.

### Phase 1: Stage 1 — Extraction (Foundations)
**Rationale:** Everything depends on extracted artifacts. Setup costs (WinXP VM, tool selection) are Day-0 prerequisites.
**Delivers:** Monorepo skeleton; `tools/extract-gmd`; `.extracted/` tree; `decomp/TOOLS.md`; WinXP VM image documented; per-asset diffable files for all `.gmd` + `.gb1`-`.gb9` backups across all snapshots.
**Avoids:** A1, A2, A6, A7, D6.
**Research flag:** **NEEDS DEEPER RESEARCH** — exact GMD-Recovery / GM Decompiler v2.1 procedure, WinXP VM provenance.

### Phase 2: Stage 2 — Client Analysis (+ Phaser/Pixi Decision)
**Rationale:** Cannot pick the client engine without knowing the feature surface.
**Delivers:** `docs/extracted-engine/`; asset catalogue; **feature-vs-engine matrix** scoring Phaser 3 vs PixiJS; ADR recording the engine decision.
**Avoids:** D3, C1/C2/C3.
**Research flag:** Standard pattern; no external research needed.

### Phase 3: Stage 3 — Server Analysis (Protocol + Save Format + Persistence Decision)
**Rationale:** Most tedious stage with poorest visible-progress feedback (D5 risk). Schema documents are the input to Stage 4.
**Delivers:** `docs/extracted-server/`; reversed 39dll opcode table; `.bno`/`.bnb`/`.bnu` schemas; persistence-layer ADR; **closed parity-feature checklist**.
**Avoids:** A4, A5, C4, C5, C7.
**Research flag:** **NEEDS DEEPER RESEARCH** — GML-grep procedure; canonical-snapshot merge across three drift'd server snapshots.

### Phase 4: Stage 4 — Server Rebuild (MVP Slice)
**Rationale:** First TypeScript code. Architectural seams must land here correctly.
**Delivers:** `packages/protocol` (~6 MVP message types); `packages/game-logic` (movement + collision + room model, pure); `apps/server` (Colyseus + Better-Auth + argon2 + better-sqlite3 + 20Hz fixed-timestep accumulator + heartbeat 15s/10s + per-account-per-message-type token bucket + protocol version byte from packet 1 + SIGTERM grace + WAL+atomic writes).
**Avoids:** B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, Anti-Patterns 1 & 2.
**Research flag:** Standard pattern (Colyseus well-documented).

### Phase 5: Stage 5 — Deploy (Fly.io + CI/CD + Observability)
**Rationale:** Standalone server is shippable evidence (D5 anti-burnout); proves deploy lifecycle before client work begins.
**Delivers:** Multi-stage Dockerfile, fly.toml, Tigris bucket, Litestream sidecar, GitHub Actions push-to-main → deploy, health endpoint, structured pino JSON logs, restore-test runbook.
**Avoids:** B7 tested on staging; Fly WS proxy idle timeout vs Colyseus ping; musl/Alpine native-build for argon2 + better-sqlite3.
**Research flag:** Standard pattern (Fly.io documented this themselves).

### Phase 6: Stage 6 — Client Rebuild (MVP Gate)
**Rationale:** **The MVP gate is THE go/no-go.** Two players, one room, movement, chat. Anything more is scope creep.
**Delivers:** `apps/client` (Vite + Phaser 3.90 or PixiJS per Stage 2 ADR); client-side prediction wrapping `packages/game-logic`; entity interpolation; reconciliation buffer; chat HUD; minimal `tools/asset-pipeline` slice (1 sprite atlas + 1 background); login screen; HiDPI nearest-neighbor + integer scale.
**Avoids:** B10 (NO FPS-style smoothing unless Stage 2 confirmed it), C1, C3, Anti-Pattern 5.
**Research flag:** Standard pattern. **NEEDS RESEARCH IF Stage 2 ADR flips to PixiJS** (then `@pixi/tilemap` + `howler` + scene wiring).

### Phase 7: Stage 7 — Full Parity (Closed-Checklist Expansion)
**Rationale:** Architecture is right when Stage 7 is **additive** to Stages 4-6, not restructuring. Differs from MVP in *breadth* not *architecture*.
**Delivers:** Every item on closed parity checklist marked done/deferred/rejected — full `.bnu` migration; all rooms imported from extraction; all sprites; MIDI→OGG with vintage soundfont; message board; modernized admin web UI; full chat; account recovery; settings.
**Avoids:** C4 (chat command verbatim port), C5 (per-user transactional migration), C6 (rooms imported, pixel-diff verified), C7 (closed-list discipline), D4 (legal-prep gate before any public action).
**Research flag:** **NEEDS DEEPER RESEARCH** — vintage soundfont selection; admin tool design; legal-prep checklist; returning-player retrospective format.

### Phase Ordering Rationale

- **Extract-then-document-then-rewrite is non-negotiable** (D1, D2). No new TypeScript before Stage 4.
- **Server before client** (Stage 4 before 6). Server-authoritative discipline (B1) requires server to exist first.
- **Deploy before client MVP** (Stage 5 before 6). Standalone server is a ship-worthy milestone (D5 anti-burnout).
- **MVP gate before full parity** (Stage 6 before 7). Stage 7 is breadth expansion onto a proven base.
- **Phaser-vs-Pixi deferred to end of Stage 2** (D3). Tool selection is a Stage-2 decision once feature surface is documented.
- **Persistence layer deferred to end of Stage 3.** Research strongly recommends SQLite + Litestream; Stage 3 confirms or surfaces a relational requirement.

### Research Flags

**Phases needing deeper research during planning:**
- **Phase 1 (Stage 1):** WinXP VM provenance, GM Decompiler v2.1 + GMD-Recovery procedure, intermediate-file conventions
- **Phase 3 (Stage 3):** Canonical-snapshot merge across three server snapshots; `.bno`/`.bnu` schema methodology; modernized admin command set
- **Phase 7 (Stage 7):** Vintage soundfont selection; legal-prep checklist; closed-checklist verification with returning players

**Phases with standard patterns (skip research-phase):**
- **Phase 2, 4, 5:** Markdown documentation; Colyseus + Better-Auth + Drizzle + better-sqlite3; Fly.io + Litestream — all well-documented
- **Phase 6:** Phaser + Colyseus tutorials exist (caveat: needs research IF Stage 2 ADR flips to PixiJS)

## Confidence Assessment

| Area | Confidence | Notes |
|------|------------|-------|
| Stack | HIGH | Versions verified via `npm view` 2026-05-01; Lucia deprecation confirmed; argon2id confirmed via OWASP 2026 |
| Features | HIGH for table-stakes/movement-sync; MEDIUM for original-game parity (definitive list comes from Stage 2/3); HIGH for anti-features (already locked) |
| Architecture | HIGH for monorepo/topology; MEDIUM for asset pipeline specifics |
| Pitfalls | HIGH for Sections A & D (direct evidence); MEDIUM for Sections B & C (ecosystem patterns + repo knowledge) |

**Overall confidence:** HIGH

### Gaps to Address

- **`.bno`/`.bnu`/`.bnb` schema unknown until Stage 3.** Parity-feature inventory cannot be finalized until then. Treat parity-critical features as P3 placeholders; finalize at Stage 3 transition.
- **Canonical-snapshot decision** across `enlyzeam-current`, `enlyzeam-archive`, `local-current` unresolved. Explicit ADR in Stage 3.
- **Phaser vs PixiJS deferred to end of Stage 2.** Stage 6 client work is partially research-flagged on this branch. Mandatory feature-vs-engine matrix as Stage 2 deliverable.
- **Legal/IP path not chosen.** Three options (private friends-only / spiritual successor with art replacement / public release as-is) have very different downstream implications. Decision deferred per PROJECT.md, but legal-prep cleanup tasks can begin immediately.
- **Vintage soundfont fidelity** for MIDI→OGG (C2) is a known unknown. Stage 2 catalogues audio; Stage 7 selects soundfont with returning-player A/B verification.
- **Returning-player testing pool** for Stage 7 closed-checklist sign-off (C7). Plan a small private retrospective with explicit "deferred items go to Stage 8 backlog" rule.

## Sources

### Primary (HIGH confidence)
- `.planning/PROJECT.md`, `.planning/codebase/CONCERNS.md`
- `decomp/wiki/03-gmd-format.md`, `08-39dll-networking.md`, `13-modern-tool-incompat.md`, `15-extraction-pipeline.md`, `16-bno-bnb-notes.md`
- npm registry (`npm view`, 2026-05-01)
- Colyseus docs, Phaser 3.90 release notes, Lucia deprecation announcement, OWASP Password Storage cheat sheet, Fly.io SQLite + Litestream guide, Gambetta Client-Side Prediction series

### Secondary (MEDIUM confidence)
- Phaser vs PixiJS comparison; Drizzle vs Prisma 2026; pnpm + Turborepo monorepo guide; WebSocket benchmarks 2026; GetStream chat moderation; Fly.io community on WS sharding

### Tertiary (LOW confidence)
- Inferential parity claims based on legacy artifact filenames (`MB_News`, `MB_Log.bnb`, `Settings.bno`, `Areas_*.bnu`, `,ServerCommands.txt`) — flagged `[parity-inferred]` throughout FEATURES.md; will be validated by Stage 2/3 GML extraction
- Capcom DMCA risk for MMBN fan projects — historical pattern, no current legal opinion in research scope

---
*Research completed: 2026-05-01*
*Ready for roadmap: yes*
