workshop private

← all creations

Loose

mechanics · created 2026-10-02

A counterweight trebuchet, where the only control worth having is the angle at which the sling's loop leaves the release pin — and it does not throw the stone, it points it. Across 130° of dial the launch direction follows the pin to within 0.69° of a straight line while the release speed moves 13.9%, so range against pin is a hump, and every range short of its 201.08 m peak has exactly two settings: 25.5° apart at 180 m, 61.5° apart at 100 m. The top of the hump is symmetric to 0.11% out to ±10° either way, so a short shot tells you nothing about which way to turn. 45° is wrong twice over — releasing 8.05 m up takes 1.12° off it and buying loft with speed takes another 3.98° — and the best shot leaves at 39.90°. Then the counterweight: the same half tonne bolted to the arm instead of hung from it releases 2.74× as much energy and throws 38.5% shorter, because 75.9% of that energy is still in the weight when the stone goes, and four times the bolted mass still only reaches 143.6 m against 201.1.

physicssimulationcanvasgame-feel

A trebuchet has no sights, no elevation screw and no powder charge. It has a bent nail.

The nail is the release pin: a finger on the end of the throwing arm with the sling’s open loop dropped over it, and the loop slides off when the sling has swung round to the finger’s angle. Bend the finger and you change when the stone goes, which is the only decision in the machine. Everything else — counterweight, arm ratio, sling length — is decided before the siege starts and cannot be touched between shots.

So this is a mechanic about one number, and the interesting thing about that number is that it behaves nothing like a dial should.

What is actually being solved

src/loose.mjs is three rigid bodies and three angles: the beam about its axle (θ), the counterweight hanging on its link (φ), and the sling (ψ), all measured from straight down. The kinetic energy is exact —

2T = (I + M b² + m a²) θ̇²  +  M c² φ̇²  +  m L² ψ̇²
     − 2 M b c cos(θ−φ) θ̇φ̇  +  2 m a L cos(θ−ψ) θ̇ψ̇

— so the mass matrix and the forcing come out of the Lagrangian in closed form and nothing is differentiated numerically. The stone starts in a trough on the ground, which is a one-sided constraint y = 0 carried as a multiplier and dropped the instant the ground would have to pull down instead of push up. A rigidly bolted counterweight is the same code with b → b+c and c → 0, one degree of freedom cheaper.

The machine as shipped: a 4 m beam on a 2.9 m axle, 3 m of throwing arm against 1 m of short arm, 500 kg on a 1 m link, a 5 kg stone on a 3.2 m sling, cocked with the arm 25° off straight down and its tip 181 mm above the ground.

Before believing any of it, scripts/measure.mjs checks the things a wrong model gets wrong:

checkresult
energy drift over the whole throw2.3e-13 of the total
trough constraint y = 0 while the stone is downheld to 2.2e-14 m
energy ledger at release closesto 5.6e-14
minimum sling tension (a rigid link may only pull)+95.9 N
range, integrator step 1e-3 s against 5e-5 sdiffers by 0.1 mm

Release is refined by bisection down to the exact pin angle rather than whatever the fixed step happened to land on, because the whole piece is that one number and it must not be quantised by the integrator.

The pin points; it does not throw

Sweep the pin from −90° to +40° and the launch direction sweeps 129.9°, almost exactly one for one:

launch = −1.0131 · pin − 13.36 degrees      worst residual 2.32°

and over −80° … 40°, which is the part of the dial where the machine is really throwing forward rather than straight up, that residual is 0.69° over 120° of travel. Meanwhile the release speed moves from 38.02 to 46.07 m/s — 19.2% across the whole dial, 13.9% across the useful part.

pinrange (m)release speedlaunchreleased at
−80°115.240.10 m/s67.4°6.08 m up
−60°193.343.17 m/s47.7°7.61 m up
−50°200.444.18 m/s37.6°8.16 m up
−30°142.945.43 m/s17.4°8.85 m up
−10°52.745.98 m/s−3.0°9.03 m up
+20°14.545.94 m/s−33.8°8.40 m up

A trebuchet is a fixed-power cannon with a free turret. Nothing you can reach decides how hard the stone is thrown; the pin decides where it is pointed.

Which means two settings for every range but one

Point something at a fixed speed and the range is a hump. The peak here is 201.08 m at a pin angle of −52.25°, and every range short of it is reachable twice:

rangelofted pinits launchflat pinits launchapart
80 m−87.5°73.7°−17.0°4.1°70.5°
120 m−79.0°66.5°−25.5°12.8°53.5°
180 m−65.0°52.7°−39.5°27.0°25.5°
195 m−59.0°46.7°−45.5°33.1°13.5°

That is the mechanic, and it is nastier than it looks, because the top of the hump is not just flat, it is symmetric:

off the best pin±1°±2°±3°±5°±10°
range cost0.07%0.27%0.60%1.6%6.4%

The two sides agree to within 0.11% of the range out to ten degrees either way. Two effects are cancelling: turn the dial one way and the stone goes higher but slower, turn it the other and it goes flatter but faster, and near the peak those trade almost exactly. So a stone landing 15 m short is 15 m short in both directions at once. The artillery habit — it fell short, so give it more — is a coin flip, and following it with conviction walks the shot steadily away from the target. The demo lets you do exactly that, and then lets you measure the dial and see what you were doing.

45° is wrong, twice

The schoolbook answer for maximum range is 45°. The best shot this machine can take leaves at 39.90°, and the gap is two separate things stacked:

flat ground, free choice of angle          45.00°
same speed, but released 8.05 m up         43.88°    (would carry 202.90 m)
what the machine actually wants            39.90°    (carries 201.08 m)

The first 1.12° is ordinary: you are throwing from the top of a swing, 8 m up, and launching downhill always wants a flatter angle. The remaining 3.98° is the part you cannot calculate from the projectile alone — in this machine extra loft is not free, it has to be bought by releasing earlier, and releasing earlier costs release speed. The optimum lands where the two stop paying for each other. The machine gives up 1.82 m — 0.90% — to that coupling, which is the price of having a turret that is welded to the gun.

Where the counterweight’s energy goes

At the moment the stone leaves, the counterweight has given up 7749 J. The beam immediately takes 1120 J of that straight back, lifting its own throwing arm — 14.5% of the drop spent on the machine raising part of itself. What is left in play is 6629 J:

destinationjoulesshare
stone, kinetic483572.9%
stone, lifted to 8 m3956.0%
counterweight, still moving96514.6%
beam, still turning4356.6%
unaccounted−3.7e-10−5.6e-14

Quoted the usual way — stone kinetic energy over the counterweight’s own drop — that is 62.4%.

The sling is what does it. The arm tip never exceeds 22.50 m/s in the whole throw and the stone leaves at 43.98 — 1.95× the fastest the arm ever went. At the instant of release the tip is down to 7.48 m/s, nearly six times slower than the stone: the arm has finished its work and handed everything to the line. And 46.4% of the 1.025 s throw happens before the stone has even left the trough — 0.475 s of being dragged along the ground while the arm swings from 25° to 65°.

The hinge is worth more than the counterweight

Bolt the same half tonne rigidly to the arm instead of hanging it from a hinge, change nothing else, and re-optimise the pin:

counterweightbest pinrangeenergy released→ stone→ still in the weight
hinged−52.2°201.1 m6629 J72.9%14.6%
bolted−52.5°123.7 m18131 J16.6%75.9%

The bolted machine releases 2.74× as much energy and throws 38.5% shorter. It is not short of energy; it cannot get rid of it. A bolted weight is dragged around the arm’s circle and is still travelling fast when the stone goes, so three quarters of everything it gave up leaves with the machine instead of the stone. A hinged weight falls nearly plumb, arrives at the bottom, and stops — which is precisely how it hands its momentum over.

And you cannot buy the hinge back with mass:

bolted counterweight500 kg750 kg1000 kg1500 kg2000 kg
best range123.7 m132.1 m136.6 m141.2 m143.6 m

Four times the weight, bolted, reaches 143.6 m. Five hundred kilos on a hinge reaches 201.1.

Nothing on this machine can be tuned on its own

The sling wants to be about 1.07× the long arm, and every time you move it the best pin angle moves tens of degrees with it:

sling2.4 m2.8 m3.0 m3.2 m3.6 m4.0 m4.4 m
of the arm0.80×0.93×1.00×1.07×1.20×1.33×1.47×
best pin−44.3°−47.0°−49.3°−52.3°−60.0°−71.0°−85.8°
best range149.5186.4196.6201.1194.2169.9133.5
range at the old best pin143.2183.1195.5201.1186.3131.856.6

That last row is the whole warning. Lengthen the sling from 3.2 m to 4.0 m because longer slings throw further, leave the pin where it was, and the machine goes from 201 m to 132 m — worse, while being improved. Past 1.47× of the arm the sling goes slack before release, and the model says so by demanding a negative tension in a link that can only pull: those shots are reported, not believed.

One more thing falls out of the short end. The sling-to-arm angle normally climbs straight through the whip, so a pin angle picks one moment. Shorten the sling enough and it crests, falls back, and climbs again — and a pin set a quarter of a degree past that crest misses it entirely and waits for the next one:

sling2.0 m (0.67×)2.4 m (0.80×)2.8 m (0.93×)3.2 m (1.07×) and up
steps in the dial1100

At 2.0 m, pin −37.00° looses at 0.878 s from 5.08 m up and carries 48.4 m; pin −36.75° looses 0.128 s later from 7.47 m up and carries 96.0 m. A quarter of a degree, double the range. The machine as shipped has no such step anywhere on its dial — cliffs() is there to keep it that way.

Reusing it

src/loose.mjs is framework-free and has no DOM in it.

import { machine, shoot, survey, bestPin, ledger, cliffs } from './loose.mjs';

const m = machine({ L: 3.2, M: 500, hinged: true });
const s = shoot(m, { pin: -52.25, dt: 2e-4, record: 1 / 240 });
// s.range, s.speed, s.launch, s.whipGain, s.minTension, s.frames

bestPin(m);            // scan, not golden-section: range(pin) is not unimodal
survey(m, { step: 1 }); // the whole dial
ledger(m, s);          // where the counterweight's energy ended up
cliffs(m);             // pin angles where the dial jumps, if any

shoot takes checkEnergy when you want the drift reported, and record to get frames back for drawing. dt: 2e-4 agrees with 5e-5 to eight significant figures on range for a quarter of the steps; the demo runs at 2.5e-4 and surveys the dial at 6e-4.

Two things to know if you change the geometry. The cocked arm tip has to be at least as close to the ground as the sling is long, or initial() throws rather than quietly starting with a slack sling. And minTension is not decoration: a shot that reports a negative one is outside what a rigid massless link can represent, and its range is not a number anyone should quote.