This release is a pre-release and may not be stable for production use.
Turn High-Energy Physics detector geometry into a scene you can actually fly through.
Detector geometries (ROOT/TGeo, DD4hep, GDML, GeoModel, …) are huge, deeply nested, and built for simulation — not for looking at. nodehammer converts them into a clean, semantically-tagged scene graph and renders it in real time with a physically-based pipeline, natively or straight in the browser.
TGeo / DD4hep ── (GDML/Geant4, GeoModel: planned)
│
▼
Semantic scene graph (.nhb / .nhb.zst)
nodes · shapes · materials · deduplicated transforms
│
┌──────┴──────┐
▼ ▼
glTF / OBJ Render IR (NHR8, FlatBuffers)
│
▼
Interactive viewer
native (Metal / GLCORE / D3D11) · web (WebGPU / GLES3, wasm)
Every stage is driven by declarative TOML config — keep_if/drop_if
selection rules with a small predicate-expression language
(tag.sensitive == "true" && any(path ~= "**/Pixels/**")), material
remapping, and analytical boolean cuts — so you can go from "the whole
detector" to "just the Pixel barrel" without touching code.
Status
nodehammer is under active, pre-1.0 development. Here's what's real today versus what's on the roadmap.
✅ Implemented
- Importers: ROOT/TGeo and DD4hep, each independently switchable at
build time (
NODEHAMMER_WITH_TGEO,NODEHAMMER_WITH_DD4HEP). - Exporters: glTF/GLB and OBJ (render IR), plus the native
.nhb/.nhb.zstFlatBuffers semantic-scene container — a documented, zstd-compressible on-disk format. - Analytical geometry surgery: semantic-level azimuthal wedge cuts and boolean operations via manifold, correct on non-manifold swept primitives, cooperative with UI progress.
- CLI:
convert,inspect,validate-config,config-flatten,dump-semantic,dump-render,viewer. - Viewer rendering pipeline, live today:
- Full offscreen HDR pipeline with ACES / Reinhard / AgX tonemapping and exposure control
- GTAO screen-space ambient occlusion, with selectable quality presets
- Nishita single-scattering atmospheric sky (real Rayleigh + Mie, a real sun disc) baked into the IBL pipeline, plus a visible background dome
- FXAA 3.11 console-quality antialiasing
- Dynamic, GPU-load-adaptive render scale with a power-saving idle profile — renders on demand and caps the idle frame rate
- Live ImPlot performance graphs in the debug panel
- High-resolution, supersampled PNG screenshot export
(
nodehammer viewer --screenshot out.png ...) — verified on Metal; the WebGL2/GLES3 and WebGPU readback paths compile and link but are not yet verified in-browser
- Builds on macOS, Linux, and Windows natively (Metal, GLCORE, and D3D11
respectively), plus a wasm build targeting both GLES3 and WebGPU from one
configure, with the browser shell auto-picking the right bundle via
navigator.gpu. All five configurations build and pass the (headless) test suite in CI. A headless compute-worker wasm module (nodehammer-compute) runs tessellation and boolean cuts off the main thread. macOS is the primary hand-verified target for the interactive viewer itself — see below for what's untested elsewhere. - Modern C++: C++23 throughout (
<print>, the works); requires GCC ≥ 14, Clang ≥ 18/libc++, or MSVC ≥ 19.37.
🚧 Planned / in progress
- GDML/Geant4 importer — CMake option and library wiring exist
(
NODEHAMMER_WITH_GEANT4); the actual importer isn't written yet. - GeoModel importer — CMake option declared only; no implementation.
- Windows viewer verification — the D3D11 backend builds and passes CI's
headless tests, but the maintainer has no Windows machine to manually
verify interactive rendering; the PNG-export readback for D3D11 is a
build-time
#errorstub for now. - Bloom and IBL-quality levels — UI controls exist and are wired
through
RenderQualitySettings, but both are no-ops for now. - Project save/export system — the archive-as-project model below is landing now (working set, IndexedDB persistence, sidecar viewer mode, layered steer, Publish package); in-viewer editor windows and a named multi-document switcher are still to come. See docs/viewer-project-strategy.md.
- Single-instance enforcement + a real macOS
.appbundle — designed, not implemented; see docs/viewer-single-instance.md.
Project model: the archive is the project
One
ZipWorkingSetis both the thing you author (edit / curate / drop files into) and the thing you publish (serialize → host → share). Authoring and publishing are the same object flowing in two directions.
A nodehammer project is a .nhproj archive: a ZIP container holding the
config, geometry, and materials for a scene, plus an optional root
nodehammer.toml that makes it self-describing. The same archive opens
natively, in the browser, and behind a published link.
| Term | Meaning |
|---|---|
| Working set | the live, editable in-memory project (ZipWorkingSet) — what the viewer edits |
| Archive | a serialized .nhproj of a working set — the portable, publishable unit |
| Project manifest | root nodehammer.toml inside the archive: [project] entry keys + [view] initial steer |
| Sidecar | nh_manifest.json next to index.html — points at archive(s), carries deployment presentation (lock, steer overrides) |
| Steer | view-state (camera, angle cut, rotation, toggles) — the ephemeral per-link layer, committed to the URL query |
| Provenance | Empty | Local(name) | Remote(url) — where the working set came from; drives persistence and posture |
| Package | the self-contained static folder emitted by Publish — drop it on any static host, zero server code |
The web build has two postures from one wasm binary, branched on whether a sidecar is present:
- Application mode (no sidecar) — empty start, editable, native-like; the working set auto-persists to IndexedDB and restores on reload. Your document.
- Viewer mode (sidecar present) — fetches the archive, content locked, re-fetched from source on reload. A publication.
Content-lock is a deployment property of the sidecar; steer is never frozen,
so a shared link keeps camera and cuts live. The only viewer→app bridge is
explicit: save the .nhproj and open it in application mode.
Full design of record, including backend mapping and mode transitions: docs/viewer-project-strategy.md.
CLI
nodehammer convert # geometry → glTF / OBJ / render IR
nodehammer inspect # explore a semantic scene
nodehammer validate-config # lint a TOML config before running it
nodehammer config-flatten # resolve config includes/overrides
nodehammer dump-semantic # dump the semantic scene as JSON
nodehammer dump-render # dump the render IR as JSON
nodehammer viewer # launch the interactive viewer
Running the executable with no arguments at all (e.g. double-clicking
nodehammer.exe in a file manager) also launches the viewer, in builds with
NODEHAMMER_WITH_VIEWER enabled.
Building
Dependencies are managed with Conan; builds with CMake + Ninja.
just recipes # export vendored recipes (sokol-shdc)
just deps # conan install (viewer=True)
just configure # cmake --preset conan-relwithdebinfo
just build
just test
Or drive conan/cmake directly — see the Justfile for the
exact flags, including the Emscripten/wasm targets (just wasm-deps,
requires emsdk) and the
spack-based dev configuration (configure-full) that turns on the TGeo and
DD4hep importers together.
Key CMake options:
| Option | Purpose | Status |
|---|---|---|
NODEHAMMER_WITH_VIEWER |
Build the sokol/Dear ImGui interactive viewer | ✅ |
NODEHAMMER_WITH_TGEO |
ROOT/TGeo importer | ✅ |
NODEHAMMER_WITH_DD4HEP |
DD4hep importer | ✅ |
NODEHAMMER_WITH_GEANT4 |
GDML/Geant4 importer | 🚧 links Geant4 only, no importer yet |
NODEHAMMER_WITH_GEOMODEL |
GeoModel importer | 🚧 declared only |
NODEHAMMER_BUILD_TESTS |
Build the Catch2 unit-test binary | ✅ |
NODEHAMMER_BUILD_SHARED |
Also build and install libnodehammer + the public headers + a CMake package config |
🚧 packaging works; the API it exposes is still being written |
With NODEHAMMER_BUILD_SHARED=ON, cmake --install adds the shared library,
include/nodehammer/, and a package config, so a consumer needs only:
find_package(nodehammer REQUIRED)
target_link_libraries(app PRIVATE nodehammer::nodehammer)
No find_dependency for zstd, flatbuffers, manifold or the rest — the shared
library absorbs them. ci/shared-build.sh runs the whole thing end to end and,
on ELF, checks that nothing third-party or internal escaped into the export
table. CI runs it on every native platform.
A consumer needs only C++20. nodehammer itself is built as C++23, but the
installed headers do not require it, and the exported target asks for no more
than cxx_std_20. ci/shared_consumer compiles at exactly that floor, so a
public header reaching past it fails there rather than in your build.
On Windows the library and its consumer must agree on the C runtime (/MD vs
/MT) and on _ITERATOR_DEBUG_LEVEL — so a Debug consumer needs a Debug
nodehammer. This is not specific to nodehammer; it is what passing std::
types across a DLL boundary requires, and mismatches usually surface as heap
corruption rather than as a link error.
Try it
The repo ships a real detector fixture — the Open Data Detector — ready to convert:
just odd # full ODD → glb (see the Justfile for single-stave recipes too)
build/RelWithDebInfo/nodehammer viewer
…in a browser
Every push to main publishes the wasm viewer to
https://paulgessinger.github.io/nodehammer/, in both of the postures the
web build supports:
/app/ |
the open application — empty start; drop a .nhproj or loose config/geometry files onto it |
/odd/ |
the full Open Data Detector, preconfigured and content-locked |
/odd-simple/ |
the simplified ODD — same, lighter to build |
Each directory is a self-contained static package of the kind the viewer's
Publish command emits. Reproduce the whole site locally with
just pages-site after just wasm-release.
Project layout
src/ core pipeline: cli, config, ir (intermediate representation),
scene building, tessellation, selection, the viewer, web glue
shaders/ sokol-shdc GLSL sources for the full render pipeline
schemas/ FlatBuffers schemas (render.fbs, semantic.fbs)
profiles/ Conan profiles (Emscripten cross-compilation)
recipes/ vendored/patched Conan recipes (sokol, sokol-shdc, imgui, implot, nfd)
fixtures/ sample detector geometries and configs
docs/ format specs and design docs (nhb format, predicate expressions,
orbit navigation, rendering-fidelity strategy, PNG export)
web/ browser viewer entry point
License
MIT © Paul Gessinger — see LICENSE. Third-party license texts for vendored/bundled assets live under LICENSES/.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nodehammer-0.2.0rc3.tar.gz.
File metadata
- Download URL: nodehammer-0.2.0rc3.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
985756d66dc33482aceefca75e8cae83202b74e9a4b6a88a7676f80ece6b8a0d
|
|
| MD5 |
2c2fc00a5ab9d31745adf4452454387c
|
|
| BLAKE2b-256 |
3027c27c2eaa86100e5df7295eb5a1e8f8a28a5a3390319d91104136567e3015
|
Provenance
The following attestation bundles were made for nodehammer-0.2.0rc3.tar.gz:
Publisher:
ci.yml on paulgessinger/nodehammer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nodehammer-0.2.0rc3.tar.gz -
Subject digest:
985756d66dc33482aceefca75e8cae83202b74e9a4b6a88a7676f80ece6b8a0d - Sigstore transparency entry: 2563323335
- Sigstore integration time:
-
Permalink:
paulgessinger/nodehammer@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Branch / Tag:
refs/tags/v0.2.0rc3 - Owner: https://github.com/paulgessinger
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Trigger Event:
push
-
Statement type:
File details
Details for the file nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 3.0 MB
- Tags: CPython 3.12+, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e18b3e15b036c5f86c446aecfe6a96032f7f07664b7c697eb006ca07733626c
|
|
| MD5 |
09cd8a0590616f34653e94adc51ff952
|
|
| BLAKE2b-256 |
2102cbc0223582f97ad0d353d913c176404a08b0a98f2e8fa5725f03b316feb1
|
Provenance
The following attestation bundles were made for nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:
Publisher:
ci.yml on paulgessinger/nodehammer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl -
Subject digest:
4e18b3e15b036c5f86c446aecfe6a96032f7f07664b7c697eb006ca07733626c - Sigstore transparency entry: 2563324299
- Sigstore integration time:
-
Permalink:
paulgessinger/nodehammer@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Branch / Tag:
refs/tags/v0.2.0rc3 - Owner: https://github.com/paulgessinger
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Trigger Event:
push
-
Statement type:
File details
Details for the file nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.
File metadata
- Download URL: nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.12+, manylinux: glibc 2.27+ ARM64, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9eb40d1aa777d2ee5b7749ae9f065b9e1c1de76fe7d13418c338ee8cb506088a
|
|
| MD5 |
f07f42c248452b4283c033eda2bd3e7e
|
|
| BLAKE2b-256 |
fd24ffa1b8a6a961ed70bd4e6a7978d13e5fd6783c3acfb80e8ee85880fac461
|
Provenance
The following attestation bundles were made for nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl:
Publisher:
ci.yml on paulgessinger/nodehammer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nodehammer-0.2.0rc3-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl -
Subject digest:
9eb40d1aa777d2ee5b7749ae9f065b9e1c1de76fe7d13418c338ee8cb506088a - Sigstore transparency entry: 2563324966
- Sigstore integration time:
-
Permalink:
paulgessinger/nodehammer@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Branch / Tag:
refs/tags/v0.2.0rc3 - Owner: https://github.com/paulgessinger
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Trigger Event:
push
-
Statement type:
File details
Details for the file nodehammer-0.2.0rc3-cp312-abi3-macosx_13_0_arm64.whl.
File metadata
- Download URL: nodehammer-0.2.0rc3-cp312-abi3-macosx_13_0_arm64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12+, macOS 13.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34c8ee29c72694e2d73573203cca90311c184a68bff43094ed85050878852218
|
|
| MD5 |
df5f442aecf9c3d949aea98c01e8b4aa
|
|
| BLAKE2b-256 |
dee11968711bb14090420288a18adad8cd95c49168836f5481d7a4a4bc6c7d03
|
Provenance
The following attestation bundles were made for nodehammer-0.2.0rc3-cp312-abi3-macosx_13_0_arm64.whl:
Publisher:
ci.yml on paulgessinger/nodehammer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nodehammer-0.2.0rc3-cp312-abi3-macosx_13_0_arm64.whl -
Subject digest:
34c8ee29c72694e2d73573203cca90311c184a68bff43094ed85050878852218 - Sigstore transparency entry: 2563324734
- Sigstore integration time:
-
Permalink:
paulgessinger/nodehammer@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Branch / Tag:
refs/tags/v0.2.0rc3 - Owner: https://github.com/paulgessinger
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@765591faf1d6bf2ff53f5d54ef6855330bcc0877 -
Trigger Event:
push
-
Statement type: