Pick a bridge style, span it, load it. The solver propagates the forces through every member — tension blue, compression red. Doing this by hand is an hour of method-of-joints; here it's instant.
A truss is a frame of straight two-force members pinned at the joints. Each member carries only an axial force — pure tension or pure compression, no bending. Given a geometry, a set of supports, and a load, you want the axial force in every member and the deflected shape.
By hand, the tool is the method of joints: isolate a joint, write ΣFx = 0 and ΣFy = 0, solve for the two unknown member forces, march to the next joint. It works, but the bookkeeping explodes — an n-bay bridge has roughly 4n members and you're hand-propagating dependencies across all of them. Three bays and you've lost an afternoon to arithmetic.
The direct stiffness method turns the whole truss into one linear system K u = f. Each member contributes a 4×4 element stiffness (a one-liner in terms of its direction cosines); you scatter them into a global matrix, fix the support DOFs, solve once, and read every member force off the displacement field. The machinery is identical whether the truss has 5 members or 500 — that's the leverage. Your brain picks the geometry and the load; the solver propagates.
Start with a simple parallel-chord Pratt truss, 4 bays, pin support at one end and roller at the other, a single point load at midspan. With your AI pair: write the bar-element stiffness in global coordinates, assemble, apply the supports, solve K u = f, recover member forces from F = (EA/L)(uj − ui)·(c, s). Then let the geometry generator loose — cycle styles and bay counts and watch the force distribution reorganize.
Spec the node/member topology, the DOF numbering convention, and the support handling with your AI pair. Have it draft. Your job is to specify, audit, verify.
Live below. Pick a style, set the span and depth, choose a load. Members color by sign of axial force; thickness scales with magnitude. Toggle the deflected shape to see how it sags.
Switch Pratt ↔ Howe under the center load and watch the colors flip: in a Pratt truss the diagonals run in tension (blue), in a Howe truss they run in compression (red). That's the whole reason Pratt trusses dominate steel construction — slender steel members are happy in tension, prone to buckling in compression. The solver reproduces a design rule you can find in any structures text.
Two DOFs per joint (horizontal + vertical displacement). Each member is a spring along its own axis with stiffness EA/L. The trick is rotating that 1D spring into global x–y coordinates using the member's direction cosines c = cosθ, s = sinθ.
The 4×4 global-coordinate bar stiffness is
k_e = (EA/L) · ⎡ c² cs -c² -cs ⎤
⎢ cs s² -cs -s² ⎥
⎢ -c² -cs c² cs ⎥
⎣ -cs -s² cs s² ⎦
acting on [uix, uiy, ujx, ujy]. Scatter into the global matrix by the four DOF indices of the member's two end nodes.
A 2D truss is stable and statically determinate when m + r = 2j (members + support reactions = twice the joints). Too few members and your stiffness matrix is singular — a mechanism. Don't fight a failed solve; it's telling you the structure can't carry load. Standard support set: a pin (2 reactions) at one end, a roller (1 reaction) at the other.
def bar_k(xi, yi, xj, yj): # 4x4 global stiffness
L = hypot(xj-xi, yj-yi); c=(xj-xi)/L; s=(yj-yi)/L
...
def assemble(nodes, members): ... # scatter into 2N x 2N
def apply_supports(K, f, fixed): ...
def solve(K, f): return np.linalg.solve(K, f)
def member_force(u, member): ... # (EA/L)(u_j - u_i)·(c,s)
numpy.linalg.solve (or
the SPD-aware scipy.linalg.cho_solve) is the right call.
The reference solver is the same Rust crate driving the panel above
— function solve_truss in
solver/src/lib.rs. The
bridge geometry generators (Pratt / Howe / Warren / K) live in this
page's JavaScript, since topology bookkeeping is easier to tweak
there; the Rust side is the pure linear-algebra core.
Note: the reference uses EA = 1 for every member, so the deflection numbers are dimensionless and the force magnitudes are relative. Real design plugs in actual section areas; the machinery is unchanged.
For the dynamic cousin of all this: Beam vibration →