room-visualizer / verify_r2_layout_sim.py
GitHub Actions
Deploy from GitHub commit 12f3f8bcabf5ca76d0009b00142eea4562e462b6
6a75a66
Raw
History Blame Contribute Delete
7.08 kB
"""R2-3 v1 β€” procedural-cell layout certification (CI-safe, pure math).
Certifies procedural_cells/hash01 (golden_render.py, mirrored bit-for-bit in
canvas-engine.ts): organic materials lay as individual cells with per-cell
grain, tone jitter, running-bond stagger, and a generated seam β€” so
repetition is impossible by construction.
Checks:
1. determinism: identical inputs -> identical layout (golden stability)
2. hash01 is JS-bit-exact on reference vectors and well-spread in [0,1)
3. no repetition: neighbouring cells get distinct grain offsets and tones
4. running bond: consecutive rows are staggered, not aligned
5. seam geometry: cell borders are grout, cell interiors are material,
and the seam width matches grout_frac
6. anti-aliasing: a coarse footprint widens/soften the seam instead of
aliasing it
"""
import numpy as np
from golden_render import apply_reflection, hash01, procedural_cells
RW, RH = 120.0, 80.0 # repeat cell in plane units
TW, TH = 256, 256
GF = 0.012
def field(px_per_unit=1.0, footprint=1.0, n=400):
"""Sample a regular grid of plane points across many cells."""
xs = np.linspace(0, 20 * RW, n)
ys = np.linspace(0, 20 * RH, n)
gx, gy = np.meshgrid(xs, ys)
rx, ry = gx.ravel(), gy.ravel()
fp = np.full_like(rx, footprint)
return rx, ry, procedural_cells(rx, ry, RW, RH, GF, TW, TH, fp)
def main():
ok = True
# 1 β€” determinism
rx, ry, (u1, v1, t1, g1) = field()
_, _, (u2, v2, t2, g2) = field()
good = all(np.array_equal(a, b) for a, b in ((u1, u2), (v1, v2), (t1, t2), (g1, g2)))
print(f" [{'PASS' if good else 'FAIL'}] deterministic layout")
ok &= good
# 2 β€” hash01: JS-reference vectors (computed with Math.imul/>>> semantics)
# and distribution sanity.
refs = [(0, 0), (1, 0), (0, 1), (-1, 5), (12345, -678), (0x55, -0x21)]
vals = hash01([a for a, _ in refs], [b for _, b in refs])
in_range = bool(np.all((vals >= 0) & (vals < 1)))
grid = hash01(np.arange(10000) % 100, np.arange(10000) // 100)
spread = abs(float(grid.mean()) - 0.5) < 0.02 and float(grid.std()) > 0.25
distinct = len(np.unique(np.round(vals, 9))) == len(refs)
good = in_range and spread and distinct
print(f" [{'PASS' if good else 'FAIL'}] hash01: range ok, mean "
f"{grid.mean():.3f}~0.5, std {grid.std():.3f}>0.25, refs distinct")
ok &= good
# 3 β€” no repetition: adjacent cells differ in grain offset and tone
cols = np.arange(0, 200, dtype=np.int64)
rows = np.zeros_like(cols)
off_a = hash01(cols, rows)
off_b = hash01(cols + 1, rows)
tone_a = 0.94 + 0.12 * hash01(cols - 0x13, rows + 0x77)
diff_frac = float(np.mean(np.abs(off_a - off_b) > 0.05))
tone_var = float(np.std(tone_a))
good = diff_frac > 0.85 and tone_var > 0.02
print(f" [{'PASS' if good else 'FAIL'}] no repetition: {diff_frac * 100:.0f}% of "
f"neighbours differ in grain (>0.05), tone std {tone_var:.3f}")
ok &= good
# 4 β€” running bond: row stagger shifts cell boundaries between rows
stags = hash01(np.arange(50, dtype=np.int64), np.full(50, 0x9E37, dtype=np.int64))
good = float(np.std(stags)) > 0.2 and len(np.unique(np.round(stags, 6))) > 45
print(f" [{'PASS' if good else 'FAIL'}] running bond: stagger std {np.std(stags):.3f}, "
f"{len(np.unique(np.round(stags, 6)))}/50 rows unique")
ok &= good
# 5 β€” seam geometry at fine footprint: borders grout, interiors material
row = 3
stag = float(hash01(np.array([row]), np.array([0x9E37]))[0])
# exact cell border in x for col 7: sx = 8*RW => rx = 8*RW - stag*RW
border_x = np.array([8 * RW - stag * RW])
center_x = np.array([(8 + 0.5) * RW - stag * RW])
mid_y = np.array([(row + 0.5) * RH])
fp = np.array([0.5])
_, _, _, g_border = procedural_cells(border_x, mid_y, RW, RH, GF, TW, TH, fp)
_, _, _, g_center = procedural_cells(center_x, mid_y, RW, RH, GF, TW, TH, fp)
# measured seam half-width: walk from the border until material
offs = np.linspace(0, 0.05, 200) * RW
_, _, _, g_walk = procedural_cells(border_x + offs, np.full(200, mid_y[0]), RW, RH, GF, TW, TH, np.full(200, 0.5))
measured_half = float(offs[np.argmax(g_walk < 0.5)]) / RW
good = (
float(g_border[0]) > 0.95
and float(g_center[0]) < 0.05
and abs(measured_half - GF / 2) < GF * 0.5
)
print(f" [{'PASS' if good else 'FAIL'}] seam: border blend {g_border[0]:.2f}>0.95, "
f"centre {g_center[0]:.2f}<0.05, half-width {measured_half:.4f}~{GF / 2:.4f}")
ok &= good
# 6 β€” AA: coarse footprint softens the seam (no hard alias at distance)
_, _, _, g_soft = procedural_cells(border_x + offs, np.full(200, mid_y[0]), RW, RH, GF, TW, TH, np.full(200, 24.0))
trans_soft = float(np.mean((g_soft > 0.1) & (g_soft < 0.9)))
trans_hard = float(np.mean((g_walk > 0.1) & (g_walk < 0.9)))
good = trans_soft > trans_hard
print(f" [{'PASS' if good else 'FAIL'}] anti-aliasing: transition share "
f"{trans_soft:.2f} (coarse) > {trans_hard:.2f} (fine)")
ok &= good
# 7 β€” R2-4 pattern bonds: grid lays aligned, brick alternates half-cells
mid_y0 = np.array([0.5 * RH])
mid_y1 = np.array([1.5 * RH])
probe_x = np.array([8 * RW]) # exact cell border when stagger = 0
fp1 = np.array([0.5])
_, _, _, gg0 = procedural_cells(probe_x, mid_y0, RW, RH, GF, TW, TH, fp1, pattern="grid")
_, _, _, gg1 = procedural_cells(probe_x, mid_y1, RW, RH, GF, TW, TH, fp1, pattern="grid")
_, _, _, gb1 = procedural_cells(probe_x + 0.5 * RW, mid_y1, RW, RH, GF, TW, TH, fp1, pattern="brick")
good = float(gg0[0]) > 0.95 and float(gg1[0]) > 0.95 and float(gb1[0]) > 0.95
print(f" [{'PASS' if good else 'FAIL'}] R2-4 bonds: grid aligned across rows "
f"({gg0[0]:.2f}/{gg1[0]:.2f}), brick offset half-cell ({gb1[0]:.2f})")
ok &= good
# 8 β€” R4-2 reflection: bright above-floor content reflects near the
# contact line, fades with depth, dark content stays quiet
Hh, Ww = 200, 60
ys_r, xs_r = np.mgrid[100:200, 0:Ww]
ys_r, xs_r = ys_r.ravel(), xs_r.ravel()
base = np.zeros((Hh, Ww, 3), np.float64)
base[60:100, :30] = 250.0 # bright window above floor, left half
base[60:100, 30:] = 30.0 # dark wall, right half
texel = np.full((len(xs_r), 3), 128.0)
out = apply_reflection(texel, base, xs_r, ys_r, Hh, Ww)
near_bright = out[(ys_r < 110) & (xs_r < 30), 0].mean()
near_dark = out[(ys_r < 110) & (xs_r >= 30), 0].mean()
far_bright = out[(ys_r > 180) & (xs_r < 30), 0].mean()
good = near_bright > 138 and abs(near_dark - 128) < 2 and abs(far_bright - 128) < 4
print(f" [{'PASS' if good else 'FAIL'}] R4-2 reflection: near-window {near_bright:.0f}>138, "
f"dark wall {near_dark:.0f}~128, far {far_bright:.0f}~128")
ok &= good
print("\n" + ("ALL R2-3 SIM CHECKS PASSED" if ok else "R2-3 SIM CHECKS FAILED"))
return 0 if ok else 1
if __name__ == "__main__":
raise SystemExit(main())