Public: anyone can read this; the crew can change it.

forked from trevato/cs

Physics moves into the engine and takes its tuning as data #7

Closed opened this
Closed without merging

`src/engine/physics.ts` now moves any body through any set of boxes and holds no Counter-Strike number: it exports `Body`, `Wish`, `MoveTuning`, `Hull`, `accelerate`, `airAccelerate`, `move`, `groundUnder`, `stuck`, `eyeHeight` and `hullHeight`, and every tuned value reaches it as a required argument in one boring order — subject, situation, tuning, hull: `move(body, wish, dt, boxes, tuning, hull)…

stopped closed without shipping deploy 2f47104

opened this

src/engine/physics.ts now moves any body through any set of boxes and holds no Counter-Strike number: it exports Body, Wish, MoveTuning, Hull, accelerate, airAccelerate, move, groundUnder, stuck, eyeHeight and hullHeight, and every tuned value reaches it as a required argument in one boring order — subject, situation, tuning, hull: move(body, wish, dt, boxes, tuning, hull), eyeHeight(body, hull), stuck(pos, height, boxes, hull), groundUnder(pos, height, boxes, reach, hull), airAccelerate(vel, dir, speed, dt, tuning). No parameter has a default, so nothing can substitute a tuning quietly. The Source numbers live in the new src/client/movement.ts as CS_MOVE and CS_HULL, with fallDamage — CS's curve, not physics — beside them. Two numbers needed a decision: the duck rate of 5/s was baked into the mover and is now CS_MOVE.duckRate, and the two-unit floor contact stayed in the engine as a solver tolerance, named CONTACT and documented as one rather than dressed up as tuning.

The moved test is src/client/movement.test.ts, not src/engine/physics.test.ts: it asserts today's numbers through CS_MOVE, and boundary.test.ts forbids an engine module from importing the game, so the test that knows CS numbers belongs to the game. It keeps all eleven original assertions unchanged and adds four that run the same solver under a second profile — half gravity, a 144×48-unit hull, a 36-unit step, 500 u/s — including a hand-checked apex, v²/2g = 301.993²/1600 ≈ 57.0 units under CS and ≈ 114.0 under half gravity, with hang time doubling. Re-baking gravity, the hull radius, the step size or the max speed into the engine fails exactly those four; I checked by doing it.

Worth looking at in the preview: movement should feel bit-for-bit identical, and it is — 40 s of a seeded ten-bot round produces the same SHA-256 over every player's position, velocity, health and duck amount before and after (47e39ec48b23de94). On the threading cost, this sandbox is loaded and noisy, so I interleaved runs and took minimums: scripts/train.ts --bench gives 7–8k steps/s on both the old and new code here (it reached 10–11k on both when the box was quiet, never the 13k the issue quotes for the forge's machine), and an isolated 300,000-tick mover benchmark against the full de_forge box set is 0.98 s before and 0.98 s after. I measured no regression, but the absolute number here is the sandbox's, not the forge's. src/rl/arena.ts needed no change — it moves only through world.applyInput — and bun test is 123 pass / 0 fail with the rebuilt static/app.46b3eaaa33.js committed.

🤖 Generated with Claude Code

Closes #3

commented

main is merged into this branch and the two landings stand together: src/engine/ is now math, trace, physics, mesh, texture and sound, while the game keeps its own numbers — CS_MOVE/CS_HULL and fall damage in src/client/movement.ts, and the asset recipes in models, materials and audio. boundary.test.ts still reads every file in src/engine/ and fails if one points at the game.

The only textual conflict was README's "Shape" section, where both sides had rewritten the same two bullets; it now names all six engine modules and both renames (textures → materials from main, physics → movement from here), and says which client modules are tuning and which are recipes. renderer.ts merged on its own and was checked by hand: it imports materials from main's side and engine/physics + movement from this one. The bundle both sides changed was rebuilt — static/app.46b3eaaa33.js and static/app.6864d577a4.js are replaced by static/app.c3680040c7.js, which the build reproduces byte for byte.

One test change, and it is not a conflict resolution: "a round is played out" simulates minutes of game at 64 Hz and crossed bun's default five-second timeout on a loaded machine, having passed on both parents. The test was right and the code was right; only the inherited wall-clock budget was wrong, so it and the whole-match test now state 60 s. bun test is 150 pass / 0 fail, and the server boots and answers / in 14 ms with the security floor intact.

To look at in the preview: a match played to the end (movement feel, step-ups and strafe gain come from the engine mover now) and the generated look and sound of it (meshes, atlas and audio come from the engine tools now) — the merge should be invisible in both.

🤖 Generated with Claude Code

commented

Closed in the owner's sweep of 2026-10-12: a week old and in conflict with main now; the branch stays if anyone wants it back.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs