diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ef4ddd2..983f66f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,6 +38,7 @@ jobs:
- name: Check Barnes-Hut self-gravity reference
run: |
node tests/barnes-hut.mjs
+ node tests/nbody-view.mjs
cargo test --manifest-path nbody/Cargo.toml --locked --offline
cargo run --manifest-path nbody/Cargo.toml --locked --offline -- verify
cargo run --manifest-path nbody/Cargo.toml --locked --offline -- verify-flat
diff --git a/.github/workflows/native-gpu.yml b/.github/workflows/native-gpu.yml
index c35a9f4..2180f43 100644
--- a/.github/workflows/native-gpu.yml
+++ b/.github/workflows/native-gpu.yml
@@ -3,9 +3,9 @@ name: Native GPU runtime
on:
push:
branches: [main]
- paths: ['runtime/**', 'rust/**', 'nbody/**', 'data/uff/**', 'tests/uff-reference.json', 'scripts/*gpu*', 'scripts/vast-runner.py', 'rust-toolchain.toml', '.github/workflows/native-gpu.yml', '.dockerignore', 'LICENSE', 'NOTICE.md']
+ paths: ['runtime/**', 'rust/**', 'nbody/**', 'data/uff/**', 'tests/uff-reference.json', 'tests/test_bh2d_hardware_sweep.py', 'scripts/*gpu*', 'scripts/bench-bh2d-hardware.py', 'scripts/bench-bh2d-hardware-launch.sh', 'scripts/bench-bh2d-hardware-launch.cmd', 'scripts/vast-runner.py', 'rust-toolchain.toml', '.github/workflows/native-gpu.yml', '.dockerignore', 'LICENSE', 'NOTICE.md']
pull_request:
- paths: ['runtime/**', 'rust/**', 'nbody/**', 'data/uff/**', 'tests/uff-reference.json', 'scripts/*gpu*', 'scripts/vast-runner.py', 'rust-toolchain.toml', '.github/workflows/native-gpu.yml', '.dockerignore', 'LICENSE', 'NOTICE.md']
+ paths: ['runtime/**', 'rust/**', 'nbody/**', 'data/uff/**', 'tests/uff-reference.json', 'tests/test_bh2d_hardware_sweep.py', 'scripts/*gpu*', 'scripts/bench-bh2d-hardware.py', 'scripts/bench-bh2d-hardware-launch.sh', 'scripts/bench-bh2d-hardware-launch.cmd', 'scripts/vast-runner.py', 'rust-toolchain.toml', '.github/workflows/native-gpu.yml', '.dockerignore', 'LICENSE', 'NOTICE.md']
workflow_dispatch:
permissions:
@@ -25,6 +25,12 @@ jobs:
python-version: '3.12'
- name: Check SSH runner and result extraction on Windows
run: python runtime/tests/test_runner.py
+ - name: Check BH2D Windows launcher propagates Python failure
+ shell: cmd
+ run: |
+ call scripts\bench-bh2d-hardware-launch.cmd --particles 512 --dry-run
+ if %ERRORLEVEL% EQU 0 exit /b 1
+ exit /b 0
runner-python:
runs-on: ubuntu-24.04
@@ -60,6 +66,8 @@ jobs:
bash -n scripts/run-gpu.sh scripts/bootstrap-gpu.sh
python runtime/tests/test_runner.py
python runtime/cuda/check_barnes_hut_layout.py
+ python tests/test_bh2d_hardware_sweep.py
+ sh scripts/bench-bh2d-hardware-launch.sh --dry-run --output "$RUNNER_TEMP/bh2d-plan" --particles 512,4096,8192
- name: Install software Vulkan for compute validation
run: |
sudo apt-get update -qq
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 41032de..fcaf318 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -29,6 +29,7 @@ jobs:
node tests/physics.mjs
node tests/app.mjs
node tests/barnes-hut.mjs
+ node tests/nbody-view.mjs
cargo test --manifest-path nbody/Cargo.toml --locked --offline
cargo run --manifest-path nbody/Cargo.toml --locked --offline -- verify
node scripts/build-site.mjs
diff --git a/NOTICE.md b/NOTICE.md
index 86f8464..025398b 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -9,14 +9,15 @@ and local PNG/WebM/JSON capture. Galaxy orbital equations and the accelerated
renderer replace the original gate–centre–mouth transfer geometry.
The adapted browser sources (`galaxy-core.js`, `app.js`, `renderer.js`,
-`index.html`, `style.css`, and the JavaScript smoke/application tests) retain
+`rotation-lab.html`, `style.css`, and the JavaScript smoke/application tests) retain
**Mozilla Public License 2.0** file notices. The full licence is in
[`LICENSES/MPL-2.0.txt`](LICENSES/MPL-2.0.txt). Their corresponding source is
provided directly in this repository and static distribution.
-The new Rust sampler and native example, build scripts, generated Wasm module
-and browser payload, and benchmark are
-**Apache-2.0**, under the repository's existing [`LICENSE`](LICENSE).
+The new N-body browser entrypoint (`index.html`, `nbody-clock.js`, and
+`nbody-viz.js`), Rust sampler and native example, build scripts, generated Wasm
+module and browser payload, and benchmark are **Apache-2.0**, under the
+repository's existing [`LICENSE`](LICENSE).
The existing repository licence has not been used to relicense the MPL files.
VORTEX's reference photographs, artwork and historical stress-test reports are
diff --git a/README.md b/README.md
index bb3cc67..1fd4eb8 100644
--- a/README.md
+++ b/README.md
@@ -7,14 +7,15 @@
It began as an adaptation of the VORTEX 2.1.0 particle lab and now combines:
-- interactive rotation-curve visualization;
+- a lightweight default N-body simulator: 768 real interacting bodies, luminous sprites and short orbital trails;
+- interactive rotation-curve visualization in the preserved rotation-law instrument;
- UFF, Newtonian, NFW, Burkert, MOND/RAR, and authored visual rotation laws;
- deterministic Rust/WebAssembly sampling in the browser;
- native Rust CPU execution with Float/libm and BAM32/Q2.30 LUT backends;
- Vulkan/`wgpu` and NVIDIA CUDA compute paths;
- memory-bounded exact-u64 logical addressing;
- reproducible benchmark receipts, topology evidence, and archived scaling studies;
-- an opt-in Barnes–Hut resident self-gravity laboratory with a direct-force oracle and live quadtree visualization;
+- a Barnes–Hut resident self-gravity laboratory with a direct-force oracle and live quadtree visualization;
- a GPU-oriented BH #2A Morton/Z-order + flat-cell CPU substrate with repeatable topology receipts;
- a BH #2B1 explicit f32/u32 transfer ABI with executable Vulkan/WGSL flat-tree traversal and matched CUDA traversal source;
- BH #2B2 multi-step resident self-gravity with persistent GPU state, GPU kick/drift/final-kick kernels, and an explicit CPU tree-rebuild boundary;
@@ -37,9 +38,10 @@ The v0.4.0 native-CPU evidence baseline remains archived at Zenodo as:
| Layer | Current state |
| --- | --- |
-| Browser instrument | Offline HTML/CSS/JS + bundled Rust/Wasm; no server or CDN required |
-| Browser logical population | Up to `2^32 = 4,294,967,296` logical stars on the Rust/Wasm path |
-| Browser rendered sample | Up to 65,536 stars per frame on Rust/Wasm + WebGL |
+| Browser N-body home page | 128–2,048 interacting bodies (768 default); planar Barnes–Hut gravity, leapfrog integration, glow/trails and orbit/zoom controls |
+| Rotation-law instrument | Preserved at `rotation-lab.html`; offline HTML/CSS/JS + bundled Rust/Wasm |
+| Rotation-law logical population | Up to `2^32 = 4,294,967,296` logical stars on the Rust/Wasm path |
+| Rotation-law rendered sample | Up to 65,536 stars per frame on Rust/Wasm + WebGL |
| Native CPU runtime | Exact positive-u64 logical population, bounded resident sample up to 16,777,216 particles |
| CPU projection backends | `float-libm` and `bam-lut-q30` |
| Native GPU runtime | Rust/`wgpu`/Vulkan plus NVIDIA CUDA/CuPy RawKernel |
@@ -61,9 +63,13 @@ The earlier v0.4.0 archive remains the **before-state** for the CPU architecture
## 1. Browser instrument
-Open **`index.html`** directly in a modern browser. No install, local server, CDN, or network connection is required, including for the bundled Rust/WebAssembly engine.
+Open **`index.html`** directly in a modern browser for the N-body simulator. No install, local server, CDN, or network connection is required. The default 768 bodies all contribute mass; reducing the resident count reduces computation. Glow sprites and ten-step trails add visual density without adding simulated particles. The camera tilts a planar physical system; it is not a 3D force solver.
-The separate **`barnes-hut.html`** entrypoint is an opt-in resident self-gravity lab with a live quadtree overlay and direct-force error probes. It does not change the default rotation-law instrument.
+Choose a binary encounter, rotating disc or cold collapse. Pause, single-step, change the seed, inspect the tree, or pause for a direct-force audit. Physics uses a fixed time step on a 60 Hz schedule, independent of monitor refresh rate. Overload drops catch-up work rather than enlarging the time step or changing the body count. Reduced-motion preference starts paused and disables trails.
+
+The original prescribed-field instrument, including its Rust/WebAssembly sampling, UFF controls and exports, is preserved at **`rotation-lab.html`**. The detailed tree laboratory remains at **`barnes-hut.html`**. The following logical-population and sampling controls describe the rotation-law instrument.
+
+The separate **`barnes-hut.html`** entrypoint is an opt-in resident self-gravity lab with a live quadtree overlay and direct-force error probes. The default browser entrypoint is the N-body simulator at **`index.html`**, while the preserved rotation-law instrument remains at **`rotation-lab.html`**.
The browser instrument lets you change morphology, mass model, viewing geometry, and time while watching the galaxy and its rotation curve respond together.
@@ -272,6 +278,16 @@ BH #2D is the active optimization path. It retains BH #2C and BH #2B2 as executa
BH #2D correctness is exercised through software Vulkan in CI, but **software-Vulkan timings are not hardware performance evidence**. A hardware speed claim requires a non-software adapter receipt.
+The remaining BH #2D evidence item has a fail-closed real-GPU sweep runner:
+
+```bash
+sh scripts/bench-bh2d-hardware-launch.sh \
+ --output runs/bh2d-hardware-sweep \
+ --adapter 0
+```
+
+It runs a source-pinned 512→65,536 resident-body sweep by default, requires hardware receipts, validates the frozen correctness/oracle gates, and hashes each receipt/log into a scaling manifest. The manifest is evidence for that exact source/workload/adapter, not an automatic production-promotion claim.
+
`--allow-software` enables verification through software Vulkan and must not be interpreted as hardware GPU performance evidence.
The CUDA checker freezes ABI/source parity without claiming CUDA execution where no NVIDIA CUDA run occurred.
@@ -467,6 +483,9 @@ sh scripts/test-cpu-runtime.sh
# Retro CPU portability
sh scripts/test-retro-cpu.sh
+# GPU evidence-runner host-side tests
+python3 tests/test_bh2d_hardware_sweep.py
+
# CUDA host-side tests
python3 tests/test_cuda_u64.py
```
diff --git a/ROADMAP.md b/ROADMAP.md
index 28ba21a..39d4764 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -199,6 +199,8 @@ Stable radix ordering starts from resident-body order and preserves that order f
The initial CI fixture proves correctness through Mesa Vulkan but does not establish a hardware speedup. Real GPU performance evidence remains an explicit BH #2D completion item.
+The repository now includes `scripts/bench-bh2d-hardware.py` to capture that evidence without weakening the boundary. The runner requires a clean tracked source tree and `--require-hardware`, validates the BH #2D correctness/determinism gates at every point, preserves repeat-matched BH #2C comparison through 4,096 bodies, and emits a source-pinned scaling manifest with receipt/log hashes. The harness is implementation support; BH #2D remains evidence-pending until a real-GPU manifest exists.
+
## BH #2E — Hardware Promotion and Scaling
After BH #2D obtains real-hardware receipts, the next promotion rung is:
@@ -397,3 +399,7 @@ All of the following remain useful research directions, but they are explicitly
These items were deferred while PE #15 was active. v0.6.0 closed that phase; any future work now requires an explicit phase with its own evidence boundary.
The previous detailed designs are preserved by the immutable `v0.5.0` source archive and tag; they are not discarded, only postponed.
+
+## Browser N-body observatory
+
+The home page now runs the existing planar Barnes–Hut solver with a modest 768-body default, selectable 128–2,048 bodies, fixed-rate integration, glow/trails and camera controls. The original prescribed-field visual is preserved at `rotation-lab.html`; `barnes-hut.html` retains the detailed tree lab. This UI upgrade supplies no native GPU timing evidence and does not change BH #2D evidence-pending or BH #2E promotion gates.
diff --git a/barnes-hut.css b/barnes-hut.css
index 339a46a..c608237 100644
--- a/barnes-hut.css
+++ b/barnes-hut.css
@@ -69,3 +69,13 @@ footer { min-height: 40px; border-top: 1px solid var(--line); color: var(--muted
.readouts div { border-right: 0; border-bottom: 1px solid var(--line); }
.readouts div:last-child { border-bottom: 0; }
}
+
+/* N-body observatory controls. */
+.gesture-note { color: var(--muted); font-size: 0.7rem; align-self: center; margin-left: auto; }
+#nbodyCanvas { touch-action: none; cursor: grab; }
+#nbodyCanvas:active { cursor: grabbing; }
+:focus-visible { outline: 2px solid var(--hot); outline-offset: 3px; }
+input[type="range"], input[type="checkbox"] { accent-color: var(--hot); }
+@media (max-width: 560px) {
+ .gesture-note { margin-left: 0; width: 100%; line-height: 1.5; }
+}
diff --git a/barnes-hut.html b/barnes-hut.html
index 1abf041..d6b9223 100644
--- a/barnes-hut.html
+++ b/barnes-hut.html
@@ -18,7 +18,7 @@
QSOL-IMC / GALAXY / SELF-GRAVITY LAB
BARNES–HUT
-
+
@@ -48,7 +48,7 @@
BARNES–HUT
What changed?
This lab is a separate self-gravitating execution path. Every resident body contributes mass to a deterministic quadtree. Distant cells may be replaced by their centre of mass when s / d < θ; nearby cells are opened. A kick–drift–kick leapfrog step rebuilds the tree after the drift.
-
The main GALAXY rotation-law instrument remains unchanged. Its huge logical populations are sampled independent test particles; they are not silently reinterpreted as mutually interacting bodies. This lab keeps the resident population explicit because self-gravity creates cross-particle coupling.
+
The GALAXY rotation-law instrument remains available separately. Its huge logical populations are sampled independent test particles; they are not silently reinterpreted as mutually interacting bodies. This lab keeps the resident population explicit because self-gravity creates cross-particle coupling.
diff --git a/docs/BARNES-HUT.md b/docs/BARNES-HUT.md
index 8491904..05494a1 100644
--- a/docs/BARNES-HUT.md
+++ b/docs/BARNES-HUT.md
@@ -2,7 +2,7 @@
GALAXY now has two deliberately distinct dynamics families:
-1. **Prescribed-field / test-particle modes** — the existing browser, CPU and GPU paths. These retain huge logical address spaces because individual resident particles do not affect one another.
+1. **Prescribed-field / test-particle modes** — the rotation-law browser instrument (`rotation-lab.html`), CPU and GPU paths. These retain huge logical address spaces because individual resident particles do not affect one another.
2. **Resident self-gravity** — the Barnes–Hut laboratory. Every resident body's mass contributes to the force field, so the complete interacting resident set is explicit and cannot be substituted by independent logical-u64 tiles.
## Why Barnes–Hut
@@ -55,6 +55,9 @@ A future GPU implementation should preserve this CPU/direct reference as its cor
## Visualization
+`index.html` is the default lightweight N-body observatory. It reuses the verified browser force solver with 768 resident bodies by default (128–2,048 selectable), fixed-rate leapfrog scheduling, seeded presets, optional trails and luminous sprites. Rendering contributes no additional gravitational mass. Orbit/zoom controls project the planar dynamics without modifying them. At 4× speed on an ordinary 60 Hz display, each rendered frame advances four physics steps. After a render gap the scheduler may batch up to 24 steps, derived from the 100 ms elapsed-time cap, then discards any remaining overload debt; hidden tabs suspend physics and under sustained load simulated time advances more slowly. Force probes pause the simulation so their result remains attached to the displayed state.
+
+
`barnes-hut.html` is an offline browser laboratory. It renders the resident bodies and can overlay quadtree cells while the system evolves. Controls expose:
- resident body count;
@@ -289,6 +292,34 @@ Kernel families are batched into command buffers to avoid measuring one CPU/GPU
Receipts classify the selected adapter as either `software-validation` or `hardware`. `--require-hardware` rejects software adapters. Mesa/llvmpipe timing is therefore correctness and diagnostic evidence only; a hardware performance claim requires a receipt from a real GPU.
+### Real-hardware sweep
+
+`scripts/bench-bh2d-hardware.py` is the evidence runner for the remaining BH #2D hardware item. It executes a strictly increasing resident-body sweep through `galaxy-bh-gpu-tree-parallel --require-hardware`, refuses a dirty tracked source tree or an existing evidence directory, validates every receipt, requires one adapter identity for the complete sweep, and hashes each receipt/log into `manifest.json`.
+
+The default sweep is:
+
+```text
+512 -> 1024 -> 2048 -> 4096 -> 8192 -> 16384 -> 32768 -> 65536
+```
+
+Counts through 4,096 retain repeat-matched BH #2C timing. Larger points explicitly require the BH #2C and bounded full-oracle skips already encoded by the verifier; they do not silently drop those gates.
+
+Example on a real GPU:
+
+```bash
+sh scripts/bench-bh2d-hardware-launch.sh \
+ --output runs/bh2d-hardware-sweep \
+ --adapter 0
+```
+
+A completed scaling manifest is hardware evidence for the exact recorded source, workload and adapter. It does **not** by itself promote BH #2D to production or establish a host-independent speed claim.
+
## Next rung
After real-hardware BH #2D receipts exist, BH #2E can evaluate scaling, memory/capacity limits and production promotion while retaining BH #2A/B2B2/B2C as frozen oracles.
+
+### Hardware harness launch and toolchain boundary
+
+Launch real evidence capture through the clean launcher: `sh scripts/bench-bh2d-hardware-launch.sh ...` on POSIX or `scripts\\bench-bh2d-hardware-launch.cmd ...` on native Windows. The launcher starts isolated Python under a newly constructed environment so inherited loader-injection variables are not resident in the evidence process. Direct Python execution is rejected. Imported use by the unit-test runner is for host validation only.
+
+The harness now selects and records a platform-specific tool boundary. Linux uses the system compiler/linker/Git path, macOS uses the native system paths plus standard Homebrew locations, and Windows records Git plus any active MSVC/LLVM linker tools before narrowing the build PATH to those resolved tool directories. Cargo and rustc are recorded separately from rustup proxies and invoked through their resolved binaries. The OS, installed system libraries and toolchain are trusted host prerequisites; this is provenance checking, not a sandbox against a hostile host. Git checks clear ambient `GIT_*` selectors and bind the checkout explicitly, including linked worktrees. Relative `CARGO_HOME` is interpreted from Cargo's repository working directory. Logs preserve raw bytes, receipt parser failures enter the failed-manifest path, and workload values are validated before any output is created. Manifests serialize strict JSON.
diff --git a/docs/ENGINE.md b/docs/ENGINE.md
index 544b3ed..65e7f16 100644
--- a/docs/ENGINE.md
+++ b/docs/ENGINE.md
@@ -95,7 +95,7 @@ represent a 2³² logical population. WebGL context loss stops the current recor
and switches to a fresh Canvas element with the smaller sample.
The payload is base64 in an external classic script, avoiding fetch and file-URL
-CORS restrictions when opening `index.html` directly. It needs no `eval`, no
+CORS restrictions when opening `rotation-lab.html` directly. It needs no `eval`, no
worker, no remote package, and no cross-origin-isolation headers. CSP explicitly
permits Wasm compilation using `wasm-unsafe-eval`. Compilation failure uses the
bounded JavaScript fallback and is reported in the interface.
diff --git a/docs/GPU-RUNTIME.md b/docs/GPU-RUNTIME.md
index 362025c..e54f244 100644
--- a/docs/GPU-RUNTIME.md
+++ b/docs/GPU-RUNTIME.md
@@ -29,7 +29,9 @@ Install Rust through [rustup](https://rustup.rs/) and a working native GPU drive
The repository pins Rust 1.85.1. Linux uses Vulkan; Windows can use Vulkan or
D3D12, and macOS uses Metal through [wgpu](https://github.com/gfx-rs/wgpu/tree/v24.0.5).
The Linux path is the cloud target. Windows/Metal hardware execution has not been
-validated by the Linux CI gate.
+validated by the Linux CI gate. The BH #2D evidence harness itself is platform-aware:
+use `scripts\\bench-bh2d-hardware-launch.cmd` on native Windows so Cargo can retain
+its recorded MSVC/LLVM linker environment without requiring a POSIX `cc`.
On Ubuntu, with the GPU vendor driver already installed:
@@ -275,6 +277,16 @@ It also records `hardware_performance_claim_allowed`. `--require-hardware` fails
Tree-build stage families are batched into command buffers before synchronization. Reported stage times cover bounds, Morton generation, radix ordering, target-position assignment, topology and aggregates rather than one host synchronization per small kernel.
+For repeatable real-hardware scaling evidence, use the fail-closed sweep runner:
+
+```bash
+sh scripts/bench-bh2d-hardware-launch.sh \
+ --output runs/bh2d-hardware-sweep \
+ --adapter 0
+```
+
+The runner defaults to 512 through 65,536 resident bodies, refuses software receipts and dirty tracked source, keeps the selected adapter fixed across the sweep, validates the BH #2D correctness/oracle status encoded in every receipt, and records SHA-256 hashes for the receipts and logs in a source-revision-pinned `manifest.json`. Use `--dry-run` to inspect the exact commands without executing GPU work.
+
## Physics and numerical behavior
The source remains UFF commit
diff --git a/index.html b/index.html
index 6aad4eb..73ef9ae 100644
--- a/index.html
+++ b/index.html
@@ -1,121 +1,131 @@
-
+
-
-
- GALAXY · Stellar motion lab
-
-
-
-
-
-
-
-
+
+
+ GALAXY · N-body simulator
+
+
+
+
-
UFF demonstration data · fixed parameters, no fit. Shaded ends extend the supplied component speeds beyond 0.5–12 kpc.
- Compare the six demo rows
Radius (kpc)
Demo ± error (km/s)
Model (km/s)
-
0.5
40 ± 5
—
-
1.0
65 ± 5
—
-
2.0
90 ± 4
—
-
5.0
115 ± 4
—
-
8.0
130 ± 6
—
-
12.0
135 ± 7
—
-
-
-
Preparing the deterministic star field.
- About this galaxy
The UFF modes use gas, disc and bulge component curves to calculate circular speeds, with a selectable halo or acceleration law and an optional central mass. Those speeds drive the stars’ orbits. The original visual mode retains its adjustable shear.
The star distribution remains an authored disc, bulge and halo. Morphology controls change that display geometry; mass-to-light controls change the dynamics. Logical stars describe a sampled population. Only the rendered count is drawn.
+
+
+
+
+ Drag to orbit · scroll to zoom · space to pause
+
+
+
+
BODIES—resident, mutually coupled
+
TREE NODES—— depth
+
FORCE TERMS—— vs direct
+
PROBE RMS ERROR—12 direct-force probes
+
+
+
768 bodies, each contributing mass. Glow and trails add depth without adding gravitational work.
+
+ Real gravity, a little optical theatre
+
Every displayed body participates in this planar N-body simulation. A deterministic Barnes–Hut quadtree approximates distant mass; a kick–drift–kick leapfrog integrator evolves positions and velocities. Bodies can pull, scatter and form tidal structures instead of following prescribed orbits.
+
Soft luminous sprites and short position-history trails make a modest population look rich. They add no mass or hidden simulated stars. The 3D-looking inclination is a projection of a 2D physical system, in normalized units with G = 1.
+
Physics targets 60 fixed steps per second at 1× speed. Under load it slows down rather than increasing the integration step or changing the population. This browser view is separate from the native GPU evidence programme.