Extracted from the T-1194 stipple, which was the first of a family: graffiti
placement, cracks in textures, drifting cloud cover — presentation decisions
that must look the same when the player returns to a place, and which the
simulation has no opinion about and should not be burdened with.
THE LINE IT DRAWS. It answers "how is this drawn", never "what is here". A
cell's biome, a settlement's position, whether a wall exists — those are world
data, derived once by the server and sampled everywhere (D-255(f) mechanism B),
and the player eventually stands on them; inventing those here would put the map
and the ground in disagreement. Stated on the class so the next consumer does
not have to re-derive it: if the answer changes what is THERE it is not a
ScatterField question; if it only changes how it is DRAWN, it is.
Bit-identity with the server's Rust noise is explicitly NOT a requirement
(Jeroen: "a seed is a seed and the functional intended outcome is repetition
here"). Nothing here is compared against a server value or round-tripped
through a save, so the contract is stability across sessions, not agreement
across languages — which is precisely why paint belongs on this side: it buys
visual density with no cross-language determinism burden.
Seeded from GameState.world_seed, so two playthroughs scatter differently and
one playthrough is stable forever.
API: domain() resolves a name to a salt ONCE (the first consumer runs ~700,000
times per canvas rebuild, so the hot calls take an int, never a string);
value/chance/pick/jitter for discrete marks; smooth() for continuous fields
like cloud cover; an optional time axis for animation. Domains keep consumers
uncorrelated — without them graffiti and cracks at the same wall coordinate
would mark identical spots and read as one artefact.
The tests pin the CONTRACT, not the numbers — freezing outputs would make any
future improvement to the mixer a breaking change for no gain. They caught a
real defect immediately: (-x, -y) collided with (x, y), because negated
coordinates produce negated products and the sign-bit mask folded the pair
together, mirroring every mark west and south of the origin onto its north-east
counterpart. Not an edge case — the descent ladder's own anchor sits at
y = -5,675,959. Fixed by zigzag-encoding coordinates before mixing.
1853 client tests, 0 failed (15 new). Global capture re-verified unchanged
after migrating the stipple onto the service.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>