The solver takes the nine hardpoints of a double-wishbone corner, plus an optional pushrod, rocker and damper. It shows how the wheel moves through bump, roll and steering, what the spring and damper see, and how hard each tube is loaded. Every number updates as you type.
.json file to your computer (in Chrome or Edge you choose where, and later saves go back to the same file). Keep it in your team's private folder and load it again with Open ▾. The app also remembers your last edits in that browser.Viewing controls: drag to orbit, right-drag or shift-drag to pan, scroll or pinch to zoom. The Front, Side and Top buttons give standard views, and Display ▾ turns on the roll-center lines, the other side of the car and joint names.
private/ folder of your copy of the code (Git ignores it).targets, or in one shared team_targets.json that designs point to with "targets_file". In the app, open that targets file with Open ▾ to apply it to the design on screen.git status should list no JSON outside designs/.The tabs above the work area pick what you are working on, and each shows how many of its targets are met. Front corner and Rear corner each edit one corner. Car (the default) puts both together:
Do you need a bar? Not always: the example car's springs alone already give a stiff roll gradient, but its LLTD sits below the front weight share, so it runs a front bar purely for balance. Pushrod or pullrod is a packaging choice: a pushrod (rod in compression, rocker and damper up high) is easier to package and service; a pullrod (rod in tension, so it can be thinner with no buckling risk; rocker and damper low) lowers that mass and frees space up top, but is harder to reach. The solver handles both: put the rod on the upper wishbone for a pullrod.
New to suspension? These tools explain each number on your own design, not on a textbook car.
Click Learn ▾ → Challenges (top right) for short exercises on the case-study car: Lift the roll center (move the four inboard pivots) and Kill the bump steer (move the tie-rod ends). The inputs column becomes a challenge panel and the results area shows only your goals as curves (Show full results brings the tabs back). The panel has the brief, live goal meters, only the points you may move, and three hints, all computed by the solver from your current geometry. Hint 1 explains the idea and draws it. Hint 2 is a live table of simple moves (for example "lower arm up 5 mm"), each shown in the direction that helps the goal furthest from target, best first, with how far you would have to move it. "Not alone" means that move helps but cannot finish the job by itself. Green cells get closer to target, red further away. Hint 3 tries every single move and pair of moves at 1 to 4 steps each way and suggests the best next step, which you can preview. It is a plain search with the solver, not AI. "What moves this?" is turned off during a challenge, and hint 3 unlocks the influence panel. Stars: one for meeting the goals, one for the bonus, one for moving no more than par. Your own design comes back when you exit.
The Compare tab puts up to four saved designs next to the live one. Save the design on screen, add an example, or open design files. You get every target with the change from a reference you pick, the hardpoints that differ, overlaid curves, and colored ghosts in the 3D view. Copy table (CSV) pastes into a spreadsheet. Saved designs stay in your browser only.
Each stage changes things the earlier stages fixed, so work in this order and recheck everything after each one.
| Stage | Points you move | What it sets |
|---|---|---|
| 0. Package the wheel | Ball joints, contact patch, tie-rod outer | Caster, KPI, scrub, trail, steering arm. Fixed early by the upright and wheel; the solver only checks them. |
| 1. Inboard pivots | Upper and lower inboard Y and Z | Roll-center height and movement, camber gain, anti-dive or anti-squat |
| 2. Tie rod | Tie rod inner end Y, Z and outer end Y, Z | Bump steer (height = slope, length = curve), Ackermann |
| 3. Pushrod, rocker, damper | Rocker points, damper mount | Motion ratio, ride frequency, damper stroke use, packaging |
| 4. Loads and whole car | Tube sizes, springs, anti-roll bar | FOS of every member, rod-end loads, roll gradient and balance |
This is the real design history of the app's example car. Each step is in the app's design menu (Case study 1 to Case study 4), so you can load it and follow along. We used the optimizer to save time, but each pass moved only one group of points for one purpose. That is the same discipline as changing one coordinate by hand.
The team's goals for this car are stored in each design's targets:
| Goal | Range | Why |
|---|---|---|
| Roll-center height | 25 – 60 mm | Enough geometric load transfer to limit roll, not so much that the car jacks. |
| Roll-center sideways movement | ±20 mm/deg | A roll center that wanders sideways makes the balance change mid-corner. |
| Camber gain | 0.35 – 0.7 deg/in | Recovers some camber in roll without big camber swings over bumps. |
| Anti-dive | 5 – 20 % | A little anti-dive steadies braking; too much stiffens and numbs the front. |
| Ackermann | 10 – 40 % | Moderate Ackermann for tight FSAE corners. |
| Bump steer | ±0.03 deg/in, max 0.05° | The wheel should not steer itself over bumps. |
| Ride frequency | 3.0 – 4.0 Hz | A common FSAE window for a car without big aero loads. |
The ball joints, wheel and contact patch came from packaging the upright inside a 13-inch wheel, which made the steering-axis numbers good from the start: caster 5.4°, KPI 4.9°, scrub 18.4 mm, trail 17.9 mm. The inboard pivots were placed by eye at round numbers. The problems were plain:
| Check | Value | Goal |
|---|---|---|
| Roll-center height | 5 mm | 25 – 60 |
| Roll-center movement | −387 mm/deg | ±20 |
| Camber gain | 0.87 deg/in | 0.35 – 0.7 |
| Anti-dive | −1.1 % | 5 – 20 |
| Bump steer | 1.59 deg/in (1.9° max) | ±0.03 |
| Damper room at full bump | 1.4 mm | ≥ 2 |
| Gap between the two dampers | 52.8 mm | ≥ 60 |
A roll center near the ground that also moves 387 mm per degree is the classic sign of nearly parallel arms of similar length, so the inboard pivots come first.
Goals for this pass: roll-center height, camber gain, anti-dive, and roll-center movement. We moved only the eight inboard pivot Y and Z coordinates:
| Point | Change | Effect |
|---|---|---|
| All four inboard pivots, Z | +25 to +38 mm | Raised the arm planes, lifting the roll center to 35 mm |
| Front vs rear pivot heights (side view) | different Z rise | Tilted the side-view swing arm: anti-dive −1.1 → 8.0 % |
| Upper inboard pivots, Y | +28 mm (outboard) | Shorter upper arm |
| Lower inboard pivots, Y | −33 mm (inboard) | Longer lower arm |
The short-upper, long-lower arm pair is what stopped the roll center wandering: −387 → −0.2 mm/deg. The front-view swing arm grew from 2.0 m to 3.3 m, so camber gain fell to 0.45 deg/in, and the outer tire now leans with the body 0.81° per degree of roll.
Goals for this pass: zero bump-steer slope, zero bump-steer curve, Ackermann near 18 %. We moved only the tie-rod ends:
| Point | Change |
|---|---|
| Tie rod inner / outer end Z | +5.8 / +8.3 mm |
| Tie rod inner / outer end Y | −17.0 / +7.1 mm |
Bump steer went from 0.094 deg/in to 0.000, with under 0.001° of toe change over ±30 mm. Ackermann fell from 33 % to 18 %, and the outer wheel's turning radius at full rack is 3.49 m.
The damper is a common 200 × 57 mm size (eye-to-eye × stroke). The rocker pivot and pushrod mount stayed where the chassis and arm put them. Only the two rocker arms and the damper's chassis mount moved, each by under 5 mm. The goals and results:
| Quantity | Before | After | Aim |
|---|---|---|---|
| Motion ratio (damper / wheel) | 0.822 | 0.804 | ≈ 0.80 |
| Motion ratio change over travel | +8.3 % | +5.2 % | slightly rising |
| Damper position at ride height | 50 % | 50 % | ≈ 50 % of stroke |
| Room at full droop / full bump | 4.5 / 3.5 mm | 4.8 / 4.2 mm | ≥ 2 mm |
| Worst rocker transmission angle | 68° | 72° | ≥ 65° |
| Gap to the other side's damper | 52.8 mm | 61.0 mm | ≥ 60 |
The Spring & damper tab then gives the spring: 52.5 N/mm (about 300 lbf/in) for a 3.5 Hz ride frequency at this motion ratio.
Strength. The Loads tab checks bump, cornering (outer and inner wheel), braking and combined braking and cornering. Braking force is shared front to rear by the brake bias (60 % front here), the same split the anti-dive figure uses. In the Car view the lateral load transfer is split by the car's own roll balance instead of the weight split. With 5/8 × 0.035 in 4130 tubes, the lower wishbone leg to the pivot at X = −230 takes 1936 N of compression in braking plus cornering against a 10 600 N buckling load (FOS 5.5). The hardest-worked part is the pushrod: 4.0 kN in a 4 g pothole, buckling FOS 3.6 against the required 2.0. Pick rod ends rated well above the "worst |force|" column. A 3 g bump would push this wheel past full bump on its spring, so the bump and pothole cases are also solved at full bump, where the arms sit at a different angle; both results count.
Impacts and the pushrod mount. Two more cases, a 4 g pothole and a 2 g curb strike, show how much harder an impact is on the parts than normal driving. Below the table, Pushrod mount bending checks the wishbone leg the pushrod sits on: the pushrod lands 17 mm off that leg's centerline, so the leg bends like a beam. In the pothole case the bare tube would reach about 720 MPa, FOS 0.60. The fix is a gusset or bracket that carries the pushrod into the ball-joint node, not a bigger tube, so the final design uses a bracket into the node (Loads & materials → Pushrod mount): FOS 5.8. Check that bracket in FEA with Export → Part loads for FEA. Rod ends and bolts then compares each member's worst force with your rod end's catalog rating and the bolt's shear capacity.
Compliance. Last on the Loads tab: every link stretches a little under load (rod ends, tube and chassis tab in series, about 6.5–7 kN/mm each here). In 1.6 g braking the front wheel toes out 0.12°, inside the 0.15° limit; a softer chassis tab would push it over. The rod-end and tab stiffnesses are estimates, so measure yours if the result is close to the limit.
Balance. With the matching example rear (3.6 Hz, 75 N/mm springs), the whole-car check
(python3 susp_solver.py car designs/example_front.json designs/example_rear.json) gives 0.72 deg/g of roll from the springs
alone. But only 44 % of the lateral load transfer is at the front, against 47 % of the weight on the front. That leans the car toward
oversteer. The tool's fix: a front anti-roll bar of about 190 Nm/deg, or softer rear springs.
| Metric | 1 · Draft | 2 · Pivots | 3 · Tie rod | 4 · Rocker |
|---|---|---|---|---|
| Checks passed | 12 / 20 | 17 / 20 | 19 / 20 | 20 / 20 |
| Roll-center height, mm | 5 | 35 | 35 | 35 |
| Roll-center movement, mm/deg | −387 | −0.2 | −0.2 | −0.2 |
| Camber gain, deg/in | 0.87 | 0.45 | 0.44 | 0.44 |
| Anti-dive, % | −1.1 | 8.0 | 8.0 | 8.0 |
| Bump steer, deg/in | 1.594 | 0.094 | 0.000 | 0.000 |
| Ackermann, % | 33 | 33 | 18 | 18 |
| Motion ratio | 0.882 | 0.822 | 0.822 | 0.804 |
| Damper gap, mm (need 60) | 52.8 | 52.8 | 52.8 | 61.0 |
| Lowest strength FOS | 4.4 | 3.7 | 3.7 | 3.7 |
The built-in ranges are deliberately broad. They catch clear mistakes, but passing them does not make a design good. Set your own team's goals as in the case study above.
| Metric | Front default | Rear default | What moves it |
|---|---|---|---|
| Static camber | −3.0 to −0.5° | −3.0 to −0.5° | Shims at the upright; easy to change later |
| Camber gain | 0.2 – 1.0 deg/in | 0.2 – 1.0 deg/in | Front-view swing arm: shorter = more gain |
| Caster / KPI | 3 – 8° / 0 – 9° | – | Ball-joint positions in side / front view |
| Scrub / trail | 0 – 30 / 5 – 30 mm | – | Steering axis vs contact patch |
| Static toe | −0.5 to +0.25° | 0 to +0.5° | Tie-rod length; set at alignment |
| Roll-center height | 0 – 75 mm | 0 – 100 mm | Inboard pivot heights |
| Anti-dive / anti-squat | 0 – 40 % | 0 – 60 % | Side-view tilt of the pivot axes |
| Ackermann | 0 – 100 % | – | Steering-arm angle and rack position |
| Bump steer | ±0.05 deg/in, max 0.10° | same | Tie-rod height (slope) and length (curve) |
| Ride frequency | 2.5 – 4.5 Hz | 2.5 – 4.5 Hz | Spring rate × motion ratio² |
| Damper stroke, transmission angle, clearances | physical limits | Rocker geometry, damper choice, tube sizes | |
Change any range in the Targets tab (it is saved in the design's JSON), or load your team's targets file with Open ▾.
The team frame is ISO 8855: X forward, Y left, Z up, in mm from the ground under the front axle, on the
centerline, with each corner entered as the left-hand one (Y positive). Build the CAD model around a coordinate system placed the same way.
If the input checks complain about the ball joints or the contact patch, the axes are mapped wrongly: Points from CAD (or the command-line
import --map option) fixes that.
The app names each inboard pivot by where it sits on the car (front = larger X). The JSON keys
follow KineSolver, where upper_inboard_front is the pivot with the smaller X: physically the rear one. This only matters
when editing a JSON file by hand.
Every change to the wishbones changes bump steer. Tune the pivots first, then the tie rod, then check again.
Links usually collide at full droop with full lock. The Packaging tab checks every combination of full droop, ride height and full bump with full left lock, center and full right lock.
Damper stroke and length decide how much wheel travel you can have. Choose the damper before you lay out the rocker.
Use the whole-car check before choosing springs and anti-roll bars.
Every change to the solver is tested automatically on GitHub before it reaches this site:
Not yet checked against an outside source: loads, ride and the whole-car balance (they are checked by physics identities only). If you have results from another tool or from your car on a rig, add them to the validation/ folder (instructions inside). They are then checked on every change.