guts/web/js/core/rng.js
jing 34f84ab162 [lane F] Round 0 scaffold: docs, contracts, lane charters, bootable stub world
GDD v1 (flow-locked hybrid movement, 5 biomes + secret, boss roster),
TECH contracts (world API, level schema v0, bus events, manifest law),
ART_BIBLE (synthetic scanner look), PIPELINE (MODELBEAST-first, fal gated),
PROCESS (PROCITY lane/round law), charters A-F + ROUND1 instructions.
Seed code: shell + boot + core (rng/bus/flags) + stub world (peristalsis
shader tube, 1 draw / 102k tris, contract-complete) + qa.sh (GREEN).
Verified in-browser; evidence docs/shots/laneF/round0_stub_tube.png.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 01:28:35 +10:00

32 lines
1.2 KiB
JavaScript

// core/rng.js (Lane F) — THE only randomness source in GUTS. qa.sh greps for violators.
// mulberry32: tiny, fast, deterministic. Same seed => same sequence, forever.
export function mulberry32(seed) {
let a = seed >>> 0;
return function () {
a |= 0; a = (a + 0x6D2B79F5) | 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// Named sub-streams so lanes don't perturb each other's sequences:
// rng('world'), rng('enemies'), ... each is an independent deterministic stream.
export function createRng(seed) {
const streams = new Map();
function hash(str) {
let h = 2166136261 >>> 0;
for (let i = 0; i < str.length; i++) { h ^= str.charCodeAt(i); h = Math.imul(h, 16777619); }
return h >>> 0;
}
const rng = (stream = 'main') => {
if (!streams.has(stream)) streams.set(stream, mulberry32((seed ^ hash(stream)) >>> 0));
return streams.get(stream);
};
rng.seed = seed;
rng.float = (stream, min = 0, max = 1) => min + rng(stream)() * (max - min);
rng.int = (stream, min, max) => Math.floor(rng.float(stream, min, max + 1));
return rng;
}