34 Commits

Author SHA1 Message Date
xfy
0693c3d165 docs: Phase 2 (Kerr) design spec 2026-07-13 18:24:49 +08:00
xfy
80c2b5dbe2 fix(camera): adjust default pitch and invert zoom scroll direction
- Set default pitch to 0.7 rad to keep the camera away from the π/2 gimbal pole, preventing horizontal drag from degenerating into an in-plane roll.
- Adjust scroll zoom logic to divide instead of multiply by the zoom factor, so that scrolling up zooms in (reduces distance) rather than out.
2026-07-13 18:11:04 +08:00
xfy
72a9996780 docs: add AGENTS.md for future agent sessions
Compact onboarding file capturing hard-won, non-obvious repo facts:

- Dual-target build (desktop + web/WebGPU) and the wasm-only
  web_sys_unstable_apis rustflag (.cargo/config.toml) that is a no-op
  on desktop — easy to break during cleanup.
- Always run --release for visual checks; the debug ray tracer is too
  slow and will look broken.
- The CPU<->shader mirror in src/physics.rs: it is a hand-maintained
  duplicate of black_hole.wgsl kept solely so the capture/escape
  boundary is testable. Editing one side without the other makes tests
  pass on code the shader contradicts.
- The three Bevy 0.19 gotchas that cause the recurring grey screen
  (nudge_camera for issue #24448, EguiPrimaryContextPass placement,
  real storage buffer asset instead of default handle) — exactly what
  this branch's recent commits fix.
- Reserved-but-intentionally-unwired fields (render_scale, spin) and
  the Rs=1 natural-units convention so an agent does not 'fix'
  intentional dead code or invent unit conversions.
- Git workflow: self-judge whether to commit, granular detailed
  commits, never push.

No code changes.
2026-07-13 17:41:03 +08:00
xfy
f80a24d191 fix: invert orbit camera yaw/pitch to view-follows-cursor direction 2026-07-13 17:38:02 +08:00
xfy
4556376b4a fix: make the black hole actually render (was stuck on grey clear color)
The app showed only the camera clear color (grey srgb 43,44,47) — the
fullscreen quad's fragment shader produced no output. Two issues; the
second was the real blocker.

1. render/material.rs: skybox.wgsl declared binding 1 as texture_cube<f32>
   but the material's #[texture(1)] defaulted to D2. The mismatched
   bind-group layout vs. shader caused the pipeline to fail to specialize.
   Fix: dimension = "cube" on the texture attribute so the layout matches.

2. SHADER COMPOSITION (the actual blocker): the shader was split across
   naga_oil modules (ray_gen, geodesic, stars, disk, planets, grid, skybox)
   pulled in via #import singularity::... This compiled and validated with
   zero errors, but at runtime calling ANY cross-module-imported function
   made the fragment output nothing (only the clear color showed). Local
   functions were fine. Confirmed by bisecting a minimal repro with the
   user watching the screen: local fn -> renders; imported fn (even pure
   math) -> grey.

   Rather than chase the naga_oil 0.22 / Bevy 0.19 composition bug, inline
   every function into black_hole.wgsl and drop the #import singularity::*
   lines. The 7 standalone module files are removed. Rendering now works.

Also fixes scene/planets.rs: upload_planets was allocating a fresh
ShaderBuffer (new handle) every frame, which re-triggered the
AsBindGroup RetryNextUpdate that the previous commit's startup pre-fill
was meant to eliminate. Now mutates the existing buffer asset in place
via set_data, keeping the handle stable.
2026-07-13 16:43:01 +08:00
xfy
0b158c57d3 chore: add matt-pocock skills and lockfile 2026-07-13 14:37:04 +08:00
xfy
ee15ddecb7 fix: make the renderer actually draw (step size, storage buffer, quad fit)
The committed Phase 1 code rendered a black screen due to three
independent bugs, fixed here:

- black_hole.wgsl: dt was sized as |eye|/steps, so the full integration
  only traveled |eye| units total — rays never reached capture or escape
  and every pixel fell through to accum=black. Now dt covers
  eye_dist + escape_r across the configured step count, and the escape
  test uses the dynamic escape_r instead of a hardcoded 1000.0.
