# Swapping the placeholder RX-7 for the real mesh (M1) The car is now a **constraint chassis** (springs + steering servos + motor-driven wheels — see `src/shared/Chassis.luau` and `CarManager.buildCarModel`). The placeholder Body/Cabin blocks are just the visual shell riding on that chassis. Making the RX-7 real means **replacing the shell, not the chassis**: weld a MeshPart body onto the `Body` part and hide the placeholder blocks. Nothing else (saving, the allowlist, car switching, driving feel, the map, anti-cheat) needs to change. ## 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-tokyo-wangan-racing/001-1993 Mazda RX-7/ ``` A single downscaled reference is included at `assets/reference/rx7-reference.png` for quick lookups. ## Step 1 — Get a mesh 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 the car **body shell as a single MeshPart** (or a small welded Model with a clear root). Wheels can be separate meshes (see Step 4). Keep the part count low (mobile perf). This step needs Studio — mesh assets upload through Roblox's asset pipeline. ## Step 2 — Store it where the server can clone it Put the shell under `ReplicatedStorage/CarModels/` (e.g. `CarModels/rx7_fc`). 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 — Attach the shell in `buildCarModel` In `CarManager.buildCarModel`, after the Body part is created: ```lua local CAR_MODELS = ReplicatedStorage:FindFirstChild("CarModels") -- inside buildCarModel, after `body` exists: local shellTemplate = CAR_MODELS and CAR_MODELS:FindFirstChild(car.Id) if shellTemplate then local shell = shellTemplate:Clone() -- Position the shell over the body, then weld it on. shell:PivotTo(body.CFrame * CFrame.new(0, SHELL_Y_OFFSET, 0)) for _, p in ipairs(shell:GetDescendants()) do if p:IsA("BasePart") then p.CanCollide = false -- the Body part remains the collider p.Anchored = false end end local weld = Instance.new("WeldConstraint") weld.Part0 = body weld.Part1 = shell.PrimaryPart or shell:FindFirstChildWhichIsA("BasePart") weld.Parent = body shell.Parent = model -- Hide the placeholder blocks: body.Transparency = 1 local cabin = model:FindFirstChild("Cabin") if cabin then cabin:Destroy() end end ``` Cars without a mesh keep the block look automatically — import one car at a time. ## Step 4 (polish) — Real wheel meshes The chassis wheels are plain cylinders (`Wheel_FL` … `Wheel_RR`). To make them look real, weld a wheel MeshPart (CanCollide=false) onto each cylinder and set the cylinder's `Transparency = 1`. The cylinder stays the physics tyre — mesh collision on wheels is unreliable and slow. ## Sizing gotcha The chassis geometry (`Chassis.BODY_SIZE`, `WHEEL_RADIUS`, `TRACK_HALF`, `WHEELBASE_HALF`) is tuned for a ~6×12 stud footprint. Scale the imported mesh to fit the chassis — don't reshape the chassis around the mesh, or the driving feel changes for every car. ## 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).