Custom Suspension — Beginner Guide (read this first)
This is the simple, click-by-click version. The deep technical details live in TUTORIAL.md
— you don’t need them to make a suspension. Follow the steps in order.
Building a specific suspension type? There’s a dedicated, illustrated tutorial for each one (MacPherson, double wishbone, multilink, trailing-arm, cantilever/pushrod) in docs/tutorials/. Planned types (solid axle, long-travel, 6×6) are in ROADMAP.md.
What are we even doing?
You’re making a suspension that moves (arms swing, springs squash) on a car in CarX.
The way it works, in plain words:
- You put little invisible markers called bones on each moving part (a wheel hub, an arm, a shock).
- Each rigid mesh part (arm, hub, shock) gets parented to its bone, so when the bone moves the part rides with it.
- Our mod (already installed in your game) grabs the car’s real wheels every frame and moves the bones to match — so your suspension squashes and steers with the car.
You do the markers and labelling in Unity. One-click tools do the hard parts for you.
The whole flow in one picture:
Words you’ll see (don’t panic)
- Bone = an empty GameObject (an invisible marker). You place them where parts move.
- Parenting = making a rigid mesh part a child of a bone, so it rides with it.
- Component (KSusp Bone) = the label you put on a bone to say what it is (its Role).
- Descriptor (.ksusp) = a small file the mod reads to know how to move the bones. A tool makes it.
What you need before starting
- The Kino content SDK Unity project open (open it with Unity Hub — it’s Unity 2023.2.20f1).
- Your suspension 3D model as separate rigid parts (each arm / hub / shock its own mesh).
- The game with the AdvancedSusp mod installed (already done).
If Unity shows a Tools ▸ KSL menu at the top, the tools are installed.
Step 1 — Put your suspension model in the scene
- Drag your suspension model into the Assets window, then into the Scene.
- Click it in the Hierarchy (left panel). This is your mesh object.
Step 2 — Place your markers (locators)
You don’t make bones. You drop empty markers (locators) at the points that matter, and the SDK turns the labelled ones into the skeleton for you (in Step 5). All markers are children of the mesh.
Here’s the pattern for one corner (you’ll repeat it for FL/FR/RL/RR). The idea: a part that swings has a chassis point (where it bolts to the body — stays still) and a hub point (where it meets the wheel — moves). The chassis point will point at the hub point.
- Hub marker — right-click the mesh → Create Empty, name it
FL_Hub, move it (W key) to the centre of the wheel/upright. - Outer points (hub end) — for each spot where an arm or the shock touches the hub, make an
empty as a child of
FL_Hub(right-clickFL_Hub→ Create Empty). Name them e.g.FL_LowerArm_end,FL_UpperArm_end,FL_Shock_low. Being children of the hub, they move + steer with the wheel — these are the Outer Targets the arms point at (Step 3). - Inner pivots (chassis end) — for each arm, make an empty directly under the mesh at the
spot where that arm bolts to the car body. Name them
FL_LowerArm,FL_UpperArm. This is where the arm’s KSusp Bone goes, and it’s the arm’s Inner Pivot (it rotates about this point). - Shock top — make an empty
FL_Tophatwhere the shock bolts to the body. Keep it on the chassis side (NOT under the hub).
Tip: build one corner completely, then copy-paste it and move it to the other three.
Naming convention (recommended)
Names are free-form — the SDK reads the Role + Corner you pick, not the name. But keep each name unique, and a tight convention saves you confusion (and duplicate-name warnings), especially on a multilink with lots of parts. Use this scheme:
Two rules
- Prefix every object with its corner:
FL_FR_RL_RR_. The prefix alone keeps names unique across the car. - Two name shapes:
- the bone that gets the component →
RL_<Part> - the hub point it aims at (its Outer Target, a child of the hub) →
RL_<Part>_end
- the bone that gets the component →
So a part and its target always read as a pair: RL_ToeLink → aims at → RL_ToeLink_end.
Example — one rear (RL) multilink corner
| Object | Name | Component |
|---|---|---|
| upright | RL_Hub |
Hub (SteerCamber) |
| upper link | RL_UpperArm |
Arm → RL_UpperArm_end |
| lower link | RL_LowerArm |
Arm → RL_LowerArm_end |
| trailing arm | RL_TrailingArm |
Arm → RL_TrailingArm_end |
| toe link | RL_ToeLink |
Arm → RL_ToeLink_end |
| camber link | RL_CamberLink |
Arm → RL_CamberLink_end |
| halfshaft / axle | RL_Halfshaft |
Arm → RL_Halfshaft_end (pivot at the diff) |
| coil | RL_Spring |
Shock |
| top mount | RL_Tophat |
(Shock’s Tophat) |
| lower shock mount | RL_Shock_low |
(Shock’s Lower Mount) |
| damper body (if any) | RL_ShockBody |
(Shock’s Body Bone) |
In one line:
RL_<Part>carries the KSuspBone;RL_<Part>_end(underRL_Hub) is the point it reaches; set Corner = RL on every component.
The _end markers and all meshes get no component. The _end target sits under the hub
so it rides with the wheel; the Arm bone sits at its chassis bushing (Inner Pivot = self).
Whatever you name them, the Corner dropdown is what actually maps a marker to its wheel.
Where each marker goes (front-left corner):
Step 3 — Label each marker (add KSuspBone, pick a Role)
There’s just one component. Click a marker → Add Component → KSusp Bone, then set the Role and Corner dropdowns. The Inspector shows only the fields that role needs and explains each one — no looking anything up.
⚠️ Two components — don’t mix them up:
- KSusp Bone → goes on every marker (hub, arm, shock). It has the Role dropdown.
- KSuspension Root → goes on the single top object only (Car Id + Setup Name). If the Inspector shows Car Id / Setup Name, you’re on the root, not a marker.
Names are free, but use the convention above (
RL_<Part>/RL_<Part>_end). The SDK reads the Role + Corner you pick, not the name — names just need to be unique. Sticking to the scheme keeps a big multilink readable and avoids duplicate-name warnings.
| The marker is… | Role | Then set |
|---|---|---|
| the hub / upright | Hub | Corner; Wheel Rotation = SteerCamber (steer + camber, no spin — the default) |
| an arm / link / tie rod / pushrod / rocker | Arm | Corner; Inner Pivot (chassis end — leave empty to use this marker’s spot) + Outer Target (the hub point it follows) |
| a shock / MacPherson strut | Shock | Corner; Tophat, Lower Mount (a hub point), Body (strut tube) / Spring bones, Axis |
| a brake / rotor bolted to the hub | RidesWithHub | Corner only |
- The single top object gets KSuspension Root (set Car Id + Setup Name).
- Outer-target markers (the hub points arms point at) need no component.
MacPherson note: use ONE Shock for the whole strut — assign the coil to Spring Bone and the strut tube to Body Bone (both get anchored at the Tophat and aim down at the Lower Mount). Do NOT set the strut tube to RidesWithHub — that rigidly rotates it with the hub and its top detaches from the fixed Tophat. Keep the Tophat on the body, not under the hub.
You don’t arrange anything into folders — each KSusp Bone already knows its corner.
What to set on each marker (mock Inspector):
Step 4 — Let the SDK organize it (one click)
- Top menu: Tools ▸ KSL ▸ Build Rig Hierarchy.
- Drag your rig root (the top object holding all the bones) into Rig root.
- Click Build Hierarchy.
It creates a neat tree (Root → Front/Rear → FL/FR/RL/RR), tucks every bone into its corner, and parents the RidesWithHub markers under the hub. You’ll see it reshuffle in the Hierarchy. (This is optional tidy-up — Attach Parts and Bake work either way.)
What the Hierarchy should look like afterwards:
Step 5 — Attach the parts to the bones (one click)
A suspension is rigid metal, so there’s no skinning — each part just rides with its bone.
- Tools ▸ KSL ▸ Attach Parts to Bones.
- Parts root = the group with your mesh pieces (e.g.
SUSP_LF). Bone root = the rig root. - Click Attach Parts. Each part is parented under its nearest bone. Check the printed list and drag any part that landed on the wrong bone.
Either way: now moving a bone in the Scene should move the suspension. Try the rotate tool on a bone, then Ctrl+Z to undo.
Step 6 — Make the descriptor file (one click)
First click your rig root, and on the KSuspensionRoot component set two things:
- Car Id = your car’s ID (the same number your chassis
.knppis bound to). - Setup Name = a short name for this version, e.g.
drift(so you can have several per car).
Then:
- Tools ▸ KSL ▸ Bake Suspension Descriptor.
- Drag the rig root in → Bake → save it. It makes a
.ksuspfile (e.g.drift.ksusp).
This little file says which car it’s for and how your suspension moves — both baked inside.
Step 7 — Put it in your chassis and build the part
You’re importing this as part of your CustomChassis in the SDK:
- Make your suspension a child of your chassis prefab (so it ships with the chassis).
- Build the chassis the normal SDK way (the CarParts tool → it makes a
.knpp). - Install that
.knpplike any custom chassis.
Step 8 — Put the descriptor in the game folder (the easy way)
Just copy your .ksusp file (e.g. drift.ksusp) into:
…\CarX Drift Racing Online\kino\suspensions\
That’s it — no renaming, no config file. The car ID is baked inside the file, so the mod knows which car it’s for.
Several setups for the same car? Drop them all in (e.g. drift.ksusp, grip.ksusp,
v2.ksusp). They won’t clash — the mod automatically picks the one whose bones match the
chassis you actually loaded.
Don’t know the car ID? Load the car in-game and look at the KSL log — the mod prints
(carId 42) for whichever car you’re in. Put that number in the rig root’s Car Id field
(Step 6) and re-bake.
Want explicit control with a config file? (optional)
Make `kino\suspensions\config.json`: ```json { "suspensions": [ { "carId": 42, "descriptor": "kino/suspensions/drift.ksusp" } ] } ``` Config entries win over the auto-scan. Use `"carId"` (precise) or `"car"` (name match).Step 9 — Play and check
- Launch the game, load that car.
- Open the KSL menu, find AdvancedSusp, make sure Enable swap is on.
(If you edited
config.jsonwhile the game is running, click Reload config.) - Drive over bumps / steer — the arms and spring should move.
If it’s not working
Open the KSL log (the dev console) and look for lines starting with
[ASM.Dumper]. They tell you exactly what happened:
| You see / it does | Likely fix |
|---|---|
| “Could not locate the player’s car” | Be loaded into a car (not in a menu). |
| “applied custom suspension to…” but nothing moves | A bone name in the descriptor doesn’t match the bone in the model — re-bake (Step 6) after any rename. |
| An arm spins like a wheel | On its hub’s KSusp Bone (Role Hub), set Wheel Rotation = SteerCamber (or SteerOnly), re-bake. |
| Hub has no camber | Hub is on SteerOnly (flat yaw) — switch it to SteerCamber, re-bake. |
| Spring doesn’t squash | On the Shock KSusp Bone, the Axis is wrong, or Tophat/Lower Mount are swapped. |
| Strut top detaches from the tophat | Put the strut tube on the Shock’s Body Bone, not RidesWithHub; re-bake. |
| An arm pivots from the wrong spot | Set its Inner Pivot to the chassis-end marker (Step 3). |
| Suspension is too wide/narrow | The hub bones aren’t following — check the Hub KSusp Bone is on the hub and the Corner is right. |
When in doubt: re-run Build Hierarchy → Attach Parts → Bake, then Reload config in-game.
The whole thing in 9 clicks
- Drop model in scene → 2. Place empty markers on the parts → 3. Add KSusp Bone + pick
Role + Corner on each → 4. Build Rig Hierarchy → 5. Attach Parts → 6. set Car Id +
Bake the
.ksusp→ 7. Put it in your chassis & build the.knpp→ 8. Drop the.ksuspinkino\suspensions\→ 9. Play.