- render/plugin.rs: the planets binding was Handle::default(), causing
  AsBindGroup to return RetryNextUpdate every frame and silently skip
  the fullscreen quad's draw. Pre-fill a MAX_PLANETS-sized zeroed
  ShaderBuffer at startup so the binding resolves immediately.
- render/plugin.rs: scale the fullscreen quad by half the window size
  to match Camera2d's default WindowSize projection (1 unit = 1 px);
  the old aspect-based scaling letterboxed the image.
- render/plugin.rs: add nudge_camera to work around Bevy 0.19 #24448,
  where a static camera stops rendering after the first frame.
- planets.wgsl: rotate world-space planet centers into disk-local space
  before the ray-sphere test (ray and centers were in different spaces).
2026-07-13 11:47:31 +08:00
xfy
87b089eb35 docs: README + silence reserved-field dead-code warning
README documents the renderer, run instructions (desktop + web), controls,
how the geodesic pipeline works, performance notes, and Phase 2 (Kerr) as
future work. Allow dead_code on BlackHoleParams since render_scale + spin
are intentionally reserved for Phase 2.
2026-07-13 10:04:44 +08:00
xfy
76d302b4e4 feat: web release build + web-tuned defaults verified 2026-07-13 10:03:01 +08:00
xfy
1e8cd93bc3 fix: keep full-screen quad filled on window resize
The quad mesh was built once at startup with the initial aspect ratio, so
widening the window afterward left empty edges. Add a FullscreenQuad marker
component and a fit_quad_to_window system that rescales the quad's Transform
to the live aspect each frame (only mutating on change).

