Environment validation

tests/environment-controls.html is a small browser fixture using the actual Environment, Daylight, WindField, RainField, cascaded shadows, water and a portable BeachUmbrella. It does not load the flight scene. tests/environment-v2.test.mjs provides CPU regression cases. The recorded results are in environment-v2-summary.json.

Run CPU checks with node --test tests/environment-v2.test.mjs. Serve the project over HTTP, open tests/environment-controls.html, and select Run rendered checks. Startup, runtime and shader failures remain visible. Preset buttons expose the actual day/sunrise/sunset/night scene; Clear → rain front runs a real-time transition, and the moon/sky button provides a direct sky view. The fixture creates one environment at a time and disposes/rebuilds it for lifecycle checks.

Evidence and thresholds

The final env5 run on 2026-09-07 passed all five CPU tests and all eight browser cases in the authorized Chrome instance. The actual 960 × 540 onscreen framebuffer is read immediately after rendering and sampled to 320 × 180 for reproducible comparisons. Planar reflections are refreshed before each capture, so cached camera views do not masquerade as state changes. The retained thumbnails show the captured states.

Pixel metrics use display-encoded RGB bytes. Mean luminance is an RGB-weighted comparison number, not physical luminance. A changed pixel has a mean absolute RGB-channel difference greater than 2. These thresholds establish observable rendering responses; they do not establish physical fidelity or photorealism.

TestRequired observationFinal env5 result
Light presetsClear→sunrise and sunrise→sunset mean RGB difference >3; night brightness <40% of dayDifferences 41.65 and 7.69; night mean 16.72 versus day 193.28
Shared windActual compiled cloth uniforms and water uniforms share the same environment objects; isolated cloth/water each change >20 pixelsIdentity preserved; 411 cloth pixels and 14,567 water pixels changed
Cloud windZero-strength cloud image stays unchanged; wind produces >100 changed pixels and direction follows the shared field0 changed pixels at zero wind; 21,786 moving-cloud pixels changed; east/north flow follows commands
Rain frontFront active at midpoint, transition ends, cloud >0.9, rain >0.8, finite drawn vertices, >5 streak-only changed pixelsCloud 0.98, rain 0.85, 2,380 vertices; 447 streak-only pixels changed
Night skyAmbient <10% of daytime; independently observable moon-phase and star-brightness responseAmbient 0.018 versus 0.868; 76 moon pixels and 11,095 star pixels changed
Cascaded shadowsScene material-preparer hook present; ground, cloth and water actually compile with CSM; no global ShaderChunk changesAll present; zero global mutations
CleanupReal effect resources dispose; hooks detach; second released environment has the same GPU counts as the firstBoth releases: 0 geometries and 1 retained renderer texture
Runtime healthNo startup/runtime/shader errorsZero errors

Wind-response captures hide the sky while comparing cloth/water, so moving clouds cannot satisfy those geometry tests. Cloud motion is then tested separately. Rain visibility is isolated by comparing identical state/time/view with the rain root visible and hidden. Moon and star controls are changed independently. The CSM check records shader objects provided by real material compilation; it does not feed mock shaders into a duplicate implementation.

The CPU suite checks wind invariants and instance isolation; preset validity; actual Three.js ray intersections against height queries; patch-boundary continuity; and spatial initialization when a rain field increases its active count. Terrain render/query comparisons use a 0.00002 m tolerance. Intersecting boundary probes lie 0.0001 m on each side of an edge and require agreement within 0.002 m. The first detail fixture includes 317 probes; the overlapping fixture includes 292 interior/edge probes. These are deterministic regression samples, not exhaustive proofs.

Regressions retained

Before the env5 engine corrections, overlapping patches produced a 0.676071 m render/query mismatch at (-5.887, -15.827): the newer query surface was below still-rendered older triangles. The original reproduction remains, with additional intersecting-edge probes. It now passes.

Before the rain correction, activating one of 128 particles and then the full field produced only two distinct positions; newly activated particles remained at their default origin. The browser front ended with valid vertex counts but no visible streak change. The unchanged activation test now passes, as does the rendered front test.

The earlier offscreen capture approach exposed WaterSurface restoring the main viewport into a differently sized render target. This was reported to the engine owner separately. Final environment comparisons read the actual onscreen framebuffer; they do not claim to verify that offscreen-viewport issue.

Limits

The fixture's final low-quality scene rendered 34 calls and 15,480 triangles. Its measured CPU tick median was approximately 1.2 ms, with p95 3 ms, during this small controlled run. These measurements are not frame-rate claims or evidence of full-flight performance. The CSM tests establish actual material preparation and shader isolation, not every camera-distance blend boundary. CPU terrain tests compare the rendered mesh and query API; GPU water terrain sampling needs its own coverage. Two disposal cycles establish no observed resource growth across those cycles, not a long-duration memory soak. No new browser capability or external application access was needed.