- JavaScript 91.7%
- CSS 5.6%
- HTML 2.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The suite only covered whole-design behaviour and UI smoke. This adds direct tests for orbit math (circular/elliptic/hyperbolic elements), the outcome() classification incl. a real max-Q breakup, staging order and ignition, SAS anti-windup bounds and the shape of the ascent programme. |
||
| src | ||
| test | ||
| tools | ||
| .gitignore | ||
| AGENTS.md | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| styles.css | ||
Kestrel — Rocket Science
Build a rocket out of lumpy parts, light it, and try to put a periapsis above 50 km on a small planet where orbit only costs ~3.1 km/s. Bad designs do not just fail, they fail in specific, teachable ways: tumbling off the pad, breaking apart at max-Q, a 400 km suborbital arc with 40 m/s of dV left.
npm install
npm run serve # http://localhost:8080
No build step — plain ES modules plus three.js from an import map.
Controls
| key | |
|---|---|
Space |
stage |
X |
cycle SAS: off → prograde → auto-ascent |
↑ / ↓ |
throttle |
, / . |
time warp |
A / D |
pitch by hand (SAS off) |
Esc |
abort |
In the builder, click a part to bolt it on top of the stack, click a stack row to remove it, and load a blueprint to see what a working rocket looks like. The analysis panel reports liftoff mass, TWR, ideal Δv, max-Q limit, max-G limit and the CG/CP margin in calibres — the four numbers that decide whether a design can possibly work.
What the simulation models
- Point-mass orbital mechanics on a 1000 km radius planet
(
mu = 9.8e12), circular orbit ≈ 3130 m/s, orbit achieved at periapsis ≥ 50 km. - Exponential atmosphere (6 km scale height, sea-level density 1.22) with
q = ½ρv², a Mach-dependent drag curve and a sound-speed profile. - Structural limits. Every part carries a
maxQand amaxG; the stack inherits the worst of both. Thin long tanks cannot take the pressure, so throttle-down through max-Q is a real decision, not decoration. - Static stability. CP is integrated per part with a proper tail-as-centre-of-pressure model (parts ahead of the CG are destabilising); SAS can only correct within actuator authority, so an airframe that is more unstable than its fins can hold will depart control regardless of pilot input.
- Gravity turn + real autopilot. AUTO pitches over on a rate-limited programme tied to dynamic pressure, then circularises near apoapsis. Because the command is rate limited, an over-powered-but-unstable rocket still departs control.
- Staging, thrust curves and a g-limiter per stage, plus TWR-limited liftoff, so a rocket that cannot lift is caught on the pad.
Tools
npm run designs # fly every blueprint headless, print the outcome table
npm run check # regression: each design must fail/succeed for the right reason
npm test # physics, builder UI, renderer, full game loop, camera framing
node tools/stats.mjs pencil # mass properties, stability breakdown
node tools/trace.mjs fatboy 60 # frame-by-frame trace of one flight
Screenshots without a browser
Headless Chrome does not drive requestAnimationFrame, so the page accepts
?demo=<blueprint>&launch=1&warp=8&drive=1&shot=<frame>, which drives the loop
from a timer and writes a canvas snapshot into the DOM:
node tools/serve.mjs 8099 &
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--headless=new --enable-unsafe-swiftshader --window-size=1280,760 \
--virtual-time-budget=60000 --dump-dom \
'http://localhost:8099/?demo=shrike&launch=1&warp=8&drive=1&shot=1200' \
| perl -ne 'print $1 if /id="shot" src="data:image\/png;base64,([^"]+)"/' \
| base64 -d > shot.png
Layout
src/constants.js planet, atmosphere, control and guidance tuning
src/orbit.js conic elements from state vectors
src/parts.js the part catalogue: mass, Isp, thrust, maxQ, aerodynamics
src/rocket.js stack → mass properties, staging plan, geometry
src/physics.js FlightSim: forces, SAS, guidance, outcome classification
src/shapes.js part meshes, built by lathing the part table
src/render.js planet, sky, chase camera, staging debris
src/build.js builder UI and its 3D preview
src/hud.js flight readouts
src/main.js game shell: builder → flight → debrief
test/ headless tests (three.js + jsdom)
tools/ headless flight, regression, framing and a static server
Known edges
The renderer keeps the scene in a vehicle-centred frame: at a 1000 km radius,
float32 has about a decimetre of precision, which is not enough for a 10 m
rocket. Everything fixed to the planet hangs off World.worldRoot, which is
shifted to the vehicle every frame.