Jumping onto a waist-high crate is the first thing anyone tries in a shooter, and here it cannot be done — not with a jump, and not with the crouch-jump that does it in CS.
Measured against physics.move with a 64-unit box and a run-up: apex 57.0 units, holding duck in the air changes it to 57.0 units, and the body ends up beside the box, not on it. The arithmetic agrees — MOVE.jumpVelocity 301.993 against gravity 800 is v²/2g = 57 units, and MOVE.stepSize only applies on the ground. The maps are full of surfaces built at exactly the height this misses: 15 boxes with a 64-unit top on de_forge and 19 on de_cinder, plus the 128-unit ones above them.
Duck does nothing in the air because the hull shrinks from the top: hullHeight is measured up from body.pos, which is the feet, so ducking lowers your eyes and never lifts your boots. In CS it is the legs that pull up, which is why a crouch-jump clears a 64-unit crate and a plain jump does not.
Done looks like
[ ] A crouch-jump clears a 64-unit crate: jump, duck in the air, land on top. A test that puts a body next to a 64-unit box, runs the real move with jump then duck, and asserts onGround with pos[2] === 64 — the test that fails today.
[ ] A plain jump still does not: the same test without duck stays on the floor, so the skill is a skill and the 64-unit crates are still cover for anyone who does not know it.
[ ] MOVE.jumpVelocity is not raised. The gain comes from the ducked hull, so standing jump height, fall speeds, strafe-jump behaviour and the 128-unit tops all stay exactly where they are.
[ ] Whatever lifts the feet is one named idea in physics.ts with a comment saying why it is the legs and not the gravity, and it cannot be used to stand inside geometry: the existing stuck refusal to un-duck under a ceiling still holds, and a ducked jump into a 72-unit gap does not leave a body clipped into a wall or a floor.
[ ] Nothing that reads a hull follows the feet by accident — eye height, the hitboxes in combat.ts, the bodies in models.ts/stride.ts and the camera all still agree about where a ducked player is. A test that a ducked player's head is where a bullet finds it.
[ ] Bots are unaffected on purpose: bots.ts never sets input.jump, so nothing a bot does changes, and the README says plainly that a crate top is a place a bot will not follow you to.
[ ] README's movement paragraph gains the crouch-jump and the 64-unit number.
Files
src/client/physics.ts, src/client/physics.test.ts, README.md; a test in src/client/world.test.ts or combat.test.ts for the hitbox agreement.
Risks
The feet moving is the load-bearing change in the whole simulation: everything that reads p.pos as "the floor under a player" — footsteps, groundUnder, corpses, the bomb drop, the pickups, fallDamage when #190 lands — is downstream of it. Keep it to the airborne ducked case if that is what it takes, and say so.
A player who can reach a crate top can also reach places the bots' findPath grid has no cell for. That is acceptable and worth a sentence in the README, but check that a bot with a target on a crate still paths somewhere sane instead of standing still.
Deciding this is wrong is a legitimate answer: if the honest fix is that no crate should be climbable, then close it by saying so in the README instead of leaving the number an accident.
Jumping onto a waist-high crate is the first thing anyone tries in a shooter, and here it cannot be done — not with a jump, and not with the crouch-jump that does it in CS.
Measured against
physics.movewith a 64-unit box and a run-up: apex 57.0 units, holding duck in the air changes it to 57.0 units, and the body ends up beside the box, not on it. The arithmetic agrees —MOVE.jumpVelocity301.993 againstgravity800 isv²/2g= 57 units, andMOVE.stepSizeonly applies on the ground. The maps are full of surfaces built at exactly the height this misses: 15 boxes with a 64-unit top on de_forge and 19 on de_cinder, plus the 128-unit ones above them.Duck does nothing in the air because the hull shrinks from the top:
hullHeightis measured up frombody.pos, which is the feet, so ducking lowers your eyes and never lifts your boots. In CS it is the legs that pull up, which is why a crouch-jump clears a 64-unit crate and a plain jump does not.Done looks like
movewith jump then duck, and assertsonGroundwithpos[2] === 64— the test that fails today.MOVE.jumpVelocityis not raised. The gain comes from the ducked hull, so standing jump height, fall speeds, strafe-jump behaviour and the 128-unit tops all stay exactly where they are.physics.tswith a comment saying why it is the legs and not the gravity, and it cannot be used to stand inside geometry: the existingstuckrefusal to un-duck under a ceiling still holds, and a ducked jump into a 72-unit gap does not leave a body clipped into a wall or a floor.combat.ts, the bodies inmodels.ts/stride.tsand the camera all still agree about where a ducked player is. A test that a ducked player's head is where a bullet finds it.bots.tsnever setsinput.jump, so nothing a bot does changes, and the README says plainly that a crate top is a place a bot will not follow you to.Files
src/client/physics.ts,src/client/physics.test.ts,README.md; a test insrc/client/world.test.tsorcombat.test.tsfor the hitbox agreement.Risks
p.posas "the floor under a player" — footsteps,groundUnder, corpses, the bomb drop, the pickups,fallDamagewhen #190 lands — is downstream of it. Keep it to the airborne ducked case if that is what it takes, and say so.findPathgrid has no cell for. That is acceptable and worth a sentence in the README, but check that a bot with a target on a crate still paths somewhere sane instead of standing still.Suggested: vesper.