currentMode( ) → string
The engine's mode, as the visibility is keyed: `edit` or `play`.
providerAvailable(p: any) → boolean
Whether a provider currently has anything to show. A provider with no
`available` predicate is always offered; one that declares it is offered
only while the thing it draws exists in the scene, so the panel lists the
overlays this scene can actually use rather than every overlay the engine
knows how to draw.
registerProvider(name: string, fn: (Emit) → void
Register (or replace) a provider under `name`. `fn(emit)` runs once per
edit-mode tick and appends its geometry via `emit`, unless `name`'s
category is disabled (`setCategory`). Registering an existing name
replaces its function; providers otherwise persist for the module's
lifetime, so re-enabling the driving component doesn't need to
re-register. A provider's category defaults on the first registration
and is otherwise untouched by re-registration, so a category toggled
by the panel survives a component disable/enable cycle.
| arg | type | description |
|---|
| name | string | |
| fn | (Emit | |
unregisterProvider(name: string) → boolean
Remove a provider and its category. A package that stops being able to
draw (its system left the scene) withdraws its overlay so the panel stops
offering a toggle for something with nothing behind it. The category's
on/off state is dropped with it, so re-registering starts from its
declared default.
| arg | type | description |
|---|
| name | string | |
providers( ) → void
Every provider that currently has something to draw, in registration
order: `{ name, label, enabled }`. The toggle panel builds from this, so
a provider appears the moment its subject exists in the scene and
disappears with it.
setCategory(name: string, on: boolean) → void
Enable or disable a provider's category. A disabled category's provider
is skipped by `update()` without unregistering it — re-enabling resumes
drawing on the next tick.
| arg | type | description |
|---|
| name | string | |
| on | boolean | |
isCategory(name: string) → boolean
Whether `name`'s category currently draws. Categories default per
`CATEGORY_DEFAULTS` the first time their provider registers; an
unregistered name reports its would-be default.
| arg | type | description |
|---|
| name | string | |
categories( ) → void
Every registered provider's category name, in registration order —
the stable order the toggle panel lists categories in.
knownCategories( ) → void
Every category this module carries a state for: the registered providers in
registration order, then any category whose state was set before its
provider registered, sorted so the order is stable.
A provider registers when the thing it draws enters the scene, so the
registered set grows through a session — a package's overlay appears only
once that package has loaded. `setCategory` accepts a name at any time and
`registerProvider` keeps the state it finds, so a preference set ahead of
registration is honoured when the provider arrives. Reading only the
registered set therefore misses categories that are live and settable, which
is what a caller means by "every category".
isRegistered(name: string) → boolean
Whether `name` has a provider registered right now — the difference between
a category that draws and one whose state is recorded for a provider that
has not arrived.
| arg | type | description |
|---|
| name | string | |
registerIcon(key: string, opts: { glyph: (string | number) → void
Register (or replace) an icon visual under `key`. `emit.icon(center, key)`
then draws it. This is how both built-in systems and user code make an entity
show a gizmo icon: register a visual once, then emit it wherever it belongs.
`opts`:
* `glyph` — a built-in procedural glyph name (`"camera"`, `"light"`,
`"audio"`, `"probe"`, `"player"`) or its numeric id. Mutually exclusive
with `texture`.
* `texture` — a `.texture` asset identity/ref/`AssetRef`; the icon samples
its alpha, so any authored image becomes an icon.
* `size` — on-screen scale as a fraction of the camera distance (default
`0.06`), so the icon holds a roughly constant size regardless of range.
Re-registering a key updates its visual (the material is rebuilt on the next
draw). The per-entity tint comes from `emit.icon`'s `color`, not from here, so
one icon can be tinted per entity.
| arg | type | description |
|---|
| key | string | |
| opts | { glyph: (string | number | |
iconKeys( ) → void
Every registered icon key, in registration order. For introspection.
anchorId( ) → string
The anchor entity's id, or nil before the first tick. Providers that need to
exclude the anchor from their own scene queries (it carries a Mesh) read
this rather than tracking their own copy.
adoptAnchor( ) → string
Adopt the anchor that is already in the scene, if there is one, and leave
exactly one behind.
`anchorId` is module state and the anchor is an ECS entity, so the two part
company whenever this module is re-instantiated — a hot reload during an
editor session, most often. The scene is the authority on how many anchors
exist, so it is what gets asked: the first one found becomes this instance's
anchor, and any others are despawned, which also drains anchors a previous
instance left behind.
ensureAnchor( ) → string
The internal identity-transform entity the Draw pass resolves its instance
slot + material override through. Temporary so it never lands in a
scene/world save, internal so it never clutters the entity list, EditorOnly
participation so world scans (bake selection, coverage reports) never see
editor viz as world geometry.
ensureIconMaterial(reg: IconReg) → void
Create (once, or after re-registration) the triangle-list material an icon
draws through, from the debugBillboard shader with the icon's glyph/size (and
texture, when texture-backed). Alpha-blended overlay that ignores depth, so
icons read on top of the scene like the rest of the overlay.
| arg | type | description |
|---|
| reg | IconReg | |
forgetGpuState( ) → void
Give up everything this module holds on the GPU, because the device holding
it is gone.
Every buffer here was made from the render device, and a lost device
invalidates all of them; the handles cached above would otherwise name
resources that no longer exist, and the grow-only sizing would keep them
because the size still fits. The material and the render feature go with
them: both are rebuilt from their spec by the `ensure*` calls the next tick
makes, which is what puts the overlay back on the device the engine is now
on. Nothing is destroyed here — a lost device took the resources already, and
destroying a handle to one is a call into a device that is not there.
wordsFor(byteLen: number) → number
A buffer is a run of 32-bit words, so a byte count sizes one as that many
quarters. Every debug payload is whole words — 92-byte vertex records and
u32 indices — so this divides evenly.
| arg | type | description |
|---|
| byteLen | number | |
stillThere(buf: any) → boolean
Internal: whether a cached handle still points at storage.
A handle outlives the storage it points at: anything may release the buffer
by the name it was created under, and every holder's handle answers `alive`
false from that moment. The grow-only caches below drop such a handle, and
the next call sizes a fresh buffer.
bytesHeld(buf: any) → number
Internal: the bytes the buffer behind a live handle holds, as the substrate
states its length. Every buffer here is `f32`, one word per record. The
length is read off the buffer each time, so the size a grow-only cache
compares against is the size of the buffer it holds, whichever handle that
is.
ensureLineVtxCapacity(vtxBytesLen: number) → any
Grow-only sizing for the line vertex buffer, recreated only when the frame's
bytes no longer fit. Returns the buffer to write into, nil when the
allocation failed.
| arg | type | description |
|---|
| vtxBytesLen | number | |
ensureIndexCapacity(vertCount: number) → void
Grow-only sizing for the shared static sequential index buffer (0,1,2,…). It
backs every debug draw — the line soup and every icon quad list — so it is
sized to the largest single draw's vertex count, with 2× headroom so growth
(and the one-off sequential fill) is rare; a steady tick never touches it.
| arg | type | description |
|---|
| vertCount | number | |
uploadIconBuffer(key: string, bytes: string) → string
Upload one icon's triangle-soup bytes to its own grow-only vertex buffer.
Returns the name the draw binds it by, nil when the allocation failed.
| arg | type | description |
|---|
| key | string | |
| bytes | string | |
update(_dt: number) → void
Clear the batch, run every registered provider, and upload the combined
geometry. Called each active frame by the debug-viz driver.
| arg | type | description |
|---|
| _dt | number | |
box(min: ?, max: ?, color: ?) → void
| arg | type | description |
|---|
| min | ? | |
| max | ? | |
| color | ? | |
line(a: ?, b: ?, color: ?) → void
| arg | type | description |
|---|
| a | ? | |
| b | ? | |
| color | ? | |
orientedBox(center: ?, rotation: ?, halfExtents: ?, color: ?) → void
| arg | type | description |
|---|
| center | ? | |
| rotation | ? | |
| halfExtents | ? | |
| color | ? | |
wireSphere(center: ?, radius: ?, color: ?) → void
| arg | type | description |
|---|
| center | ? | |
| radius | ? | |
| color | ? | |
wireCapsule(center: ?, rotation: ?, radius: ?, halfHeight: ?, color: ?) → void
| arg | type | description |
|---|
| center | ? | |
| rotation | ? | |
| radius | ? | |
| halfHeight | ? | |
| color | ? | |
cross(center: ?, size: ?, color: ?) → void
| arg | type | description |
|---|
| center | ? | |
| size | ? | |
| color | ? | |
octahedron(center: ?, size: ?, color: ?) → void
| arg | type | description |
|---|
| center | ? | |
| size | ? | |
| color | ? | |
rawLineSoup(vtxBytes: ?, vertexCount: ?) → void
| arg | type | description |
|---|
| vtxBytes | ? | |
| vertexCount | ? | |
icon(center: ?, key: ?, color: ?) → void
| arg | type | description |
|---|
| center | ? | |
| key | ? | |
| color | ? | |
setVisible(on: boolean, mode: string?) → void
Show or hide the overlay in `mode` (the engine's current mode when
omitted). Hiding the mode the engine is in drops the current batch so the
overlay stops drawing at once.
| arg | type | description |
|---|
| on | boolean | |
| mode | string? | |
isVisible(mode: string?) → boolean
Whether the overlay draws in `mode` (the engine's current mode when
omitted). The driver rebuilds the overlay only while this holds.
| arg | type | description |
|---|
| mode | string? | |
setPlaySession(on: boolean) → void
Show or hide the overlay in play mode: a debug session over the running
game. `M.setVisible(on, "play")`.
| arg | type | description |
|---|
| on | boolean | |
isPlaySession( ) → boolean
Whether the overlay draws in play mode. `M.isVisible("play")`.
setScope(ids: { string }?) → void
Limit the overlay to a set of entities. Pass an array of ids (or nil/empty to
clear). Providers consult `inScope` per entity, so this focuses every enabled
category on the same objects. In-memory only, never persisted.
| arg | type | description |
|---|
| ids | { string }? | |
clearScope( ) → void
Clear the scope so every entity draws again.
inScope(id: string) → boolean
Whether `id` is in scope. True when no scope is set (draw everything), else
true only for ids in the scope set. Providers guard each entity with this.
| arg | type | description |
|---|
| id | string | |
isScoped( ) → boolean
Whether a scope is currently set. Providers that behave differently when
focused on specific objects (e.g. bounds drawing per-entity instead of one
box per top-level object) branch on this.
scopeIds( ) → void
The current scope as an array of ids (empty when unscoped) — for
introspection by the debug toolbox.
clear( ) → void
Drop the batched draw without tearing down GPU resources, so the render
feature enqueues nothing until the next `update`. Used when leaving edit
mode with no active play session — cheap enough to call every frame.
teardown( ) → void
Tear down the live feature, material, buffers, and anchor. Registered
providers stay registered — re-enabling rebuilds GPU state without
re-registering.