diff --git a/PROJECT-BRIEF.md b/PROJECT-BRIEF.md new file mode 100644 index 0000000..e364b0f --- /dev/null +++ b/PROJECT-BRIEF.md @@ -0,0 +1,274 @@ +# PROJECT-BRIEF.md — What we're building and where everything is + +> **Read this first, before `CLAUDE.md`.** +> `CLAUDE.md` tells you *how to operate the tools safely*. +> This file tells you *what the game is, why it's built this way, and where the +> resources live*. You need both. +> +> Verified against the live repo, the NAS, and Gitea on **2026-08-06**. Every +> path and number below was checked, not recalled. + +--- + +## 1. The game in one paragraph + +**Tokyo Wangan Racing** is a Roblox night-driving game set on a neon Tokyo +expressway, built around a real 1993 Mazda RX-7 the owner actually owns. It is +modelled on **Tokyo Xtreme Racer**, not on lap-racing games: **Daikoku Futo PA +(the parking area) is the hub.** You park, choose how you want to run, and drive +out onto the Wangan. You never "join a match." + +The core bet: **driving feel is the whole game.** Racing, economy, and +progression are all deliberately deferred until the car is genuinely fun to just +drive around. Do not add game layers on top of a car that doesn't feel good yet. + +### The three modes + +Selected in the PA, armed when you cross the exit gate, ended when you pull back +into the PA. Defined in `src/shared/Modes.luau`. + +| Mode | 日本語 | What it is | Challenges? | Timed? | +|---|---|---|---|---| +| **CRUISE** | 流し | Free roam, bank kilometres, meet drivers | yes | no | +| **DUEL** | バトル | Open a gap and *hold* it — who breaks first | yes | no | +| **TIME ATTACK** | タイムアタック | Solo flying lap, sector splits, personal best | **no** | yes | + +Cruise and Duel both allow challenges, so a cruise turns into a battle +organically. **Time Attack opts out on purpose** so a hot lap is never ruined — +that's a design decision, not an oversight. Don't "fix" it. + +### The circuit + +Closed loop, **~49,400 studs (13.8 km)**, samples evenly spaced 60 studs apart so +the loop closes seamlessly. Roughly a 2:46 lap at 300 km/h. Scale is +**1 stud = 0.28 m**. Coordinates: `+X = east`, `+Z = north`. + +Landmark zones (themed, **not** geographically accurate): Daikoku Futo PA, +Rainbow Bridge, Odaiba (Unicorn Gundam + ferris wheel), Yamate-style tunnel, +Tokyo Tower replica, Tatsumi PA, bilingual green signage (大黒PA, レインボーブリッジ, +お台場, 辰巳PA). + +--- + +## 2. Where you are in the plan + +Source of truth: `docs/ROADMAP.md` and `docs/GDD.md`. Current position: + +- **M0 — drive-only MVP: DONE.** Spawn, drive, switch cars, respawn, persistence. +- **M1 — make driving feel GOOD: IN PROGRESS. This is the current work.** + - done: constraint chassis (springs, prismatic suspension, servo steering, + motor wheels, engine braking), chase camera, two-layer engine sound + - **not done: import the real RX-7 mesh** (`docs/MESH_SWAP.md`) + - **not done: real 13B rotary audio** from the owner's actual car + (`docs/ROTARY_SOUND.md`) — current loops are stand-ins + - **not done: tune accel curve + grip** — needs a Studio playtest +- **M2 — more cars + map polish:** map v3 and ambience done; more meshes pending. +- **M3+ — racing, economy, hardening, traffic AI:** deliberately not started. + +> **M1's exit test:** *the RX-7 is genuinely fun to just drive around.* +> Ship nothing else until that's true. If asked to build a racing/economy +> feature, flag that it's M3/M4 and confirm before starting. + +--- + +## 3. Repo layout and architecture + +Repo: `~/roblox/tokyo-wangan-racing` (Git Bash path on this box). + +**Server-authoritative: clients request, the server decides.** The RX-7 +allowlist and anti-cheat are server-side. Keep the client dumb. + +``` +ReplicatedStorage/Shared src/shared GameConfig, Cars, Circuit, Modes, + Chassis, Remotes, ProfileTemplate +ServerScriptService/Server src/server init.server + managers +ServerScriptService/ServerPackages ServerPackages ProfileStore (Wally) +StarterPlayerScripts/Client src/client HUD, car picker, controllers +``` + +Mapping is declared in `default.project.json` (Rojo). + +| Module | Responsibility | +|---|---| +| `src/server/MapBuilder.luau` | **3,479 lines — the big one.** Procedurally builds the entire expressway, PA, ramps, barriers, signage. | +| `src/server/CarManager.luau` | Spawns the equipped car; enforces the RX-7 allowlist | +| `src/server/ModeManager.luau` | Mode selection, exit-gate arming, mode end | +| `src/server/DataManager.luau` | ProfileStore wrapper — session lock, reconcile, Studio mock | +| `src/server/AntiCheat.luau` | Speed/teleport sanity check — a speed bump, not a fortress | +| `src/server/Ambience.luau` | Atmosphere haze, bloom, 22:00→03:00 clock drift | +| `src/shared/Circuit.luau` | The 1,050-line circuit spline — sample positions, PA geometry | +| `src/shared/Chassis.luau` | Shared chassis tuning constants | +| `src/client/ChassisController.luau` | Drives the chassis client-side (driver owns network physics) | +| `src/client/CameraController.luau` | Damped chase cam, flat horizon, speed FOV kick | +| `src/client/SoundController.luau` | Two-layer engine crossfade + tyre squeal | + +**Cars:** RX-7 (restricted), City Runabout (public default), Silvia S15, Skyline +GT-R R34, stylized hypercar. The **RX-7 is demo-locked** to the owner + his son +via `GameConfig.RX7AllowedUserIds`, enforced in `CarManager` and the `EquipCar` +remote. Stats only affect feel — no prices, no unlocks in the MVP. + +--- + +## 4. Resources you can reach — and how + +### 4a. Live Roblox Studio (this machine, local) + +Two channels, different jobs. **Use [A] to verify what [B] did.** + +``` +[A] MCP bridge -> READ run Luau in the datamodel, screenshot the viewport +[B] Rojo -> WRITE push .luau source into Studio (~1 s) +``` + +- `mcp__roblox_studio__execute_luau` — `datamodel_type` **must be `"Edit"`**, + never `"Server"` (Server edits a throwaway Play copy that dies on stop). +- `mcp__roblox_studio__screen_capture` — Studio's **3D viewport only**. Not the + desktop, not Explorer, not Blender. +- Rojo: `rojo serve default.project.json --port 34872`, then **somebody must + click Rojo → Connect in Studio.** It never auto-connects, and an ESTABLISHED + socket on 34872 is idle heartbeat, *not* a sync session. + +Full operational detail, version pins, and the failure decoder: **`CLAUDE.md`**. + +### 4b. Reference material on the NAS (1.5 GB, verified present) + +Host `unraid-1` (10.10.10.43), reachable over SSH. Base path: + +``` +/mnt/user/data/yy-roblox-games/0-tokyo-wangan-racing/ +``` + +| Folder | Contents (verified counts) | +|---|---| +| `001-original-images/001-1993-Mazda-RX-7/` | **12 files** — the real car, for the mesh swap | +| `001-original-images/002-1993-Nissan-Skyline-GT-R/` | **38 files** | +| `003-google-earth-images/` | **12 files** — `daikoku-futo-01..12.png`, aerial geometry | +| `004-video-reference/` | `aerial/`, `contact-sheets/`, `docs/`, `entrance-routes/` | +| `002-completed-models/` | empty — finished models land here | + +> ⚠️ **The README currently prints a stale path** for the RX-7 reference +> (`001-1993 Mazda RX-7/` with spaces, at the top level). The real path is +> `001-original-images/001-1993-Mazda-RX-7/` with hyphens. Use the real one. + +Copy a file over rather than working blind: +```bash +scp unraid-1:'/mnt/user/data/yy-roblox-games/0-tokyo-wangan-racing/003-google-earth-images/daikoku-futo-01.png' /tmp/ +``` + +### 4c. Reference material committed in-repo + +- `reference/ramps/` — 12 integrity-checked photos of Daikoku/Oi/Heiwajima/ + Shibaura PAs, plus `INDEX.md`, `BUILD_SPEC.md`, and OSM/satellite scripts. + **All CC BY / CC BY-SA — reference-only for shape study. Do not trace directly + into shipped assets without attribution.** +- `docs/daikoku-reference-spec.md` — measured spec for the PA entrance geometry +- `docs/japanese-road-standards.md` — real road-geometry standards +- `docs/CAR_PHYSICS_REFERENCE.txt`, `docs/MESH_SWAP.md`, `docs/ROTARY_SOUND.md` +- `assets/audio/` — current stand-in RX-7 loops (idle / rev / whistle) +- `audio-work/` — raw recordings from real car meets, for the rotary audio work +- `c1_georeference.json` — georeferencing data behind the circuit + +### 4d. Git / CI + +Remote: `ssh://git@git.devlabhq.net:2222/jesse/tokyo-wangan-racing.git` +(self-hosted Gitea on UNRAID-1, SSH key auth already working from this box). + +CI runs on a **self-hosted Gitea Actions runner** (`.gitea/workflows/ci.yml`), +Ubuntu 24.04 job container — rojo's binary needs glibc 2.39. + +### 4e. Existing tooling — check before writing new probes + +`tools/` already holds **109 files, 58 of them diagnostic/verification scripts** +(`diag_*.luau`, `verify_*.luau`, `capture_*.py`, `check_*.luau`). There is a +very high chance a probe already exists for what +you need — `verify_auxlane.luau`, `verify_shared_ramps.luau`, +`check_live_source.luau`, `scripts/verify_map.luau`, and capture helpers for +flyovers/ramps/defects. **Look there first.** + +--- + +## 5. Quality gates — CI enforces all three + +```bash +stylua --check src/ # formatting +selene src/ # lint +rojo build --output build.rbxl # must compile +``` + +Conventions: +- Tunables go in `GameConfig`, not scattered magic numbers. +- Add a save key by adding it to `ProfileTemplate` (auto-reconciles). Never + remove a key without a migration. +- Test in Studio after every server change (ProfileStore uses a mock in Studio). + +--- + +## 6. The things that will bite you + +These are compressed from hard-won experience. The long versions live in +`CLAUDE.md` — but these three matter most: + +### Never regenerate hand-deleted work +**The single most important rule on this project.** If the user deleted +something in Studio, the *source* must honor it or the next rebuild silently +resurrects it — and they will catch it immediately. + +Live example, currently in `MapBuilder.luau`: +```lua +AUX_SUPPRESS_FROM = 525 -- user deleted this aux-lane stretch +AUX_SUPPRESS_TO = 550 +AUX_BLEND = 5 -- smoothstep; a hard cut caused a 26-stud fence jog +``` +**Do not remove that suppression.** Hand-placed assets live in +`workspace.PAProps`, which the builder never touches. Before any rebuild, ask: +*does this regenerate something removed by hand?* + +### Measure before reasoning, and re-measure after +Write a **read-only probe**, get real numbers, *then* form a theory. A code +change is not proof — verify against the bug's signature. Enumerate names, not +just totals: a raw count hides a partial removal. + +### Beat the `require()` cache +After a Rojo sync the datamodel still holds **old bytecode** — no error, no +warning, and you will measure the previous build and believe it: +```lua +local tmp = game.ServerScriptService.Server.MapBuilder:Clone() +tmp.Parent = game.ServerScriptService +local MapBuilder = require(tmp) -- fresh bytecode, guaranteed +``` + +### Verified-good baseline (2026-08-06) — regression-check against these + +| metric | value | +|---|---| +| total parts | 16,788 | +| PAWestSlip | 60 segs, 34.4° total bend, worst 1.4°, 0 kinks >5° | +| PAEastSlip | 60 segs, 30.7° total bend, worst 1.3°, 0 kinks >5° | +| AuxLane parts | 30 — **samples 525–550 deliberately absent (user-deleted)** | +| barrier coverage | 823 samples, 0 unguarded | +| fence jogs >10 studs | 0 | + +### Never fabricate +If Studio is closed, say "Studio is closed." Never invent a screenshot, a part +count, or a measurement you didn't obtain. `{'error': '', 'isError': True}` on +every MCP call means **Studio is closed** — not that your script is broken. +Reporting a blocker honestly always beats a plausible-looking fake. + +--- + +## 7. First five minutes in a new session + +```bash +tasklist | findstr /I "Roblox" # 1. is Studio even running? +claude mcp list # 2. bridge registered + connected? +curl -s http://127.0.0.1:34872/api/rojo # 3. rojo serving? +cd ~/roblox/tokyo-wangan-racing && git status --short && git log --oneline -5 +``` + +Then read `docs/ROADMAP.md` to confirm what milestone is active, and check +`tools/` for an existing probe before writing a new one. + +**Working state as of 2026-08-06:** clean tree, 0 uncommitted files, HEAD at +`dc0df91`. (An older note in `START-HERE.md` warns about "36 uncommitted files" +on the Linux box — that has since been committed and pushed. Trust `git status` +over that note.) diff --git a/README.md b/README.md index fa64bba..e7f2e8e 100644 --- a/README.md +++ b/README.md @@ -102,4 +102,5 @@ the `EquipCar` remote). One function changes: `CarManager.buildCarModel`. Full step-by-step in `docs/MESH_SWAP.md`. Reference photos live on the NAS at -`unraid-1:/mnt/user/data/yy-roblox-games/0-tokyo-wangan-racing/001-1993 Mazda RX-7/`. +`unraid-1:/mnt/user/data/yy-roblox-games/0-tokyo-wangan-racing/001-original-images/001-1993-Mazda-RX-7/` +(12 files). See `PROJECT-BRIEF.md` for the full reference-asset inventory.