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 #3
Planner's note, not a change of scope: pull #7 no longer merges. The forge reports it three commits ahead of a base fifteen hours old, mergeable: false, conflicting in seven files: README.md, src/client/combat.ts, src/client/hud.ts, src/client/observe.ts, src/client/physics.test.ts, src/client/physics.ts, src/client/world.ts.
That matters beyond the conflict markers, because what landed in between changed the rules this issue is worked under:
- #25 landed the engine's door.
src/engine/index.tsis now the only path into the engine from outside, andboundary.test.tsfails a deep import and fails a module that is not re-exported by the door. Sosrc/engine/physics.tshas to be added to the door and its names added to theSURFACElist in the test, and every consumer imports them from../engine/index.ts, never from../engine/physics.ts. - #26 landed the purity rule.
purity.test.tsimports every shipping engine module in a second process with the browser globals as recording getters; a new engine module that reads one at load time fails. Physics reads none today, so this should be free — but it is now a test, not a convention. - #19 landed the golden digest.
src/client/replay.test.tspins a seeded round and a seeded duel tick by tick. The claim "this extraction changed nothing" is now somethingbun testdecides rather than something the pull asserts; if a digest moves, the extraction is wrong.
The body of this issue is unchanged and still right. Rebasing onto main and replaying the move file by file — physics.ts and its test first, then world.ts, then combat.ts, observe.ts and hud.ts one import line at a time, README.md last — is the shortest path; the conflicts are almost all the import lines #25 rewrote underneath the branch.
This is the critical path: #5 and #18 wait on it, and #13 waits on those.
This issue's work is now carried by #62, replayed on today's main instead of rebased. Pull #7 has not been touched in twenty hours and does not merge: its seven conflicting files are the import lines that #25's door, #47's scene split and #49's overlay rewrote underneath it, and three of those landed after it was opened. Replaying is smaller work than rebasing, and #18's HUD half and #13's movement tuning are the last two items of direction #1 still waiting on this.
Nothing about the design is discarded. #62 says to read pull #7's description first and make the same two decisions it already made well: the duck rate of 5/s becomes CS_MOVE.duckRate rather than staying baked into the mover, and the two-unit floor contact stays in the engine as the solver tolerance it is. The argument order is the one #7 chose — subject, situation, tuning, hull — and the test that knows CS's numbers becomes the game's src/client/movement.test.ts, with the second tuning profile that makes a re-baked constant fail.
This issue now waits for #62, and when #62 lands it should be closed with a word, along with whatever a person decides to do with pull #7. Nothing in #62 touches that branch.
Delivered, by the split rather than by this issue: #131 made the tuning arguments in place and #140 moved the solver to src/engine/physics.ts with Counter-Strike's numbers in src/client/movement.ts. src/engine/index.ts exports the physics group and the golden digests did not move.
Closing it, so that what was queued behind it — #18, #63, #67, #113 — is ready rather than waiting on an issue whose work is already on main. #124 (a second tuning profile, the test that proves the solver is general) is still open and still worth doing; it stands on its own.
src/engine/physics.tsshould move any body through any set of boxes, and the Source-tuned numbers this game uses become a profile the game hands in.Done looks like
src/engine/physics.tsholdsBody,Wish,accelerate,airAccelerate,move,groundUnder,stuck,eyeHeightandhullHeight, and theMoveTuningandHulltypes.MOVEandHULLlive in the game —src/client/movement.ts, exportingCS_MOVEandCS_HULLwith the same values — and reach the engine as arguments:move(body, wish, dt, boxes, tuning, hull),eyeHeight(body, hull), and so on. Keep the argument order boring and identical everywhere.fallDamageis CS's curve rather than physics: it moves to the game with the tuning, unless it falls out of the tuning honestly.physics.test.tsstill asserts today's numbers, now throughCS_MOVE, and one new test runs the same body under a second tuning — half gravity, or a taller hull — and would fail if any constant were still baked in.src/client/{world,combat,observe,hud,renderer}.tsandsrc/rl/arena.ts.bun testgreen, the bundle rebuilt withbun run scripts/build.tsand the newstatic/app.<hash>.jscommitted, and a round on the preview feels identical: same run speed, same jump height, 18-unit steps, strafe jumping still rewarded.Files I expect to change
src/engine/physics.ts,src/engine/physics.test.ts(moved),src/client/movement.ts(new),src/client/{world,combat,observe,hud,renderer}.ts,src/rl/arena.ts,README.md,static/app.<hash>.js.Risks
Movement is the thing a player feels, and no test catches "feels wrong" — trust the numbers in the existing tests rather than your eyes, and change none of them. A default argument that silently substitutes the wrong tuning is the failure mode to avoid: make the parameter required. Threading a tuning through the hottest loop in training also costs something — run
bun run scripts/train.ts --bench, confirm it still steps around 13,000 ticks a second, and say what you measured in the pull.Whose brief fits
Torque — exact numerics with the units stated and tests that match a hand calculation. Vesper fits it too if Torque is busy.