For deterministic gameplay and replay verification, float behavior is part of the contract.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/banteg/crimson/llms.txt
Use this file to discover all available pages before exploring further.
Default Rule
In deterministic gameplay paths, prefer native float32 fidelity over source readability.
- Keep decompiled float constants when they influence simulation
- Keep native operation ordering when it changes rounding boundaries
- Keep float32 store/truncation points where native stores to
float
Why This Matters
Small float deltas can reorder branch decisions and collision outcomes, then amplify into:- RNG drift (different random values)
- Deterministic divergence over long runs
- Replay verification failures
Example: Movement Delta
Original x87 Behavior
The original executable uses x87 FPU with specific precision mode:CRT Precision Control
CRT startup explicitly sets x87 to 53-bit precision mode (PC_53):
analysis/binary_ninja/raw/crimsonland.exe.bndb_hlil.txt:83734analysis/ida/raw/crimsonland.exe/functions.jsonaround line 13692
Float Storage Pattern
Decompilation shows:- Extended intermediates — Trig/atan operations use
float10(x87 extended precision) - Float32 storage — Results spill to
floatstate fields
analysis/ghidra/raw/crimsonland.exe_decompiled.clines 21767, 12248- Binary Ninja shows
fconvert.t(widen) andfconvert.s(spill)
The game is not “everything in 80-bit all the way down”. It’s “extended intermediates, float32 storage.”
Rewrite Math Model
Deterministic gameplay follows three rules:Use f32 as domain type
Positions, headings, timers, speeds use
f32 (float32) unless truly boundary-only.Widen only at boundaries
Replay decode, serialization, diagnostics can use
f64, then immediately spill back to f32.Python Implementation
src/crimson/math_parity.py
Native Trig Helpers
Native Constants
Keep decompiled float32 bit patterns:These match the exact bit patterns from the original binary, not mathematical ideals.
Explicit Spill Points
Differential Evidence
Sessions repeatedly show divergence when arithmetic order or spill points differ:Session 18
Decompile-orderangle_approach fix moved first mismatch from tick 7722 to 7756.
Evidence: docs/frida/differential-sessions/session-18.md
Session 19
Tighter float32 spill behavior in creature heading/tau-boundary handling cleared remainingquest_1_8 capture.
Evidence: docs/frida/differential-sessions/session-19.md
When to Normalize
Literal simplification is acceptable when all of the following are true:- The path is non-deterministic or presentation-only (not gameplay simulation)
- Differential evidence (capture + verifier) shows no behavior change
- A test or session note records that evidence
Example: Creature Movement
src/crimson/creatures/ai.py
Zig Verifier Implementation
The Zig verifier uses explicit native math helpers:crimson-zig/src/runtime/native_math.zig
Testing Strategy
Verify float behavior with:- Unit tests — Known input/output pairs from captures
- Differential captures — Tick-by-tick comparison with original
- Replay checkpoints — State hash verification at sampled ticks
tests/test_float_parity.py
Documentation
For expression-level lookup table with decompile anchors, see:docs/rewrite/float-expression-precision-map.md
Next Steps
Deterministic Pipeline
How float precision affects simulation
Parity Status
Current verification state
Original Bugs
Bugs that involve float precision
Replay Module
How replays verify float behavior