Skip to content

Project API

TeoLim edited this page Sep 7, 2026 · 10 revisions

Project API

NWBLot projects plug into the loader through a small callback surface. The Testbed is the current project using that API, and it is the best reference for how projects should create a world, register systems, and request shutdown.

Required Project Functions

The project-facing API consists of:

  • QueryProjectFrameClientSize
  • QueryProjectWindowTitle
  • ConfigureProjectRuntime
  • CreateProjectEntryCallbacks
  • CreateInitialProjectWorld
  • DestroyInitialProjectWorld

QueryProjectFrameClientSize returns a client-area size. Testbed returns 1280x900.

QueryProjectWindowTitle returns the platform window title. Testbed returns NWB Testbed.

ConfigureProjectRuntime(ProjectStartupContext&) runs after the loader creates its Core::Frame but before graphics/device initialization. The context provides graphics, the project object arena, and filesystemFactory. Use it for pre-device policies such as the required bindless heap ABI, an HDR10 request, or a project-owned IFilesystem factory; return false to stop startup. Testbed sets the bindless heap ABI and requests HDR10 through this callback, and leaves filesystemFactory empty so every mount uses VolumeFileSystem. See HDR10 Presentation and Filesystem.

CreateProjectEntryCallbacks returns an IProjectEntryCallbacks implementation. Testbed returns ProjectTestbed.

CreateInitialProjectWorld creates and wires the ECS world.

DestroyInitialProjectWorld unregisters render passes and frame graph contributors, waits for graphics work, clears the world, and releases it.

Callback Object

IProjectEntryCallbacks has three overridable callbacks:

  • onStartup
  • onShutdown
  • onUpdate(f32 delta)

The default implementation returns success and does nothing. Real projects normally use:

  • onStartup to create scene entities and register input handlers.
  • onUpdate to update project-side state and return whether runtime should continue.
  • onShutdown to release project-only resources.

Testbed creates the initial world in the ProjectTestbed constructor, verifies the required systems are present, creates scene entities during onStartup, and destroys the world during shutdown/destruction.

Project Runtime Context

ProjectRuntimeContext provides engine services that project code is allowed to use:

  • graphics backend facade
  • input dispatcher
  • project object arena
  • thread pool
  • job system
  • typed asset manager
  • mounted IFilesystem
  • frame graph registry
  • read-only perf session
  • shader path resolver
  • telemetry capture setter
  • telemetry upload flush callback
  • perf capture setter
  • request quit callback

Convenience methods:

  • setTelemetryCapture(options)
  • flushTelemetryUpload(clearAfterUpload)
  • setPerfCapture(options)
  • gpuTimingView()

The context is assembled by the loader after graphics initialization, cooked volume mounting, asset codec registration, asset manager creation, and shader archive loading. Project code can therefore assume those services exist when callbacks are created.

Testbed World Wiring

Testbed creates a Core::ECS::World using the context object arena and thread pool. It then adds these systems:

  • MeshSystem
  • RendererSystem
  • ModelSystem
  • MeshSkinningSystem
  • UiSystem

The renderer is constructed with:

  • the world
  • Core::Graphics
  • AssetManager
  • shader path resolver

The model system is constructed with model renderer hooks, so model expansion can create renderer-facing components.

The mesh skinning system is constructed with graphics, asset manager, the mesh system, and shader path resolver. It registers as a render pass before the main renderer, so skinned runtime mesh data is ready for renderer consumption.

The UI system is constructed with world, graphics, input, asset manager, and shader path resolver.

Render Pass Registration

Testbed registers render passes in this order:

  1. MeshSkinningSystem
  2. RendererSystem
  3. UiSystem

That order is important:

  • skinning updates runtime mesh buffers before scene rendering
  • renderer draws the scene into deferred/transparency/composite targets
  • UI renders after scene composition

Testbed also registers RendererSystem as a frame graph contributor so telemetry capture can include renderer frame-graph information.

World Destruction

DestroyInitialProjectWorld validates that expected systems still exist, then:

  1. unregisters renderer frame graph contribution
  2. removes skinning, renderer, and UI render passes
  3. waits for graphics jobs
  4. waits for the graphics device to idle when available
  5. clears the ECS world
  6. releases the world pointer

This avoids destroying ECS-owned renderer state while backend command work may still reference it.

Shutdown Rule

Project code should request shutdown through:

ProjectRuntimeContext::requestQuit

Do not call platform-specific quit APIs from project code or smoke-test projects. The frame owns the platform loop and can exit without submitting another graphics frame when quit is requested during project update.

Testbed Scene Creation

During onStartup, Testbed creates:

  • an active camera entity
  • a camera entity positioned in front of the character
  • a 45-degree directional light
  • a point light
  • a skinned character model entity
  • a static ground plane model entity
  • a UI entity with an ImGui draw callback

The character and ground plane are model-driven. Their ECS entities contain ModelComponent and RendererComponent with typed asset references; model expansion and renderer systems do the rest.

Clone this wiki locally