Skip to content

Opal Graph Explorer

Status: Core shipped in the workbench Graph dock (src/game/graph-explorer/, wired from src/app/phases/graph-explorer.js). Modes: Scene Hierarchy, Event Map, Prefab Anatomy, Asset Dependencies, Component Map, Runtime Trace (+ internal event-bus demo). Live refresh and d3-force layout are in place. Remaining polish: animated trace replay, prefab component inspector focus, richer contextual entry points.
Layer: editor — must not be imported by runtime (see Architecture).
Related: The assets panel graph view (src/game/assets/editor/asset-graph-view.js) and reference-scan.js are an earlier asset-dependency slice; prefer the shared Graph Explorer adapters over growing a second graph stack.
Note: Sections below retain design-plan detail used while building the feature. Prefer the status callout and the live dock UI when they disagree with older milestone prose.

Overview

The Graph Explorer is a developer-facing visualization system for inspecting Opal project structure, scene data, prefabs, component relationships, events, asset dependencies, and runtime execution traces through interactive node graphs.

The goal is not to replace the existing inspectors, hierarchy panels, or Object Flow editor. The Graph Explorer is an understanding layer: it helps developers see how systems relate, why something is happening, and what will break if a file, object, prefab, component, asset, or event changes.

This feature turns Opal’s internal data into navigable visual maps.

Goals

  1. Help developers understand complex projects quickly.
  2. Make prefabs, components, events, and assets inspectable as relationships, not just lists.
  3. Provide teaching tools for sample games such as Garden Defense.
  4. Support debugging by showing runtime traces and event flow.
  5. Reuse a shared graph view model across many data sources.
  6. Keep graph visualization separate from authored game/runtime data.
  7. Avoid making D3 the application architecture; use it only for layout, transforms, and interaction primitives where useful.

Non-Goals

  1. Do not replace Object Flow’s editable node graph.
  2. Do not make every graph editable in v1.
  3. Do not serialize graph explorer UI state into scene or prefab data, except optional editor preferences.
  4. Do not introduce runtime dependencies from game logic into editor-only graph visualization code.
  5. Do not require all graph modes to ship at once.

Design Principle

The Graph Explorer should answer five questions:

  1. What is this?
  2. What owns it?
  3. What does it depend on?
  4. What depends on it?
  5. What happens when it runs?

Every graph mode should be judged against those questions.


Core Concept

The Graph Explorer is built around one shared graph document shape:

js
{
  id: "graph-explorer-view",
  title: "Garden Slime Prefab",
  mode: "prefab-anatomy",

  nodes: [
    {
      id: "slime-prefab",
      type: "prefab",
      label: "Garden Slime",
      subtitle: "Prefab",
      group: "prefab",
      icon: "box",
      badges: [
        { label: "4 components", tone: "info" },
        { label: "2 events", tone: "event" }
      ],
      status: "ok",
      data: {}
    }
  ],

  edges: [
    {
      id: "edge-health-died-flow",
      from: "health",
      to: "object-flow",
      type: "emits",
      label: "health/died",
      direction: "forward",
      status: "ok",
      data: {}
    }
  ],

  groups: [
    {
      id: "components",
      label: "Components",
      type: "section"
    }
  ],

  meta: {
    sourceKind: "prefab",
    sourceId: "prefab_garden_slime"
  }
}

Each graph mode is an adapter that converts an existing Opal data source into this shared shape.


Graph Modes

1. File Tree / Architecture Graph

Purpose

Visualize source files, folders, architecture layers, and import relationships.

Primary Users

Engine contributors and maintainers.

Data Sources

  • Source tree
  • Architecture layer classifier (architecture-boundaries.test.js layer sets)
  • Relative imports
  • Test coverage metadata, if available later
  • Git/churn metadata, optional later

Layouts

  • Collapsible tree for folder structure
  • Layered dependency graph for imports
  • Force graph for highly connected modules
  • Treemap or packed circles for file size/churn later

Nodes

  • Folder
  • File
  • Architecture layer
  • Test file
  • Barrel/export file

Edges

  • Contains
  • Imports
  • Re-exports
  • Violates boundary
  • Tested by

Useful Badges

  • Layer: core, runtime, behavior, project, editor, app
  • Import count
  • Imported-by count
  • Test coverage
  • Boundary violation
  • Barrel file

Example

text
src/game/flow/catalog.js
  Layer: behavior
  Imports: runtime, core, behavior
  Imported by: interaction, rules, tests
  Risk: high centrality

V1 Scope

  • Folder tree
  • Layer coloring
  • Import edges
  • Boundary violation highlighting
  • Click file to show details

