Commit graph

6 commits

Author SHA1 Message Date
Maximus Gorog
a01d5c1fa9 Quiet the debug-noise that was lagging the browser
You're right — the telemetry path itself was contributing to perceived
browser lag, not just the GPU work. Two specific sources removed:

render/mod.rs::rebuild_chunk:
  - Per-chunk log::info!("rebuild_chunk {coord}: {ms}ms ...") fired
    ~289 times during world init, plus on every edit. Chrome's console
    buffer accumulates these and DevTools recalcs on each new line.
    Removed entirely. The bench toggles + FPS HUD already give us the
    measurement signal; per-chunk timing was noise once verified.

web/main.js setupFpsHud:
  - Was a 5 Hz setInterval that did `el.textContent = ...` and two
    `classList.toggle` calls each tick (15 DOM writes/sec). Now:
      * Polls at 1 Hz (the EMA already smooths)
      * Only writes textContent when the displayed string actually
        changes (skip is the common case once stabilized)
      * Only writes class when the tier (green/warn/bad) crosses
        a threshold
    Same readout, ~15× fewer DOM writes.

web/main.js setupStatusLoop (HP bar):
  - Same dedupe pattern. 10 Hz polling, but DOM writes only when
    hp or alive changes from the last sample. Was firing 3 style
    writes per tick unconditionally; now zero in steady state.

No functionality changes — every telemetry getter, every bench
toggle, every test-harness export still works (just verified via
the 18-check functional contract suite).

Wasm release built; tests 63/63 pass.
2026-05-24 17:22:30 -06:00
Maximus Gorog
bb006839cc Runtime perf: cheap fog, sky overdraw kill, fewer cloud octaves, in-game FPS HUD
The features added in Rounds A–D were correct but expensive. The hot
path per frame was sky_color() called from apply_fog for EVERY distant
pixel — 4-octave cloud fbm + star hash + sun/moon disc per fragment,
hundreds of thousands of pixels per frame. Profile-driven cuts that
keep all features but stop paying for them in the wrong places:

1. apply_fog now mixes terrain toward sky_dome (cheap gradient) not
   sky_color (gradient + clouds + sun + moon + stars). Distant terrain
   still fades to the right-direction sky color at every time of day;
   the per-pixel cost drops by ~80%. Full sky_color still runs for
   the SKY BACKGROUND pass where it's actually paid for.

2. Sky pipeline draws AFTER terrain with depth_compare = LessEqual.
   The full-screen sky was previously written first then over-painted
   by terrain — sky's expensive fragment shader ran on every screen
   pixel. Now it only runs on pixels with no terrain in front of them
   (depth = 1.0 cleared), which on most views is 30–60% of the screen
   instead of 100%.

3. fbm2 reduced from 4 → 3 octaves. Negligible visual change at the
   scales we sample, ~25% cheaper per cloud-pixel.

4. Cloud branch skips entirely when day_strength < 0.05 (full night).
   Clouds invisible at night anyway, fbm + smoothstep + mix skipped.

5. In-game FPS HUD (top-right corner):
   - Telemetry struct gains frame_dt_ms (EMA-smoothed in app.rs
     with coefficient 0.85 so the number is readable, not flickery).
   - wasm bridge: get_frame_dt_ms().
   - main.js setupFpsHud() polls it at 5Hz, color-coded:
       green ≤ 18ms (≥55fps), amber 18-33ms, red beyond.
   - Reads what THE GAME measures, not the browser's
     requestAnimationFrame which gets throttled to 1 Hz on
     unfocused windows.

No features removed. God rays, FXAA, ACES tonemap, bounce baking,
specular materials, leaf translucency — all still there. Tests:
63 passing. Wasm release clean.
2026-05-24 15:44:14 -06:00
Maximus Gorog
3187b9ca07 Death overlay no longer covers the settings menu
The death overlay sat at z-index 100 while the settings menu sat at
z-index 60, so a player who died and then opened the menu (or whose
respawn timing overlapped with opening the menu) would see the red
death curtain on top of every settings widget. Worse, the overlay
also applies `backdrop-filter: blur(2px)` which would have tinted the
menu visibly even if z-order had been fixed differently.

Fix: a single CSS rule
  body.menu-open #death { display: none; }
makes the menu and death overlays mutually exclusive whenever the
menu is open. The death overlay returns immediately when the menu is
closed (assuming the player is still dead). Verified live in the
running browser via the test harness:

  body.dead alone           → death visible (display: flex)
  body.dead + body.menu-open → death hidden  (display: none)
  body.menu-open removed     → death visible again

