Scope cut: drive-only MVP (remove racing + economy)
CI / quality (push) Successful in 1m1s

Per user direction, the MVP is now simply driving cars on the expressway.
- Removed RaceManager and Economy modules entirely
- Slimmed Remotes to DataUpdated / SpawnCar / EquipCar
- ProfileTemplate now just remembers the last driven car (v2)
- Cars: dropped price/rep/upgrade fields; kept identity + driving stats
- CarManager: stat-based tuning only; RX-7 allowlist via GameConfig.canDrive
- DataManager: assign default car on join; downgrade RX-7 if de-allowlisted
- Client: replaced garage/economy UI with a simple car picker + respawn
- Docs: GDD/ROADMAP/README rewritten for drive-only; added docs/MESH_SWAP.md
- Gates: stylua clean, selene 0/0, rojo builds
This commit is contained in:
2026-07-22 00:11:11 -04:00
parent 5fc03d611d
commit 07a67204ca
14 changed files with 347 additions and 781 deletions
+29 -43
View File
@@ -1,52 +1,38 @@
# Game Design Document — Fast & Furious: Tokyo Expressway (MVP)
## Vision
A progression-fantasy street racer. You start in a humble-but-iconic 1993 Mazda
RX-7 and claw your way up to hypercars on a neon-drenched Tokyo expressway at night.
Easy to pick up, satisfying to grind, fair to spend on.
A neon Tokyo expressway you can cruise at night in cool cars — starting with a
real 1993 Mazda RX-7. The long-term dream is a full street-racing simulator, but
the **MVP is deliberately tiny: just drive.**
## The one-sentence pitch
"Start in the RX-7, own the expressway."
## MVP scope (what's built) — JUST DRIVING
- Spawn on a neon Tokyo expressway at night.
- Drive a car around the highway (built on Roblox's reliable VehicleSeat).
- Switch between cars via a simple "CARS" picker.
- Respawn your car if you flip or fall off.
- The **RX-7 is demo-locked** to the owner + son (Roblox UserId allowlist,
enforced server-side). Everyone else drives the public cars.
- Your last car is remembered between sessions (ProfileStore).
## Core loop (the addictive 60 seconds)
1. **Spawn** on the expressway in your equipped car.
2. **Race** the time-trial down the highway to the finish line.
3. **Earn** cash + reputation for finishing.
4. **Spend** in the Garage: upgrade your current car or buy the next tier.
5. A faster car / better tune makes the next race feel better → back to step 1.
That's it. No racing, no money, no rep, no upgrades, no daily rewards. The point
of the MVP is to get the car feeling good on the road and be testable fast.
Daily rewards + rising rep gates give a reason to come back tomorrow.
## Why this cut
Driving feel is the hardest, most important part of a car game. Everything else
(racing, economy, progression) is worthless if the car isn't fun to drive. So the
MVP nails driving first; the rest is layered on later once it feels right.
## Pillars
- **Progression fantasy** — junker → hypercar, always a visible next goal.
- **Nighttime Tokyo vibe** — neon, speed, style.
- **Fair monetization** — spending accelerates the grind, never buys wins.
- **Server-authoritative** — no exploiting money or unlocking cars.
## Pillars (for the eventual full game)
- Progression fantasy — junker → hypercar (LATER).
- Nighttime Tokyo vibe — neon, speed, style (NOW: the map).
- Fair monetization (LATER).
- Server-authoritative — no exploiting (NOW: allowlist + anti-cheat foundations).
## MVP feature set (what's built)
- 5-tier car catalogue; **RX-7 is the free starter** (Tier 2).
- Drivable cars via VehicleSeat (proven, swap-in real mesh later).
- Procedural expressway map with kill-walls (can't leave the road).
- Garage + Dealership UI: view / buy / equip / upgrade.
- Upgrade system: Engine / Tires / Nitro, cost-scaled with diminishing returns.
- Solo time-trial race with server-validated payouts.
- Reputation gates on higher-tier cars.
- Daily login reward.
- Robust saving via ProfileStore (session-locked, reconciling).
- Basic movement anti-cheat.
## Deferred (see ROADMAP)
Racing, checkpoints, money/economy, reputation, upgrades, customization, daily
rewards, traffic AI, leaderboards, monetization, crews/PvP, full city map.
## Deliberately deferred (see ROADMAP)
Traffic AI, head-to-head/drag racing, car customization cosmetics, crews/PvP,
full city map, mobile-tuned optimization pass, monetization products.
## Economy first-pass numbers (tune freely in `GameConfig`)
- Start: $1,500, 0 rep, own the RX-7.
- Race finish: +$650 (base+win) and +15 rep.
- Daily: +$300, +10 rep.
- Upgrades: base $500, ×1.6 per level, cap level 5 per part.
- Car tiers: Junk $800 → S15 $12k (50 rep) → R34 $45k (180 rep) → Hyper $250k (600 rep).
## Win condition / retention
No hard "end" — the chase up the tiers plus daily rewards and (future) leaderboards
supply the long tail. First-session goal: earn enough to feel one upgrade land
inside the first 10 minutes.
## Cars in the picker
RX-7 (restricted), City Runabout (public default), Silvia S15, Skyline GT-R R34,
and a stylized hypercar. Stats (Speed/Accel/Handling, 0-100) only affect driving
feel — there are no prices or unlocks in the MVP.
+84
View File
@@ -0,0 +1,84 @@
# Swapping the placeholder RX-7 for the real mesh (M1)
Right now every car is a coloured block + a `VehicleSeat` so the game is drivable
today. This is the **one file** you touch to make the RX-7 a real model:
`src/server/CarManager.luau` → the `buildCarModel` function.
Nothing else (saving, the allowlist, car switching, the map, anti-cheat) needs to
change. That's the whole point of isolating model-building in one function.
## Reference photos
The real car's reference photos live on the NAS (too large to commit to git):
```
unraid-1:/mnt/user/data/yy-roblox-games/0-fast-n-furious-sim/001-1993 Mazda RX-7/
```
A single downscaled reference is included at `assets/reference/rx7-reference.png`
for quick lookups.
## Step 1 — Get a model into Roblox
Options, easiest first:
1. **Buy or find a free RX-7 FD model** on the Roblox Creator Marketplace/toolbox,
or
2. **Model it** in Blender from the reference photos and import the mesh
(`.fbx`/`.obj`) via Studio's 3D importer, or
3. Commission one.
You want a single `Model` whose parts are welded together, with a clear "body"
part you can drive. Keep the part count low (mobile perf).
## Step 2 — Store it where Rojo/Studio can clone it
Put the finished `Model` under `ReplicatedStorage` (e.g. a `CarModels` folder).
Two ways to manage it:
- **Simple:** keep it in the Studio place file as a real Instance (not synced by
Rojo). Fine for a single hero car.
- **Version-controlled:** export the model to a `.rbxm` and reference it from the
Rojo project so it lives in git. See Rojo's `$path` docs for `.rbxm` model files.
## Step 3 — Rewrite `buildCarModel` to clone the real mesh
Replace the block-building body of `buildCarModel(car, maxSpeed, torque, turnSpeed)`
with something like:
```lua
local CAR_MODELS = ReplicatedStorage:WaitForChild("CarModels")
local function buildCarModel(car, maxSpeed, torque, turnSpeed)
-- Look up a real model by car id; fall back to the block builder if missing.
local template = CAR_MODELS:FindFirstChild(car.Id)
if not template then
return buildBlockCar(car, maxSpeed, torque, turnSpeed) -- keep the old code as a fallback
end
local model = template:Clone()
-- Ensure it has a VehicleSeat named "DriveSeat" welded to the driving body.
local seat = model:FindFirstChild("DriveSeat")
if not seat then
seat = Instance.new("VehicleSeat")
seat.Name = "DriveSeat"
-- weld seat to model.PrimaryPart, position it in the cabin...
seat.Parent = model
end
seat.MaxSpeed = maxSpeed
seat.Torque = torque
seat.TurnSpeed = turnSpeed
assert(model.PrimaryPart, "Car model needs a PrimaryPart set")
return model
end
```
Keep the current block-builder renamed as `buildBlockCar` so any car without a
real mesh still works. That way you can import cars one at a time.
## Step 4 (recommended, M1) — Move to a real chassis
The `VehicleSeat` is great for "it drives today" but for real suspension/grip,
adopt a proven **constraint chassis** (A-Chassis or a modern equivalent). At that
point `buildCarModel` clones the chassis rig and attaches the RX-7 body to it.
Still one function; still no changes elsewhere.
## Verify
- `rojo build --output build.rbxl` compiles.
- In Studio: Play → you spawn in the real RX-7 → it drives → it saves.
- Non-allowlisted test account still can't select the RX-7 (server enforced).
+40 -42
View File
@@ -1,62 +1,60 @@
# Roadmap — realistic solo-dev plan
This replaces the original doc's optimistic 12-week timeline. It assumes **one
part-time developer learning as they go**. Ship the vertical slice, then layer
polish. Each milestone is independently playable/testable.
Assumes **one part-time developer learning as they go**. The MVP is intentionally
tiny — *just driving* — so there's a fun, testable thing FAST. Everything else is
layered on only after the driving feels good.
> Rule of thumb: the original guide's "weeks" are really "milestones." Expect
> **4–8 months** of part-time work to a polished, launch-ready MVP. That's normal.
> The goal of this order is that you always have something that *runs*.
> Expect **months, not weeks** to a polished full game. That's normal. This order
> guarantees you always have something that runs.
---
## ✅ M0 — Vertical slice (DONE — this repo)
Drive → race → earn → buy/upgrade → **save**. Server-authoritative. Placeholder
RX-7 block car, procedural expressway. Proves the whole stack end to end.
## ✅ M0 — Drive-only MVP (DONE — this repo)
Spawn on the neon expressway, drive a car, switch cars, respawn. RX-7 demo-locked
to owner + son. Cars persist between sessions. CI green on a self-hosted runner.
## M1 — Make it feel good (the real work)
## M1 — Make driving feel GOOD (the real work, do this next)
- [ ] Import the **real RX-7 mesh**; swap `CarManager.buildCarModel` only.
- [ ] Adopt a proven **constraint chassis** (A-Chassis or modern equivalent) for
real suspension/grip instead of the raw VehicleSeat. Do NOT hand-roll physics.
- [ ] Tune driving feel: acceleration curve, grip, camera.
- [ ] Sound: engine loop, boost, tire screech.
**Exit test:** the RX-7 is genuinely fun to just drive around.
See `docs/MESH_SWAP.md` for the exact steps.
- [ ] Adopt a proven **constraint chassis** (A-Chassis or a modern equivalent)
for real suspension/grip instead of the raw VehicleSeat. Do NOT hand-roll
physics.
- [ ] Tune acceleration curve, grip, and the chase camera.
- [ ] Sound: engine loop, tire screech, boost.
**Exit test:** the RX-7 is genuinely fun to just drive around. Ship nothing else
until this is true.
## M2 — Race depth
- [ ] Checkpoints + lap/segment timing (extend `RaceManager`).
- [ ] Personal best times saved to profile.
- [ ] A second race type (drag / point-to-point).
- [ ] Countdown + results screen.
## M2 — More cars + polish (still no racing)
- [ ] Import a few more real car meshes.
- [ ] Better map: more expressway sections, ramps, tunnels, scenery.
- [ ] Day/night, weather mood.
## M3 — Content & progression polish
- [ ] Flesh out the 25-car catalogue across tiers.
- [ ] Car customization cosmetics (rims, wraps, neon) — visual only for MVP.
- [ ] Daily missions (not just login): "win 3 races", "earn $5k".
- [ ] Tutorial for the first 10 minutes.
## M3 — Racing (the first "game" layer)
- [ ] Checkpoints + timing (a new RaceManager — the old one was removed in M0).
- [ ] Personal best times.
- [ ] Simple point-to-point and drag modes.
## M4 — Systems hardening
- [ ] Leaderboards (OrderedDataStore: top rep, fastest times).
- [ ] Anti-cheat pass 2 (validate race times against car stats).
- [ ] DataStore stress test / backup-version restore drill.
- [ ] Performance pass: StreamingEnabled tuning, part budget, mobile test.
## M4 — Progression & economy (only once racing is fun)
- [ ] Money from races, a garage, buying/unlocking cars, upgrades, reputation.
(These systems existed as scaffolding and were cut for the MVP; reintroduce
them deliberately when they have a purpose.)
## M5 — Monetization (only after it's fun)
- [ ] 2× Cash gamepass (the classic first product).
- [ ] VIP membership (daily bonus, cosmetic-only exclusives).
- [ ] Nitro/boost dev-products — **never** pay-to-win on ranked races.
- [ ] Receipt handling via ProfileStore `LastSavedData`.
## M5 — Systems hardening & monetization
- [ ] Leaderboards, anti-cheat pass 2, DataStore backup drill.
- [ ] Performance pass (StreamingEnabled, part budget, mobile).
- [ ] Fair gamepasses/products — never pay-to-win.
## M6 — Traffic AI (deferred hardest system)
- [ ] Start with **spline-following** dummy cars on fixed paths (cheap, no lag).
Only attempt true pathfinding AI if performance allows.
- [ ] Spawn/despawn by distance to keep part count sane.
- [ ] Spline-following dummy cars first (cheap). True AI only if perf allows.
---
## Standing engineering rules
- Every change must pass `stylua --check`, `selene`, and `rojo build` (CI enforces).
- Keep the client dumb: it requests, the server decides. No exceptions for money.
- Add new tunables to `GameConfig`, not scattered magic numbers.
- Every change must pass `stylua --check`, `selene`, and `rojo build` — CI on the
self-hosted Gitea runner enforces all three on every push.
- Keep the client dumb: it requests, the server decides. The RX-7 allowlist and
anti-cheat live server-side.
- Add tunables to `GameConfig`, not scattered magic numbers.
- Add a save key by adding it to `ProfileTemplate` (auto-reconciles); never remove
a key without a migration.
a key without a migration (bump `ProfileStoreName` `_vN` in dev to wipe).
- Test in Studio after every server change (ProfileStore uses a mock store there).