Rigid bodies fall, slide, roll, bounce, stack and sleep on the map (headless) #17

Merged
agra merged 36 commits from task/3900-rigid-bodies-fall-slide-roll-bounce-stac into master 2026-10-30 05:26:54 +02:00
Owner

Tracker: #3900

Step 1 of plan #3865: the physics core, headless. Nothing changes in the app.

What it delivers

  • src/physics/shapes.sx: sphere, capsule (along local +Y), box and convex hull shapes. hullOf builds a hull deterministically from the points' triples in index order, merges coplanar faces, wraps each face's corners and drops collinear points; it fails Flat on points that span no volume. Least and greatest extents, the core radius, exact inertia about the origin (a hull's by tetrahedra from the origin, so an off-centre hull takes the parallel-axis term), Mat3, Pose and the sweep's lerp/nlerp between.
  • src/physics/distance.sx: GJK closest points between cores (point, segment, polytope, map triangle), after b2ShapeDistance; an interior face point is weighed by its areas, which keeps its precision on the test scene's 600 m ground triangles. A sliver face of the simplex, its corners nearly in a line, whose weights come out off the face, takes its point on the nearest of its edges; a tetrahedron counts a face as one the origin lies outside where the origin lies past the face or past the corner opposite it, as a nearly flat one can round that corner to the origin's side. Conservative advancement (timeOfImpact, planeTimeOfImpact) to a target separation, bounding the turn by nlerp's fastest rate, 4 tan(φ/2).
  • src/physics/contacts.sx: manifolds once the closest points lie within SPECULATIVE, never otherwise. Polytope pairs take the separating axis over faces and edge pairs and clip the incident face (Gregorius), keeping every clipped point at its own separation, reduced to 4 (the deepest, then the three spanning the largest area). Of edge pairs as far apart, which parallel edges give, the pair whose own edges lie nearest along the axis makes the contact. A capsule's segment is clipped to the reference face whatever its tilt, one point when its clipped part projects to one point. A capsule whose closest points lie on a polytope's edge it runs parallel to (PARALLEL, coreCore's 0.05) has a point at each end of its part along the edge, each at its own separation, as two parallel capsules do. Spheres and capsules between themselves take their cores' closest points, two for parallel capsules. The map's bounds are planes.
    • A map triangle is a two-sided hull of one face. A face's contact is the part of the body over the face, and the face reaches on past each edge concave from it whose wedge holds the body's origin: the neighbour there rises toward the face and cannot keep the body out. Past such an edge it takes only the part of the body alongside the edge and no more than SLOP behind its plane: the wedge it reaches into lies in front of its plane, and the triangles bounding that wedge end at the edge's ends.
    • The touched face. A contact with a face as the reference is that face's. A body clear of the triangle with part of its core over the face touches the face its closest points' normal leaves: the plane through the closest points keeps the triangle on one side and the body on the other, so that part lies wholly on that side. A body that overlaps the triangle is not held to this: a capsule standing 0.55 m into the terrain, its core crossing one triangle and passing under the next, clear of it, has its part over that next triangle below it. Any other contact lies on the triangle's edges its point on the triangle (the manifold point taken back half its separation) comes within ON_EDGE (0.1 mm) of. It touches the face whose wedge holds the body's side about those edges, or inside the face the side of the plane holding it. The body's side is its core's point nearest the triangle where the two do not overlap and that point lies more than SLOP off the plane, and its origin otherwise: a long body's origin can lie across the plane from the part of it the triangle touches, and a point within the slop of the plane can lie on either side. About an edge no other triangle shares both wedges are whole turns, and the body touches the face on whose side of the plane its side lies. A body whose side lies beyond another triangle sharing the edges has no contact with the triangle; where two edges disagree, the contact keeps its features' direction. The task names the side of the plane the contact normal leaves; there an edge pair's axis about a shared edge, turned out of the plane by a body's tilt, picks the face by its sign (the tilted overlap cases), and the side of the plane holding the origin puts a plank leaning on a block's top edge against the top's underside.
    • Smooth and sharp. Where an edge is sharp from the touched face, the contact keeps its features' direction, unless that direction turns past the normal of the triangle sharing the edge: that triangle's face holds the body there, and this triangle gives no contact, as Box2D's chain segments leave a normal past a convex neighbour's to the neighbour. A capsule's one point there is joined by the end of its part over the face farther from that point, at its separation along the contact's direction from the face's plane, so that a capsule turning about the edge onto the face meets it on a speculative point. Where every edge is smooth, the contact is the face's. A capsule's end past an edge smooth from the face, short of the neighbour's normal and nearer this face's, lies in the gap over neither face, and the face's contact reaches to it at its own separation; past a concave or flat edge an end lies past the neighbour's normal and gets nothing from this face. When no part of the body lies over the face, the body lies past the edges: where the features' direction turns no more than AS_NEAR past any neighbour's normal, which only a convex or flat edge allows, the triangle whose normal lies nearer that direction than each neighbour's keeps the features' contact, and elsewhere the neighbours' faces hold the body. Nearer is within AS_NEAR, 1e-4 in the two dot products, and past the neighbour's normal is past it by more than AS_NEAR on turnOf's scale: each triangle rounds a contact on the bisector its own way, and both keep it rather than neither. At a coplanar seam the bisector is the shared normal, the very bound past the neighbour's normal reads, and a ball centred over the seam, which each triangle's clip can round off its own face, was held by neither triangle without that tolerance.
  • src/physics/solver.sx: Box2D v3's constants in one place, soft contacts (30 Hz between bodies, 60 Hz against the map, ζ 10), the biased push of normal impulses, integration, the relax of normals then Coulomb friction across both tangents together, restitution once a tick from the pre-solve velocity (max of the two, the map 0, nothing under 1 m/s), Blender's (1 − d)^dt damping.
  • src/physics/dynamics.sx: bodies and PhysicsWorld (addBody, applyImpulse, setPose, setVelocity, step), the sort-and-sweep pairs, map candidates from within, the bounds as walls, contacts between bodies first and the map's last in every pass, warm starting by key and feature id, points solved in feature-id order, the continuous sweep of every body travelling more than SPECULATIVE a tick (the core's sweep for a triangle touched at time 0, the lost gravity taken off), islands and sleeping. It imports nothing from src/sim/: init takes the tick's length.
    • Which bodies. A body is swept when the task's travel, |v|·dt plus |ω|·dt times its greatest extent from its velocity at the tick's end, or the most any of its points moved over the tick, |Δx| plus twice its greatest extent times the distance between the start and end orientations, passes SPECULATIVE. A contact that stops a body late in the tick leaves it with little velocity after it moved several centimetres, through a triangle that had no contact at the tick's start: capsules dropped on the first map's terrain went 8.5 mm into it at 0a1c6a5 that way.
    • The early-out. The sweep passes over a triangle the body moves along: its nearest point comes no more than SPECULATIVE closer to the plane, without passing from in front of it to more than the slop behind, and its centroid ends at least the core radius in front. The middle clause is beyond the task's rule: a body starting a tick just beyond SPECULATIVE of a ramp has no contact with it, and closing on the ramp's plane by less than SPECULATIVE it sank up to (v·dt − SPECULATIVE)·sin θ, 7.2 mm into 30° at 2.3 m/s and 10.9 mm into 10° at 5 m/s.
  • src/physics/collision.sx: each triangle's six wedges of free space (Wedges, a turn per edge and face on turnOf's scale, a whole turn for an edge no other triangle shares), built by buildWorld from the triangles' corners; inner is unchanged. An edge is smooth from a face where its wedge spans at most 180° + 5°, and concave where it spans less than 180° by more than FLAT_EDGE, 0.0015 on turnOf's scale (0.086°, over the 0.081° COPLANAR allows two normals): the first map's fir trunk proxies are slivers 13.9 m tall whose diagonals round up to 6e-4 short of flat. src/world/world_format.sx carries the wedges at world file version 4, 24 bytes a triangle, and the bake writes them from both scenes: the first map's world file is 17.4 MB where six bits made it 12.8 MB.
    • The task asks the world file for six bits. The contact rule above needs each wedge's turn, not only its class, to tell which wedge holds a body, so the file carries the turns and the bits are read from them (Wedges.smooth).
  • tools/bake.sh: the stamp hashes every repository file the stage reaches through @import, resolved beside the importing file and then from the root, instead of the hand-kept STAGE_MODULES.
  • Tests: physics_shapes, physics_distance, physics_contacts, physics_bodies, physics_stack (hand-built ground and baked/test_scene.hbw), physics_determinism. tests/support/worlds.sx gains incline and tessellated; tests/bake_stage.sx checks the wedges the world file holds.
    • Sliding across seams runs from 8 starts across a quarter cell, at 5 and at 20 m/s, each within 1% of its distance. At fc21030 a box whose front started a tick within SPECULATIVE short of the next cell took a horizontal contact from it: 4.343 and 3.868 m of 5 from 0.125 and 0.375 m along, 16.34 m of 20 from 0.125 m.
    • The overlap case sinks a box 0.4 m into ground facing down (as Shapes.floor's does) and facing up, across their diagonal, upright and tilted 0.5° and −2° about x. Upright it rises at 3.62 and 3.13 m/s, under 4 m/s, and rests within 1 cm of the ground from tick 15 on (from tick 14 on both); tilted, every case rests within 6.9 mm from tick 15. At 7a250f3 an edge pair's axis tilted out of the plane picked its face by its sign: 3 of the 4 tilted cases were 0.40 to 0.45 m off at tick 15.
    • physics_stack adds: a box spinning in place at 2 rad/s with no gravity stays awake; of two boxes resting 4 m apart, an impulse to one leaves the other asleep, its pose bit for bit, for 60 ticks; setVelocity and setPose on the sleeping tower's top box, even to the values it has, wake the whole tower.
    • physics_contacts adds an octagonal prism lying on a triangle, tilted 2° toward each of two neighbouring corners in turn: of its 8 clipped corners the 4 kept include that corner, at its gap. It adds a box on the ground 1 cm short of a 30° ramp rising from the ground's edge, which has the ramp's face normal at its bottom face's 4 corners, each at its distance from the ramp's plane, and checks that the box edge-down across a triangle's edge has its contact midway between the two edges (at 7a250f3 it lay on the box's far edge, 14 cm up). The wedge cases read the wedges: the edge under a wall on a floor's diagonal is concave from above and flat from below, and rewinding a neighbour leaves the first triangle's wedges bit for bit.
    • Ramp: a 0.5 m box of friction 0 slides across level ground into a ramp rising from the ground's edge, from 8 starts across a tick's travel, and never ends a tick more than 6 mm inside it: 0.11 and 0.14 mm into 30° at 5 and 20 m/s (39 and 164 mm at 7a250f3), 4.9 mm into 30° at 2.3 m/s and 3.7 mm into 10° at 5 m/s, the early-out cases (19 and 15 mm at 7a250f3). Probes at 5° to 45° and 1.5 to 20 m/s ended at most 4.9 mm in, the slop the early-out allows.
    • A ball along a low wall: a ball rolling along a wall 0.2 m high, 2 mm clear of it, its centre under the wall's top, moves bit for bit as it does with no wall. At 7a250f3 the top's triangle took the ball as touching its underside: the ball sank 41 mm into the ground and stopped.
    • Up past a block's top edge: with gravity 0, a box and a ball beside a block, 2 mm clear of its side, their tops 1 cm below its top, sent up at 2 m/s, each rise 2 m in 1 s within 2% (1.972 and 1.984 m). At 7a250f3 the ball rose 0.13 m; with the top edge's contact kept past the side's normal, the box rose 0.59 m and the ball 1.89 m.
    • A plank leaning on a block's top edge: a plank 2 m long leaning at 55° from the ground onto a block's top edge, its centre outside and below the top, rests there, moving 0.09 mm. Touching the face on the side of the plane holding the origin pushes it 1.25 m off the edge, and finding the contact's edges by the region of the manifold point on the triangle, as 7a250f3 did, 1.09 m off.
    • A ball over convex creases: a ball rolling at 3 m/s over facets each 3° steeper than the last never rises off them more than its flight over such a crease, v² sin² 3° / 2g = 1.3 mm. At 7a250f3 a sphere got the face's plane point past a smooth edge and rose 3.3 mm.
    • Ridges: a ball and a capsule lying along the ridge, both of radius 0.15, the capsule 1.5 m long, set at rest on ridges bent 3° and 4.6°, which are smooth, on the ridge and 2 mm off it, and the capsule along a sharp ridge bent 6°, 0, 2 and 4 mm off it. Past the edge each lies over neither face. The capsules 2 mm off the smooth ridges are also yawed off the ridge's line (0.002 rad on 3°, 0.005 rad on 4.6°) and set in a world turned 1.1 rad about +Y: each then lies partly over one face and partly past the edge. Over 2 s none goes more than 6 mm into the map, measured from the two half-spaces under the ridge, not by GJK: 0.03 to 0.35 mm. At 0a1c6a5 the yawed and turned capsules sank 25.5, 66.6, 15.2 and 16.5 mm: the earlier claim that no Ridges body goes past 6 mm held only for capsules lying exactly along the ridge's line. At d8820ae a body on a smooth ridge fell through the map (19 m in 2 s), 2 mm off it sank 89 to 107 mm, and the capsule 2 mm off the sharp ridge, its one point see-sawing between its ends, sank 18.4 mm.
    • A slow ball over a crease: a ball rolling at 0.25 m/s off level ground over a crease 4.6° convex goes at most 0.58 mm into the map (12.6 mm at d8820ae).
    • Pivoting across a sharp ridge: a capsule of radius 0.15, 1.5 m long, lying along face A of a ridge bent 6°, its axis square to the ridge or 30° or 45° off, its centre 0.05 or 0.15 m past it, set turning at 2 rad/s onto face B, and one 0.3 m past it turning by its own weight. None ends a tick more than 6 mm into the map: at most 0.1 mm, against 12.8 to 21.3 mm at 0a1c6a5, where B gave only the ridge's one point and the capsule's end landed on B with no point of its own.
    • Over a plate: the same capsule, 0.15 m past, square and 30° off, turning at 3 and 4 rad/s onto a plate 12 mm above face B, a quad that shares no edge, ends no tick more than 6 mm into the plate or the map: at most 0.13 mm, against 6.8 to 11.6 mm at 0a1c6a5. The plate's edge under the capsule has the plate's upper face for the capsule above it; with the front face taken always, as 0a1c6a5's wedges did for an edge no other triangle shares, the plate's far end point was dropped.
    • On the first map (baked/first_map.hbw): capsules of radius 0.15, 1.5 m long, set down on a tree trunk's top tipping off beside it (review run 1782's repro, 91.7 mm into the trunk at 0a1c6a5), across a sharp crease of the terrain (17.3 mm), and two turning about a sharp crease onto a strip whose far side rises (0.3 and 8.5 mm at 0a1c6a5). None ends a tick more than 6 mm into the map over 2 s: 0.9, 0.7, 0.4 and 0.7 mm. The last two need the sweep's displacement: the contact holding the turning end stops the turn late in the tick after the end has passed into the rising triangle, and without it they go 10.0 and 8.5 mm in.
    • physics_contacts adds three cases for the gap's ends: a capsule lying across a coplanar seam has from each floor triangle points over that triangle alone; a capsule lying along a smooth 4.6° crease, yawed, its end in the gap on A's side of the bisector, has from B no point at that end; and a capsule lying on B of a sharp 30° crease, its end 3 cm past the edge, has from B points over B alone.
    • physics_contacts adds a capsule lying along a triangle's edge, 3 mm past it, its far end 0.01 m higher: 2 points, each at its own end's distance from the edge; and lying along it 45° round from the face, where the edge holds its closest points before any face does: 2 points (1 point each at d8820ae). It adds a ball past a 3° crease, over neither face, its centre a quarter and then three quarters of the way from one normal to the other: the triangle whose normal lies nearer gives the features' contact at the gap, the other none (at d8820ae neither gave one). And a ball on the bisector of a convex crease's normals, over 400 creases of 1° to 5° turned about +Y, has the features' contact from both triangles: with AS_NEAR 0, 8 of the 400 had it from neither.
    • physics_contacts adds a ball centred over the diagonal two coplanar triangles share, resting on it and sunk 1 and 10 mm into it, over 4000 quads tilted up to 20° and turned about +Y: one triangle at least gives it a contact. At 1ed4462, 31 of the 12,000 had a contact from neither. And a capsule lying along a box's top edge 45° round from its faces, rising 0.025 along it from 1 mm off and running out past the edge's end, the box having three other edges parallel to it: 2 points on that edge, one at its low end at the gap, the other at the edge's end at the capsule's own separation there (0.012249), each with its own feature id.
    • Probes after review run 1782's, at the head and at 0a1c6a5 alike:
      • capsules (radius 0.15) lying along ridges of 2° to 6°, 0 to 4 mm off them, yawed 0 to ±0.005 rad, in worlds turned 0, 0.37 and 1.1 rad: 101 of 300 went past 6 mm at 0a1c6a5 (95.9 mm deepest), none at the head (2.3 mm);
      • capsules of both sizes dropped at 320 places and yaws each on the first map's terrain (normal y > 0.95), lifted clear by 5 mm: the large ones went past 6 mm 2 times at 0a1c6a5 (8.5 and 12.0 mm) and never at aa261b9 in that sample (3.9 mm), which held for that sample only: review run 1797's seeds found one at aa261b9, 10.0 mm (its finding 1), and the next round's sample one at aa261b9 and at the head alike, 8.7 mm, rolling at 14.6 rad/s; the small ones 9 times at both, each rolling at 46 to 50 rad/s (the rolling sink below);
      • 2000 more small capsules and 600 dropped 0.6 to 2.6 m from the first map's 1041 trunk proxies: of the drops past 6 mm while not rolling fast (under 30 rad/s), 15 at 0a1c6a5 and 10 at the head. One lay inside a trunk at its start. The other nine spin at 16 to 29 rad/s; the three traced spin about their own axis, wedged against a steep face, climbing a fir trunk's proxy or slowing on a slope, their ground end 8.7 to 18.1 mm deep: the rolling sink, deeper under the push. In the deepest of them, a capsule rolling into a fir proxy, part of the depth is another mechanism: the proxy's side quads are slivers 13 m tall, their diagonals read 0.01° concave by rounding, and the side's face then reaches past its diagonal across the neighbour into the next side's region; with concave held to 0.086° past flat the capsule goes 11.5 mm in, not 18.1. Review run 1797 found that mechanism statically, and FLAT_EDGE (below) answers it.
    • Probes after review run 1773's. Of 120,000 balls centred over a coplanar seam, tilted up to 20° and turned, 342 had a contact from neither triangle at 1ed4462 and none at the head. A ball of 0.15 m sliding at 2 m/s along a coplanar seam over a 3° crease, the world turned 0.37 rad, went 10.6 mm into the map at 1ed4462, 4 ticks touching it with no contact, and one of 0.05 m 13.1 mm; at the head 1.9 and 2.8 mm. A ball of 0.15 m sent at 2 m/s down a 20° slope along a seam, turned 1.1 rad, went 17.9 mm in at 1ed4462 and 3.7 mm at the head, as at every turn, its rolling sink.
    • physics_distance adds two poses GJK misread at d8820ae. A capsule lying past a triangle's edge, turned off it by under 0.001 rad, met a sliver face whose weights put its closest point 1311 m along the edge, at a distance of 0.001 for 0.05. A capsule lying flat over a tilted triangle, 0.1 m clear of it, read as overlapping it. Over 200,000 poses about the first, GJK misread 140 by more than 1e-4 at d8820ae, by up to 1.47 mm and some short of the true distance, and 4 at the head, by at most 0.12 mm, each over it. Of 100,000 capsules lying flat over random triangles, 20 read as overlapping at d8820ae and none at the head.
    • Probes after the review's. Of 320 balls set at rest on the first map's terrain grid lines x = 60 and z = −60, 40 sank past 6 mm at d8820ae, up to 133 mm, and none at the head, whose deepest, 5.3 mm, are balls rolling down at 30 rad/s (the rolling sink below). Of 49 bodies dropped on a random heightfield of 12 × 12 cells, no sphere went past 1 cm at either; the capsules' cores read as overlapping it 3 times at d8820ae, GJK's flat tetrahedron, and never at the head, which they came within 1.4 mm of.
    • Smooth slope: a box of friction 0.083 sent at 0.8 m/s down facets of 10° and 13° by turns slows on 10° and speeds up on 13°, crosses all four creases, never comes farther than the slop from the map by GJK distance (0.55 mm at most), and never moves up faster than 0.05 m/s (0.029). The old case's box, of friction 0.1, never slid: against the map's 0.5 the combined 0.224 holds on 10°.
    • Figures at the head, printed by aa261b9's six physics tests in arms of fa141fe and of aa261b9, every line identical but two: the capsule tipping off a trunk's top on the first map goes 0.944 mm in, 1.145 mm at aa261b9, and the capsule across a sharp terrain crease 0.717 mm, 0.712 mm at aa261b9. Either FLAT_EDGE or the reach bound alone moves them, and with both taken out both read as at aa261b9: a face reaching past a terrain or trunk edge that reads concave by rounding gave those capsules points beside its plane. Arms of aa261b9 and of 0a1c6a5 printed alike, as did those of 0a1c6a5 and 1ed4462 and those of 1ed4462 and d8820ae: towers 5.6 mm (hand-built) and 9.4 mm (test scene) off their columns, asleep at ticks 46 and 53; pyramids 0.3 and 0.2 mm, asleep at 30; the 100 kg box on the 10 kg one 3.9 and 0.9 mm, asleep at 84 and 63; seams at 5 and 20 m/s from 8 starts, 4.999998 to 5.000000 m and 20.000000 m; the overlap cases on both windings, Ramp, the plank, the ball beside a wall, the box and ball up past a rim, Smooth slope and the balls over creases as above.
    • A ball rolling at 14 rad/s rests about 2.3 mm into the map, here as at 7a250f3, alone and beside the wall: each contact's anchor turns with the ball during the tick, as in Box2D's relax. Nothing here pins or changes it.
    • The early-out measures the body's nearest point against the triangle's whole plane, on the side its centroid starts. A long tilted body whose part far from the triangle lies across that plane is passed over while another part enters the triangle. A plank turning down about its end on the floor, its far end over a slab whose top lies above the plank's centroid, sinks into the slab's corner (passed over through its top and its side), here as at 0a1c6a5, and keeps out of it with the early-out off; the capsule over a plate goes 6.7 to 13.2 mm into the plate when turning at 6 to 8 rad/s, its surface already under the plate's plane at the ridge. The task names this rule; nothing here changes it.
    • A box centred on a single-quad fence's top, tilted 0.004 rad along its 10 m edge, rests 13.4 mm into it, as review run 1765 found: the edge pair of the box's edge and the fence's top beats the box's face and gives one point. Nothing here changes it.
    • A fir trunk proxy. physics_contacts builds the first map's trunk proxy at (-48.1, 6.9 to 20.8, -40.6) from its 22 baked triangles, as literals, and sets four bodies at least 1 mm clear of it. No triangle gives any of them a point deeper than the slop. At aa261b9 they get points at:
      • −0.139 m: a capsule beside a side, past its corner, where the side's diagonal reads 1e-5 short of flat and opened that side's face past it (FLAT_EDGE);
      • −0.122 m: a box over the top, its origin inside the column the sides bound, whose part outside a side's plane lies alongside that side's corner edge, concave from inside (the plane bound);
      • −0.139 m: a capsule over the top, its core inside that column above where the sides end (the extent bound);
      • −0.090 m: a box over the cap's middle triangle, its origin below the cap's plane outside the trunk, taken by its origin as touching the cap from below (the side the closest points' normal leaves).
    • A buried capsule. physics_contacts sets a capsule standing with 0.55 m of it in the first map's terrain, at (-31, 24.7, -97), from that terrain cell's 6 triangles, as literals. Its core crosses one triangle and passes under the other, clear of it, across their diagonal, 0.2° concave from above. Each triangle's contact pushes it up, and the cell keeps its buried end at −0.552 m. Taking the over-face side for any body whose core is clear, rather than one clear of the triangle, gives the second triangle's back face, and dropped on the map the capsule then falls through it (y −48.7 after 4 s); aa261b9 passes the case.
    • Probes after review run 1797's, at the head and at aa261b9:
      • the reviewer's static probe: 20,000 poses of each shape near the 15,317 steep triangles of the first map that have a wedge within 0.0015 short of flat, those at least 1 mm clear of the map. At aa261b9 55 of 15,696 small capsules, 131 of 9,679 large ones and 164 of 8,619 boxes had a point deeper than 5 mm, down to −3.57 m. At the head none did.
      • the same about every steep triangle (|n.y| < 0.3): 71, 170 and 166 at aa261b9, none at the head; and about every triangle of the map: 3, 15 and 13 at aa261b9, none at the head.
      • 200,000 poses of each shape about the trunk proxy built alone: 200 of 18,837 small capsules, 565 of 42,779 large ones and 489 of 35,631 boxes had a point deeper than 5 mm at aa261b9, none at the head.
      • the reviewer's static repros: finding 1's capsule (triangle 186997, −0.255 m) has from it 0.0757 m, the gap 0.0083 m; finding 2's (cap triangle 182891, −0.096 and −0.327 m) has nothing from it.
      • finding 1's dynamic repro, a capsule dropped at (−30.987884, 25.300947, −97.023788), yaw 0.282268: 9.9 mm into the map over 2 s at aa261b9 (the kick at tick 110), 7.1 mm at the head. It is wedged against the trunk, spinning up from 12.7 to 14.9 rad/s, and its depth grows with the spin: the rolling sink below.
      • the capsules lying along ridges (2° to 6°, 0 to 4 mm off, yawed 0 to ±0.005 rad, turned 0, 0.37 and 1.1 rad): 300 runs, none past 6 mm, 2.42 mm deepest, at both.
      • Ramp at 5°, 10°, 15°, 20°, 30°, 40° and 45°, at 1.5, 2.3, 5, 10 and 20 m/s, from 8 starts each: at most 4.98 mm in, at both.
      • capsules of both sizes set on the first map's terrain at 320 places each (normal y > 0.95, lifted clear by 5 mm): small ones past 6 mm twice at both (6.6 mm deepest), the large one once at both (8.7 mm), rolling at 14.6 to 18 rad/s.
      • 2,000 small and 594 large capsules dropped 0.6 to 2.6 m over 1,797 small level triangles (trunk tops and others), many falling to the terrain beside them: past 6 mm 354 and 91 times at aa261b9, 375 and 100 at the head; with another seed 325 and 106, then 340 and 121. A third of the runs differ between the two, and the deepest roll at 20 to 72 rad/s, some landing at 15 m/s on 27° slopes; the worst at the head, 65 mm, lands so and rolls up to 44 rad/s. With FLAT_EDGE and the reach bound both taken out the runs are bit for bit aa261b9's: the extra depth comes from the points this round drops, whose push, beside the face's own, held rolling capsules up. The rolling sink is unchanged here, as before.

The tuned values are Box2D v3's, unchanged. hulken's own: FEATURE_TOLERANCE (0.5 mm, a face over an edge pair), SINGLE_POINT (0.1 mm), TOI_TOLERANCE (a quarter of the slop), ON_EDGE (0.1 mm), AS_NEAR (1e-4), PARALLEL (0.05, coreCore's bound, now named) and FLAT_EDGE (0.0015 on turnOf's scale).

Mutants

Each mutant was applied alone, as exact text, in a scratch git archive arm, and the six physics tests (shapes, distance, contacts, bodies, stack, determinism) rerun; each line names the cases that fail. The list ran in an arm of 1ed4462, but for the five marked (0a1c6a5). In an arm of 0a1c6a5, 21 ran: the five; every mutant below of the branch past smooth edges, AS_NEAR, nearer, alongEdge, polySegment's two sites and GJK's three rules, each failing as its line says; and three more, which fail too: nearer against the triangle's in-plane direction and against the face's own normal (the ball past a 3° crease: both triangles keep it), and GJK's sliver fallback taking its first edge, not its nearest (the capsule turned a little off a triangle's edge in physics_distance). 74 of the 77 below fail.

  • Map friction taken as the body's, not √(μ · 0.5): Slide (1.695 m against 1.178 m) and the slipping sphere.
  • Friction between bodies the product, not √(μa μb): Slide on a body (2.861 m against 1.147 m).
  • Friction bounded along each tangent alone, not the two together: Slide on a body, sent across both tangents (0.805 m), and the tower on the test scene.
  • Restitution against the map the product, not the max: Bounce on the map (no rebound).
  • Restitution between bodies the min, not the max: Bounce between bodies.
  • No bounce threshold: Bounce threshold (rose 7.5 mm).
  • Restitution from the velocity after the solve: Bounce on the map.
  • A margin grown by the closing distance (0.8 m, the 50 m/s ball's tick, in the existence checks and the candidate boxes): the contacts test's box 0.025 m above a triangle, the bounces, both near misses and Sliding across seams (14.89 m of 20).
  • Points beyond SPECULATIVE dropped from every clipped manifold: Tilted landing (49 mm deep after 1 m, 79 mm after 2 m), the contacts test's turned box, its octagonal prism and its box short of a ramp, and Ramp (15 mm).
  • A capsule gives only its lowest point unless it lies flat: Pivoting onto the floor (6.8 m), Pressed onto the map (13.7 mm), Swinging in over a shelf's edge and the contacts test's tilted capsule.
  • No continuous sweep: Speed (the ball passes the wall), Landing, Tilted landing, the bounces, the spinning box, the shelf swing, Ramp and Bounds.
  • Swept only past half the least extent: Landing (53 mm deep after 1 m, 83 mm after 2 m), Tilted landing, Ramp and Bounds.
  • No early-out: Sliding across seams (3.73 to 4.88 m of 5 from all 8 starts, 17.06 to 17.33 m of 20) and the bounces' spread.
  • The early-out without its crossing clause: Ramp, 7.2 mm into 30° at 2.3 m/s and 10.9 mm into 10° at 5 m/s.
  • Time 0 counted as a hit: Brushing past a wall's end (0 m of 20), and the box and the ball sent up past a block's top edge (0.005 and 0.22 m of 2).
  • A time-0 triangle passed over with no core sweep: Swinging in over a shelf's edge.
  • The whole velocity kept on a hit: the bounces' ratios to their own drops spread 4.5% at restitution 0.5 (0.971 to 1.016) and 4.6% at 0.8.
  • The map's contacts solved before the contacts between bodies: Pressed onto the map (17.4 mm).
  • The map's contacts at the bodies' 30 Hz: Pressed onto the map (10.5 mm) and the overlap case's rest (3.7 and 3.8 cm off).
  • A speculative point free to close by twice its separation: the bounces' spread and Landing (6.4 mm).
  • A speculative point held to half its separation: the tower on hand-built ground (10.05 mm off its column).
  • An overlap pushed out with no 3 m/s cap: the overlap case (7.21 m/s upright, 6.37 and 6.32 m/s tilted).
  • No smooth edges: the 3° convex crease, the concave edge, the wall on the floor's diagonal, the ball past a 3° crease, the overlap case and Ramp.
  • Every edge smooth: the edge contact across a triangle's unshared edge, and Brushing past a wall's end (10.5 m).
  • The touched face always the front: the 3° crease, the 30° ridge, the concave edge, the box short of a ramp, the balls past and on the bisector of a crease, Pressed onto the map, the overlap case, Smooth slope, Ramp, the plank, Ridges and A slow ball over a crease.
  • The touched face the side the contact normal leaves, within IN_PLANE the side holding the origin (7a250f3's rule): the tilted overlap cases (0.40 to 0.45 m off).
  • The touched face the side of the plane holding the origin: A plank leaning on a block's top edge (1.25 m off).
  • A contact's edges by the region of its point on the triangle (7a250f3's closestOnTriangle(point).edges): A plank leaning on a block's top edge (1.09 m off) and A ball over convex creases (rose 15.4 mm).
  • The features' contact kept for a body with no part over a smooth edge's face, whatever its direction (fc21030's rule): Sliding across seams (3.34 to 3.85 m of 5, 14.65 m of 20), Smooth slope, A ball over convex creases and the ball past a 3° crease.
  • An empty face clip past smooth edges giving no contact (d8820ae's rule): Ridges (a body on the ridge through the map, 19 m), A slow ball over a crease, the ball past a 3° crease, the ball on the bisector and the ball centred over a coplanar seam (2152 of the 12,000 left to neither triangle).
  • The features' contact past smooth edges kept past a neighbour's normal: Sliding across seams (3.34 to 3.85 m of 5, 14.65 m of 20), Smooth slope and A ball over convex creases.
  • The features' contact past smooth edges kept by every triangle about the edge: the ball past a 3° crease (the triangle whose normal lies farther gives it too).
  • The features' contact kept by the triangle whose normal lies farther: the ball past a 3° crease.
  • AS_NEAR 0: the ball on the bisector of a convex crease (8 of the 400 creases left it to neither triangle), and the ball centred over a coplanar seam (88 of the 12,000 left to neither).
  • Past a smooth edge, past the neighbour's normal by any turn, with no tolerance (0a1c6a5): the ball centred over a coplanar seam (31 of the 12,000 left to neither triangle).
  • AS_NEAR 0.01: the ball past a 3° crease (both triangles keep it).
  • Faces reaching past no concave edge: Ramp (39 and 164 mm into 30° at 5 and 20 m/s) and the contacts test's box short of a ramp.
  • A face reaching past its concave edges wherever the body's origin lies: the box sent up past a block's top edge (it held under it, −0.035 m).
  • A sharp edge's contact kept past the neighbour's normal: the box and the ball sent up past a block's top edge (0.59 and 1.89 m of 2).
  • Cores given the face's plane point past every smooth edge (7a250f3's): A ball over convex creases (rose 3.3 mm, against 1.3 mm of flight), the capsules lying along Ridges and the ball past a 3° crease.
  • Of edge pairs as far apart, the first kept: the contacts test's box edge-down across a triangle's edge (its contact on its far edge, and the face normal in place of the edge's), Sliding across seams (4.34 m of 5, 16.34 m of 20) and Smooth slope.
  • ON_EDGE 0: the same edge contact, Sliding across seams (3.34 m of 5), Smooth slope, A plank leaning on a block's top edge and A ball over convex creases.
  • A convex edge smooth to 45° (the wedge bound): the 30° ridge, and the concave edge's convex back.
  • The wedge measured by the neighbour's winding, not its corners: rewinding the neighbour leaves the first triangle's wedges and swaps the neighbour's own.
  • Edge-edge axes never chosen: the edge contact.
  • A capsule parallel to an edge giving one point, at both of polySegment's sites: the capsules lying along a triangle's edge and along a box's edge, and Ridges (the capsules 2 mm off, 15 to 18 mm deep).
  • One point where the edge, not the face, holds the closest points (polySegment's first site): the capsules lying along a triangle's edge 45° round from its face and along a box's edge.
  • One point where no part of the segment lies over the face (its second site): the capsule lying along a triangle's edge past it, and Ridges.
  • The points along an edge at the closest points' separation, not their own: the capsule lying along a triangle's edge (its raised end at 0.0010 for 0.0110), and the capsule lying along a box's edge (its far point at 0.0010 for 0.0122).
  • alongEdge taking any edge the segment runs parallel to, not the one its closest points lie on (0a1c6a5): the capsule lying along a box's edge (both points on the box's opposite lower edge, 0.708 and 0.719 m off).
  • PARALLEL 0.01 (0a1c6a5): the capsule lying along a box's edge, turned 0.025 off it (1 point).
  • alongEdge's points not clipped to the edge's extent (0a1c6a5): the capsule lying along a box's edge (its far point at 0.0510 for 0.0122, from the capsule's own end).
  • alongEdge's two points sharing one feature id (0a1c6a5): the capsule lying along a box's edge.
  • Islands never sleep: the tower settles and sleeps.
  • A body sleeping alone once still, not with its island: the tower, and the impulse waking it.
  • A body still at any speed: the spinning box stays awake, the tower on the test scene, and the slides.
  • A body still without its spin term: the spinning box stays awake (it slept, its spin zeroed).
  • The map's contacts joining islands: the box apart from the struck one stays asleep.
  • A contact wakes no sleeping body: a ball thrown at the sleeping tower wakes it.
  • An impulse wakes only its own body: the impulse to the top box wakes the whole tower.
  • setPose waking nothing: setting the top box's pose wakes the tower.
  • setVelocity waking nothing: setting the top box's velocity wakes the tower.
  • No bounds: Bounds.
  • No sweep against the bounds: Bounds.
  • No warm starting: Slide (the 0.98 box creeps 7.5 mm), A plank leaning on a block's top edge (1.9 mm) and the tower.
  • Damping 1 − d·dt, not (1 − d)^dt: Damping (1.212 m/s against 1.0).
  • No linear damping: Damping (2.0 m/s).
  • GJK weighing a face's point by Ericson's va/vb/vc: the tower on the test scene's 600 m ground triangles, and the capsule lying along a triangle's edge in physics_distance.
  • GJK keeping a sliver face's weights off the face (d8820ae's): the capsule lying along a triangle's edge, turned a little off it (its closest point 1311 m along the edge).
  • GJK holding the origin inside a tetrahedron by its faces' signs alone (d8820ae's): the capsule lying flat over a tilted triangle (read as overlapping it).
  • A time of impact that does not bound the turn: a box turned onto the floor by its spin alone (133 mm deep).
  • A capsule's inertia a cylinder's alone: the shapes test's capsule inertia, and Pressed onto the map.
  • Hulls keeping collinear points as corners: the hull of a box's corners has 8 vertices.
  • The 4-point reduction started from the clip's first point, not the deepest: the tilted octagonal prism keeps the corner it tilts toward (4.1 mm against 1 mm).

