Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
7fe6f3c
docs(brief): add M1.1.12 milestone brief
guysenpai Aug 4, 2026
eca0e4c
docs(brief): mark M1.1.12 specs read and open execution
guysenpai Aug 4, 2026
8f39761
docs(forge): sweep the stale two-term constraint-key prose
guysenpai Aug 4, 2026
bc1b5c2
feat(forge): freeze the character-controller api surface
guysenpai Aug 4, 2026
f677957
docs(brief): record M1.1.12 gate A execution
guysenpai Aug 4, 2026
71fb7a1
fix(forge): reserve PackedId.dead as the no-handle sentinel
guysenpai Aug 4, 2026
9330b5e
docs(brief): record the ground_body sentinel deviation
guysenpai Aug 4, 2026
7ecebb7
docs(forge): replace two justifications derived from outside the engine
guysenpai Aug 4, 2026
dd8ff4a
docs(brief): record the inner-body justification deviation
guysenpai Aug 4, 2026
29644f9
feat(forge): add collideShapeBody, the shape-against-body adapter
guysenpai Aug 4, 2026
44579a1
feat(forge): add the character controller store
guysenpai Aug 4, 2026
1d886be
test(forge): add the character controller acceptance suite
guysenpai Aug 4, 2026
54ae5d7
docs(brief): record M1.1.12 gate B execution
guysenpai Aug 4, 2026
4d03223
fix(forge): complete the character descriptor domain guards
guysenpai Aug 4, 2026
8f25d1e
feat(forge): determine the ground by a bounded downward sweep
guysenpai Aug 4, 2026
7df1174
test(forge): extend the character suite to ground determination
guysenpai Aug 4, 2026
5c3566a
docs(brief): record M1.1.12 gate C execution
guysenpai Aug 4, 2026
36aab2a
feat(math): re-export the exact triangle cross direction
guysenpai Aug 4, 2026
5ed3270
feat(forge): move a character by sweep, slide and depenetration
guysenpai Aug 4, 2026
0e869bb
test(forge): extend the character suite to the move
guysenpai Aug 4, 2026
8334c67
docs(brief): record M1.1.12 gate D execution
guysenpai Aug 4, 2026
db53683
feat(forge): climb steps and stick to the floor on descent
guysenpai Aug 4, 2026
024d5ae
test(forge): extend the character suite to step height
guysenpai Aug 4, 2026
ed604ff
docs(brief): record M1.1.12 gate E execution
guysenpai Aug 4, 2026
e1c60f2
feat(forge): slope-cap the slide, and resize, push and teleport
guysenpai Aug 4, 2026
970b5f5
test(forge): extend the character suite to resize, push and teleport
guysenpai Aug 4, 2026
cc6e23e
docs(brief): record M1.1.12 gate F execution
guysenpai Aug 4, 2026
8e3bb90
fix(forge): reserve before mutating on the presence write paths
guysenpai Aug 4, 2026
9d20f73
fix(forge): cap the slide at zero and never push through a plane
guysenpai Aug 5, 2026
10cc0fb
test(forge): pin the steep-face descent and the push-out direction
guysenpai Aug 5, 2026
b7286e1
docs(brief): record the M1.1.12 gate F corrections
guysenpai Aug 5, 2026
b11ed40
test(bench): add the character controller throughput bench
guysenpai Aug 5, 2026
7d332fe
docs(claude-md): update for M1.1.12
guysenpai Aug 5, 2026
2b93741
docs(brief): close M1.1.12
guysenpai Aug 5, 2026
4d288b5
fix(forge): close six review findings on the character controller
guysenpai Aug 5, 2026
d740011
test(forge): pin the six findings and a seventh found while probing
guysenpai Aug 5, 2026
5110a67
docs(brief): record the gate G round and hold the closure artifacts
guysenpai Aug 5, 2026
604fcec
fix(forge): cap the character's push per body, not per contact
guysenpai Aug 5, 2026
969e93d
test(forge): pin the push ceiling and report the seventh stopped
guysenpai Aug 5, 2026
e09898b
docs(forge): document the exact-tangency precondition on the descriptor
guysenpai Aug 5, 2026
81fc748
docs(claude-md): update for M1.1.12
guysenpai Aug 5, 2026
626b015
docs(brief): close M1.1.12
guysenpai Aug 5, 2026
a9c62c9
fix(forge): depenetrate to the padding stand-off, not to touching
guysenpai Aug 5, 2026
bbaa8a8
test(forge): flip the tangency pin and re-derive three expectations
guysenpai Aug 5, 2026
aed8d3a
docs(brief): record the third round and correct the artifacts
guysenpai Aug 5, 2026
3bee325
fix(forge): floor the depenetration stand-off so zero padding works
guysenpai Aug 5, 2026
746193d
test(forge): pin zero padding, and a 1 km limit that is not its residual
guysenpai Aug 5, 2026
f42fbec
fix(forge): bound padding above, and give every advance the stand-off
guysenpai Aug 5, 2026
3af40a5
test(forge): pin the padding bound and add the descriptor domain table
guysenpai Aug 5, 2026
9b828bf
fix(forge): scope the stand-off floor, and drop the padding guard
guysenpai Aug 5, 2026
bbafa6c
test(forge): pin the floor's scope and the stall's collider-size bound
guysenpai Aug 5, 2026
cbbe979
fix(forge): a non-opposing contact no longer consumes the slide budget
guysenpai Aug 6, 2026
3700677
test(forge): flip three stall pins, and fix a vacuous invariance test
guysenpai Aug 6, 2026
068280b
docs(claude-md): update for M1.1.12
guysenpai Aug 6, 2026
0da3419
docs(brief): close M1.1.12
guysenpai Aug 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions CLAUDE.md

Large diffs are not rendered by default.

387 changes: 387 additions & 0 deletions bench/forge_3d_character.zig

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions bench/results/forge_3d_character.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# forge_3d kinematic character controller bench

- Build mode: ReleaseFast
- 2000 calls per mode per rep, 8 INTERLEAVED reps, best rep reported
- Anti-DCE checksum: 31917.672

| mode | ns/call | calls/s | calls per 16.67 ms frame |
|---|---|---|---|
| moveCharacter / plane | 212.0 | 4716981 | 78616 |
| moveCharacter / stairs | 2235.5 | 447327 | 7455 |
| moveCharacter / wall | 1764.5 | 566733 | 9446 |
| moveCharacter / mesh floor | 7979.0 | 125329 | 2089 |
| resizeCharacter | 203.0 | 4926108 | 82102 |

**Reported, not gated.** No envelope is pre-registered: this is the first measurement of
this path, and registering a bound before measuring its baseline is the failure mode
recorded at M1.1.8.

Runs are INTERLEAVED — every rep runs all five modes in sequence and the best rep per mode
is kept — so a thermal ramp or a scheduling burst lands on all five rather than on
whichever happened to be measured while it passed. Best-of-N per mode cannot resolve a gap
under about 5 %, which is the size of the gaps between these rows.

The five rows are five different code paths, not five scales of one: the plane row runs the
ground sweep alone, the stairs row arms the climb's three sweeps, the wall row arms the
slide, the mesh row puts the ground sweep and the contact fallback on a `.triangle_soup`
shape, and `resizeCharacter` is the only row that allocates.
2,347 changes: 2,347 additions & 0 deletions briefs/M1.1.12-character-controller.md

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,34 @@ pub fn build(b: *std.Build) void {
);
forge_mesh_bench_step.dependOn(&forge_mesh_bench_run.step);

// -------------------------------- M1.1.12 forge character controller bench --
//
// `moveCharacter` on a plane / stairs / a wall / a triangle mesh, plus
// `resizeCharacter`, INTERLEAVED across reps. Writes
// `bench/results/forge_3d_character.md`. REPORTED, not gated — no envelope is
// pre-registered (bench header).
const forge_char_bench_module = b.createModule(.{
.root_source_file = b.path("bench/forge_3d_character.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
});
forge_char_bench_module.addImport("forge_3d", forge_3d_module);
forge_char_bench_module.addImport("weld_forge", forge_api_module);
const forge_char_bench_exe = b.addExecutable(.{
.name = "forge-character-bench",
.root_module = forge_char_bench_module,
});
b.installArtifact(forge_char_bench_exe);
const forge_char_bench_run = b.addRunArtifact(forge_char_bench_exe);
forge_char_bench_run.step.dependOn(b.getInstallStep());
if (b.args) |args| forge_char_bench_run.addArgs(args);
const forge_char_bench_step = b.step(
"bench-forge-character",
"Run the M1.1.12 forge character controller bench (five paths interleaved, writes bench/results/forge_3d_character.md)",
);
forge_char_bench_step.dependOn(&forge_char_bench_run.step);

// -------------------------------------- M1.0.5 scene loader bench --------
//
// `loadFromBytes` on a ~10k-entity image synthesized in-bench via the
Expand Down
11 changes: 11 additions & 0 deletions src/foundation/math/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ pub const CrossOutcome = vec.CrossOutcome;
/// Whether a triangle is EXACTLY flat, decided in integer arithmetic. THE classifier: callers that
/// must not admit a flat triangle ask this, never `triangleCross`.
pub const triangleIsFlat = @import("exact.zig").triangleIsFlat;
/// A vector PARALLEL to the exact area vector of three points, or `null` when that vector is
/// EXACTLY zero — the exact tier `triangleIsFlat` is written on, exposed for callers that need the
/// DIRECTION together with that exact null.
///
/// Re-exported at M1.1.12 for its second consumer: the character controller's edge slide, whose
/// direction is `n₁ × n₂` and whose `null` must mean "the two normals are exactly parallel" and
/// nothing weaker. The tiered `triangleCross` cannot serve there — its `.direction` comes from the
/// first float tier that forms a non-zero vector, so on exactly parallel normals it returns a
/// rounding residue that reads as a valid crease. That is the very confusion §1.11.17 records as
/// having nearly shipped.
pub const triangleCrossDirection = @import("exact.zig").triangleCrossDirection;
/// The power-of-two exponent that reduces three points below unit magnitude.
pub const pow2ReductionExponent = vec.pow2ReductionExponent;

Expand Down
18 changes: 17 additions & 1 deletion src/modules/forge/api/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ pub const EntityId = types.EntityId;
pub const BodyId = types.BodyId;
/// Opaque collision-shape handle (`u32`, same packing as `BodyId`).
pub const ShapeId = types.ShapeId;
/// The `index:24 | generation:8` packing shared by `BodyId`/`ShapeId`.
/// Opaque character-controller handle (`u32`, same packing as `BodyId`).
pub const CharacterId = types.CharacterId;
/// The `index:24 | generation:8` packing shared by `BodyId`, `ShapeId` and
/// `CharacterId`, and the `PackedId.dead` all-ones reservation those three use for
/// "no handle".
pub const PackedId = types.PackedId;
/// Simulation class of a body (static / kinematic / dynamic).
pub const BodyType = types.BodyType;
Expand All @@ -44,6 +48,18 @@ pub const BodyDescriptor = types.BodyDescriptor;
/// Physics pose (position + rotation, no scale).
pub const Transform = types.Transform;

// --- Character controller (`engine-physics-forge.md` §1.12) ---

/// Everything needed to create one character controller. A controller is VIRTUAL —
/// it takes part in no solver pass, and its pose is written by `moveCharacter` alone.
pub const CharacterDescriptor = types.CharacterDescriptor;
/// The TERNARY ground verdict. Zig mirror of the Etch enum owned by
/// `engine-movement.md` §2 — same order, same values.
pub const GroundState = types.GroundState;
/// Result of one `moveCharacter`: the resolved BASE position plus the five ground
/// quantities, of which `ground_state` is the discriminator.
pub const CharacterMoveResult = types.CharacterMoveResult;

// --- Queries (the complete frozen family, `engine-tier-interfaces.md` §1) ---

/// Number of object layers a query mask can address; `addBody` rejects a body
Expand Down
Loading
Loading