Skip to content

Add Inspector debug panel to extras with an examples toolbar toggle - #9371

Open
mvaligursky wants to merge 33 commits into
mainfrom
mv-inspector
Open

mvaligursky wants to merge 33 commits into
mainfrom
mv-inspector

Conversation

@mvaligursky

Copy link
Copy Markdown
Contributor

Adds Inspector, an in-page debug panel for a running app: the entity hierarchy with live component properties, the frame graph of the last frame, the render targets on the device, and the physics world drawn through Bullet's debug drawer. It docks over the canvas, can pause and single-step the app, and pops out into its own window.

Changes:

  • Inspector class in extras, hooked to the app's update and destroy events, with four tabs:
    • Hierarchy: entity tree with component badges and enable checkboxes; the selection is outlined in the viewport. The property view reflects on the public getters of components and scripts, so components it has never seen show all their state. Deprecated getters are skipped.
    • Frame graph: the passes of the last frame in execution order, as the render pass trace prints them, with layer steps of forward passes, wrapper passes indented, and optional per-pass GPU timings (WebGPU; WebGL reports the frame only).
    • Render targets: every target on the device including the backbuffer, with attachments and formats, cross-linked with the passes that used it.
    • Physics: rigid bodies and joints listed with type, shape, mass and state; the Ammo world drawn with wireframe, AABB, contacts, constraints, limits, normals, frames and keep-awake options, range culling and depth test. Lines are read straight from the Ammo heap into typed arrays and drawn in one call. Drawing is suspended while the panel is hidden.
  • Pause sets the app time scale to zero and suspends the sound manager; Step advances exactly one frame. Hotkeys default to backquote, F9 and F10, shown on the buttons.
  • scripts/esm/inspector/entity-inspector.mjs: a thin Script hosting the panel, so it can be added to an Editor project like any other script.
  • Examples browser: a toolbar button shows the inspector on any example, docked left under the toolbar and hiding the description overlay while shown. Examples that create their own instance can export it or set the new NO_INSPECTOR flag. Thumbnail capture suppresses the panel.
  • jsdom tests covering the panel lifecycle, visibility and hotkey, hierarchy locking and enable checkboxes, pause and step, physics draw options and visibility gating, frame graph capture and value formatting.

API Changes:

  • New Inspector in extras: new Inspector(app, options) with visible, dock, width, top, paused, selected, physicsDraw, physicsDrawOptions, lockedNode, highlight, highlightColor, the hotkey properties, select(), step(), refresh(), popOut(), dockBack(), destroy(), and a visible event.
  • New InspectorOptions and InspectorPhysicsDrawOptions typedefs. The Ammo debug drawer itself stays internal.

Examples:

  • New debug/entity-inspector: an animated character, primitives, a camera frame with bloom, and a steady rain of physics crates that are destroyed after a few seconds, with the inspector open by default.

Performance:

  • Adds about 60 KB minified (18 KB gzipped) to the UMD bundle. ES module builds tree-shake it away when unused.

@github-actions

github-actions Bot commented Sep 12, 2026 •

Copy link
Copy Markdown

Public API report

This PR changes the public API surface (+50 / −0), per the docs' rules (@ignore / @Private / undocumented are excluded).

Show API diff
+CameraFly._capture: CanvasCapture
+CameraFly._controller: FlyController
+CameraFly._fov: number
+CameraFly._frame: InputFrame<{ move: number[]; rotate: number[] }>
+CameraFly._keys: Set<string>
+CameraFly._onKeyDown(e: KeyboardEvent): void
+CameraFly._onKeyUp(e: KeyboardEvent): void
+CameraFly._onPointer(e: Event): void
+CameraFly._ortho: boolean
+CameraFly._orthoHeight: number
+CameraFly._pose: Pose
+CameraFly._saved: { fov: number; orthoHeight: number; position: Vec3; rotation: Quat } | null
+CameraFly.app: AppBase
+CameraFly.camera: CameraComponent
+CameraFly.constructor(app: AppBase, camera: CameraComponent, onEnd: () => void)
+CameraFly.get zooms(): boolean
+CameraFly.speed: number
+CanvasCapture._listener: (e: Event) => void
+CanvasCapture.canvas: HTMLCanvasElement
+CanvasCapture.constructor(canvas: HTMLCanvasElement, onEvent: (e: Event) => void)
+Inspector.constructor(app: AppBase, options?: InspectorOptions)
+Inspector.destroy(): void
+Inspector.onVisibleChange: (visible: boolean) => void | null
+Inspector.set paused(value: boolean)
+Inspector.set visible(value: boolean)
+Inspector.step(): void
+InspectorOptions.dock?: "right" | "left"
+InspectorOptions.lockedNode?: GraphNode | null
+InspectorOptions.onVisibleChange?: (visible: boolean) => void
+InspectorOptions.pauseKey?: string
+InspectorOptions.stepKey?: string
+InspectorOptions.storageKey?: string | null
+InspectorOptions.toggleKey?: string
+InspectorOptions.top?: number
+InspectorOptions.visible?: boolean
+InspectorOptions.width?: number
+ViewportPicker._picker: Picker | null
+ViewportPicker._queue: Promise<any>
+ViewportPicker.app: AppBase
+ViewportPicker.constructor(app: AppBase)
+ViewportPicker.pick(clientX: number, clientY: number): Promise<{ camera: CameraComponent; entity: Entity; instance: MeshInstance } | null>
+WireframeMode._styles: Map<MeshInstance, number>
+WireframeMode.apply(app: AppBase): void
+WireframeMode.restore(): void
+class CameraFly
+class CanvasCapture
+class Inspector
+class ViewportPicker
+class WireframeMode
+interface InspectorOptions

