Large Worlds {#large-worlds}
July 16, 2026 · View on GitHub
In Fixed3D every world is a large world. Positions are Q48.16 fixed point:
a uniform resolution of 1/65536 (about 1.5e-5 meters) at the origin, at
10,000 km from the origin, and everywhere else. There is no precision falloff
with distance, so there is no separate large-world mode to enable — and the
double-precision mode from Box3D is removed. Defining
BOX3D_DOUBLE_PRECISION is a compile error in this tree.
For context: float Box3D loses position resolution far from the origin (a float has a step of about one meter at 1e7 meters), and solves this with an optional double-precision world-position mode that costs only a few percent. If a big world is all you need, that mode is the pragmatic choice — see the README's "Should I use this?" section. What fixed point adds is that resolution is uniform: sub-millimeter everywhere, with nothing to configure.
The world-position API
The Box3D API's world-position vocabulary is kept so code written against it compiles unchanged. In the default build the types collapse (see the optional 128-bit builds at the end of this page for the exception):
b3Posis an alias forb3Vec3.b3WorldTransformis an alias forb3Transform.- The boundary helpers (
b3ToPos,b3ToVec3,b3SubPos,b3OffsetPos,b3RoundDownFloat,b3RoundUpFloat) remain as trivial pass-throughs.
Everywhere the Box3D API accepts or returns a world position —
b3BodyDef.position, b3Body_GetPosition / b3Body_GetTransform, the query
origins (b3World_OverlapShape, b3World_CastShape, b3World_CastMover,
b3World_CastRay), hit points, and the body move event — the fixed-point
build uses the same b3Pos names with full precision at any distance. There
is no re-differencing machinery because there is nothing to re-difference:
a query at 1e7 meters is exactly as precise as one at the origin, including
the broad phase, whose AABBs are stored in the same fixed-point coordinates
and never quantize.
Operating range
Positions are representable out to ±1.4e14 meters at full resolution. The practical simulation envelope is smaller: keep world coordinates within about ±1e7 meters (10,000 km — a 20,000 km cubed world) so that squared-distance forms remain representable in Q48.16. The engine's internal reductions run at 128 bits where it matters, but API-level distance and length math on coordinates much beyond 1e7 meters can exceed the fixed-point range.
Debug drawing
b3World_Draw hands every callback world coordinates in b3Pos. The engine
side is uniformly precise, but a float renderer is not: converting an
absolute coordinate at 1e7 meters through b3FixToFloat snaps to the float
grid (about one meter there). Keep a draw origin near the camera and
difference in fixed point before converting to float — b3SubPos( p, drawOrigin ) is exact — and a distant scene renders crisply. The sample app
sets the draw origin from the camera eye each frame, and the Large World
sample uses it to render a stack at 1e7 with no jitter.
Everything runs 120 million kilometers out
Every sample scene, every benchmark scene, and the determinism test build
their content around a shared world origin 120,000,000 km — about 0.8
astronomical units, most of the way to the Sun — from (0,0,0) on all three
axes (GetSceneOrigin() in shared/utils.h — a constant with no setter,
so nothing can quietly opt back to the origin). For scale: Box3D's
double-precision mode supports a ±120,000 km cube, with its
single-precision broad phase costing about a meter of bounding-box padding
at the edge. This origin is a thousand times past that edge, at the same
1/65536 resolution the engine has everywhere. Working out here enforces
the large-world claim continuously: all performance numbers are measured,
and every sample is exercised, three orders of magnitude beyond the
comparable world. An exactly representable origin shift is a bit-exact
rigid translation of the whole simulation — the falling-ragdolls
determinism scene sleeps on the identical step at 0.8 AU as at the origin
(the sleep step has carried unchanged through four origin moves), and the
benchmark workloads (contact counts, solver stack high-water marks) are
bit-identical — so working out there costs nothing and proves the
uniform-precision claim on every run. Sentinel probes hold clean further
still, out to 1.2e14 m (~800 AU, 85% of the Q48.16 range). The
World > Far samples vary the offset independently of the shared origin.
Determinism
There is a single precision mode, so there is a single set of determinism expectations: the same simulation produces bit-identical results across platforms and worker counts. (Box3D is also deterministic — see the FAQ — fixed point only changes how that is achieved.)
Ludicrous mode: optional 128-bit positions and broadphase
One opt-in build extends the range past ±1.4e14 meters. Almost nobody
needs it — Q48.16's default envelope already covers hundreds of
astronomical units — but it exists, it is verified, and it is measured.
See docs/design/wide-world-positions.md for the full record.
BOX3D_LUDICROUS_MODE widens b3Pos, b3WorldTransform.p, and the
broadphase AABBs to Q112.16 in __int128 (range ±2.6e33 units — far past
a light-year) while the entire solver interior stays Q48.16. The boundary
helpers listed above become real conversions, which is why they exist in
the API at all, and collision is active across the full range: a box
dropped onto a box at 1e15 meters — a tenth of a light-year out — settles
bit-identically to the same scene at the origin. Measured cost: +1.6%
geomean (only tree-query-bound scenes pay measurably; widening the
positions alone measured free, the broadphase is the entire cost). The
name is the documentation: you do not need a physics broadphase that
works a light-year from the origin. Off by default; bit-identical when
off. The samples application has not been ported to this build — engine,
tests, and benchmarks all work.