Also remove the misleading 'Render scale' slider — it isn't wired to a real
sub-resolution render target in Phase 1 (the full-screen quad always renders
at window resolution). Lowering Steps is the real perf lever. Documented in
a code comment for future work.
2026-07-13 10:00:42 +08:00
xfy
7e0ac65d55 feat: full egui control panel + pointer routing 2026-07-13 09:57:54 +08:00
xfy
90e8c9b3a4 feat: cubemap skybox layer (optional, procedural stars default) 2026-07-13 09:54:21 +08:00
xfy
5fa2621e6a fix(shaders): use #define_import_path + namespaced imports
The whole-file #import "file.wgsl" form (without ::) does not reliably
bring functions into scope in naga_oil/Bevy 0.19 — the renderer was
failing at runtime with 'no definition in scope for identifier:
ray_direction' (and rot_x, deriv, etc.), producing a blank screen despite
'cargo build' passing (shaders aren't compile-checked at build time).

Fix: add #define_import_path to each module file and import symbols
explicitly via namespace::name (the canonical Bevy pattern from the
shader_material_2d example). Verified the full shader pipeline compiles
and runs at runtime with zero WGSL errors.

This was a pre-existing bug masked by incomplete runtime verification in
earlier tasks; it is NOT specific to Task 15's grid work. All earlier
visual features (shadow, Doppler disk, Einstein halo, stars, planets,
grid) now actually render.
2026-07-13 09:51:08 +08:00
xfy
661d28a6a1 feat: lensed Flamm paraboloid curvature grid 2026-07-13 09:37:25 +08:00
xfy
8931904495 feat: lensed planet ray-sphere intersection in geodesic tracer
Add planets as ray-traced spheres inside the RK4 geodesic loop. A new
planets.wgsl shader tests each integrator segment against a storage
buffer of SphereData (center/radius/color/emissive) and composites hits
front-to-back alongside the accretion disk. Lambert shading with a fixed
light direction; emissive flag bypasses shading.

- assets/shaders/planets.wgsl: segment-sphere intersection + shading
- src/scene/: Planet component, upload_planets system, default planet
- black_hole.wgsl: wire planet_hit into the compositing loop
- geodesic_schwarzschild.wgsl: replace tuple return with Deriv struct
2026-07-10 17:06:19 +08:00
xfy
983413e9af feat: egui UI wired with live disk brightness + steps 2026-07-10 10:54:22 +08:00
xfy
1b1eda0772 feat: accretion disk with Doppler beaming + lensed Einstein halo 2026-07-10 10:48:31 +08:00
xfy
fbe1685a38 feat: procedural lensed starfield background 2026-07-10 10:45:24 +08:00
xfy
d5e3008343 test: CPU-mirrored geodesic physics + bcrit/capture unit tests 2026-07-10 10:43:11 +08:00
xfy
9d81df1c14 feat: Schwarzschild RK4 geodesic integrator + black shadow 2026-07-10 10:39:46 +08:00
xfy
9665d12348 feat: per-pixel camera ray generation 2026-07-10 10:36:18 +08:00
xfy
265ec9925d feat: BlackHoleUniforms + camera/params mirror system 2026-07-10 10:33:10 +08:00
xfy
1a2b157ef3 feat: BlackHoleParams tunable resource 2026-07-10 10:27:10 +08:00
xfy
d039064efa feat: orbit camera controller (yaw/pitch/zoom) 2026-07-10 10:25:16 +08:00
xfy
a45d42c07a feat: full-screen quad + BlackHoleMaterial pipeline 2026-07-10 10:20:38 +08:00
xfy
9c8f384d0e feat: web build via trunk with WebGPU detection + fallback 2026-07-10 10:12:57 +08:00
xfy
25e2207e0d feat: minimal bevy window opens 2026-07-10 09:48:38 +08:00
xfy
ea6b15524d build: add bevy 0.19 and bevy_egui 0.41 dependencies 2026-07-10 09:45:59 +08:00
xfy
02368a0a74 docs(plan): Phase 1 Schwarzschild implementation plan
20 tasks covering: deps, minimal window, web/Trunk/WebGPU, full-screen
Material2d pipeline, orbit camera, params resource, uniforms+mirror, ray
gen, RK4 Schwarzschild integrator, CPU physics tests, lensed starfield,
Doppler accretion disk w/ Einstein halo, egui panel, storage-buffer
planets, Flamm grid, cubemap skybox, render scale, web verification,
README. Verified against Bevy 0.19 API (group-2 material bind group,
component spawning, WgpuSettings defaults).
2026-07-09 18:57:42 +08:00
xfy
041e8f3b21 docs(spec): correct Bevy 0.19 API details (verified)
- Material2d bind group is group 2 (#{MATERIAL_BIND_GROUP}), not group 1
- RenderPlugin has no wgpu_backends field; enable bevy 'webgpu' feature instead
- WgpuSettings::default() auto-selects BROWSER_WEBGPU on wasm32
- Imports from bevy::sprite_render (Material2d, AlphaMode2d)
- Component-based spawning (Camera2d, Mesh2d/MeshMaterial2d), no bundles
- getrandom 0.4/wasm_js handled transitively by Bevy
2026-07-09 18:47:44 +08:00
xfy
c1bfe2b25e docs(spec): add desktop + web (WebGPU) platform support
- WebGPU-only web target (Bevy forces WebGPU/WebGL2 at build time; WebGL2
  lacks storage buffers our planets feature needs)
- Add §13 Platform support: build toolchain (trunk/wasm32), backend gating,
  fallback message, web defaults (render_scale 0.75, steps 200)
- Add src/web.rs, web/index.html, Trunk.toml to file structure
- Add web-sys dep; add web build + perf verification milestones
- Update storage-buffer risk note: valid on native + WebGPU
2026-07-09 18:30:56 +08:00
xfy
60bfdb9ca6 docs(spec): add egui parameter UI (bevy_egui 0.41) + dependencies section
- Switch interaction from keyboard to a collapsible egui 'Controls' panel
  with grouped sections (Camera/Disk/Doppler/Renderer/Background/Grid/Planets)
- Pin bevy_egui 0.41.0 (verified against crates.io: bevy ^0.19 + egui ^0.35)
- Add Dependencies section §0; add src/ui.rs to file structure
- Clarify mouse-input routing between egui panel and orbit controller
2026-07-09 18:26:24 +08:00
xfy
c2d4bf779a docs: add Interstellar black hole renderer design spec
Analyzes reference video (BH + tilted Doppler disk + lensed halo + stars),
specifies full 8-feature scope (adds cubemap skybox, lensed planets, Flamm
grid), Schwarzschild Phase 1 with Kerr Phase 2 follow-up, Bevy 0.19
full-screen Material2d architecture.
2026-07-09 18:20:38 +08:00
xfy
3d34c0920d Initial commit: scaffold Rust project with Cargo 2026-07-09 17:55:14 +08:00