Informational only — this never fails the build.

@github-actions

github-actions Bot commented Sep 12, 2026 •

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2639.5 KB (+152.4 KB, +6.13%) 688.5 KB (+46.8 KB, +7.30%) 536.2 KB (+38.0 KB, +7.64%)
playcanvas.min.mjs 2636.6 KB (+152.2 KB, +6.13%) 687.1 KB (+47.1 KB, +7.35%) 535.8 KB (+38.2 KB, +7.67%)

Martin Valigursky added 2 commits September 15, 2026 15:26
# Conflicts:
#	src/extras/renderers/texture-renderer.js
…pector

- Render and model components expand into collapsed sections per mesh
  instance and per distinct material, with every reflected property.
- New Textures tab lists the device's textures largest first, tagged when
  they are render target attachments, with a live corner preview and
  channel selection; texture values in any property panel link to it.
- Texture sampler state shows as constant names in a Sampling section.
- Sections can start collapsed; a depth-format helper is shared.
Materials are found through the mesh instances of the components and layers,
the debug line batches and the loaded material assets. Each shows its textures,
compiled variants and properties, and the mesh instances the material lists as
using it, each opening in place.

Material values elsewhere link to the tab, including the material of each mesh
instance, and the Textures and Shaders tabs list the materials using a texture
or shader. The Meshes, Materials and Memory tabs share one walk over the mesh
instances, so the Memory tab now also attributes the buffers of meshes on
disabled entities, and lists a material's uniform buffer once.
Hovering any texture link, in the property view or a list, draws the texture in
the corner of the viewport the way the Textures tab previews its selection,
until the pointer leaves the link.
The frame graph lists passes flat, in the order they execute, with the numbers
aligned. A pass owning others, through its before and after passes or as a
multi-view wrapper, brackets them in a gutter on the left, one lane per level,
with a tick on its own row. A merged pass keeps its number.
…ered

Hovering a pass in the frame graph, or any render target link, previews the
target's first attachment in the corner of the viewport. A link inside a hovered
row previews its own target while the pointer is over it.
Lists the script classes the script registry holds and those created on
entities straight from their class, with the entities using each, its declared
attributes and lifecycle methods, and its source as the browser keeps it. The
script component of an entity links each of its scripts to the tab.
…t subtrees

A drop down next to the filter picks whether the text matches entity names,
component types or script names, suggesting the component types or script names
in the scene. Each row with children shows both its child count and the number
of nodes in its whole subtree.
…ssets list

The render, material, texture, animation, gsplat and model assets a container
creates are listed right under it, indented and bracketed, and marked embedded.
Each links to its container and a container lists its contents by kind, read
from the container's resource. The Textures tab follows a texture's asset on to
its container.
An animation track, material or texture handed to its users without the asset
is still found: the anim layers playing a track, the mesh instances drawing with
a material and the materials sampling a texture are listed on the asset. A
container lists which of its contents are in use.
Pick outlines the entity under the pointer and selects it on click, through the
screen camera whose viewport holds the pointer. Fly moves a camera with the
mouse and WASD, swapping in the flown pose and projection just for rendering so
the app keeps moving its own camera, and zooms an orthographic view. Both take
the pointer ahead of the app while on.

The Cameras tab lists every camera in render order, draws the frustum of the
selected one, and switches the render mode of one camera or all of them to the
debug views of the material inputs, or the whole scene to wireframe, with a
reset putting back what each had. The panel toolbar and bars wrap on a narrow
panel.

This branch was successfully deployed

2 active deployments
Preview – engine — 6cc718c9 Deployed Sep 30, 2026 by vercel[bot]
Preview – engine-api-docs — 6cc718c9 Deployed Sep 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant