{"id":51299720,"url":"https://github.com/delta9000/x3d-cpp","last_synced_at":"2026-06-30T18:01:47.928Z","repository":{"id":366728284,"uuid":"1277402719","full_name":"delta9000/x3d-cpp","owner":"delta9000","description":"Headless, renderer-agnostic X3D 4.0 domain-runtime SDK for C++ — runtime + code generator.","archived":false,"fork":false,"pushed_at":"2026-06-23T05:04:25.000Z","size":4234,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-23T05:22:54.688Z","etag":null,"topics":["3d","code-generation","cpp","sdk","x3d"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/delta9000.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-22T21:37:04.000Z","updated_at":"2026-06-23T03:47:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/delta9000/x3d-cpp","commit_stats":null,"previous_names":["delta9000/x3d-cpp"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/delta9000/x3d-cpp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delta9000%2Fx3d-cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delta9000%2Fx3d-cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delta9000%2Fx3d-cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delta9000%2Fx3d-cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/delta9000","download_url":"https://codeload.github.com/delta9000/x3d-cpp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/delta9000%2Fx3d-cpp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34977672,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d","code-generation","cpp","sdk","x3d"],"created_at":"2026-06-30T18:01:42.074Z","updated_at":"2026-06-30T18:01:47.921Z","avatar_url":"https://github.com/delta9000.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# x3d-cpp-gen\n\nA headless, renderer-agnostic **X3D domain-runtime SDK** in C++. Load an X3D\nscene (XML, ClassicVRML, VRML97, or JSON; versions 3.0–4.1), run its event /\nbehavior model tick-by-tick, and pull out renderer-ready geometry — meshes,\nmaterials, lights, camera, background — for *your* backend. **No GPU, no\nwindowing, no rendering opinion**: the runtime stays spec-correct and\nbackend-free, and you bring (or borrow) the renderer.\n\nThe C++ node layer is **generated from the official X3D Unified Object Model\n(UOM)**, so every node and field is spec-correct by construction.\n\n## Gallery — real X3D, rendered headless\n\nEvery image below is **real X3D**, parsed by the SDK and drawn by the\n[headless CPU rasterizer example](examples/cpu_raster/) — **no GPU, no display,\nno system dependencies** (image I/O is a vendored single-header stb, compiled\nin). It consumes the same renderer-agnostic extraction seam any GL/Vulkan/CAVE\nconsumer would, which is the whole point: the runtime stays spec-correct and\nbackend-free.\n\n| | |\n|---|---|\n| ![Textured PBR lion bust](docs/images/gallery/lion-head.png) | ![PhysicalMaterial spheres in a skybox](docs/images/gallery/skybox-pbr.png) |\n| A ~47k-triangle CC0 lion bust ([Poly Haven](https://polyhaven.com/a/lion_head)), textured PBR (base + ORM + normal map) under a three-point rig. | Glossy `PhysicalMaterial` spheres inside a `Background` panorama skybox. |\n| ![Metallic-roughness grid](docs/images/gallery/pbr-grid.png) | ![RGB three-point lighting](docs/images/gallery/rgb-lighting.png) |\n| Metallic × roughness sweep — the analytic Cook-Torrance/GGX BRDF. | RGB three-point directional lighting accumulating on a sphere. |\n\n![Primitive texcoords](docs/images/gallery/primitives.png)\n\nThe analytic primitives (`Box`, `Sphere`, `Cone`, `Cylinder`), each wearing a\ndifferent `proc:` texture, so the per-primitive texture-coordinate generation\nreads off the surface — checker on the box faces, lat/long on the sphere, brick\nup the cone, rainbow bars around the cylinder.\n\n![Utah teapot — 32 NURBS patches](docs/images/gallery/teapot-nurbs.png)\n\nThe **Utah teapot** (Martin Newell, 1975 — [public domain](http://www.holmes3d.net/graphics/teapot/)),\nits 32 bicubic Bézier patches expressed as order-4 `NurbsPatchSurface` nodes — a Bézier\npatch *is* a NURBS patch (clamped knots, unit weights). Tessellated with **analytic\nnormals** (the cross product of the surface partial derivatives), so the ceramic shading\nruns smoothly across all 32 patch seams. Scene: `assets/gallery/hero_teapot_nurbs.x3d`.\n\nReproduce them with `mise run cpuraster`, then render any scene under\n`examples/cpu_raster/assets/` (e.g. `… assets/models/lion_head/lion_head_lit.x3d -o lion.png`).\n\n### Animated — interpolators over time\n\nSeamless loops the **headless** CPU rasterizer produced by stepping simulation\ntime frame-by-frame (`--animate`) and muxing with ffmpeg — the same\n`TimeSensor → Interpolator → ROUTE` machinery a browser runs, with no GPU or\ndisplay:\n\n![Kelp Forest flythrough](docs/images/gallery/anim-kelp.gif)\n\nA guided-tour flythrough of a **real, 600+ item X3D world** — the NPS/MOVES\n*Kelp Forest Exhibit* (Inline composition, PROTO fish \u0026 kelp, `ElevationGrid`\nterrain, swimming/swaying/pumping animation) — rendered entirely headless.\nExhibit © NPS MOVES Institute (free use with credit); fetched, not bundled.\n[Full-quality WebM](docs/videos/demos/kelp_flythrough.webm) ·\n[how it's built](examples/cpu_raster/assets/kelp_flythrough/). And the synthetic\ninterpolator demos:\n\n| | |\n|---|---|\n| ![X3D logo bounce grazing the corner](docs/images/gallery/anim-dvd.gif) | ![uvgrid sphere orbiting a path](docs/images/gallery/anim-position.gif) |\n| The X3D \"DVD logo\": a `PositionInterpolator` with true edge reflections that grazes the corner without hitting it. | A textured sphere orbiting a closed path (`PositionInterpolator → Transform.translation`). |\n| ![sphere cycling hue](docs/images/gallery/anim-color.gif) | ![sphere spinning via SLERP](docs/images/gallery/anim-orientation.gif) |\n| A `ColorInterpolator` cycling a material through the HSV hue arc. | An `OrientationInterpolator` spinning a sphere via quaternion SLERP. |\n\nFull-quality WebM:\n[dvd](docs/videos/demos/dvd.webm) ·\n[position](docs/videos/demos/position.webm) ·\n[orientation](docs/videos/demos/orientation.webm) ·\n[color](docs/videos/demos/color.webm) — regenerate everything with `mise run demos`; see\n[`examples/cpu_raster/`](examples/cpu_raster/README.md#animation-demos).\n\n## Quickstart — three ways in\n\n### 1. The `x3d` CLI (no code)\n\nBuild the tools (`mise run build` → `build/x3d`), then drive scenes from the\nshell — convert between encodings, validate against the spec, headlessly\nsimulate behavior, or export geometry:\n\n```bash\nx3d convert  scene.x3dv -o scene.x3d -f xml   # ClassicVRML → XML (or vrml|json)\nx3d validate scene.x3d  --json                # conformance + profile-fit diagnostics\nx3d sim      scene.x3d  --ticks 120           # run the event/behavior loop, trace field changes\nx3d extract  scene.x3d  -o scene.stl          # geometry → binary STL\nx3d canonicalize scene.x3d                     # X3D Canonical Form (X3DC14N)\n```\n\n### 2. Embed the SDK (one header)\n\nLink `x3d_cpp::sdk` and `#include \"x3d/sdk.hpp\"` — everything an embedder needs\nis in namespace `x3d::sdk`. Parse once, tick each frame, consume the delta:\n\n```cpp\n#include \"x3d/sdk.hpp\"\nnamespace sdk = x3d::sdk;\n\nsdk::X3DDocument doc = sdk::parseFile(\"scene.x3d\");   // 4 encodings + gzip, with diagnostics\nsdk::X3DExecutionContext ctx;\nctx.buildSceneGraph(doc.getScene());\nctx.buildFrom(doc.getScene());\n\nsdk::SceneExtractor ex(ctx, doc.getScene());\nsdk::RenderDelta f0 = ex.fullSnapshot();              // upload f0.added (meshes/materials/lights)\nconst auto t0 = std::chrono::steady_clock::now();     // monotonic clock start\nwhile (running) {\n  double now = std::chrono::duration\u003cdouble\u003e(std::chrono::steady_clock::now() - t0).count();  // seconds since start\n  ctx.tick(now);                                      // advance time, routes, scripts, behaviors\n  sdk::RenderDelta d = ex.delta();                    // apply d.added / removed / updated*\n}\n```\n\nThe SDK does **no** file IO, image decoding, or rasterization — those are\nembedder-supplied **seams**: *ports* in the ports-and-adapters sense, where the\nIO-free core owns the interface and you supply the backend (`AssetResolver`,\n`TextureResolver`, `FontMetrics`, `ScriptEngine`, …), each proven swappable by a\nsecond backend. See [`docs/sdk/`](docs/sdk/).\n\nFor a downstream-style CMake project that does not depend on the source tree,\nsee [`examples/embed_minimal/`](examples/embed_minimal/). It uses only:\n\n```cmake\nfind_package(x3d_cpp CONFIG REQUIRED)\ntarget_link_libraries(my_app PRIVATE x3d_cpp::sdk)\n```\n\n### 3. Render it headless (the gallery above)\n\nThe [`examples/cpu_raster/`](examples/cpu_raster/) reference consumer turns the\nextraction output into a PNG on the CPU — no GPU, no display — which is exactly\nhow the gallery shots are made:\n\n```bash\nmise run cpuraster   # build + test the rasterizer (build-cpuraster/)\nbuild-cpuraster/examples/cpu_raster/x3d_cpu_raster scene.x3d -o scene.png\n```\n\n## Generating the C++ bindings\n\nThe node layer is regenerated from the X3D UOM (build-time codegen, not needed\nto *use* the SDK):\n\n```bash\nuv run x3d-cpp-gen --out ./generated_cpp_bindings\n```\n\nRuns from any working directory; the spec XML and Jinja templates ship with the\npackage and are resolved relative to the install, not the CWD.\n\n### Options\n\n- `-s, --spec` — path to the X3D UOM XML (default: packaged 4.0 model)\n- `-o, --out` — output directory (default: `./generated_cpp_bindings`)\n- `--templates` — Jinja templates directory (default: packaged)\n- `--clang-format` — formatter executable (env `CLANG_FORMAT`; empty to disable)\n- `--compiler` — C++ compiler for the smoke test (env `CXX`; empty to skip)\n- `--no-test` — skip generating/compiling the smoke test\n\nThe generated smoke test (`generated_cpp_bindings/test.cpp`) is value-asserting:\nfor every concrete node it default-constructs an instance and asserts each\nreadable field with a spec default returns exactly that default (comparing the\nfield getter against the node's static `getDefault\u003cName\u003e()`), plus explicit\nliteral pins for a few well-known nodes (e.g. `Box` size=={2,2,2}, solid==true).\n`uv run x3d-cpp-gen` compiles and runs it.\n\n## Dev tasks (mise)\n\nThe repo ships a `mise.toml` task runner:\n\n```bash\nmise run gen           # regenerate the committed C++ bindings into generated_cpp_bindings/\nmise run test          # pytest (unit suite + full-tree golden-drift test)\nmise run golden        # golden-drift gate (regenerate to a temp dir, diff every *.hpp)\nmise run build         # cmake configure + build + ctest\nmise run corpus-fetch  # fetch the X3D test corpus the differential gates need (see \"Test corpus\")\nmise run ci            # full local pipeline: test + golden + conformance-gate + build +\n                       #   cli-gate-regression (the last needs a corpus — run corpus-fetch first)\n```\n\n(`scripts/check_golden.sh` is the same golden gate, runnable directly.)\n\n## Golden-file policy\n\n`generated_cpp_bindings/*.hpp` are **golden**: they are committed and treated as\nthe source of truth for codegen output. The only generation artifacts that are\nNOT golden are `test.cpp` / `test_exec` (gitignored).\n\nCodegen changes are therefore **intentional and explicit**:\n\n1. Change a template (`src/x3d_cpp_gen/templates/`) or emitter.\n2. Regenerate: `uv run x3d-cpp-gen --out generated_cpp_bindings` (or `mise run gen`).\n3. Review and **commit** the new headers.\n\nThe golden-drift gate (`scripts/check_golden.sh`, `tests/test_golden_tree.py`,\nand the `golden` CI job) regenerates into a temp dir and fails on ANY *.hpp\ndifference, so uncommitted codegen drift can never land silently.\n\n## CI\n\n`.github/workflows/ci.yml` runs on demand (`workflow_dispatch` — the full\nmatrix is heavy; re-enable the `push:` / `pull_request:` triggers to make it\nautomatic). Forgejo Actions reads the same file if the repo is mirrored there:\n\n- **python** — `uv sync` + `uv run pytest` (unit suite + full-tree golden test).\n- **golden** — the golden-drift gate (regenerate + diff).\n- **cpp** — `cmake` build + `ctest` across a compiler matrix that pins the\n  **baseline GCC 11 / Clang 14** and also runs the current distro compilers.\n\n## Configuration (optional external resources)\n\nThe SDK and its generator build and test with **no external data** — the\ngenerated bindings and the X3D Unified Object Model are bundled, so **nothing\nhere is required to build, test, or use the SDK** (`mise run test` / `golden` /\n`build` need none of it). A few *optional* developer tools and conformance gates\nplug in via environment variables. The RAG and JDK seams skip cleanly when\nunset; the **corpus differential gates** instead *fail-closed* when asked to run\nwithout a corpus (a gate with no inputs must never green) — fetch one in seconds\nwith `mise run corpus-fetch` (see [Test corpus](#test-corpus)):\n\n| Variable | Used by | What plugs in |\n|----------|---------|---------------|\n| `X3D_CORPUS_DIR` | corpus sweep, CLI/canon gates (`mise run corpus` / `cli-gate` / `canon-gate`) | Root of a local [X3D example archive](https://www.web3d.org/x3d/content/examples/) checkout. Defaults to `.x3d-corpus/` populated by `mise run corpus-fetch` — see [Test corpus](#test-corpus). |\n| `X3D_SPEC_PROSE_DIR` | `scripts/spec_rag.py` | Directory of X3D normative-prose markdown (one `*.md` per section, mirrored from web3d.org). |\n| `X3D_EMBED_URL` | `scripts/spec_rag.py`, `scripts/code_rag.py` | OpenAI-compatible embeddings endpoint (`POST {\"model\",\"input\"}` → `{\"data\":[{\"embedding\":[…]}]}`). Default `http://localhost:8080/v1/embeddings`. |\n| `X3D_QDRANT_URL` | the RAG scripts | Base URL of a [Qdrant](https://qdrant.tech/) vector store. Default `http://localhost:6333`. |\n| `X3D_JDK_BIN` / `JAVA_HOME` | `tools/x3d-cli/gen_canon_goldens.sh` | A JDK ≥ 25 (X3DJSAIL `-canonical` needs it). Auto-discovered via `JAVA_HOME` / `mise` / `PATH` if unset. |\n\n## Test corpus\n\nThe differential gates (`mise run cli-gate` / `canon-gate` / `cli-gate-regression`)\nand the full sweep (`mise run corpus`) validate the SDK against the **Web3D X3D\nExample Archive**. None of this is needed to build, test, or use the SDK — only\nto run those gates.\n\nGet it with one command:\n\n```bash\nmise run corpus-fetch          # ~9 MB, a few seconds\nmise run cli-gate-regression   # now PASS (was fail-closed with no corpus)\n```\n\n`corpus-fetch` (`scripts/fetch_corpus.sh`) downloads exactly what the gates need\n— the committed curated subset (`tools/x3d-cli/goldens/subset.txt`) **plus its\ntransitive `Inline`/`EXTERNPROTO` scene dependencies** — into the layout the\ngates expect:\n\n```\n.x3d-corpus/x3d-code/www.web3d.org/x3d/content/examples/...\n```\n\nIt lands in `.x3d-corpus/` (gitignored) by default, which the gate tasks pick up\nautomatically; set `X3D_CORPUS_DIR` to use a different location (e.g. a full\narchive checkout). Notes:\n\n- **Subset vs. dependencies.** `subset.txt` lists the files to *test*; validating\n  them needs the scenes they pull in via `Inline`/`EXTERNPROTO`, so the fetcher\n  resolves that closure. A bare subset would produce false \"regressions\".\n- **A few subset entries may be unavailable** upstream (pruned since the subset\n  was committed); the gates tolerate this and the fetcher reports which.\n- **Authoritative source.** Master is the Web3D `x3d` SourceForge **SVN** repo\n  (`svn.code.sf.net/p/x3d/code`); `corpus-fetch` pulls the same files over HTTP\n  from `www.web3d.org`. For a full, version-pinned archive, `svn checkout` that\n  repo into `$X3D_CORPUS_DIR/x3d-code/`.\n- **License.** The example scenes are open-source under the BSD-style *Web3D\n  Consortium Open-Source License for Models and Software* (each carries\n  `\u003cmeta name='license' content='../license.html'/\u003e`). The fetcher downloads\n  from the source and never redistributes them, so they are not bundled here.\n\n## License\n\n[MIT](LICENSE) © 2026 Ben Sandbrook. Bundled and optional third-party\ncomponents (including the Web3D Consortium X3D Unified Object Model, under a\nBSD-style license) are credited in [NOTICE](NOTICE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelta9000%2Fx3d-cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdelta9000%2Fx3d-cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdelta9000%2Fx3d-cpp/lists"}