In an arm of aa261b9, 42 ran: the previous round's 21, every one of which fails as its line says, and 21 of this round's rules, of which 15 fail:

  • The body's side the origin always, never its nearest core point: On the first map, the capsule tipping off a trunk's top (104 mm into it).
  • The edges' side by the origin alone: the same (104 mm).
  • The nearest core point with no SLOP guard: Smooth slope (stopped at x 0.24) and Ramp (39 and 164 mm into 30° at 5 and 20 m/s, 16.8 mm at 2.3 m/s): review run 1782's "gap.onB everywhere breaks Ramp", which the guard answers about every edge.
  • The nearest core point also where the shapes overlap: the overlap case (1.3 to 8.2 cm off from tick 15).
  • No end reaching into the gap past a smooth convex edge, and none where a face is the reference: Ridges' yawed and turned capsules (15.2 to 66.6 mm).
  • The gap's ends without the pastNeighbour clause: the capsule lying across a coplanar seam (each floor triangle reaches to the end over the other).
  • The gap's ends without nearer: the capsule lying along a smooth crease, its end on A's side of the bisector (B reaches to it).
  • The gap's ends past sharp edges too: the capsule lying on B of a 30° crease (B reaches 3 cm past the edge).
  • No far end at a sharp edge, and the nearer end of the part over the face in its place: Pivoting across a sharp ridge (all six turning starts, 12.8 to 21.3 mm).
  • An edge no other triangle shares taking the front face always (0a1c6a5's wedges): Over a plate (6.8 to 11.6 mm).
  • Swept by the velocity at the tick's end alone: On the first map, the two capsules turning onto a strip (10.0 and 8.5 mm); the displacement without its turn, or without its translation: the second (8.5 mm).

Six survive:

  • Inside the face, the side of the plane holding the origin. A contact inside the face whose features are not a face reference comes only from an edge pair's axis, for shapes that overlap, where the side point is the origin anyway. No figure moves.
  • The nearest core point about edges within SMOOTH_EDGE of flat alone, the origin about others, as review run 1782's prototype had it. No figure moves, nor any of Ramp at 5° to 45° and 1.5 to 20 m/s, or boxes sliding into walls of 60° to 90° sharing the ground's edge. With the guard, a point more than the slop off the plane decides the side about any edge; this round keeps the one rule.
  • No gap ends on the touched face (the path where the features are a smooth edge's), and an end past two of the face's edges reaching into the gap: no case or probe reaches either; no figure moves.
  • The far end at its separation along the face's normal, not along the contact's direction: the two differ by the cosine of the angle between them, which the edge's bend bounds (0.55% at the 6° ridge); deepest figures move by 1 or 2 µm.
  • The far end with no check that the contact's direction leaves the face: that direction can turn below the face only where the side point is the origin and the shapes nearly overlap; no figure moves.

Three survive from earlier rounds, judged equivalent, as review run 1765 accepted:

  • The early-out without its centroid clause. The clause differs only for a body whose nearest point comes no more than SPECULATIVE closer to the plane while its centroid ends within its core radius of it. That centroid lies a quarter of the least extent from the plane at most, so the body is already three quarters of it deep. Translation moves the centroid as far as the nearest point, so only such a body that is also turning can tell the two rules apart.
  • A body whose side lies beyond another triangle sharing the contact's edges keeps its features' contact, in place of none. The body then lies in a wedge another triangle bounds, as a box on one floor triangle against a wall standing on the diagonal does for the other floor triangle. The features' direction from the shared edge points into that wedge, the way the wall's and the floor's own contacts already push.
  • Edges that disagree give no contact, in place of the features' contact. They disagree only at a corner, for a body whose side lies in one face's wedge about one edge and the other's about the other: a body reaching past the corner on one side and not the other. Either choice leaves the body to the triangles about that corner.

Past-the-neighbour where an edge is sharp takes no tolerance: there the triangle across the edge reads the same direction as its own normal, far from the bound. Boxes resting over a ridge with their contact on the bound of the edge's normals sleep at the same tick, within microns, whichever side of the bound rounding puts them. No mutant is held to D7's order among contacts between bodies, nor to friction solved in the relax alone, as the task says.

After review run 1797, in an arm of 086b739, the 42 mutants of the earlier rounds ran again, with 15 of that commit's own; in an arm of fa141fe, this round's final 15 ran, and the six earlier ones that touch the far end and the side point. Every earlier mutant fails as its line says, but for:

  • The body's side the origin always, and the edges' side by the origin alone, which the capsule tipping off a trunk's top killed (104 mm into it at aa261b9), now survive: taken by the origin, the trunk's faces have no points there, as the reach bound drops the ones that face gave past the trunk's corner. The side still decides some speculative points: compared with a copy of collideTriangle that takes the origin, over 60,000 poses of the three shapes near the first map's triangles, 5 of 12,769 small capsules and 13 of 4,754 large ones clear of the map have a different manifold, and 16 of 15,544 small capsules near its steep triangles; each a point at a positive separation from one rule and none from the other, never a point deeper than the slop from either.
  • The nearest core point with no SLOP guard fails the buried capsule now, not Smooth slope or Ramp: the reach bound drops the points past the ramp's foot that pushed the box in.

This round's mutants, each failing the case named:

  • FLAT_EDGE 0: the capsule beside the trunk's side, past its corner (−0.139 m).
  • FLAT_EDGE 0.2: Ramp at 10° and 5 m/s (14.5 mm in).
  • No reach bound: the box and the capsule over the trunk's top (−0.122 and −0.121 m).
  • No plane bound: the box over the top (−0.113 m).
  • No extent bound: the capsule over the top (−0.121 m).
  • The plane bound with no slop: Ramp at 30° and 2.3 m/s and at 10° and 5 m/s (19.2 and 14.5 mm in): a box resting a millimetre into the ground has its front corners a hair behind the ramp's plane at its foot.
  • The reach bound on polytopes alone: the capsule over the top; on segments alone: the box over the top.
  • No over-face side: the box over the cap's middle triangle (−0.090 m).
  • The over-face side for any body whose core is clear: the buried capsule (the second triangle's normal y −0.98, the cell's deepest point −0.084 m for −0.552 m).
  • The over-face side the side of the plane holding the origin: two of the trunk's bodies (−0.086 and −0.092 m), and On the first map the capsule tipping off a trunk's top (53 mm in).
  • overFace taking a polytope's part over the face from the front face's clip alone: the box over the cap.

One survives: the far end bounded too, the reach bound applied to the far end a sharp edge's segment takes. No case or probe reads a difference, and this round leaves that end unbounded, as it was.

The bake stamp

In a scratch git archive arm of 7a250f3, a new module src/world/extra.sx that only src/world/world_format.sx imports, with the stamp functions of the head's and of master's tools/bake.sh run there under bash:

  • the head's stamp 1588a2ed… → one byte added to extra.sx → 3b84241e…; one byte then added to src/sim/player.sx → 3b84241e…, unchanged;
  • master's STAGE_MODULES stamp 5e6a351b… → the same byte in extra.sx → 5e6a351b…, unchanged.

The walk from tools/bake/stage_main.sx reaches src/physics/collision.sx, src/render/constants.sx, src/scene/baked_format.sx, src/world/world_format.sx and the two tools/bake/ files, the old list exactly, and src/world/extra.sx once it is imported.

Gates

  • full at 53c8d23: passed, gate run 840.
  • full at e0dba82: passed, gate run 841.
  • full at 3c0acd8: passed, gate run 842.
  • full at fc21030: passed, gate run 843.
  • full at 7a250f3: passed, gate run 849 (31 of 31).
  • fast at 7c8d2f5: passed, gate run 855 (31 of 31).
  • full at 4f6d30c: passed, gate run 856 (31 of 31).
  • full at d8820ae: passed, gate run 858 (31 of 31).
  • full at e3cdf79: passed, gate run 862 (31 of 31).
  • full at 1ed4462: passed, gate run 863 (31 of 31).
  • full at 0a1c6a5: passed, gate run 868 (31 of 31).
  • fast at a067031: passed, gate run 874 (31 of 31).
  • full at aa261b9: passed, gate run 877 (31 of 31).
  • full at 086b739: passed, gate run 880 (31 of 31).
  • full at fa141fe: passed, gate run 882 (31 of 31).
Tracker: [#3900](https://sak.swipelab.com/tasks/3900) Step 1 of plan #3865: the physics core, headless. Nothing changes in the app. ## What it delivers - `src/physics/shapes.sx`: sphere, capsule (along local +Y), box and convex hull shapes. `hullOf` builds a hull deterministically from the points' triples in index order, merges coplanar faces, wraps each face's corners and drops collinear points; it fails `Flat` on points that span no volume. Least and greatest extents, the core radius, exact inertia about the origin (a hull's by tetrahedra from the origin, so an off-centre hull takes the parallel-axis term), `Mat3`, `Pose` and the sweep's lerp/nlerp `between`. - `src/physics/distance.sx`: GJK closest points between cores (point, segment, polytope, map triangle), after `b2ShapeDistance`; an interior face point is weighed by its areas, which keeps its precision on the test scene's 600 m ground triangles. A sliver face of the simplex, its corners nearly in a line, whose weights come out off the face, takes its point on the nearest of its edges; a tetrahedron counts a face as one the origin lies outside where the origin lies past the face or past the corner opposite it, as a nearly flat one can round that corner to the origin's side. Conservative advancement (`timeOfImpact`, `planeTimeOfImpact`) to a target separation, bounding the turn by nlerp's fastest rate, 4 tan(φ/2). - `src/physics/contacts.sx`: manifolds once the closest points lie within `SPECULATIVE`, never otherwise. Polytope pairs take the separating axis over faces and edge pairs and clip the incident face (Gregorius), keeping every clipped point at its own separation, reduced to 4 (the deepest, then the three spanning the largest area). Of edge pairs as far apart, which parallel edges give, the pair whose own edges lie nearest along the axis makes the contact. A capsule's segment is clipped to the reference face whatever its tilt, one point when its clipped part projects to one point. A capsule whose closest points lie on a polytope's edge it runs parallel to (`PARALLEL`, coreCore's 0.05) has a point at each end of its part along the edge, each at its own separation, as two parallel capsules do. Spheres and capsules between themselves take their cores' closest points, two for parallel capsules. The map's bounds are planes. - **A map triangle** is a two-sided hull of one face. A face's contact is the part of the body over the face, and the face reaches on past each edge concave from it whose wedge holds the body's origin: the neighbour there rises toward the face and cannot keep the body out. Past such an edge it takes only the part of the body alongside the edge and no more than `SLOP` behind its plane: the wedge it reaches into lies in front of its plane, and the triangles bounding that wedge end at the edge's ends. - **The touched face.** A contact with a face as the reference is that face's. A body clear of the triangle with part of its core over the face touches the face its closest points' normal leaves: the plane through the closest points keeps the triangle on one side and the body on the other, so that part lies wholly on that side. A body that overlaps the triangle is not held to this: a capsule standing 0.55 m into the terrain, its core crossing one triangle and passing under the next, clear of it, has its part over that next triangle below it. Any other contact lies on the triangle's edges its point on the triangle (the manifold point taken back half its separation) comes within `ON_EDGE` (0.1 mm) of. It touches the face whose wedge holds the body's side about those edges, or inside the face the side of the plane holding it. The body's side is its core's point nearest the triangle where the two do not overlap and that point lies more than `SLOP` off the plane, and its origin otherwise: a long body's origin can lie across the plane from the part of it the triangle touches, and a point within the slop of the plane can lie on either side. About an edge no other triangle shares both wedges are whole turns, and the body touches the face on whose side of the plane its side lies. A body whose side lies beyond another triangle sharing the edges has no contact with the triangle; where two edges disagree, the contact keeps its features' direction. The task names the side of the plane the contact normal leaves; there an edge pair's axis about a shared edge, turned out of the plane by a body's tilt, picks the face by its sign (the tilted overlap cases), and the side of the plane holding the origin puts a plank leaning on a block's top edge against the top's underside. - **Smooth and sharp.** Where an edge is sharp from the touched face, the contact keeps its features' direction, unless that direction turns past the normal of the triangle sharing the edge: that triangle's face holds the body there, and this triangle gives no contact, as Box2D's chain segments leave a normal past a convex neighbour's to the neighbour. A capsule's one point there is joined by the end of its part over the face farther from that point, at its separation along the contact's direction from the face's plane, so that a capsule turning about the edge onto the face meets it on a speculative point. Where every edge is smooth, the contact is the face's. A capsule's end past an edge smooth from the face, short of the neighbour's normal and nearer this face's, lies in the gap over neither face, and the face's contact reaches to it at its own separation; past a concave or flat edge an end lies past the neighbour's normal and gets nothing from this face. When no part of the body lies over the face, the body lies past the edges: where the features' direction turns no more than `AS_NEAR` past any neighbour's normal, which only a convex or flat edge allows, the triangle whose normal lies nearer that direction than each neighbour's keeps the features' contact, and elsewhere the neighbours' faces hold the body. Nearer is within `AS_NEAR`, 1e-4 in the two dot products, and past the neighbour's normal is past it by more than `AS_NEAR` on `turnOf`'s scale: each triangle rounds a contact on the bisector its own way, and both keep it rather than neither. At a coplanar seam the bisector is the shared normal, the very bound past the neighbour's normal reads, and a ball centred over the seam, which each triangle's clip can round off its own face, was held by neither triangle without that tolerance. - `src/physics/solver.sx`: Box2D v3's constants in one place, soft contacts (30 Hz between bodies, 60 Hz against the map, ζ 10), the biased push of normal impulses, integration, the relax of normals then Coulomb friction across both tangents together, restitution once a tick from the pre-solve velocity (max of the two, the map 0, nothing under 1 m/s), Blender's (1 − d)^dt damping. - `src/physics/dynamics.sx`: bodies and `PhysicsWorld` (`addBody`, `applyImpulse`, `setPose`, `setVelocity`, `step`), the sort-and-sweep pairs, map candidates from `within`, the bounds as walls, contacts between bodies first and the map's last in every pass, warm starting by key and feature id, points solved in feature-id order, the continuous sweep of every body travelling more than `SPECULATIVE` a tick (the core's sweep for a triangle touched at time 0, the lost gravity taken off), islands and sleeping. It imports nothing from `src/sim/`: `init` takes the tick's length. - **Which bodies.** A body is swept when the task's travel, |v|·dt plus |ω|·dt times its greatest extent from its velocity at the tick's end, or the most any of its points moved over the tick, |Δx| plus twice its greatest extent times the distance between the start and end orientations, passes `SPECULATIVE`. A contact that stops a body late in the tick leaves it with little velocity after it moved several centimetres, through a triangle that had no contact at the tick's start: capsules dropped on the first map's terrain went 8.5 mm into it at 0a1c6a5 that way. - **The early-out.** The sweep passes over a triangle the body moves along: its nearest point comes no more than `SPECULATIVE` closer to the plane, without passing from in front of it to more than the slop behind, and its centroid ends at least the core radius in front. The middle clause is beyond the task's rule: a body starting a tick just beyond `SPECULATIVE` of a ramp has no contact with it, and closing on the ramp's plane by less than `SPECULATIVE` it sank up to (v·dt − `SPECULATIVE`)·sin θ, 7.2 mm into 30° at 2.3 m/s and 10.9 mm into 10° at 5 m/s. - `src/physics/collision.sx`: each triangle's six wedges of free space (`Wedges`, a turn per edge and face on `turnOf`'s scale, a whole turn for an edge no other triangle shares), built by `buildWorld` from the triangles' corners; `inner` is unchanged. An edge is smooth from a face where its wedge spans at most 180° + 5°, and concave where it spans less than 180° by more than `FLAT_EDGE`, 0.0015 on `turnOf`'s scale (0.086°, over the 0.081° `COPLANAR` allows two normals): the first map's fir trunk proxies are slivers 13.9 m tall whose diagonals round up to 6e-4 short of flat. `src/world/world_format.sx` carries the wedges at world file version 4, 24 bytes a triangle, and the bake writes them from both scenes: the first map's world file is 17.4 MB where six bits made it 12.8 MB. - The task asks the world file for six bits. The contact rule above needs each wedge's turn, not only its class, to tell which wedge holds a body, so the file carries the turns and the bits are read from them (`Wedges.smooth`). - `tools/bake.sh`: the stamp hashes every repository file the stage reaches through `@import`, resolved beside the importing file and then from the root, instead of the hand-kept `STAGE_MODULES`. - Tests: `physics_shapes`, `physics_distance`, `physics_contacts`, `physics_bodies`, `physics_stack` (hand-built ground and `baked/test_scene.hbw`), `physics_determinism`. `tests/support/worlds.sx` gains `incline` and `tessellated`; `tests/bake_stage.sx` checks the wedges the world file holds. - Sliding across seams runs from 8 starts across a quarter cell, at 5 and at 20 m/s, each within 1% of its distance. At fc21030 a box whose front started a tick within `SPECULATIVE` short of the next cell took a horizontal contact from it: 4.343 and 3.868 m of 5 from 0.125 and 0.375 m along, 16.34 m of 20 from 0.125 m. - The overlap case sinks a box 0.4 m into ground facing down (as `Shapes.floor`'s does) and facing up, across their diagonal, upright and tilted 0.5° and −2° about x. Upright it rises at 3.62 and 3.13 m/s, under 4 m/s, and rests within 1 cm of the ground from tick 15 on (from tick 14 on both); tilted, every case rests within 6.9 mm from tick 15. At 7a250f3 an edge pair's axis tilted out of the plane picked its face by its sign: 3 of the 4 tilted cases were 0.40 to 0.45 m off at tick 15. - `physics_stack` adds: a box spinning in place at 2 rad/s with no gravity stays awake; of two boxes resting 4 m apart, an impulse to one leaves the other asleep, its pose bit for bit, for 60 ticks; `setVelocity` and `setPose` on the sleeping tower's top box, even to the values it has, wake the whole tower. - `physics_contacts` adds an octagonal prism lying on a triangle, tilted 2° toward each of two neighbouring corners in turn: of its 8 clipped corners the 4 kept include that corner, at its gap. It adds a box on the ground 1 cm short of a 30° ramp rising from the ground's edge, which has the ramp's face normal at its bottom face's 4 corners, each at its distance from the ramp's plane, and checks that the box edge-down across a triangle's edge has its contact midway between the two edges (at 7a250f3 it lay on the box's far edge, 14 cm up). The wedge cases read the wedges: the edge under a wall on a floor's diagonal is concave from above and flat from below, and rewinding a neighbour leaves the first triangle's wedges bit for bit. - **Ramp:** a 0.5 m box of friction 0 slides across level ground into a ramp rising from the ground's edge, from 8 starts across a tick's travel, and never ends a tick more than 6 mm inside it: 0.11 and 0.14 mm into 30° at 5 and 20 m/s (39 and 164 mm at 7a250f3), 4.9 mm into 30° at 2.3 m/s and 3.7 mm into 10° at 5 m/s, the early-out cases (19 and 15 mm at 7a250f3). Probes at 5° to 45° and 1.5 to 20 m/s ended at most 4.9 mm in, the slop the early-out allows. - **A ball along a low wall:** a ball rolling along a wall 0.2 m high, 2 mm clear of it, its centre under the wall's top, moves bit for bit as it does with no wall. At 7a250f3 the top's triangle took the ball as touching its underside: the ball sank 41 mm into the ground and stopped. - **Up past a block's top edge:** with gravity 0, a box and a ball beside a block, 2 mm clear of its side, their tops 1 cm below its top, sent up at 2 m/s, each rise 2 m in 1 s within 2% (1.972 and 1.984 m). At 7a250f3 the ball rose 0.13 m; with the top edge's contact kept past the side's normal, the box rose 0.59 m and the ball 1.89 m. - **A plank leaning on a block's top edge:** a plank 2 m long leaning at 55° from the ground onto a block's top edge, its centre outside and below the top, rests there, moving 0.09 mm. Touching the face on the side of the plane holding the origin pushes it 1.25 m off the edge, and finding the contact's edges by the region of the manifold point on the triangle, as 7a250f3 did, 1.09 m off. - **A ball over convex creases:** a ball rolling at 3 m/s over facets each 3° steeper than the last never rises off them more than its flight over such a crease, v² sin² 3° / 2g = 1.3 mm. At 7a250f3 a sphere got the face's plane point past a smooth edge and rose 3.3 mm. - **Ridges:** a ball and a capsule lying along the ridge, both of radius 0.15, the capsule 1.5 m long, set at rest on ridges bent 3° and 4.6°, which are smooth, on the ridge and 2 mm off it, and the capsule along a sharp ridge bent 6°, 0, 2 and 4 mm off it. Past the edge each lies over neither face. The capsules 2 mm off the smooth ridges are also yawed off the ridge's line (0.002 rad on 3°, 0.005 rad on 4.6°) and set in a world turned 1.1 rad about +Y: each then lies partly over one face and partly past the edge. Over 2 s none goes more than 6 mm into the map, measured from the two half-spaces under the ridge, not by GJK: 0.03 to 0.35 mm. At 0a1c6a5 the yawed and turned capsules sank 25.5, 66.6, 15.2 and 16.5 mm: the earlier claim that no Ridges body goes past 6 mm held only for capsules lying exactly along the ridge's line. At d8820ae a body on a smooth ridge fell through the map (19 m in 2 s), 2 mm off it sank 89 to 107 mm, and the capsule 2 mm off the sharp ridge, its one point see-sawing between its ends, sank 18.4 mm. - **A slow ball over a crease:** a ball rolling at 0.25 m/s off level ground over a crease 4.6° convex goes at most 0.58 mm into the map (12.6 mm at d8820ae). - **Pivoting across a sharp ridge:** a capsule of radius 0.15, 1.5 m long, lying along face A of a ridge bent 6°, its axis square to the ridge or 30° or 45° off, its centre 0.05 or 0.15 m past it, set turning at 2 rad/s onto face B, and one 0.3 m past it turning by its own weight. None ends a tick more than 6 mm into the map: at most 0.1 mm, against 12.8 to 21.3 mm at 0a1c6a5, where B gave only the ridge's one point and the capsule's end landed on B with no point of its own. - **Over a plate:** the same capsule, 0.15 m past, square and 30° off, turning at 3 and 4 rad/s onto a plate 12 mm above face B, a quad that shares no edge, ends no tick more than 6 mm into the plate or the map: at most 0.13 mm, against 6.8 to 11.6 mm at 0a1c6a5. The plate's edge under the capsule has the plate's upper face for the capsule above it; with the front face taken always, as 0a1c6a5's wedges did for an edge no other triangle shares, the plate's far end point was dropped. - **On the first map** (`baked/first_map.hbw`): capsules of radius 0.15, 1.5 m long, set down on a tree trunk's top tipping off beside it (review run 1782's repro, 91.7 mm into the trunk at 0a1c6a5), across a sharp crease of the terrain (17.3 mm), and two turning about a sharp crease onto a strip whose far side rises (0.3 and 8.5 mm at 0a1c6a5). None ends a tick more than 6 mm into the map over 2 s: 0.9, 0.7, 0.4 and 0.7 mm. The last two need the sweep's displacement: the contact holding the turning end stops the turn late in the tick after the end has passed into the rising triangle, and without it they go 10.0 and 8.5 mm in. - `physics_contacts` adds three cases for the gap's ends: a capsule lying across a coplanar seam has from each floor triangle points over that triangle alone; a capsule lying along a smooth 4.6° crease, yawed, its end in the gap on A's side of the bisector, has from B no point at that end; and a capsule lying on B of a sharp 30° crease, its end 3 cm past the edge, has from B points over B alone. - `physics_contacts` adds a capsule lying along a triangle's edge, 3 mm past it, its far end 0.01 m higher: 2 points, each at its own end's distance from the edge; and lying along it 45° round from the face, where the edge holds its closest points before any face does: 2 points (1 point each at d8820ae). It adds a ball past a 3° crease, over neither face, its centre a quarter and then three quarters of the way from one normal to the other: the triangle whose normal lies nearer gives the features' contact at the gap, the other none (at d8820ae neither gave one). And a ball on the bisector of a convex crease's normals, over 400 creases of 1° to 5° turned about +Y, has the features' contact from both triangles: with `AS_NEAR` 0, 8 of the 400 had it from neither. - `physics_contacts` adds a ball centred over the diagonal two coplanar triangles share, resting on it and sunk 1 and 10 mm into it, over 4000 quads tilted up to 20° and turned about +Y: one triangle at least gives it a contact. At 1ed4462, 31 of the 12,000 had a contact from neither. And a capsule lying along a box's top edge 45° round from its faces, rising 0.025 along it from 1 mm off and running out past the edge's end, the box having three other edges parallel to it: 2 points on that edge, one at its low end at the gap, the other at the edge's end at the capsule's own separation there (0.012249), each with its own feature id. - Probes after review run 1782's, at the head and at 0a1c6a5 alike: - capsules (radius 0.15) lying along ridges of 2° to 6°, 0 to 4 mm off them, yawed 0 to ±0.005 rad, in worlds turned 0, 0.37 and 1.1 rad: 101 of 300 went past 6 mm at 0a1c6a5 (95.9 mm deepest), none at the head (2.3 mm); - capsules of both sizes dropped at 320 places and yaws each on the first map's terrain (normal y > 0.95), lifted clear by 5 mm: the large ones went past 6 mm 2 times at 0a1c6a5 (8.5 and 12.0 mm) and never at aa261b9 in that sample (3.9 mm), which held for that sample only: review run 1797's seeds found one at aa261b9, 10.0 mm (its finding 1), and the next round's sample one at aa261b9 and at the head alike, 8.7 mm, rolling at 14.6 rad/s; the small ones 9 times at both, each rolling at 46 to 50 rad/s (the rolling sink below); - 2000 more small capsules and 600 dropped 0.6 to 2.6 m from the first map's 1041 trunk proxies: of the drops past 6 mm while not rolling fast (under 30 rad/s), 15 at 0a1c6a5 and 10 at the head. One lay inside a trunk at its start. The other nine spin at 16 to 29 rad/s; the three traced spin about their own axis, wedged against a steep face, climbing a fir trunk's proxy or slowing on a slope, their ground end 8.7 to 18.1 mm deep: the rolling sink, deeper under the push. In the deepest of them, a capsule rolling into a fir proxy, part of the depth is another mechanism: the proxy's side quads are slivers 13 m tall, their diagonals read 0.01° concave by rounding, and the side's face then reaches past its diagonal across the neighbour into the next side's region; with concave held to 0.086° past flat the capsule goes 11.5 mm in, not 18.1. Review run 1797 found that mechanism statically, and `FLAT_EDGE` (below) answers it. - Probes after review run 1773's. Of 120,000 balls centred over a coplanar seam, tilted up to 20° and turned, 342 had a contact from neither triangle at 1ed4462 and none at the head. A ball of 0.15 m sliding at 2 m/s along a coplanar seam over a 3° crease, the world turned 0.37 rad, went 10.6 mm into the map at 1ed4462, 4 ticks touching it with no contact, and one of 0.05 m 13.1 mm; at the head 1.9 and 2.8 mm. A ball of 0.15 m sent at 2 m/s down a 20° slope along a seam, turned 1.1 rad, went 17.9 mm in at 1ed4462 and 3.7 mm at the head, as at every turn, its rolling sink. - `physics_distance` adds two poses GJK misread at d8820ae. A capsule lying past a triangle's edge, turned off it by under 0.001 rad, met a sliver face whose weights put its closest point 1311 m along the edge, at a distance of 0.001 for 0.05. A capsule lying flat over a tilted triangle, 0.1 m clear of it, read as overlapping it. Over 200,000 poses about the first, GJK misread 140 by more than 1e-4 at d8820ae, by up to 1.47 mm and some short of the true distance, and 4 at the head, by at most 0.12 mm, each over it. Of 100,000 capsules lying flat over random triangles, 20 read as overlapping at d8820ae and none at the head. - Probes after the review's. Of 320 balls set at rest on the first map's terrain grid lines x = 60 and z = −60, 40 sank past 6 mm at d8820ae, up to 133 mm, and none at the head, whose deepest, 5.3 mm, are balls rolling down at 30 rad/s (the rolling sink below). Of 49 bodies dropped on a random heightfield of 12 × 12 cells, no sphere went past 1 cm at either; the capsules' cores read as overlapping it 3 times at d8820ae, GJK's flat tetrahedron, and never at the head, which they came within 1.4 mm of. - **Smooth slope:** a box of friction 0.083 sent at 0.8 m/s down facets of 10° and 13° by turns slows on 10° and speeds up on 13°, crosses all four creases, never comes farther than the slop from the map by GJK distance (0.55 mm at most), and never moves up faster than 0.05 m/s (0.029). The old case's box, of friction 0.1, never slid: against the map's 0.5 the combined 0.224 holds on 10°. - Figures at the head, printed by aa261b9's six physics tests in arms of fa141fe and of aa261b9, every line identical but two: the capsule tipping off a trunk's top on the first map goes 0.944 mm in, 1.145 mm at aa261b9, and the capsule across a sharp terrain crease 0.717 mm, 0.712 mm at aa261b9. Either `FLAT_EDGE` or the reach bound alone moves them, and with both taken out both read as at aa261b9: a face reaching past a terrain or trunk edge that reads concave by rounding gave those capsules points beside its plane. Arms of aa261b9 and of 0a1c6a5 printed alike, as did those of 0a1c6a5 and 1ed4462 and those of 1ed4462 and d8820ae: towers 5.6 mm (hand-built) and 9.4 mm (test scene) off their columns, asleep at ticks 46 and 53; pyramids 0.3 and 0.2 mm, asleep at 30; the 100 kg box on the 10 kg one 3.9 and 0.9 mm, asleep at 84 and 63; seams at 5 and 20 m/s from 8 starts, 4.999998 to 5.000000 m and 20.000000 m; the overlap cases on both windings, Ramp, the plank, the ball beside a wall, the box and ball up past a rim, Smooth slope and the balls over creases as above. - A ball rolling at 14 rad/s rests about 2.3 mm into the map, here as at 7a250f3, alone and beside the wall: each contact's anchor turns with the ball during the tick, as in Box2D's relax. Nothing here pins or changes it. - The early-out measures the body's nearest point against the triangle's whole plane, on the side its centroid starts. A long tilted body whose part far from the triangle lies across that plane is passed over while another part enters the triangle. A plank turning down about its end on the floor, its far end over a slab whose top lies above the plank's centroid, sinks into the slab's corner (passed over through its top and its side), here as at 0a1c6a5, and keeps out of it with the early-out off; the capsule over a plate goes 6.7 to 13.2 mm into the plate when turning at 6 to 8 rad/s, its surface already under the plate's plane at the ridge. The task names this rule; nothing here changes it. - A box centred on a single-quad fence's top, tilted 0.004 rad along its 10 m edge, rests 13.4 mm into it, as review run 1765 found: the edge pair of the box's edge and the fence's top beats the box's face and gives one point. Nothing here changes it. - **A fir trunk proxy.** `physics_contacts` builds the first map's trunk proxy at (-48.1, 6.9 to 20.8, -40.6) from its 22 baked triangles, as literals, and sets four bodies at least 1 mm clear of it. No triangle gives any of them a point deeper than the slop. At aa261b9 they get points at: - −0.139 m: a capsule beside a side, past its corner, where the side's diagonal reads 1e-5 short of flat and opened that side's face past it (`FLAT_EDGE`); - −0.122 m: a box over the top, its origin inside the column the sides bound, whose part outside a side's plane lies alongside that side's corner edge, concave from inside (the plane bound); - −0.139 m: a capsule over the top, its core inside that column above where the sides end (the extent bound); - −0.090 m: a box over the cap's middle triangle, its origin below the cap's plane outside the trunk, taken by its origin as touching the cap from below (the side the closest points' normal leaves). - **A buried capsule.** `physics_contacts` sets a capsule standing with 0.55 m of it in the first map's terrain, at (-31, 24.7, -97), from that terrain cell's 6 triangles, as literals. Its core crosses one triangle and passes under the other, clear of it, across their diagonal, 0.2° concave from above. Each triangle's contact pushes it up, and the cell keeps its buried end at −0.552 m. Taking the over-face side for any body whose core is clear, rather than one clear of the triangle, gives the second triangle's back face, and dropped on the map the capsule then falls through it (y −48.7 after 4 s); aa261b9 passes the case. - **Probes after review run 1797's,** at the head and at aa261b9: - the reviewer's static probe: 20,000 poses of each shape near the 15,317 steep triangles of the first map that have a wedge within 0.0015 short of flat, those at least 1 mm clear of the map. At aa261b9 55 of 15,696 small capsules, 131 of 9,679 large ones and 164 of 8,619 boxes had a point deeper than 5 mm, down to −3.57 m. At the head none did. - the same about every steep triangle (|n.y| < 0.3): 71, 170 and 166 at aa261b9, none at the head; and about every triangle of the map: 3, 15 and 13 at aa261b9, none at the head. - 200,000 poses of each shape about the trunk proxy built alone: 200 of 18,837 small capsules, 565 of 42,779 large ones and 489 of 35,631 boxes had a point deeper than 5 mm at aa261b9, none at the head. - the reviewer's static repros: finding 1's capsule (triangle 186997, −0.255 m) has from it 0.0757 m, the gap 0.0083 m; finding 2's (cap triangle 182891, −0.096 and −0.327 m) has nothing from it. - finding 1's dynamic repro, a capsule dropped at (−30.987884, 25.300947, −97.023788), yaw 0.282268: 9.9 mm into the map over 2 s at aa261b9 (the kick at tick 110), 7.1 mm at the head. It is wedged against the trunk, spinning up from 12.7 to 14.9 rad/s, and its depth grows with the spin: the rolling sink below. - the capsules lying along ridges (2° to 6°, 0 to 4 mm off, yawed 0 to ±0.005 rad, turned 0, 0.37 and 1.1 rad): 300 runs, none past 6 mm, 2.42 mm deepest, at both. - Ramp at 5°, 10°, 15°, 20°, 30°, 40° and 45°, at 1.5, 2.3, 5, 10 and 20 m/s, from 8 starts each: at most 4.98 mm in, at both. - capsules of both sizes set on the first map's terrain at 320 places each (normal y > 0.95, lifted clear by 5 mm): small ones past 6 mm twice at both (6.6 mm deepest), the large one once at both (8.7 mm), rolling at 14.6 to 18 rad/s. - 2,000 small and 594 large capsules dropped 0.6 to 2.6 m over 1,797 small level triangles (trunk tops and others), many falling to the terrain beside them: past 6 mm 354 and 91 times at aa261b9, 375 and 100 at the head; with another seed 325 and 106, then 340 and 121. A third of the runs differ between the two, and the deepest roll at 20 to 72 rad/s, some landing at 15 m/s on 27° slopes; the worst at the head, 65 mm, lands so and rolls up to 44 rad/s. With `FLAT_EDGE` and the reach bound both taken out the runs are bit for bit aa261b9's: the extra depth comes from the points this round drops, whose push, beside the face's own, held rolling capsules up. The rolling sink is unchanged here, as before. The tuned values are Box2D v3's, unchanged. hulken's own: `FEATURE_TOLERANCE` (0.5 mm, a face over an edge pair), `SINGLE_POINT` (0.1 mm), `TOI_TOLERANCE` (a quarter of the slop), `ON_EDGE` (0.1 mm), `AS_NEAR` (1e-4), `PARALLEL` (0.05, coreCore's bound, now named) and `FLAT_EDGE` (0.0015 on `turnOf`'s scale). ## Mutants Each mutant was applied alone, as exact text, in a scratch `git archive` arm, and the six physics tests (shapes, distance, contacts, bodies, stack, determinism) rerun; each line names the cases that fail. The list ran in an arm of 1ed4462, but for the five marked (0a1c6a5). In an arm of 0a1c6a5, 21 ran: the five; every mutant below of the branch past smooth edges, `AS_NEAR`, `nearer`, `alongEdge`, `polySegment`'s two sites and GJK's three rules, each failing as its line says; and three more, which fail too: `nearer` against the triangle's in-plane direction and against the face's own normal (the ball past a 3° crease: both triangles keep it), and GJK's sliver fallback taking its first edge, not its nearest (the capsule turned a little off a triangle's edge in `physics_distance`). 74 of the 77 below fail. - Map friction taken as the body's, not √(μ · 0.5): Slide (1.695 m against 1.178 m) and the slipping sphere. - Friction between bodies the product, not √(μa μb): Slide on a body (2.861 m against 1.147 m). - Friction bounded along each tangent alone, not the two together: Slide on a body, sent across both tangents (0.805 m), and the tower on the test scene. - Restitution against the map the product, not the max: Bounce on the map (no rebound). - Restitution between bodies the min, not the max: Bounce between bodies. - No bounce threshold: Bounce threshold (rose 7.5 mm). - Restitution from the velocity after the solve: Bounce on the map. - A margin grown by the closing distance (0.8 m, the 50 m/s ball's tick, in the existence checks and the candidate boxes): the contacts test's box 0.025 m above a triangle, the bounces, both near misses and Sliding across seams (14.89 m of 20). - Points beyond `SPECULATIVE` dropped from every clipped manifold: Tilted landing (49 mm deep after 1 m, 79 mm after 2 m), the contacts test's turned box, its octagonal prism and its box short of a ramp, and Ramp (15 mm). - A capsule gives only its lowest point unless it lies flat: Pivoting onto the floor (6.8 m), Pressed onto the map (13.7 mm), Swinging in over a shelf's edge and the contacts test's tilted capsule. - No continuous sweep: Speed (the ball passes the wall), Landing, Tilted landing, the bounces, the spinning box, the shelf swing, Ramp and Bounds. - Swept only past half the least extent: Landing (53 mm deep after 1 m, 83 mm after 2 m), Tilted landing, Ramp and Bounds. - No early-out: Sliding across seams (3.73 to 4.88 m of 5 from all 8 starts, 17.06 to 17.33 m of 20) and the bounces' spread. - The early-out without its crossing clause: Ramp, 7.2 mm into 30° at 2.3 m/s and 10.9 mm into 10° at 5 m/s. - Time 0 counted as a hit: Brushing past a wall's end (0 m of 20), and the box and the ball sent up past a block's top edge (0.005 and 0.22 m of 2). - A time-0 triangle passed over with no core sweep: Swinging in over a shelf's edge. - The whole velocity kept on a hit: the bounces' ratios to their own drops spread 4.5% at restitution 0.5 (0.971 to 1.016) and 4.6% at 0.8. - The map's contacts solved before the contacts between bodies: Pressed onto the map (17.4 mm). - The map's contacts at the bodies' 30 Hz: Pressed onto the map (10.5 mm) and the overlap case's rest (3.7 and 3.8 cm off). - A speculative point free to close by twice its separation: the bounces' spread and Landing (6.4 mm). - A speculative point held to half its separation: the tower on hand-built ground (10.05 mm off its column). - An overlap pushed out with no 3 m/s cap: the overlap case (7.21 m/s upright, 6.37 and 6.32 m/s tilted). - No smooth edges: the 3° convex crease, the concave edge, the wall on the floor's diagonal, the ball past a 3° crease, the overlap case and Ramp. - Every edge smooth: the edge contact across a triangle's unshared edge, and Brushing past a wall's end (10.5 m). - The touched face always the front: the 3° crease, the 30° ridge, the concave edge, the box short of a ramp, the balls past and on the bisector of a crease, Pressed onto the map, the overlap case, Smooth slope, Ramp, the plank, Ridges and A slow ball over a crease. - The touched face the side the contact normal leaves, within `IN_PLANE` the side holding the origin (7a250f3's rule): the tilted overlap cases (0.40 to 0.45 m off). - The touched face the side of the plane holding the origin: A plank leaning on a block's top edge (1.25 m off). - A contact's edges by the region of its point on the triangle (7a250f3's `closestOnTriangle(point).edges`): A plank leaning on a block's top edge (1.09 m off) and A ball over convex creases (rose 15.4 mm). - The features' contact kept for a body with no part over a smooth edge's face, whatever its direction (fc21030's rule): Sliding across seams (3.34 to 3.85 m of 5, 14.65 m of 20), Smooth slope, A ball over convex creases and the ball past a 3° crease. - An empty face clip past smooth edges giving no contact (d8820ae's rule): Ridges (a body on the ridge through the map, 19 m), A slow ball over a crease, the ball past a 3° crease, the ball on the bisector and the ball centred over a coplanar seam (2152 of the 12,000 left to neither triangle). - The features' contact past smooth edges kept past a neighbour's normal: Sliding across seams (3.34 to 3.85 m of 5, 14.65 m of 20), Smooth slope and A ball over convex creases. - The features' contact past smooth edges kept by every triangle about the edge: the ball past a 3° crease (the triangle whose normal lies farther gives it too). - The features' contact kept by the triangle whose normal lies farther: the ball past a 3° crease. - `AS_NEAR` 0: the ball on the bisector of a convex crease (8 of the 400 creases left it to neither triangle), and the ball centred over a coplanar seam (88 of the 12,000 left to neither). - Past a smooth edge, past the neighbour's normal by any turn, with no tolerance (0a1c6a5): the ball centred over a coplanar seam (31 of the 12,000 left to neither triangle). - `AS_NEAR` 0.01: the ball past a 3° crease (both triangles keep it). - Faces reaching past no concave edge: Ramp (39 and 164 mm into 30° at 5 and 20 m/s) and the contacts test's box short of a ramp. - A face reaching past its concave edges wherever the body's origin lies: the box sent up past a block's top edge (it held under it, −0.035 m). - A sharp edge's contact kept past the neighbour's normal: the box and the ball sent up past a block's top edge (0.59 and 1.89 m of 2). - Cores given the face's plane point past every smooth edge (7a250f3's): A ball over convex creases (rose 3.3 mm, against 1.3 mm of flight), the capsules lying along Ridges and the ball past a 3° crease. - Of edge pairs as far apart, the first kept: the contacts test's box edge-down across a triangle's edge (its contact on its far edge, and the face normal in place of the edge's), Sliding across seams (4.34 m of 5, 16.34 m of 20) and Smooth slope. - `ON_EDGE` 0: the same edge contact, Sliding across seams (3.34 m of 5), Smooth slope, A plank leaning on a block's top edge and A ball over convex creases. - A convex edge smooth to 45° (the wedge bound): the 30° ridge, and the concave edge's convex back. - The wedge measured by the neighbour's winding, not its corners: rewinding the neighbour leaves the first triangle's wedges and swaps the neighbour's own. - Edge-edge axes never chosen: the edge contact. - A capsule parallel to an edge giving one point, at both of `polySegment`'s sites: the capsules lying along a triangle's edge and along a box's edge, and Ridges (the capsules 2 mm off, 15 to 18 mm deep). - One point where the edge, not the face, holds the closest points (`polySegment`'s first site): the capsules lying along a triangle's edge 45° round from its face and along a box's edge. - One point where no part of the segment lies over the face (its second site): the capsule lying along a triangle's edge past it, and Ridges. - The points along an edge at the closest points' separation, not their own: the capsule lying along a triangle's edge (its raised end at 0.0010 for 0.0110), and the capsule lying along a box's edge (its far point at 0.0010 for 0.0122). - `alongEdge` taking any edge the segment runs parallel to, not the one its closest points lie on (0a1c6a5): the capsule lying along a box's edge (both points on the box's opposite lower edge, 0.708 and 0.719 m off). - `PARALLEL` 0.01 (0a1c6a5): the capsule lying along a box's edge, turned 0.025 off it (1 point). - `alongEdge`'s points not clipped to the edge's extent (0a1c6a5): the capsule lying along a box's edge (its far point at 0.0510 for 0.0122, from the capsule's own end). - `alongEdge`'s two points sharing one feature id (0a1c6a5): the capsule lying along a box's edge. - Islands never sleep: the tower settles and sleeps. - A body sleeping alone once still, not with its island: the tower, and the impulse waking it. - A body still at any speed: the spinning box stays awake, the tower on the test scene, and the slides. - A body still without its spin term: the spinning box stays awake (it slept, its spin zeroed). - The map's contacts joining islands: the box apart from the struck one stays asleep. - A contact wakes no sleeping body: a ball thrown at the sleeping tower wakes it. - An impulse wakes only its own body: the impulse to the top box wakes the whole tower. - `setPose` waking nothing: setting the top box's pose wakes the tower. - `setVelocity` waking nothing: setting the top box's velocity wakes the tower. - No bounds: Bounds. - No sweep against the bounds: Bounds. - No warm starting: Slide (the 0.98 box creeps 7.5 mm), A plank leaning on a block's top edge (1.9 mm) and the tower. - Damping 1 − d·dt, not (1 − d)^dt: Damping (1.212 m/s against 1.0). - No linear damping: Damping (2.0 m/s). - GJK weighing a face's point by Ericson's va/vb/vc: the tower on the test scene's 600 m ground triangles, and the capsule lying along a triangle's edge in `physics_distance`. - GJK keeping a sliver face's weights off the face (d8820ae's): the capsule lying along a triangle's edge, turned a little off it (its closest point 1311 m along the edge). - GJK holding the origin inside a tetrahedron by its faces' signs alone (d8820ae's): the capsule lying flat over a tilted triangle (read as overlapping it). - A time of impact that does not bound the turn: a box turned onto the floor by its spin alone (133 mm deep). - A capsule's inertia a cylinder's alone: the shapes test's capsule inertia, and Pressed onto the map. - Hulls keeping collinear points as corners: the hull of a box's corners has 8 vertices. - The 4-point reduction started from the clip's first point, not the deepest: the tilted octagonal prism keeps the corner it tilts toward (4.1 mm against 1 mm). In an arm of aa261b9, 42 ran: the previous round's 21, every one of which fails as its line says, and 21 of this round's rules, of which 15 fail: - The body's side the origin always, never its nearest core point: On the first map, the capsule tipping off a trunk's top (104 mm into it). - The edges' side by the origin alone: the same (104 mm). - The nearest core point with no `SLOP` guard: Smooth slope (stopped at x 0.24) and Ramp (39 and 164 mm into 30° at 5 and 20 m/s, 16.8 mm at 2.3 m/s): review run 1782's "gap.onB everywhere breaks Ramp", which the guard answers about every edge. - The nearest core point also where the shapes overlap: the overlap case (1.3 to 8.2 cm off from tick 15). - No end reaching into the gap past a smooth convex edge, and none where a face is the reference: Ridges' yawed and turned capsules (15.2 to 66.6 mm). - The gap's ends without the `pastNeighbour` clause: the capsule lying across a coplanar seam (each floor triangle reaches to the end over the other). - The gap's ends without `nearer`: the capsule lying along a smooth crease, its end on A's side of the bisector (B reaches to it). - The gap's ends past sharp edges too: the capsule lying on B of a 30° crease (B reaches 3 cm past the edge). - No far end at a sharp edge, and the nearer end of the part over the face in its place: Pivoting across a sharp ridge (all six turning starts, 12.8 to 21.3 mm). - An edge no other triangle shares taking the front face always (0a1c6a5's wedges): Over a plate (6.8 to 11.6 mm). - Swept by the velocity at the tick's end alone: On the first map, the two capsules turning onto a strip (10.0 and 8.5 mm); the displacement without its turn, or without its translation: the second (8.5 mm). Six survive: - **Inside the face, the side of the plane holding the origin.** A contact inside the face whose features are not a face reference comes only from an edge pair's axis, for shapes that overlap, where the side point is the origin anyway. No figure moves. - **The nearest core point about edges within `SMOOTH_EDGE` of flat alone,** the origin about others, as review run 1782's prototype had it. No figure moves, nor any of Ramp at 5° to 45° and 1.5 to 20 m/s, or boxes sliding into walls of 60° to 90° sharing the ground's edge. With the guard, a point more than the slop off the plane decides the side about any edge; this round keeps the one rule. - **No gap ends on the touched face** (the path where the features are a smooth edge's), **and an end past two of the face's edges reaching into the gap:** no case or probe reaches either; no figure moves. - **The far end at its separation along the face's normal,** not along the contact's direction: the two differ by the cosine of the angle between them, which the edge's bend bounds (0.55% at the 6° ridge); deepest figures move by 1 or 2 µm. - **The far end with no check that the contact's direction leaves the face:** that direction can turn below the face only where the side point is the origin and the shapes nearly overlap; no figure moves. Three survive from earlier rounds, judged equivalent, as review run 1765 accepted: - **The early-out without its centroid clause.** The clause differs only for a body whose nearest point comes no more than `SPECULATIVE` closer to the plane while its centroid ends within its core radius of it. That centroid lies a quarter of the least extent from the plane at most, so the body is already three quarters of it deep. Translation moves the centroid as far as the nearest point, so only such a body that is also turning can tell the two rules apart. - **A body whose side lies beyond another triangle sharing the contact's edges keeps its features' contact,** in place of none. The body then lies in a wedge another triangle bounds, as a box on one floor triangle against a wall standing on the diagonal does for the other floor triangle. The features' direction from the shared edge points into that wedge, the way the wall's and the floor's own contacts already push. - **Edges that disagree give no contact,** in place of the features' contact. They disagree only at a corner, for a body whose side lies in one face's wedge about one edge and the other's about the other: a body reaching past the corner on one side and not the other. Either choice leaves the body to the triangles about that corner. Past-the-neighbour where an edge is sharp takes no tolerance: there the triangle across the edge reads the same direction as its own normal, far from the bound. Boxes resting over a ridge with their contact on the bound of the edge's normals sleep at the same tick, within microns, whichever side of the bound rounding puts them. No mutant is held to D7's order among contacts between bodies, nor to friction solved in the relax alone, as the task says. After review run 1797, in an arm of 086b739, the 42 mutants of the earlier rounds ran again, with 15 of that commit's own; in an arm of fa141fe, this round's final 15 ran, and the six earlier ones that touch the far end and the side point. Every earlier mutant fails as its line says, but for: - **The body's side the origin always, and the edges' side by the origin alone,** which the capsule tipping off a trunk's top killed (104 mm into it at aa261b9), now survive: taken by the origin, the trunk's faces have no points there, as the reach bound drops the ones that face gave past the trunk's corner. The side still decides some speculative points: compared with a copy of `collideTriangle` that takes the origin, over 60,000 poses of the three shapes near the first map's triangles, 5 of 12,769 small capsules and 13 of 4,754 large ones clear of the map have a different manifold, and 16 of 15,544 small capsules near its steep triangles; each a point at a positive separation from one rule and none from the other, never a point deeper than the slop from either. - **The nearest core point with no `SLOP` guard** fails the buried capsule now, not Smooth slope or Ramp: the reach bound drops the points past the ramp's foot that pushed the box in. This round's mutants, each failing the case named: - `FLAT_EDGE` 0: the capsule beside the trunk's side, past its corner (−0.139 m). - `FLAT_EDGE` 0.2: Ramp at 10° and 5 m/s (14.5 mm in). - No reach bound: the box and the capsule over the trunk's top (−0.122 and −0.121 m). - No plane bound: the box over the top (−0.113 m). - No extent bound: the capsule over the top (−0.121 m). - The plane bound with no slop: Ramp at 30° and 2.3 m/s and at 10° and 5 m/s (19.2 and 14.5 mm in): a box resting a millimetre into the ground has its front corners a hair behind the ramp's plane at its foot. - The reach bound on polytopes alone: the capsule over the top; on segments alone: the box over the top. - No over-face side: the box over the cap's middle triangle (−0.090 m). - The over-face side for any body whose core is clear: the buried capsule (the second triangle's normal y −0.98, the cell's deepest point −0.084 m for −0.552 m). - The over-face side the side of the plane holding the origin: two of the trunk's bodies (−0.086 and −0.092 m), and On the first map the capsule tipping off a trunk's top (53 mm in). - `overFace` taking a polytope's part over the face from the front face's clip alone: the box over the cap. One survives: **the far end bounded too,** the reach bound applied to the far end a sharp edge's segment takes. No case or probe reads a difference, and this round leaves that end unbounded, as it was. ## The bake stamp In a scratch `git archive` arm of 7a250f3, a new module `src/world/extra.sx` that only `src/world/world_format.sx` imports, with the stamp functions of the head's and of master's `tools/bake.sh` run there under bash: - the head's stamp 1588a2ed… → one byte added to `extra.sx` → 3b84241e…; one byte then added to `src/sim/player.sx` → 3b84241e…, unchanged; - master's `STAGE_MODULES` stamp 5e6a351b… → the same byte in `extra.sx` → 5e6a351b…, unchanged. The walk from `tools/bake/stage_main.sx` reaches `src/physics/collision.sx`, `src/render/constants.sx`, `src/scene/baked_format.sx`, `src/world/world_format.sx` and the two `tools/bake/` files, the old list exactly, and `src/world/extra.sx` once it is imported. ## Gates - `full` at 53c8d23: passed, gate run 840. - `full` at e0dba82: passed, gate run 841. - `full` at 3c0acd8: passed, gate run 842. - `full` at fc21030: passed, gate run 843. - `full` at 7a250f3: passed, gate run 849 (31 of 31). - `fast` at 7c8d2f5: passed, gate run 855 (31 of 31). - `full` at 4f6d30c: passed, gate run 856 (31 of 31). - `full` at d8820ae: passed, gate run 858 (31 of 31). - `full` at e3cdf79: passed, gate run 862 (31 of 31). - `full` at 1ed4462: passed, gate run 863 (31 of 31). - `full` at 0a1c6a5: passed, gate run 868 (31 of 31). - `fast` at a067031: passed, gate run 874 (31 of 31). - `full` at aa261b9: passed, gate run 877 (31 of 31). - `full` at 086b739: passed, gate run 880 (31 of 31). - `full` at fa141fe: passed, gate run 882 (31 of 31).
agra added 10 commits 2026-10-29 21:09:46 +02:00
buildWorld keeps each triangle's six wedges of free space, a turn per edge
and face, where it kept six smooth bits; the world file carries them. A
contact on a triangle's boundary touches the face whose wedge holds the
body's origin about the edges it lies on, not the side its normal leaves.
A face's contact reaches past each edge concave from it whose wedge holds
the origin. A contact on a sharp edge whose direction turns past the
neighbour's normal is the neighbour's.

A 0.5 m box sliding into a 30° ramp at 5 and 20 m/s sank 39 and 164 mm at
7a250f3, and now at most 0.13 mm. A box sunk across a diagonal and tilted
0.5° or -2° rests within 7 mm of the ground from tick 15, where 3 of the 4
new cases were driven 0.40 to 0.45 m off. A ball rolling beside a 0.2 m
wall moves bit for bit as with no wall; at 7a250f3 the wall's top drove it
41 mm into the ground. A ball beside a block below its top, sent up at
2 m/s, rose 0.13 m at 7a250f3 and now 2.0 m; a ball over 3° convex creases
rose 3.3 mm off them and now none.
A box that starts a tick just beyond SPECULATIVE of a ramp has no contact
with it, and closing on the ramp's plane by less than SPECULATIVE it was
passed over: it sank up to (v dt - SPECULATIVE) sin of the ramp's angle.
Into a 30° ramp at 2.3 m/s and a 10° ramp at 5 m/s it sank 7.2 and 10.9 mm
past the face reaching over the concave edge, and now 4.9 and 3.7 mm.
The box of friction 0.1 never slid: against the map's 0.5 a combined 0.224
holds on 10°. A box of friction 0.083 sent at 0.8 m/s slows on 10° and
speeds up on 13°, and crosses four creases. The case bounds the box's GJK
distance to the map by the slop and its upward speed by 0.05 m/s.
A manifold point lies midway between the surfaces, so the point projected
onto the triangle could read as inside its face by its half separation. A
plank leaning from the ground onto a block's top edge, its centre below
the top, then touched the top's underside and was pushed 0.19 m off the
edge. Each point is taken back onto the triangle, and an edge 0.1 mm from
it counts.

Parallel edges give one separating axis, and the first pair found kept it:
a long box edge-down across a triangle's edge had its contact on its far
edge, 14 cm from the one touching (and so at 7a250f3). Of pairs as far
apart, the pair whose own edges lie nearest along the axis is kept.
FLAT_EDGE and PAST_NEIGHBOUR's slack changed nothing a case or a probe
reads. On a tessellated plane turned 30° and sloped, where 468 wedges read
as concave by rounding, a box of friction 0 slid the same distance to
6 digits with and without FLAT_EDGE; boxes resting over a ridge, their
contact on the boundary of the edge's normals, slept at the same tick
within microns with and without the slack.
A fir trunk proxy's side quads are slivers 13.9 m tall, and their diagonals
round up to 6e-4 short of flat on turnOf's scale. Read as concave, a side's
face reached past its diagonal with nothing but its other two edges to
bound it, across the coplanar neighbour and the trunk's corner, and a body
clear of the trunk got points up to metres deep. physics_contacts builds
the first map's trunk proxy at (-48.1, 6.9 to 20.8, -40.6) from its baked
triangles and holds a capsule beside a side past its corner to no point
deeper than the slop.
A face's contact reached past a concave edge over everything past it,
beyond the neighbour and past the edge's ends, and a body clear of the map
there got points deep behind the face: over a fir trunk proxy's top, a
side's face reached from inside past its corner edge to a box's part
outside the side's plane and to a capsule whose core lay in the column
the sides bound, above where they end. A box over the cap's middle
triangle, its origin below the cap's plane outside the trunk, was taken
by its origin as touching the cap from below. physics_contacts holds a
body in each of these places, clear of the trunk, to no point deeper than
the slop, and a capsule standing 0.55 m into the first map's terrain to
contacts that push it up and keep its buried end.
Past a concave edge the wedge a face reaches into lies in front of its
plane, and past the edge's ends the triangles bounding it end too: those
two bounds are what hold the trunk cases, and the neighbour's half-plane
the wedge test also measured decided nothing a case or probe reads. The
far end a sharp edge's segment takes needs no bound. physics_contacts
holds a box over the trunk's top whose part outside a side's plane lies
alongside the side's corner edge, which only the plane bound answers.
agra merged commit 1d505fffbb into master 2026-10-30 05:26:54 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sx/hulken!17
No description provided.