Files
tokyo-wangan-racing/PROJECT-BRIEF.md
T
jesse 74899a7197
CI / quality (push) Failing after 51s
docs: PROJECT-BRIEF.md — game/design/resource orientation for Claude
CLAUDE.md covers tool operation; this covers what the game IS, where it
sits in the roadmap, and where reference assets actually live.

Also fixes a stale NAS path in README (RX-7 reference dir is
001-original-images/001-1993-Mazda-RX-7, not a top-level spaced name).
2026-08-06 09:35:05 -04:00

275 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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://[email protected]: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.)