2. Scene Hierarchy Graph

Purpose

Show scene objects spatially as a hierarchy and expose object status at a glance.

Primary Users

Game creators and demo learners.

Data Sources

  • scene-graph.js
  • customObjects
  • hierarchyLayerKind
  • hierarchyLayerBadges
  • Selected object/component metadata

Layouts

  • Top-down tree
  • Radial tree
  • Compact hierarchy graph

Nodes

  • Scene root
  • Game object
  • Sprite
  • Camera
  • Trigger
  • UI root
  • Prefab instance

Edges

  • Parent/child
  • Optional object reference
  • Optional event link
  • Optional constraint/link relationship

Useful Badges

  • Children
  • Components
  • Tap action
  • Hidden
  • Locked
  • Prefab instance
  • Has Object Flow
  • Has diagnostics

V1 Scope

  • Read-only hierarchy graph
  • Click object to select it in scene
  • Highlight current selection
  • Show object details side panel
  • Filter by object type/status

3. Prefab Anatomy Graph

Purpose

Show what a prefab contains: objects, components, flows, events, asset references, and overrides.

Primary Users

Developers studying demo prefabs and creators building reusable gameplay objects.

Data Sources

  • Prefab record
  • Prefab instance data
  • ComponentHost serialized components
  • Object Flow graphs
  • Asset references (reference-scan.js, prefab/scene serializers)
  • Override detector

Layout

A structured left-to-right graph:

text
Prefab Root
  → Objects
  → Components
  → Flow Graphs
  → Events Out
  → Asset References

Nodes

  • Prefab root
  • Object
  • Component
  • Component field
  • Object Flow graph
  • Event
  • Asset reference
  • Override
  • Child prefab instance

Edges

  • Contains
  • Owns component
  • Uses asset
  • Emits event
  • Listens to event
  • Overrides field
  • Spawns prefab

Example: Garden Slime

text
Garden Slime Prefab
  Components:
    SpriteRenderer
    Health: hp=3
    Tappable
    Object Flow

  Flow:
    On Tap → Health.damage(1)
    Health.died → Spawn Coin → Emit slime_defeated → Destroy Self

  Asset refs:
    slime_sprite_sheet
    slime_pop_audio
    coin_prefab

V1 Scope

  • Read-only prefab anatomy view
  • Component cards
  • Asset reference cards
  • Flow summary block
  • Event inputs/outputs
  • Click node to open inspector / Object Flow / prefab asset

4. Event Bus Map

Purpose

Show who emits and listens to events across the scene, prefabs, components, and Object Flow.

Primary Users

Everyone. This is likely the highest-value graph mode.

Data Sources

  • Rules / Object Flow graphs
  • Component event descriptors
  • Custom event catalog
  • Scene Flow
  • Prefab graphs
  • Runtime trace later

Layout

Emitters on the left, events in the center, listeners on the right.

text
[Emitter] → [Event Key] → [Listener]

Nodes

  • Event key
  • Component event
  • Custom event
  • Scene event
  • Emitter object/prefab
  • Listener object/prefab
  • Flow graph
  • Payload field

Edges

  • Emits
  • Listens
  • Reads payload field
  • Writes payload field
  • Forwards event

Useful Badges

  • Scope: local, scene, global, targeted
  • Payload fields
  • Emitter count
  • Listener count
  • No listeners
  • No emitters
  • Payload mismatch
  • Deprecated key

Example: Garden Defense

text
slime_defeated
  emitted by:
    Garden Slime / Health.died
  listened by:
    Scene Flow / Add Score
    Hero / Say Milestone
    Nest Spawner / Accelerate

V1 Scope

  • Scan rules and component events
  • Show emitters/listeners
  • Show custom event scopes
  • Warn for event keys with no listeners
  • Warn for listeners with no emitters
  • Click event to filter Object Flow list

5. Flow Summary Graph

Purpose

Show high-level logic for a flow graph without exposing every editable node detail.

Primary Users

Learners, debuggers, and creators navigating large graphs.

Data Sources

  • Object Flow graph
  • Scene Flow graph
  • Flow node registry
  • Compiler diagnostics

Layout

Layered DAG:

text
Trigger → Conditions → Actions → Events Out

Nodes

  • Trigger
  • Condition
  • Action
  • Event out
  • Data getter/setter
  • Broken node
  • Comment/group

Edges

  • Execution path
  • Data path
  • True/false branch
  • Event output

V1 Scope

  • Read-only summary
  • Collapse chains
  • Show broken nodes
  • Show component calls
  • Show event emits
  • Click to open actual Object Flow editor

6. Component Relationship Graph

Purpose

Visualize how components depend on, call, emit to, or read from other components.

Primary Users

Engine contributors and advanced creators.

Data Sources

  • Component registry
  • Component definitions
  • requires
  • Actions
  • Conditions
  • Events
  • Field metadata
  • Optional static hints for component calls

Layout

Force graph or hub-and-spoke per selected component.

Nodes

  • Component type
  • Action
  • Condition
  • Event
  • Field
  • Required component
  • Interface/capability, later

Edges

  • Requires
  • Calls
  • Reads
  • Writes
  • Emits
  • Optional dependency

Example: Hazard

text
Hazard
  requires Collider2D
  calls Health.damage
  optionally calls SpriteRenderer.vanish
  reads Team.name
  emits hazard/hurt

V1 Scope

  • Requires graph
  • Events/actions/conditions display
  • Component detail side panel
  • Later: static call graph hints

7. Asset Dependency Graph

Purpose

Show how scenes, prefabs, sprites, audio, UI, and other assets reference each other.

Primary Users

Creators preparing exports and developers debugging missing assets.

Data Sources

  • Asset library
  • Scene records
  • Prefab records
  • reference-scan.js (forward/reverse index)
  • SpriteRenderer fields
  • Audio action references
  • UI document asset references

Layout

Dependency graph or tree grouped by asset type.

Nodes

  • Scene
  • Prefab
  • Image
  • Audio
  • UI document
  • Script
  • Folder
  • Missing reference
  • Unused asset

Edges

  • Uses
  • Contains
  • Spawns
  • References
  • Missing

Useful Questions

  • What will this scene export?
  • Which assets are unused?
  • Which assets are missing?
  • Which prefabs depend on this sprite?
  • What uses this audio file?

V1 Scope

  • Scene → asset references
  • Prefab → asset references
  • Missing asset warnings
  • Unused asset list

Current partial implementation

The assets panel graph view (src/game/assets/editor/asset-graph-view.js) already renders a filtered asset dependency graph inside the dock. When Graph Explorer lands, reuse reference-scan.js for indexing and replace the bespoke renderer with the shared graph explorer stack.


8. Prefab Variant / Inheritance Graph

Purpose

Show prefab family trees and field overrides.

Primary Users

Advanced prefab creators.

Data Sources

  • Prefab records
  • Variant/parent metadata
  • Override detection

Layout

Tree or layered inheritance graph.

Nodes

  • Base prefab
  • Variant prefab
  • Override group
  • Added component
  • Removed component
  • Overridden field

Edges

  • Inherits from
  • Overrides
  • Adds
  • Removes

Example

text
Base Slime
  ├─ Berry Slime
  │   overrides SpriteRenderer.sprite
  │   overrides Loot.points = 2
  └─ Thorn Slime
      adds Hazard
      overrides Health.hp = 5

V1 Scope

Defer until prefab variants are mature.


9. Runtime Trace Graph

Purpose

Show what executed during play.

Primary Users

Debuggers and learners.

Data Sources

  • Runtime trace store
  • Compiled FlowProgram source maps
  • Event dispatch logs
  • Component event emits
  • Action execution results

Layout

Execution path graph with animated pulses or counts.

Nodes

  • Trigger
  • Flow node
  • Component action
  • Event
  • Object
  • Error

Edges

  • Executed next
  • Emitted event
  • Called component
  • Spawned prefab
  • Destroyed object

Useful Badges

  • Fired count
  • Last fired time
  • Last input value
  • Error count
  • Duration
  • Object id

Example

text
On Tap
  12x → Health.damage
  4x  → Health.died
  4x  → Spawn Coin
  4x  → Add Score
  4x  → Emit slime_defeated
  4x  → Destroy Self

V1 Scope

Defer until trace/source-map systems are stable, but design the graph model so this mode can plug in later.


UI Design

Main Entry Point

Add a new editor tab:

text
Graph Explorer

Inside it:

text
View:
  Scene Hierarchy
  Prefab Anatomy
  Event Map
  Flow Summary
  Component Relationships
  Asset Dependencies
  Architecture

Contextual Entry Points

Right-click actions:

text
Object → View object graph
Prefab asset → View prefab anatomy
Event key → Show event map
Component → Show component relationships
Scene → Show scene hierarchy graph
Asset → Show dependencies
File/dev mode → Show import graph

Layout

The Graph Explorer should use a three-region layout:

text
┌─────────────────────────────────────────────┐
│ Toolbar: mode, search, filters, layout       │
├───────────────┬─────────────────────────────┤
│ Filters/Tree  │ Graph canvas                 │
│               │                             │
├───────────────┴───────────────┬─────────────┤
│ Details panel / selection info │ Warnings    │
└───────────────────────────────┴─────────────┘

Interactions

Required:

  • Pan
  • Zoom
  • Fit to view
  • Search nodes
  • Select node
  • Select edge
  • Expand/collapse
  • Filter by type
  • Focus neighbors
  • Open source inspector/editor

Later:

  • Pin nodes
  • Save graph bookmarks
  • Compare two graph states
  • Animate runtime trace
  • Export graph image

Technical Architecture

Folder Proposal

text
src/game/graph-explorer/
  graph-model.js
  graph-renderer.js
  graph-layouts.js
  graph-interactions.js
  graph-filters.js
  graph-details-panel.js

  adapters/
    scene-hierarchy-graph.js
    prefab-anatomy-graph.js
    event-bus-graph.js
    flow-summary-graph.js
    component-relationship-graph.js
    asset-dependency-graph.js
    architecture-graph.js

  styles/
    graph-explorer.css

  graph-explorer.test.js

Classify as editor in architecture-boundaries.test.js.

Alternative colocation:

text
src/game/scene-editor/graph-explorer/

A top-level graph-explorer editor feature is clearer because it visualizes many systems.

Shared Graph Model

Pure model module:

js
export function createGraphExplorerDocument({
  id,
  title,
  mode,
  nodes = [],
  edges = [],
  groups = [],
  meta = {},
}) {
  return normalizeGraphExplorerDocument({ id, title, mode, nodes, edges, groups, meta });
}

Node fields:

js
{
  id,
  type,
  label,
  subtitle,
  group,
  icon,
  badges,
  status,
  position,
  collapsed,
  data
}

Edge fields:

js
{
  id,
  from,
  to,
  type,
  label,
  direction,
  status,
  data
}

Status values:

js
"ok"
"warning"
"error"
"missing"
"disabled"
"runtime"

Edge types:

js
"contains"
"imports"
"uses"
"emits"
"listens"
"calls"
"reads"
"writes"
"requires"
"spawns"
"overrides"
"executes"

Adapters

Each adapter is pure:

js
export function buildPrefabAnatomyGraph(prefab, context) {
  return createGraphExplorerDocument({
    id: `prefab:${prefab.id}`,
    title: prefab.name,
    mode: "prefab-anatomy",
    nodes,
    edges,
    groups,
    meta,
  });
}

Adapters must not touch DOM.

Renderer

DOM/SVG view patterned after the Object Flow DOM workspace (interaction/dom-workspace.js, dom-workspace-viewport.js, dom-workspace-interactions.js):

  • DOM cards for nodes
  • SVG paths for edges
  • D3 for layout helpers and zoom/pan (src/vendor/d3-zoom.js today; add narrow modules only as needed)
  • Opal-owned selection/details state
  • No runtime/game dependency on D3

The assets panel asset-graph-view.js is a prototype of this renderer pattern but is not yet adapter-driven.

Layout Engine

Start simple:

js
layoutTree(document)
layoutLayered(document)
layoutForce(document)

V1 can ship with tree/layered layouts only.

D3 may be used for:

  • d3-hierarchy
  • d3-force
  • d3-zoom

Vendor only narrow D3 modules when they remove meaningful complexity.


Milestones

Milestone 1 — Shared Graph Viewer

Build the generic graph viewer with mock data.

Deliverables:

  • GraphExplorerDocument model
  • DOM/SVG graph renderer
  • Pan/zoom/fit
  • Select node/edge
  • Details panel
  • Search
  • Type filters
  • Mock graph fixtures
  • Unit tests for normalization

Acceptance Criteria:

  • Can render at least 100 nodes and 150 edges smoothly.
  • Search focuses a node.
  • Details panel updates on selection.
  • Graph model is independent of any one data source.

Milestone 2 — Scene Hierarchy Graph

Deliverables:

  • buildSceneHierarchyGraph(sceneGraph, objects)
  • Tree layout
  • Object badges
  • Click node selects object
  • Filter hidden/locked/prefab/camera/trigger
  • Tests for graph conversion

Acceptance Criteria:

  • Scene hierarchy graph matches the existing hierarchy tree.
  • Selecting graph node selects the scene object.
  • Collapsed nodes hide children.
  • Badges match existing hierarchy status.

Milestone 3 — Event Bus Map

Deliverables:

  • buildEventBusGraph(rules, components, prefabs)
  • Custom event nodes
  • Emitters/listeners
  • Payload chips
  • Missing emitter/listener warnings
  • Click event filters related flows

Acceptance Criteria:

  • Shows all custom events.
  • Shows component events when used by flow.
  • Warns on listener with no emitter.
  • Warns on emitter with no listener.
  • Works with Garden Defense demo.

Milestone 4 — Prefab Anatomy Graph

Deliverables:

  • buildPrefabAnatomyGraph(prefab)
  • Object/component/flow/asset nodes
  • Event input/output nodes
  • Open inspector/Object Flow from graph selection
  • Tests with Garden Slime prefab fixture

Acceptance Criteria:

  • Shows prefab root, contained objects, components, flow summary, and assets.
  • Clicking component opens component inspector.
  • Clicking flow opens Object Flow.
  • Missing assets display warnings.

Milestone 5 — Asset Dependency Graph

Deliverables:

  • buildAssetDependencyGraph(scene, assets, prefabs)
  • Scene/prefab/image/audio/UI nodes
  • Missing/unused asset detection
  • Export-readiness summary
  • Migrate assets panel graph onto shared renderer

Acceptance Criteria:

  • Shows assets used by current scene.
  • Shows unused assets.
  • Shows missing references.
  • Can focus on one asset and show dependents.

Milestone 6 — Component Relationship Graph

Deliverables:

  • buildComponentRelationshipGraph(registry)
  • Requires/calls/emits/fields/actions/conditions
  • Component details side panel

Acceptance Criteria:

  • Shows requires relationships.
  • Shows actions, conditions, events.
  • Hazard/Pickup/Spawner relationships are understandable.
  • Registry metadata drives graph without hardcoded component-specific UI.

Milestone 7 — Runtime Trace Graph

Deliverables:

  • Trace graph adapter
  • Execution counts
  • Last fired event path
  • Error path highlighting
  • Replay last trace

Acceptance Criteria:

  • During play, fired nodes pulse or count.
  • Trace graph can explain “tap slime → damage → death → coin → score.”
  • Selecting a trace node shows last values.

Garden Defense Teaching Use Case

The Garden Defense demo should include a “Study this demo” entry point.

Suggested views:

  1. Scene Graph — Hero, Flower bed, Slime nest, HUD, Bonus bush
  2. Prefab Anatomy — Garden Slime, Coin/Sun Seed, Slime Nest, Bonus Bush
  3. Event Mapslime_defeated, gold_added, milestone_reached
  4. Runtime Trace — Last slime tap sequence

Example teaching flow:

text
Open Garden Defense
Click “Study this demo”
Graph Explorer opens Event Map
User clicks slime_defeated
Explorer shows:
  emitted by Garden Slime prefab
  listened by Score Scene Flow
  listened by Hero Speech Flow
  listened by Nest Spawner acceleration

This turns the shipped demo into a self-documenting learning project.


Risks

Risk: Graph Explorer becomes another bespoke editor

Mitigation: One shared graph document model; pure adapters; one renderer; no one-off graph widgets outside the shared model.

Risk: D3 bleeds into app architecture

Mitigation: D3 only in graph-explorer layout/interaction modules; authored data remains Opal-owned; runtime does not import graph explorer.

Risk: Too many graph modes delay shipping

Mitigation: Ship Scene Hierarchy + Event Bus + Prefab Anatomy first; defer architecture/component/asset/runtime graphs as follow-ons (asset graph partially exists in the assets panel).

Risk: Graphs become visually noisy

Mitigation: Default filtered views; details on selection; collapse dense subgraphs; semantic grouping; do not show every edge at once.

Risk: Data sources are not normalized enough

Mitigation: Build adapters incrementally; fixture tests per adapter; prefer warnings over silent omissions.


Recommended V1

Ship these first:

  1. Shared graph viewer
  2. Scene hierarchy graph
  3. Event bus map
  4. Prefab anatomy graph for selected prefab

Do not start with architecture/file graphs unless the feature is initially developer-only. For creators, Event Bus Map and Prefab Anatomy are the most impressive and useful.

V1 Success Criteria

A developer opens the Garden Defense demo and can visually answer:

text
Where do slimes come from?
What happens when I tap a slime?
What makes the score increase?
Which prefab spawns coins?
Which event connects slime death to the rest of the scene?
Which assets does the slime prefab use?

If the Graph Explorer answers those questions cleanly, it is already valuable.


Future Vision

Long-term, the Graph Explorer becomes Opal’s “understanding mode.”

Instead of only editing objects and flows, developers can inspect systems:

text
Show me this prefab.
Show me who listens to this event.
Show me why this object moved.
Show me what this asset is used by.
Show me what ran during play.
Show me what will break if I delete this.

That is the difference between a game editor and a game engine that teaches its own architecture.

Opal Engine — MIT licensed