No JS changes needed — purely a stylesheet fix.
2026-05-24 12:07:15 -06:00
Maximus Gorog
c0589d0dfc Tick/toc instrumentation across build + test + mesh phases
run.sh:
  - phase() wrapper logs elapsed seconds per build step.
  - Tracks total build+startup at the end.
  - Output is "==> phase / [Ns] phase" so the slow steps are obvious.

test/run.py:
  - Per-step time.perf_counter() around each scenario step.
  - "slowest steps" summary printed at the end so the worst
    offenders are immediately visible.
  - Total wall-clock time at scenario end.

src/render/mod.rs:
  - browser_now() helper: web_sys::performance().now() on wasm,
    Instant-based on native. Monotonic ms timestamps for tick/toc.
  - Renderer::rebuild_chunk wraps build_chunk_mesh in a t0/t1
    measurement and logs anything over 5ms with vertex/index counts.
    Surfaces sky_visibility cost in the browser console.

web/main.js:
  - Exposes window.voxel_game = wasm after init so the test
    harness can drive scenarios declaratively (set_scene_time,
    teleport, look_at, get_position, etc.).

src/shader.wgsl:
  - Fix duplicate `let to_eye` declaration introduced in Round D
    (specular's normalized to_eye conflicted with fog's raw version).
    Renamed fog's local to_eye_raw. The test harness caught this
    immediately — first WGSL compile error, first scenario run.

Findings from running scenarios/lighting-times-of-day.yaml:
  - 289 chunks × ~100ms avg = ~29s mesh-build on main thread.
  - Page-ready latency dominated by this. window.voxel_game appears
    almost immediately (init resolves before chunks build), but
    the world is invisible until meshes are uploaded.
  - sky_visibility (8 cosine rays × HashMap voxel lookups) is the
    hot path inside build_chunk_mesh.

Next: make chunk-mesh build progressive (one or two chunks per tick
instead of all up-front), so the world becomes visible immediately
and pops in over a few seconds.
2026-05-24 11:49:08 -06:00
Maximus Gorog
b52c1927cf Render + UI polish since pre-alpha-0.0.1
- Greedy meshing now bakes per-vertex AO with 4-corner sampling and an
  anisotropic-diagonal split when corner AO disagrees.
- WGSL: extracted sky_dome() for hemisphere ambient sampling so vertical
  faces match the sun-side sky tint at day; ambient_strength mixed by
  day strength instead of a flat constant.
- Step-1 post pipeline: render scene into an offscreen color texture,
  pass-through to the surface. Foundation for FXAA/shafts that will
  follow.
- Input bug: merge_held() now recomputes per tick from sticky keyboard +
  live touch bridge, so releasing the joystick actually stops the
  player (previous OR-into-self bug ate playtests).
- Touch UI hit-zones reordered (menu/hotbar above the joystick z-index);
  hotbar widened to 10 slots with tap-to-select on mobile.
- find_safe_spawn anchors on natural_surface_y so spawn is deterministic
  from noise — towers built at spawn no longer climb the spawn point.
- move_axis is sub-stepped (0.45-block max) so high-velocity falls can't
  teleport the player inside terrain.
2026-05-23 18:44:56 -06:00
Maximus Gorog
3a4ae970b2 pre-alpha 0.0.1 — initial multiplayer voxel sandbox
Web/wasm Rust voxel game with:
- wgpu 23 client (WebGPU when available, WebGL2 fallback)
- Chunked terrain (17x17 chunks, deterministic value-noise generator)
- Greedy meshing with frustum + distance culling
- Sky shader, leaf wind shader, distance fog
- Player physics: substepped AABB collision, gravity, fall damage,
  natural-surface respawn
- Touch UI (MCPE-style joystick + jump/break/place/sprint),
  gamepad polling with axis calibration, mouse+keyboard
- HP / death-screen / respawn flow
- 10-slot hotbar with mouse-wheel + hotkey + tap cycling
- Settings menu (mouse sens, FOV, render distance, input mode toggle)
- Axum multiplayer server: WebSocket protocol, edit log,
  10Hz player broadcasts
- 31 unit tests covering spawn invariants, collision sweeps,
  raycast hit/miss, greedy mesh winding, fall damage, oriented
  box rotation, hotbar block roundtrip, and the input-merge
  regression that latched movement after touch release

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 23:33:47 -06:00