Nova64 now treats runtime/ as the stable public/runtime layer and moves renderer-specific implementation into backend folders.
runtime/
api-3d.js
gpu-threejs.js
gpu-babylon.js
api-3d/
backends/
threejs/
babylon/
shared/
runtime/
Public entrypoints, stable cart-facing wrappers, and compatibility re-exports.runtime/backends/threejs/
Three.js-specific implementation modules used by runtime/api-3d.js and the public runtime/gpu-threejs.js wrapper.runtime/backends/babylon/
Babylon-specific implementation modules composed by the public runtime/gpu-babylon.js wrapper.runtime/shared/
Cross-backend contracts and helpers that should not belong to only one renderer.createCube, setCameraPosition, createPointLight, and similar functions must not change names.nova64.* namespaces stable.runtime/api-3d/* import paths working through re-export wrappers while backend internals live in runtime/backends/threejs/*.runtime/gpu-threejs.js as the public Three.js entrypoint, even though the implementation now lives in runtime/backends/threejs/gpu-threejs.js.runtime/gpu-babylon.js as the public Babylon entrypoint, even though the implementation now lives in runtime/backends/babylon/gpu-babylon.js.runtime/shared/backend-surface.js defines the shared backend surface used to keep Three.js and Babylon aligned.
It currently separates:
This contract is used to:
Each backend exposes explicit capability flags:
runtime/backends/threejs/capabilities.jsruntime/backends/babylon/capabilities.jsUse capability checks for behavior that is intentionally unsupported instead of silent no-ops. Current examples include Babylon particles, post-processing, and dithering behavior.
Nova64 now has a shared cart-reset pipeline so cart loads do not depend on scattered one-off cleanup calls.
Primary pieces:
runtime/cart-reset.js
Internal registry for named cart reset hooks.runtime/console.js
Calls the shared reset pipeline at the start of Nova64.loadCart(...).src/main.js
Registers the default runtime reset hooks used by the browser console bootstrap.The default browser/runtime reset sequence now covers:
novaStoreWhy this exists:
Rule for future runtime work:
tests/playwright/api-compatibility.spec.js
Required backend surface, camera access, point-light mutation, instancing, and unsupported-capability behavior.tests/playwright/wad-vox-regression.spec.js
Focused WAD, VOX, and Wizardry Babylon smoke coverage.tests/playwright/backend-parity.spec.js
Broader cross-backend cart parity coverage.tests/playwright/visual-regression.spec.js
Visual guardrails for skybox and PBR scenes where Babylon should stay close to Three.js without claiming pixel-perfect parity.runtime/gpu-threejs.js
Thin public wrapper over runtime/backends/threejs/gpu-threejs.js.runtime/gpu-babylon.js
Thin public wrapper over runtime/backends/babylon/gpu-babylon.js.The Babylon backend implementation is grouped into focused modules. The main implementation areas are:
bootstrap.jscompat.jsscene.jscamera.jslights.jsprimitives.jstransforms.jsmodels.jsinstancing.jssurface.jsCurrent Babylon design rules:
engine must mean the Nova64 engine adapter, not the raw Babylon renderer.getRenderer() returns the raw Babylon engine when direct renderer access is needed.runtime/xr.js; do not use Three.js renderer.xr objects in Babylon mode.runtime/backends/babylon/compat.js is the normalization layer for Babylon objects that need to satisfy long-standing Three-style cart expectations.
It currently provides parity shims for:
scene.traverse, scene.childrenisObject3D, isMesh, isLight, typemesh.visiblematerial.color, material.map, material.transparent, material.opacityneedAlphaBlendingForMesh, needAlphaTesting, needAlphaTestingForMesh, isReady, isReadyForSubMeshcolor.set(...), color.setHex(...), color.getHex(), color.getHexString()texture.repeat, texture.offset, texture.wrapS, texture.wrapT, texture.needsUpdateDesign rules for this layer:
Recent parity work focused on the places where carts were still clearly broken under Babylon:
@babylonjs/core is now pinned to the current latest 9.x line used by the backend parity work.enableAR() now creates a native Babylon WebXR AR entry point, while enableVR() creates a Babylon WebXR entry point when the browser supports it.VideoTexture objects into Babylon scenes; Babylon uses a DOM video layer and transparent scene clear color for AR-style passthrough.ar-hand-demo now initializes its 3D scene even when webcam or MediaPipe hand tracking cannot start, so Babylon/headless smoke coverage does not fail on camera availability.engine.setMeshMaterial(meshProxy, material).material.color.set(0x336699) and texture.repeat.set(...) now behave consistently on Babylon too.wizardry-3d no longer depends on the old store polyfill behavior; plain-object game store initializers now work with real Zustand too.hello-skybox rendering.pbr-showcase and wad-demo render reliably.runtime/backends/babylon/voxel.js for atlas textures, chunk meshes, and simple voxel entity boxes instead of trying to add raw Three.js meshes into a Babylon scene.runtime/api-voxel.js now builds backend-neutral voxel mesh payloads and delegates chunk/entity creation to the active renderer, which fixes the Babylon gpu.scene.add is not a function crash path in carts like minecraft-demo and voxel-creatures.Math.random(), so Babylon and Three load the same terrain unless a cart explicitly requests a custom seed.minecraft-demo.runtime/backends/babylon/noa-prototype.js and runtime/backends/babylon/noa-adapter.js; use them to investigate noa-engine incrementally without letting a Babylon-only engine bypass Nova64's shared voxel API. See docs/BABYLON_NOA_PROTOTYPE.md and docs/BABYLON_NOA_INTEGRATION.md for the current guardrails.tsl-showcase Galaxy scene now uses deterministic star placement, which makes Babylon-vs-Three visual comparisons measure renderer parity instead of per-load randomness.createCube(...) now accepts rectangular width/height/depth/color signatures as well as the classic cube size/color signature in both backends, keeping scene prop dimensions stable in demos such as particles-demo.createSphere(...) now accepts material options as the fourth argument as well as the explicit segments/options form, matching cart usage in glow-heavy demos such as the galaxy particle scene.createCylinder(...) now accepts the cart-facing radius/height/color signatures and the older tapered radiusTop/radiusBottom/height signature in both backends, preventing Babylon from interpreting colors as giant cylinder heights.createPlane(...) forwards material options through both backends, including opacity and transparency, so shared translucent scene props do not become opaque rectangles on Three.js.finalizeInstances(...), and refresh bounds so the same instanced cart content remains visible under Babylon.particles-demo stay much closer to Three.js.directionX, directionY, and directionZ in both backends; the default remains upward, but carts such as the waterfall scene can emit downward water without relying on inverted gravity.engine.createDataTexture(pixels, w, h) as a material-proxy entry point routing through texture.createFromImage in the bridge; cart code that calls engine.createDataTexture and then passes the handle to engine.createMaterial({ map: tex }) works the same way as the Three.js and Babylon adapters.material.create bridge command now accepts uvOffset (Vector3) alongside uvScale, enabling setWallUVs to pass WAD texture X/Y offsets through to StandardMaterial3D::set_uv1_offset so DOOM wall textures align precisely instead of being clamped to origin.WADTextureManager._uploadDataTexture now delegates to engine.createDataTexture internally, removing duplicated bridge-transport code.getCamera() in nova64.camera returning { position: { x, y, z } }, so billboard sprite code like const cam = getCamera(); Math.atan2(cam.position.x - e.x, ...) works without throwing on the Godot host.createPlane already creates double-sided planes by default (matches the Babylon plane double-sided fix), so WAD floor/ceiling and sprite billboards render correctly from all viewing angles.setLightVisible(id, visible) backend API, allowing carts to temporarily hide scene-local lights during alternate scene states such as Indie Odyssey combat without destroying and recreating them.GlowLayer, so emissive cart geometry such as Indie Odyssey's neon grid reads as glow instead of flat colour.emissiveIntensity for PBR and Standard materials; carts can tune backend parity without replacing materials or branching into raw Babylon APIs.Current visual status:
hello-skybox is back in close visual range with Three.js and covered by Playwright visual regression.pbr-showcase is much closer than the earlier broken Babylon output, but it still does not match Three.js perfectly because Babylon does not yet have full PMREM and post-processing parity in Nova64.tsl-showcase scene 1, Galaxy Spiral, has a focused visual regression check and currently stays below the intentionally loose shader/parity threshold after the deterministic star-field and Babylon bloom tuning work.wad-demo now has focused Babylon visual guardrails and is back down in the low-single-digit diff range in the gameplay-frame regression check on a clean server.minecraft-demo now has deterministic terrain and a focused voxel visual regression guardrail, with the Babylon gameplay-frame diff back down into the low-to-mid teens instead of the earlier broken ~35%+ range caused by seed drift and chunk-face culling.pbr-showcase is intentionally looser than simple skybox scenes so it can still catch major regressions without pretending the two backends are identical today.particles-demo now has a focused visual regression pass again after the cylinder signature fix and Babylon particle bloom/material tuning; the demo is still not pixel-identical, but the fire scene should no longer show the old center-pillar artifact.particles-demo also has a waterfall-specific visual regression check, and instancing-demo now uses deterministic scene layouts plus its own visual parity guardrail.These are the most useful narrow checks for the current Babylon parity surface:
pnpm test:babylon:apipnpm exec playwright test tests/playwright/api-compatibility.spec.js --reporter=linepnpm exec playwright test tests/playwright/wad-vox-regression.spec.js --grep "wad-demo" --reporter=linepnpm exec playwright test tests/playwright/wad-vox-regression.spec.js --grep "Voxel Regression" --reporter=linepnpm exec playwright test tests/playwright/backend-parity.spec.js --grep 'Minecraft Demo|Voxel Terrain|Voxel Creative|Voxel Creatures' --reporter=linepnpm exec playwright test tests/playwright/visual-regression.spec.js --grep "minecraft-demo should stay reasonably similar" --reporter=linepnpm exec playwright test tests/playwright/visual-regression.spec.js --grep "wad-demo gameplay frame" --reporter=linepnpm exec playwright test tests/playwright/visual-regression.spec.js --grep "tsl-showcase galaxy" --reporter=linepnpm exec playwright test tests/playwright/visual-regression.spec.js --grep "particles-demo" --reporter=linepnpm exec playwright test tests/playwright/xr-ar-babylon.spec.js --reporter=lineUse the WAD-specific visual and regression slices first when touching Babylon WAD rendering, UVs, materials, lights, or compatibility shims. Use the voxel-focused regression and backend-parity slices first when touching runtime/api-voxel.js or runtime/backends/babylon/voxel.js.
Use the XR/AR slice first when touching runtime/xr.js, runtime/mediapipe.js, or demos that call WebXR/MediaPipe APIs.
Use the TSL Galaxy slice first when touching Babylon post-processing, procedural shader materials, particle glow, or the tsl-showcase cart.
Remaining Babylon parity work is tracked in ../BACKLOG.md.
Keep this document focused on backend architecture, runtime contracts, and
validation guidance rather than a second backlog.
When adding a new cart-facing 3D API:
runtime/shared/backend-surface.js if it is required or capability-gated.When behavior is backend-specific: