@zenfg/inspector 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -0
  3. package/dist/FrameGraphInspector.d.ts +153 -0
  4. package/dist/FrameGraphInspector.d.ts.map +1 -0
  5. package/dist/FrameGraphInspector.js +580 -0
  6. package/dist/FrameGraphInspector.js.map +1 -0
  7. package/dist/debugCaptureModel.d.ts +166 -0
  8. package/dist/debugCaptureModel.d.ts.map +1 -0
  9. package/dist/debugCaptureModel.js +364 -0
  10. package/dist/debugCaptureModel.js.map +1 -0
  11. package/dist/index.d.ts +17 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +15 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/panelAliasAnalysis.d.ts +20 -0
  16. package/dist/panelAliasAnalysis.d.ts.map +1 -0
  17. package/dist/panelAliasAnalysis.js +113 -0
  18. package/dist/panelAliasAnalysis.js.map +1 -0
  19. package/dist/panelCytoscapeGraphRenderer.d.ts +71 -0
  20. package/dist/panelCytoscapeGraphRenderer.d.ts.map +1 -0
  21. package/dist/panelCytoscapeGraphRenderer.js +559 -0
  22. package/dist/panelCytoscapeGraphRenderer.js.map +1 -0
  23. package/dist/panelDiagnosticsView.d.ts +22 -0
  24. package/dist/panelDiagnosticsView.d.ts.map +1 -0
  25. package/dist/panelDiagnosticsView.js +123 -0
  26. package/dist/panelDiagnosticsView.js.map +1 -0
  27. package/dist/panelDomHelpers.d.ts +26 -0
  28. package/dist/panelDomHelpers.d.ts.map +1 -0
  29. package/dist/panelDomHelpers.js +129 -0
  30. package/dist/panelDomHelpers.js.map +1 -0
  31. package/dist/panelGraphLayout.d.ts +28 -0
  32. package/dist/panelGraphLayout.d.ts.map +1 -0
  33. package/dist/panelGraphLayout.js +223 -0
  34. package/dist/panelGraphLayout.js.map +1 -0
  35. package/dist/panelGraphRenderer.d.ts +20 -0
  36. package/dist/panelGraphRenderer.d.ts.map +1 -0
  37. package/dist/panelGraphRenderer.js +2 -0
  38. package/dist/panelGraphRenderer.js.map +1 -0
  39. package/dist/panelGraphScene.d.ts +98 -0
  40. package/dist/panelGraphScene.d.ts.map +1 -0
  41. package/dist/panelGraphScene.js +559 -0
  42. package/dist/panelGraphScene.js.map +1 -0
  43. package/dist/panelGraphView.d.ts +9 -0
  44. package/dist/panelGraphView.d.ts.map +1 -0
  45. package/dist/panelGraphView.js +88 -0
  46. package/dist/panelGraphView.js.map +1 -0
  47. package/dist/panelGraphVisuals.d.ts +38 -0
  48. package/dist/panelGraphVisuals.d.ts.map +1 -0
  49. package/dist/panelGraphVisuals.js +330 -0
  50. package/dist/panelGraphVisuals.js.map +1 -0
  51. package/dist/panelIcons.d.ts +4 -0
  52. package/dist/panelIcons.d.ts.map +1 -0
  53. package/dist/panelIcons.js +43 -0
  54. package/dist/panelIcons.js.map +1 -0
  55. package/dist/panelInspectorView.d.ts +33 -0
  56. package/dist/panelInspectorView.d.ts.map +1 -0
  57. package/dist/panelInspectorView.js +357 -0
  58. package/dist/panelInspectorView.js.map +1 -0
  59. package/dist/panelMemoryView.d.ts +21 -0
  60. package/dist/panelMemoryView.d.ts.map +1 -0
  61. package/dist/panelMemoryView.js +134 -0
  62. package/dist/panelMemoryView.js.map +1 -0
  63. package/dist/panelPassesView.d.ts +31 -0
  64. package/dist/panelPassesView.d.ts.map +1 -0
  65. package/dist/panelPassesView.js +183 -0
  66. package/dist/panelPassesView.js.map +1 -0
  67. package/dist/panelResourcesView.d.ts +19 -0
  68. package/dist/panelResourcesView.d.ts.map +1 -0
  69. package/dist/panelResourcesView.js +89 -0
  70. package/dist/panelResourcesView.js.map +1 -0
  71. package/dist/panelSelection.d.ts +5 -0
  72. package/dist/panelSelection.d.ts.map +1 -0
  73. package/dist/panelSelection.js +88 -0
  74. package/dist/panelSelection.js.map +1 -0
  75. package/dist/panelTypes.d.ts +40 -0
  76. package/dist/panelTypes.d.ts.map +1 -0
  77. package/dist/panelTypes.js +2 -0
  78. package/dist/panelTypes.js.map +1 -0
  79. package/dist/panelVisualTheme.d.ts +76 -0
  80. package/dist/panelVisualTheme.d.ts.map +1 -0
  81. package/dist/panelVisualTheme.js +39 -0
  82. package/dist/panelVisualTheme.js.map +1 -0
  83. package/dist/panelWorkbenchHelpers.d.ts +34 -0
  84. package/dist/panelWorkbenchHelpers.d.ts.map +1 -0
  85. package/dist/panelWorkbenchHelpers.js +162 -0
  86. package/dist/panelWorkbenchHelpers.js.map +1 -0
  87. package/dist/panelWorkbenchView.d.ts +77 -0
  88. package/dist/panelWorkbenchView.d.ts.map +1 -0
  89. package/dist/panelWorkbenchView.js +409 -0
  90. package/dist/panelWorkbenchView.js.map +1 -0
  91. package/dist/query.d.ts +11 -0
  92. package/dist/query.d.ts.map +1 -0
  93. package/dist/query.js +21 -0
  94. package/dist/query.js.map +1 -0
  95. package/dist/styles.d.ts +8 -0
  96. package/dist/styles.d.ts.map +1 -0
  97. package/dist/styles.js +1073 -0
  98. package/dist/styles.js.map +1 -0
  99. package/package.json +29 -0
  100. package/src/FrameGraphInspector.ts +632 -0
  101. package/src/debugCaptureModel.ts +583 -0
  102. package/src/index.ts +21 -0
  103. package/src/panelAliasAnalysis.ts +164 -0
  104. package/src/panelCytoscapeGraphRenderer.ts +617 -0
  105. package/src/panelDiagnosticsView.ts +160 -0
  106. package/src/panelDomHelpers.ts +151 -0
  107. package/src/panelGraphLayout.ts +281 -0
  108. package/src/panelGraphRenderer.ts +21 -0
  109. package/src/panelGraphScene.ts +787 -0
  110. package/src/panelGraphView.ts +108 -0
  111. package/src/panelGraphVisuals.ts +364 -0
  112. package/src/panelIcons.ts +56 -0
  113. package/src/panelInspectorView.ts +377 -0
  114. package/src/panelMemoryView.ts +154 -0
  115. package/src/panelPassesView.ts +222 -0
  116. package/src/panelResourcesView.ts +115 -0
  117. package/src/panelSelection.ts +99 -0
  118. package/src/panelTypes.ts +28 -0
  119. package/src/panelVisualTheme.ts +39 -0
  120. package/src/panelWorkbenchHelpers.ts +216 -0
  121. package/src/panelWorkbenchView.ts +465 -0
  122. package/src/query.ts +22 -0
  123. package/src/styles.ts +1076 -0
@@ -0,0 +1,409 @@
1
+ import { formatBytes, formatGpuFrameDuration, formatPoolHitRate, labelNode, } from "./panelDomHelpers.js";
2
+ import { createPanelIcon, setPanelButtonContent } from "./panelIcons.js";
3
+ import { DiagnosticsView } from "./panelDiagnosticsView.js";
4
+ import { InspectorView } from "./panelInspectorView.js";
5
+ import { MemoryView } from "./panelMemoryView.js";
6
+ import { PassesView } from "./panelPassesView.js";
7
+ import { ResourcesView } from "./panelResourcesView.js";
8
+ import { renderGraphView, resizeGraph } from "./panelGraphView.js";
9
+ import { formatEstimatedBytes } from "./panelWorkbenchHelpers.js";
10
+ export class FrameGraphDebugWorkbench {
11
+ graphView;
12
+ callbacks;
13
+ root = document.createElement('div');
14
+ summary = document.createElement('div');
15
+ commandBar = document.createElement('div');
16
+ brand = document.createElement('div');
17
+ tabList = document.createElement('div');
18
+ commandActions = document.createElement('div');
19
+ commandStatus = document.createElement('span');
20
+ workspace = document.createElement('div');
21
+ main = document.createElement('main');
22
+ emptyHost = document.createElement('div');
23
+ overviewRoot = document.createElement('section');
24
+ graphRoot = document.createElement('section');
25
+ passes;
26
+ resources;
27
+ memory;
28
+ diagnostics;
29
+ inspector;
30
+ inspectorOpenButton = document.createElement('button');
31
+ captureButton = document.createElement('button');
32
+ importButton = document.createElement('button');
33
+ importInput = document.createElement('input');
34
+ exportButton = document.createElement('button');
35
+ exportMenu = document.createElement('div');
36
+ downloadButton = document.createElement('button');
37
+ copyButton = document.createElement('button');
38
+ tabButtons = new Map();
39
+ views = new Map();
40
+ activeTab = 'graph';
41
+ hasSnapshot = false;
42
+ snapshot;
43
+ selected;
44
+ hovered;
45
+ constructor(graphView, callbacks, actions, options) {
46
+ this.graphView = graphView;
47
+ this.callbacks = callbacks;
48
+ this.root.className = 'zenfg-inspector-workbench';
49
+ this.summary.className = 'zenfg-inspector-capture-summary';
50
+ this.commandBar.className = 'zenfg-inspector-workbench-command-bar';
51
+ this.brand.className = 'zenfg-inspector-brand';
52
+ if (options.branding === false)
53
+ this.commandBar.classList.add('branding-hidden');
54
+ else
55
+ this.brand.textContent = options.branding;
56
+ this.tabList.className = 'zenfg-inspector-workbench-tabs';
57
+ this.tabList.setAttribute('role', 'tablist');
58
+ this.tabList.setAttribute('aria-label', 'FrameGraph debug views');
59
+ this.commandActions.className = 'zenfg-inspector-workbench-actions';
60
+ this.commandActions.setAttribute('role', 'toolbar');
61
+ this.commandActions.setAttribute('aria-label', 'FrameGraph commands');
62
+ this.commandStatus.className = 'zenfg-inspector-command-status';
63
+ this.commandStatus.setAttribute('role', 'status');
64
+ this.commandStatus.setAttribute('aria-live', 'polite');
65
+ this.workspace.className = 'zenfg-inspector-workspace inspector-open';
66
+ this.main.className = 'zenfg-inspector-main';
67
+ this.emptyHost.className = 'zenfg-inspector-workbench-empty';
68
+ this.emptyHost.setAttribute('role', 'status');
69
+ this.emptyHost.setAttribute('aria-live', 'polite');
70
+ this.overviewRoot.className = 'zenfg-inspector-view zenfg-inspector-overview-view';
71
+ this.overviewRoot.id = `${options.idPrefix}-view-overview`;
72
+ this.overviewRoot.setAttribute('role', 'tabpanel');
73
+ this.overviewRoot.append(this.summary);
74
+ this.graphRoot.className = 'zenfg-inspector-view zenfg-inspector-graph-view';
75
+ this.graphRoot.id = `${options.idPrefix}-view-graph`;
76
+ this.graphRoot.setAttribute('role', 'tabpanel');
77
+ this.graphRoot.append(this.graphView.toolbar, this.graphView.host);
78
+ this.passes = new PassesView(callbacks, options.idPrefix);
79
+ this.resources = new ResourcesView(callbacks, options.idPrefix);
80
+ this.memory = new MemoryView(callbacks, options.idPrefix);
81
+ this.diagnostics = new DiagnosticsView(callbacks, options.idPrefix);
82
+ this.inspector = new InspectorView(callbacks, (open) => this.handleInspectorOpenChange(open), options.idPrefix);
83
+ this.views.set('overview', this.overviewRoot);
84
+ this.views.set('graph', this.graphRoot);
85
+ this.views.set('passes', this.passes.root);
86
+ this.views.set('resources', this.resources.root);
87
+ this.views.set('memory', this.memory.root);
88
+ this.views.set('diagnostics', this.diagnostics.root);
89
+ for (const [tab, label] of [
90
+ ['overview', 'Overview'],
91
+ ['graph', 'Graph'],
92
+ ['passes', 'Passes'],
93
+ ['resources', 'Resources'],
94
+ ['memory', 'Memory'],
95
+ ['diagnostics', 'Diagnostics'],
96
+ ]) {
97
+ const button = document.createElement('button');
98
+ button.type = 'button';
99
+ button.id = `${options.idPrefix}-tab-${tab}`;
100
+ button.textContent = label;
101
+ button.setAttribute('role', 'tab');
102
+ button.setAttribute('aria-controls', `${options.idPrefix}-view-${tab}`);
103
+ button.addEventListener('click', () => this.setActiveTab(tab));
104
+ this.tabButtons.set(tab, button);
105
+ this.tabList.appendChild(button);
106
+ }
107
+ this.inspectorOpenButton.type = 'button';
108
+ this.inspectorOpenButton.hidden = true;
109
+ this.inspectorOpenButton.className = 'zenfg-inspector-open-inspector';
110
+ setPanelButtonContent(this.inspectorOpenButton, 'inspector', 'Inspector');
111
+ this.inspectorOpenButton.title = 'Open selection inspector';
112
+ this.inspectorOpenButton.addEventListener('click', () => this.inspector.setOpen(true));
113
+ this.captureButton.type = 'button';
114
+ this.captureButton.className = 'zenfg-inspector-capture-action';
115
+ this.captureButton.addEventListener('click', actions.onCapture);
116
+ this.importButton.type = 'button';
117
+ this.importButton.textContent = 'Import';
118
+ this.importButton.addEventListener('click', () => this.importInput.click());
119
+ this.importInput.type = 'file';
120
+ this.importInput.accept = '.fgsnapshot.json,.json,application/json';
121
+ this.importInput.hidden = true;
122
+ this.importInput.addEventListener('change', () => {
123
+ const file = this.importInput.files?.[0];
124
+ this.importInput.value = '';
125
+ if (file)
126
+ actions.onImport(file);
127
+ });
128
+ this.exportButton.type = 'button';
129
+ this.exportButton.textContent = 'Export';
130
+ this.exportButton.setAttribute('aria-haspopup', 'menu');
131
+ this.exportButton.setAttribute('aria-expanded', 'false');
132
+ this.exportButton.setAttribute('aria-controls', `${options.idPrefix}-export-menu`);
133
+ this.exportButton.addEventListener('click', () => {
134
+ this.setExportMenuOpen(this.exportMenu.hidden !== false);
135
+ });
136
+ this.exportMenu.className = 'zenfg-inspector-export-menu';
137
+ this.exportMenu.id = `${options.idPrefix}-export-menu`;
138
+ this.exportMenu.setAttribute('role', 'menu');
139
+ this.exportMenu.hidden = true;
140
+ this.downloadButton.type = 'button';
141
+ this.downloadButton.textContent = 'Download JSON';
142
+ this.downloadButton.setAttribute('role', 'menuitem');
143
+ this.downloadButton.addEventListener('click', () => {
144
+ this.setExportMenuOpen(false);
145
+ actions.onDownload();
146
+ });
147
+ this.copyButton.type = 'button';
148
+ this.copyButton.className = 'zenfg-inspector-copy-action';
149
+ this.copyButton.textContent = 'Copy JSON';
150
+ this.copyButton.setAttribute('role', 'menuitem');
151
+ this.copyButton.addEventListener('click', () => {
152
+ this.setExportMenuOpen(false);
153
+ actions.onCopyJson();
154
+ });
155
+ this.exportMenu.append(this.downloadButton, this.copyButton);
156
+ this.commandActions.append(this.commandStatus, this.inspectorOpenButton, this.captureButton, this.importButton, this.exportButton, this.importInput);
157
+ if (options.branding === false)
158
+ this.commandBar.append(this.tabList, this.commandActions, this.exportMenu);
159
+ else
160
+ this.commandBar.append(this.brand, this.tabList, this.commandActions, this.exportMenu);
161
+ this.root.addEventListener('click', (event) => {
162
+ const target = event.target;
163
+ if (!target || typeof target.nodeType !== 'number' || this.exportMenu.hidden)
164
+ return;
165
+ const targetNode = target;
166
+ if (!this.exportButton.contains(targetNode) && !this.exportMenu.contains(targetNode))
167
+ this.setExportMenuOpen(false);
168
+ });
169
+ this.root.addEventListener('keydown', (event) => {
170
+ if (event.key !== 'Escape' || this.exportMenu.hidden)
171
+ return;
172
+ this.setExportMenuOpen(false);
173
+ this.exportButton.focus();
174
+ });
175
+ this.main.append(this.emptyHost, ...this.views.values());
176
+ this.workspace.append(this.main, this.inspector.root);
177
+ this.root.append(this.commandBar, this.workspace);
178
+ this.showEmptyState('empty', 'Drop a ZenFG Snapshot here or choose Import.', 'Files are processed locally in your browser.');
179
+ this.setSnapshotActionState({
180
+ providerAvailable: false,
181
+ hasCapture: false,
182
+ capturing: false,
183
+ importing: false,
184
+ copying: false,
185
+ copied: false,
186
+ });
187
+ }
188
+ setSnapshot(snapshot, selected) {
189
+ this.hasSnapshot = true;
190
+ this.snapshot = snapshot;
191
+ this.selected = selected;
192
+ this.hovered = undefined;
193
+ this.renderSummary(snapshot);
194
+ this.passes.setSnapshot(snapshot);
195
+ this.resources.setSnapshot(snapshot);
196
+ this.memory.setSnapshot(snapshot);
197
+ this.diagnostics.setSnapshot(snapshot);
198
+ this.inspector.setSnapshot(snapshot);
199
+ this.passes.setSelection(selected);
200
+ this.resources.setSelection(selected);
201
+ this.memory.setSelection(selected);
202
+ this.diagnostics.setSelection(selected);
203
+ this.inspector.setSelection(selected, false);
204
+ this.emptyHost.hidden = true;
205
+ this.updateActiveTab();
206
+ this.updateWorkspaceState();
207
+ if (this.activeTab === 'graph')
208
+ this.renderGraph();
209
+ }
210
+ showEmptyState(kind, message, detail) {
211
+ this.hasSnapshot = false;
212
+ this.snapshot = undefined;
213
+ this.selected = undefined;
214
+ this.hovered = undefined;
215
+ this.emptyHost.hidden = false;
216
+ this.emptyHost.dataset.state = kind;
217
+ const icon = createPanelIcon(kind === 'capturing' ? 'spinner' : kind === 'error' ? 'error' : kind === 'waiting' ? 'waiting' : 'empty');
218
+ const label = document.createElement('span');
219
+ label.className = 'zenfg-inspector-empty-message';
220
+ label.textContent = message;
221
+ const detailLabel = document.createElement('span');
222
+ detailLabel.className = 'zenfg-inspector-empty-detail';
223
+ detailLabel.textContent = detail ?? '';
224
+ this.emptyHost.replaceChildren(icon, label, ...(detail ? [detailLabel] : []));
225
+ this.updateActiveTab();
226
+ this.updateWorkspaceState();
227
+ }
228
+ setSnapshotActionState(state) {
229
+ const captureLabel = state.capturing ? 'Capturing…' : 'Capture';
230
+ setPanelButtonContent(this.captureButton, state.capturing ? 'spinner' : 'capture', captureLabel);
231
+ this.captureButton.disabled = state.capturing || !state.providerAvailable;
232
+ this.captureButton.hidden = !state.providerAvailable;
233
+ this.captureButton.classList.toggle('active', state.capturing);
234
+ this.captureButton.setAttribute('aria-busy', state.capturing ? 'true' : 'false');
235
+ this.captureButton.dataset.tone = state.capturing ? 'pending' : 'accent';
236
+ this.captureButton.title = !state.providerAvailable
237
+ ? 'Waiting for a FrameGraph capture source.'
238
+ : state.capturing
239
+ ? 'Capturing the next rendered frame.'
240
+ : 'Capture and display the next rendered frame.';
241
+ this.importButton.textContent = state.importing ? 'Importing…' : 'Import';
242
+ this.importButton.disabled = state.importing;
243
+ this.importButton.setAttribute('aria-busy', state.importing ? 'true' : 'false');
244
+ this.exportButton.disabled = !state.hasCapture;
245
+ this.downloadButton.disabled = !state.hasCapture;
246
+ if (!state.hasCapture)
247
+ this.setExportMenuOpen(false);
248
+ const copyLabel = state.copying ? 'Copying…' : state.copied ? 'Copied' : 'Copy JSON';
249
+ const copyIcon = state.copying ? 'spinner' : state.copied ? 'check' : 'copy';
250
+ setPanelButtonContent(this.copyButton, copyIcon, copyLabel);
251
+ this.copyButton.disabled = !state.hasCapture || state.copying;
252
+ this.copyButton.classList.toggle('active', state.copying || state.copied);
253
+ this.copyButton.setAttribute('aria-busy', state.copying ? 'true' : 'false');
254
+ this.copyButton.dataset.tone = state.copied ? 'success' : state.copying ? 'pending' : 'neutral';
255
+ this.copyButton.title = state.hasCapture
256
+ ? 'Copy the current canonical FrameGraph Snapshot JSON.'
257
+ : 'Load a snapshot before exporting.';
258
+ this.commandStatus.textContent = state.message ?? '';
259
+ this.commandStatus.hidden = !state.message;
260
+ this.commandStatus.dataset.tone = state.message ? state.messageTone ?? 'error' : 'neutral';
261
+ if (state.message)
262
+ this.commandStatus.title = state.message;
263
+ else
264
+ this.commandStatus.removeAttribute('title');
265
+ }
266
+ setSelection(selected) {
267
+ this.selected = selected;
268
+ this.passes.setSelection(selected);
269
+ this.resources.setSelection(selected);
270
+ this.memory.setSelection(selected);
271
+ this.diagnostics.setSelection(selected);
272
+ this.inspector.setSelection(selected);
273
+ if (this.activeTab === 'graph')
274
+ this.renderGraph();
275
+ }
276
+ setHovered(hovered) {
277
+ this.hovered = hovered;
278
+ if (this.activeTab === 'graph')
279
+ this.renderGraph();
280
+ }
281
+ setActiveTab(tab) {
282
+ if (this.activeTab === tab)
283
+ return;
284
+ this.activeTab = tab;
285
+ this.updateActiveTab();
286
+ if (tab === 'graph') {
287
+ window.requestAnimationFrame(() => {
288
+ resizeGraph(this.graphView);
289
+ this.renderGraph();
290
+ });
291
+ }
292
+ }
293
+ refreshGraphStructure() {
294
+ if (!this.snapshot)
295
+ return;
296
+ this.passes.setSnapshot(this.snapshot);
297
+ if (this.activeTab === 'graph')
298
+ this.renderGraph();
299
+ }
300
+ resizeGraph(fit = false) {
301
+ if (fit)
302
+ this.graphView.fitOnNextRender = true;
303
+ window.requestAnimationFrame(() => {
304
+ resizeGraph(this.graphView);
305
+ if (this.activeTab === 'graph')
306
+ this.renderGraph();
307
+ });
308
+ }
309
+ updateActiveTab() {
310
+ for (const [tab, button] of this.tabButtons) {
311
+ const active = tab === this.activeTab;
312
+ button.disabled = !this.hasSnapshot;
313
+ button.classList.toggle('active', active);
314
+ button.setAttribute('aria-selected', active ? 'true' : 'false');
315
+ const view = this.views.get(tab);
316
+ view.hidden = !this.hasSnapshot || !active;
317
+ view.setAttribute('aria-labelledby', button.id);
318
+ }
319
+ }
320
+ renderGraph() {
321
+ if (!this.snapshot)
322
+ return;
323
+ renderGraphView(this.graphView, this.snapshot, this.selected, this.hovered, this.callbacks.onSelect, this.callbacks.onHover, this.callbacks.onGroupToggle);
324
+ }
325
+ renderSummary(snapshot) {
326
+ const frameGraphSegments = snapshot.executionSegments.filter((segment) => segment.kind === 'frame-graph').length;
327
+ const opaqueIntervals = snapshot.executionSegments.length - frameGraphSegments;
328
+ const metrics = snapshot.metrics;
329
+ const coverage = metrics.timingEligibleNodeCount === 0
330
+ ? 'No eligible passes'
331
+ : `${metrics.timedNodeCount}/${metrics.timingEligibleNodeCount} timed`;
332
+ const slowest = metrics.slowestNode
333
+ ? `${labelNode(metrics.slowestNode)} · ${(metrics.slowestNode.gpuDurationMicros / 1000).toFixed(3)} ms`
334
+ : 'Unknown';
335
+ const protocol = snapshot.protocol;
336
+ const runtime = protocol.producer.runtime;
337
+ const producer = [
338
+ protocol.producer.name,
339
+ protocol.producer.version,
340
+ protocol.producer.language,
341
+ ].filter(Boolean).join(' · ');
342
+ const runtimeLabel = runtime
343
+ ? [runtime.implementation, runtime.graphicsApi, runtime.backend].filter(Boolean).join(' · ') || 'Unknown'
344
+ : 'Unknown';
345
+ const poolRetained = snapshot.resourcePool.status === 'available'
346
+ ? `${snapshot.resourcePool.estimatedRetainedBytes === undefined ? 'Unknown' : formatBytes(snapshot.resourcePool.estimatedRetainedBytes)} · ${snapshot.resourcePool.retainedCount} allocations`
347
+ : 'Unavailable';
348
+ this.summary.replaceChildren(this.createSummaryGroup('Capture', [
349
+ ['Source', snapshot.source.label],
350
+ ['Schema', `${protocol.format} v${protocol.version.major}.${protocol.version.minor}`],
351
+ ['Producer', producer],
352
+ ['Runtime', runtimeLabel],
353
+ ['Frame', String(snapshot.frameIndex)],
354
+ ...(snapshot.source.migratedFromLegacy ? [['Migration', 'Legacy V0 → V1']] : []),
355
+ ['Timing', snapshot.profiling.status === 'available' ? 'Available' : snapshot.profiling.reason],
356
+ ]), this.createSummaryGroup('GPU', [
357
+ ['GPU Span', snapshot.profiling.status === 'available' ? `${formatGpuFrameDuration(snapshot)} ms` : 'Unknown'],
358
+ ['Coverage', coverage],
359
+ ['Slowest', slowest],
360
+ ]), this.createSummaryGroup('Work', [
361
+ ['Nodes', `${snapshot.nodes.length} retained · ${snapshot.culledNodes.length} culled`],
362
+ ['Segments', `${frameGraphSegments} FG · ${opaqueIntervals} opaque`],
363
+ ['Groups', snapshot.availability.groups ? String(snapshot.debugGroups.length) : 'Unknown'],
364
+ ['Recording order', snapshot.availability.recordingOrder ? 'Available' : 'Unknown'],
365
+ ]), this.createSummaryGroup('Resources', [
366
+ ['Logical / physical', `${snapshot.resources.length} / ${snapshot.physicalAllocations.length}`],
367
+ ['Texture views', snapshot.availability.textureViews ? String(snapshot.textureViewById.size) : 'Unknown'],
368
+ ['Access regions', snapshot.availability.accessRegions ? 'Available' : 'Unknown'],
369
+ ['Transient estimate', formatEstimatedBytes(metrics.transientEstimatedByteSize)],
370
+ ]), this.createSummaryGroup('Pool', [
371
+ ['Retained', poolRetained],
372
+ ['Reuse', formatPoolHitRate(snapshot)],
373
+ ]));
374
+ }
375
+ createSummaryGroup(title, rows) {
376
+ const group = document.createElement('section');
377
+ const heading = document.createElement('h2');
378
+ heading.textContent = title;
379
+ group.appendChild(heading);
380
+ for (const [label, value] of rows) {
381
+ const row = document.createElement('div');
382
+ const term = document.createElement('span');
383
+ term.textContent = label;
384
+ const description = document.createElement('strong');
385
+ description.textContent = value;
386
+ description.title = value;
387
+ row.append(term, description);
388
+ group.appendChild(row);
389
+ }
390
+ return group;
391
+ }
392
+ setExportMenuOpen(open) {
393
+ this.exportMenu.hidden = !open;
394
+ this.exportButton.setAttribute('aria-expanded', open ? 'true' : 'false');
395
+ }
396
+ handleInspectorOpenChange(_open) {
397
+ this.updateWorkspaceState();
398
+ if (this.activeTab === 'graph')
399
+ this.resizeGraph(false);
400
+ }
401
+ updateWorkspaceState() {
402
+ const inspectorOpen = this.hasSnapshot && this.inspector.isOpen;
403
+ this.workspace.classList.toggle('has-capture', this.hasSnapshot);
404
+ this.workspace.classList.toggle('inspector-open', inspectorOpen);
405
+ this.inspector.root.classList.toggle('unavailable', !this.hasSnapshot);
406
+ this.inspectorOpenButton.hidden = !this.hasSnapshot || inspectorOpen;
407
+ }
408
+ }
409
+ //# sourceMappingURL=panelWorkbenchView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panelWorkbenchView.js","sourceRoot":"","sources":["../src/panelWorkbenchView.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FrameGraphDebugViewModel } from './debugCaptureModel.ts';\nimport {\n\tformatBytes,\n\tformatGpuFrameDuration,\n\tformatPoolHitRate,\n\tlabelNode,\n} from './panelDomHelpers.ts';\nimport { createPanelIcon, setPanelButtonContent } from './panelIcons.ts';\nimport { DiagnosticsView } from './panelDiagnosticsView.ts';\nimport { InspectorView } from './panelInspectorView.ts';\nimport { MemoryView } from './panelMemoryView.ts';\nimport { PassesView } from './panelPassesView.ts';\nimport { ResourcesView } from './panelResourcesView.ts';\nimport { renderGraphView, resizeGraph } from './panelGraphView.ts';\nimport type { GraphViewState, Selection, WorkbenchTab } from './panelTypes.ts';\nimport { formatEstimatedBytes, type WorkbenchCallbacks } from './panelWorkbenchHelpers.ts';\n\nexport type FrameGraphDebugWorkbenchActions = {\n\tonCapture(): void;\n\tonImport(file: File): void;\n\tonDownload(): void;\n\tonCopyJson(): void;\n};\nexport type FrameGraphDebugWorkbenchOptions = {\n\tbranding: string | false;\n\tidPrefix: string;\n};\nexport type FrameGraphDebugEmptyStateKind = 'waiting' | 'capturing' | 'empty' | 'error';\n\n\nexport type FrameGraphDebugSnapshotActionState = {\n\tproviderAvailable: boolean;\n\thasCapture: boolean;\n\tcapturing: boolean;\n\timporting: boolean;\n\tcopying: boolean;\n\tcopied: boolean;\n\tmessage?: string;\n\tmessageTone?: 'neutral' | 'error';\n};\n\nexport class FrameGraphDebugWorkbench {\n\treadonly root = document.createElement('div');\n\tprivate readonly summary = document.createElement('div');\n\tprivate readonly commandBar = document.createElement('div');\n\tprivate readonly brand = document.createElement('div');\n\tprivate readonly tabList = document.createElement('div');\n\tprivate readonly commandActions = document.createElement('div');\n\tprivate readonly commandStatus = document.createElement('span');\n\tprivate readonly workspace = document.createElement('div');\n\tprivate readonly main = document.createElement('main');\n\tprivate readonly emptyHost = document.createElement('div');\n\tprivate readonly overviewRoot = document.createElement('section');\n\tprivate readonly graphRoot = document.createElement('section');\n\tprivate readonly passes: PassesView;\n\tprivate readonly resources: ResourcesView;\n\tprivate readonly memory: MemoryView;\n\tprivate readonly diagnostics: DiagnosticsView;\n\tprivate readonly inspector: InspectorView;\n\tprivate readonly inspectorOpenButton = document.createElement('button');\n\tprivate readonly captureButton = document.createElement('button');\n\tprivate readonly importButton = document.createElement('button');\n\tprivate readonly importInput = document.createElement('input');\n\tprivate readonly exportButton = document.createElement('button');\n\tprivate readonly exportMenu = document.createElement('div');\n\tprivate readonly downloadButton = document.createElement('button');\n\tprivate readonly copyButton = document.createElement('button');\n\tprivate readonly tabButtons = new Map<WorkbenchTab, HTMLButtonElement>();\n\tprivate readonly views = new Map<WorkbenchTab, HTMLElement>();\n\tprivate activeTab: WorkbenchTab = 'graph';\n\tprivate hasSnapshot = false;\n\tprivate snapshot: FrameGraphDebugViewModel | undefined;\n\tprivate selected: Selection | undefined;\n\tprivate hovered: Selection | undefined;\n\n\tconstructor(\n\t\tprivate readonly graphView: GraphViewState,\n\t\tprivate readonly callbacks: WorkbenchCallbacks,\n\t\tactions: FrameGraphDebugWorkbenchActions,\n\t\toptions: FrameGraphDebugWorkbenchOptions,\n\t) {\n\t\tthis.root.className = 'zenfg-inspector-workbench';\n\t\tthis.summary.className = 'zenfg-inspector-capture-summary';\n\t\tthis.commandBar.className = 'zenfg-inspector-workbench-command-bar';\n\t\tthis.brand.className = 'zenfg-inspector-brand';\n\t\tif (options.branding === false) this.commandBar.classList.add('branding-hidden');\n\t\telse this.brand.textContent = options.branding;\n\t\tthis.tabList.className = 'zenfg-inspector-workbench-tabs';\n\t\tthis.tabList.setAttribute('role', 'tablist');\n\t\tthis.tabList.setAttribute('aria-label', 'FrameGraph debug views');\n\t\tthis.commandActions.className = 'zenfg-inspector-workbench-actions';\n\t\tthis.commandActions.setAttribute('role', 'toolbar');\n\t\tthis.commandActions.setAttribute('aria-label', 'FrameGraph commands');\n\t\tthis.commandStatus.className = 'zenfg-inspector-command-status';\n\t\tthis.commandStatus.setAttribute('role', 'status');\n\t\tthis.commandStatus.setAttribute('aria-live', 'polite');\n\t\tthis.workspace.className = 'zenfg-inspector-workspace inspector-open';\n\t\tthis.main.className = 'zenfg-inspector-main';\n\t\tthis.emptyHost.className = 'zenfg-inspector-workbench-empty';\n\t\tthis.emptyHost.setAttribute('role', 'status');\n\t\tthis.emptyHost.setAttribute('aria-live', 'polite');\n\n\t\tthis.overviewRoot.className = 'zenfg-inspector-view zenfg-inspector-overview-view';\n\t\tthis.overviewRoot.id = `${options.idPrefix}-view-overview`;\n\t\tthis.overviewRoot.setAttribute('role', 'tabpanel');\n\t\tthis.overviewRoot.append(this.summary);\n\t\tthis.graphRoot.className = 'zenfg-inspector-view zenfg-inspector-graph-view';\n\t\tthis.graphRoot.id = `${options.idPrefix}-view-graph`;\n\t\tthis.graphRoot.setAttribute('role', 'tabpanel');\n\t\tthis.graphRoot.append(this.graphView.toolbar, this.graphView.host);\n\t\tthis.passes = new PassesView(callbacks, options.idPrefix);\n\t\tthis.resources = new ResourcesView(callbacks, options.idPrefix);\n\t\tthis.memory = new MemoryView(callbacks, options.idPrefix);\n\t\tthis.diagnostics = new DiagnosticsView(callbacks, options.idPrefix);\n\t\tthis.inspector = new InspectorView(callbacks, (open) => this.handleInspectorOpenChange(open), options.idPrefix);\n\n\t\tthis.views.set('overview', this.overviewRoot);\n\t\tthis.views.set('graph', this.graphRoot);\n\t\tthis.views.set('passes', this.passes.root);\n\t\tthis.views.set('resources', this.resources.root);\n\t\tthis.views.set('memory', this.memory.root);\n\t\tthis.views.set('diagnostics', this.diagnostics.root);\n\t\tfor (const [tab, label] of [\n\t\t\t['overview', 'Overview'],\n\t\t\t['graph', 'Graph'],\n\t\t\t['passes', 'Passes'],\n\t\t\t['resources', 'Resources'],\n\t\t\t['memory', 'Memory'],\n\t\t\t['diagnostics', 'Diagnostics'],\n\t\t] as const) {\n\t\t\tconst button = document.createElement('button');\n\t\t\tbutton.type = 'button';\n\t\t\tbutton.id = `${options.idPrefix}-tab-${tab}`;\n\t\t\tbutton.textContent = label;\n\t\t\tbutton.setAttribute('role', 'tab');\n\t\t\tbutton.setAttribute('aria-controls', `${options.idPrefix}-view-${tab}`);\n\t\t\tbutton.addEventListener('click', () => this.setActiveTab(tab));\n\t\t\tthis.tabButtons.set(tab, button);\n\t\t\tthis.tabList.appendChild(button);\n\t\t}\n\n\t\tthis.inspectorOpenButton.type = 'button';\n\t\tthis.inspectorOpenButton.hidden = true;\n\t\tthis.inspectorOpenButton.className = 'zenfg-inspector-open-inspector';\n\t\tsetPanelButtonContent(this.inspectorOpenButton, 'inspector', 'Inspector');\n\t\tthis.inspectorOpenButton.title = 'Open selection inspector';\n\t\tthis.inspectorOpenButton.addEventListener('click', () => this.inspector.setOpen(true));\n\n\t\tthis.captureButton.type = 'button';\n\t\tthis.captureButton.className = 'zenfg-inspector-capture-action';\n\t\tthis.captureButton.addEventListener('click', actions.onCapture);\n\t\tthis.importButton.type = 'button';\n\t\tthis.importButton.textContent = 'Import';\n\t\tthis.importButton.addEventListener('click', () => this.importInput.click());\n\t\tthis.importInput.type = 'file';\n\t\tthis.importInput.accept = '.fgsnapshot.json,.json,application/json';\n\t\tthis.importInput.hidden = true;\n\t\tthis.importInput.addEventListener('change', () => {\n\t\t\tconst file = this.importInput.files?.[0];\n\t\t\tthis.importInput.value = '';\n\t\t\tif (file) actions.onImport(file);\n\t\t});\n\t\tthis.exportButton.type = 'button';\n\t\tthis.exportButton.textContent = 'Export';\n\t\tthis.exportButton.setAttribute('aria-haspopup', 'menu');\n\t\tthis.exportButton.setAttribute('aria-expanded', 'false');\n\t\tthis.exportButton.setAttribute('aria-controls', `${options.idPrefix}-export-menu`);\n\t\tthis.exportButton.addEventListener('click', () => {\n\t\t\tthis.setExportMenuOpen(this.exportMenu.hidden !== false);\n\t\t});\n\t\tthis.exportMenu.className = 'zenfg-inspector-export-menu';\n\t\tthis.exportMenu.id = `${options.idPrefix}-export-menu`;\n\t\tthis.exportMenu.setAttribute('role', 'menu');\n\t\tthis.exportMenu.hidden = true;\n\t\tthis.downloadButton.type = 'button';\n\t\tthis.downloadButton.textContent = 'Download JSON';\n\t\tthis.downloadButton.setAttribute('role', 'menuitem');\n\t\tthis.downloadButton.addEventListener('click', () => {\n\t\t\tthis.setExportMenuOpen(false);\n\t\t\tactions.onDownload();\n\t\t});\n\t\tthis.copyButton.type = 'button';\n\t\tthis.copyButton.className = 'zenfg-inspector-copy-action';\n\t\tthis.copyButton.textContent = 'Copy JSON';\n\t\tthis.copyButton.setAttribute('role', 'menuitem');\n\t\tthis.copyButton.addEventListener('click', () => {\n\t\t\tthis.setExportMenuOpen(false);\n\t\t\tactions.onCopyJson();\n\t\t});\n\t\tthis.exportMenu.append(this.downloadButton, this.copyButton);\n\n\t\tthis.commandActions.append(\n\t\t\tthis.commandStatus,\n\t\t\tthis.inspectorOpenButton,\n\t\t\tthis.captureButton,\n\t\t\tthis.importButton,\n\t\t\tthis.exportButton,\n\t\t\tthis.importInput,\n\t\t);\n\t\tif (options.branding === false) this.commandBar.append(this.tabList, this.commandActions, this.exportMenu);\n\t\telse this.commandBar.append(this.brand, this.tabList, this.commandActions, this.exportMenu);\n\t\tthis.root.addEventListener('click', (event) => {\n\t\t\tconst target = event.target;\n\t\t\tif (!target || typeof (target as Node).nodeType !== 'number' || this.exportMenu.hidden) return;\n\t\t\tconst targetNode = target as Node;\n\t\t\tif (!this.exportButton.contains(targetNode) && !this.exportMenu.contains(targetNode)) this.setExportMenuOpen(false);\n\t\t});\n\t\tthis.root.addEventListener('keydown', (event) => {\n\t\t\tif (event.key !== 'Escape' || this.exportMenu.hidden) return;\n\t\t\tthis.setExportMenuOpen(false);\n\t\t\tthis.exportButton.focus();\n\t\t});\n\t\tthis.main.append(this.emptyHost, ...this.views.values());\n\t\tthis.workspace.append(this.main, this.inspector.root);\n\t\tthis.root.append(this.commandBar, this.workspace);\n\t\tthis.showEmptyState('empty', 'Drop a ZenFG Snapshot here or choose Import.', 'Files are processed locally in your browser.');\n\t\tthis.setSnapshotActionState({\n\t\t\tproviderAvailable: false,\n\t\t\thasCapture: false,\n\t\t\tcapturing: false,\n\t\t\timporting: false,\n\t\t\tcopying: false,\n\t\t\tcopied: false,\n\t\t});\n\t}\n\n\tsetSnapshot(snapshot: FrameGraphDebugViewModel, selected: Selection | undefined): void {\n\t\tthis.hasSnapshot = true;\n\t\tthis.snapshot = snapshot;\n\t\tthis.selected = selected;\n\t\tthis.hovered = undefined;\n\t\tthis.renderSummary(snapshot);\n\t\tthis.passes.setSnapshot(snapshot);\n\t\tthis.resources.setSnapshot(snapshot);\n\t\tthis.memory.setSnapshot(snapshot);\n\t\tthis.diagnostics.setSnapshot(snapshot);\n\t\tthis.inspector.setSnapshot(snapshot);\n\t\tthis.passes.setSelection(selected);\n\t\tthis.resources.setSelection(selected);\n\t\tthis.memory.setSelection(selected);\n\t\tthis.diagnostics.setSelection(selected);\n\t\tthis.inspector.setSelection(selected, false);\n\t\tthis.emptyHost.hidden = true;\n\t\tthis.updateActiveTab();\n\t\tthis.updateWorkspaceState();\n\t\tif (this.activeTab === 'graph') this.renderGraph();\n\t}\n\n\tshowEmptyState(kind: FrameGraphDebugEmptyStateKind, message: string, detail?: string): void {\n\t\tthis.hasSnapshot = false;\n\t\tthis.snapshot = undefined;\n\t\tthis.selected = undefined;\n\t\tthis.hovered = undefined;\n\t\tthis.emptyHost.hidden = false;\n\t\tthis.emptyHost.dataset.state = kind;\n\t\tconst icon = createPanelIcon(kind === 'capturing' ? 'spinner' : kind === 'error' ? 'error' : kind === 'waiting' ? 'waiting' : 'empty');\n\t\tconst label = document.createElement('span');\n\t\tlabel.className = 'zenfg-inspector-empty-message';\n\t\tlabel.textContent = message;\n\t\tconst detailLabel = document.createElement('span');\n\t\tdetailLabel.className = 'zenfg-inspector-empty-detail';\n\t\tdetailLabel.textContent = detail ?? '';\n\t\tthis.emptyHost.replaceChildren(icon, label, ...(detail ? [detailLabel] : []));\n\t\tthis.updateActiveTab();\n\t\tthis.updateWorkspaceState();\n\t}\n\n\tsetSnapshotActionState(state: FrameGraphDebugSnapshotActionState): void {\n\t\tconst captureLabel = state.capturing ? 'Capturing…' : 'Capture';\n\t\tsetPanelButtonContent(this.captureButton, state.capturing ? 'spinner' : 'capture', captureLabel);\n\t\tthis.captureButton.disabled = state.capturing || !state.providerAvailable;\n\t\tthis.captureButton.hidden = !state.providerAvailable;\n\t\tthis.captureButton.classList.toggle('active', state.capturing);\n\t\tthis.captureButton.setAttribute('aria-busy', state.capturing ? 'true' : 'false');\n\t\tthis.captureButton.dataset.tone = state.capturing ? 'pending' : 'accent';\n\t\tthis.captureButton.title = !state.providerAvailable\n\t\t\t? 'Waiting for a FrameGraph capture source.'\n\t\t\t: state.capturing\n\t\t\t\t? 'Capturing the next rendered frame.'\n\t\t\t\t: 'Capture and display the next rendered frame.';\n\n\t\tthis.importButton.textContent = state.importing ? 'Importing…' : 'Import';\n\t\tthis.importButton.disabled = state.importing;\n\t\tthis.importButton.setAttribute('aria-busy', state.importing ? 'true' : 'false');\n\t\tthis.exportButton.disabled = !state.hasCapture;\n\t\tthis.downloadButton.disabled = !state.hasCapture;\n\t\tif (!state.hasCapture) this.setExportMenuOpen(false);\n\n\t\tconst copyLabel = state.copying ? 'Copying…' : state.copied ? 'Copied' : 'Copy JSON';\n\t\tconst copyIcon = state.copying ? 'spinner' : state.copied ? 'check' : 'copy';\n\t\tsetPanelButtonContent(this.copyButton, copyIcon, copyLabel);\n\t\tthis.copyButton.disabled = !state.hasCapture || state.copying;\n\t\tthis.copyButton.classList.toggle('active', state.copying || state.copied);\n\t\tthis.copyButton.setAttribute('aria-busy', state.copying ? 'true' : 'false');\n\t\tthis.copyButton.dataset.tone = state.copied ? 'success' : state.copying ? 'pending' : 'neutral';\n\t\tthis.copyButton.title = state.hasCapture\n\t\t\t? 'Copy the current canonical FrameGraph Snapshot JSON.'\n\t\t\t: 'Load a snapshot before exporting.';\n\n\t\tthis.commandStatus.textContent = state.message ?? '';\n\t\tthis.commandStatus.hidden = !state.message;\n\t\tthis.commandStatus.dataset.tone = state.message ? state.messageTone ?? 'error' : 'neutral';\n\t\tif (state.message) this.commandStatus.title = state.message;\n\t\telse this.commandStatus.removeAttribute('title');\n\t}\r\n\n\tsetSelection(selected: Selection | undefined): void {\n\t\tthis.selected = selected;\n\t\tthis.passes.setSelection(selected);\n\t\tthis.resources.setSelection(selected);\n\t\tthis.memory.setSelection(selected);\n\t\tthis.diagnostics.setSelection(selected);\n\t\tthis.inspector.setSelection(selected);\n\t\tif (this.activeTab === 'graph') this.renderGraph();\n\t}\n\n\tsetHovered(hovered: Selection | undefined): void {\n\t\tthis.hovered = hovered;\n\t\tif (this.activeTab === 'graph') this.renderGraph();\n\t}\n\n\tsetActiveTab(tab: WorkbenchTab): void {\n\t\tif (this.activeTab === tab) return;\n\t\tthis.activeTab = tab;\n\t\tthis.updateActiveTab();\n\t\tif (tab === 'graph') {\n\t\t\twindow.requestAnimationFrame(() => {\n\t\t\t\tresizeGraph(this.graphView);\n\t\t\t\tthis.renderGraph();\n\t\t\t});\n\t\t}\n\t}\n\n\trefreshGraphStructure(): void {\n\t\tif (!this.snapshot) return;\n\t\tthis.passes.setSnapshot(this.snapshot);\n\t\tif (this.activeTab === 'graph') this.renderGraph();\n\t}\n\n\tresizeGraph(fit = false): void {\n\t\tif (fit) this.graphView.fitOnNextRender = true;\n\t\twindow.requestAnimationFrame(() => {\n\t\t\tresizeGraph(this.graphView);\n\t\t\tif (this.activeTab === 'graph') this.renderGraph();\n\t\t});\n\t}\n\n\tprivate updateActiveTab(): void {\n\t\tfor (const [tab, button] of this.tabButtons) {\n\t\t\tconst active = tab === this.activeTab;\n\t\t\tbutton.disabled = !this.hasSnapshot;\n\t\t\tbutton.classList.toggle('active', active);\n\t\t\tbutton.setAttribute('aria-selected', active ? 'true' : 'false');\n\t\t\tconst view = this.views.get(tab)!;\n\t\t\tview.hidden = !this.hasSnapshot || !active;\n\t\t\tview.setAttribute('aria-labelledby', button.id);\n\t\t}\n\t}\n\n\tprivate renderGraph(): void {\n\t\tif (!this.snapshot) return;\n\t\trenderGraphView(\n\t\t\tthis.graphView,\n\t\t\tthis.snapshot,\n\t\t\tthis.selected,\n\t\t\tthis.hovered,\n\t\t\tthis.callbacks.onSelect,\n\t\t\tthis.callbacks.onHover,\n\t\t\tthis.callbacks.onGroupToggle,\n\t\t);\n\t}\n\n\tprivate renderSummary(snapshot: FrameGraphDebugViewModel): void {\n\t\tconst frameGraphSegments = snapshot.executionSegments.filter((segment) => segment.kind === 'frame-graph').length;\n\t\tconst opaqueIntervals = snapshot.executionSegments.length - frameGraphSegments;\n\t\tconst metrics = snapshot.metrics;\n\t\tconst coverage = metrics.timingEligibleNodeCount === 0\n\t\t\t? 'No eligible passes'\n\t\t\t: `${metrics.timedNodeCount}/${metrics.timingEligibleNodeCount} timed`;\n\t\tconst slowest = metrics.slowestNode\n\t\t\t? `${labelNode(metrics.slowestNode)} · ${(metrics.slowestNode.gpuDurationMicros! / 1000).toFixed(3)} ms`\n\t\t\t: 'Unknown';\n\t\tconst protocol = snapshot.protocol;\n\t\tconst runtime = protocol.producer.runtime;\n\t\tconst producer = [\n\t\t\tprotocol.producer.name,\n\t\t\tprotocol.producer.version,\n\t\t\tprotocol.producer.language,\n\t\t].filter(Boolean).join(' · ');\n\t\tconst runtimeLabel = runtime\n\t\t\t? [runtime.implementation, runtime.graphicsApi, runtime.backend].filter(Boolean).join(' · ') || 'Unknown'\n\t\t\t: 'Unknown';\n\t\tconst poolRetained = snapshot.resourcePool.status === 'available'\n\t\t\t? `${snapshot.resourcePool.estimatedRetainedBytes === undefined ? 'Unknown' : formatBytes(snapshot.resourcePool.estimatedRetainedBytes)} · ${snapshot.resourcePool.retainedCount} allocations`\n\t\t\t: 'Unavailable';\n\t\tthis.summary.replaceChildren(\n\t\t\tthis.createSummaryGroup('Capture', [\n\t\t\t\t['Source', snapshot.source.label],\n\t\t\t\t['Schema', `${protocol.format} v${protocol.version.major}.${protocol.version.minor}`],\n\t\t\t\t['Producer', producer],\n\t\t\t\t['Runtime', runtimeLabel],\n\t\t\t\t['Frame', String(snapshot.frameIndex)],\n\t\t\t\t...(snapshot.source.migratedFromLegacy ? [['Migration', 'Legacy V0 → V1'] as const] : []),\n\t\t\t\t['Timing', snapshot.profiling.status === 'available' ? 'Available' : snapshot.profiling.reason],\n\t\t\t]),\n\t\t\tthis.createSummaryGroup('GPU', [\n\t\t\t\t['GPU Span', snapshot.profiling.status === 'available' ? `${formatGpuFrameDuration(snapshot)} ms` : 'Unknown'],\n\t\t\t\t['Coverage', coverage],\n\t\t\t\t['Slowest', slowest],\n\t\t\t]),\n\t\t\tthis.createSummaryGroup('Work', [\n\t\t\t\t['Nodes', `${snapshot.nodes.length} retained · ${snapshot.culledNodes.length} culled`],\n\t\t\t\t['Segments', `${frameGraphSegments} FG · ${opaqueIntervals} opaque`],\n\t\t\t\t['Groups', snapshot.availability.groups ? String(snapshot.debugGroups.length) : 'Unknown'],\n\t\t\t\t['Recording order', snapshot.availability.recordingOrder ? 'Available' : 'Unknown'],\n\t\t\t]),\n\t\t\tthis.createSummaryGroup('Resources', [\n\t\t\t\t['Logical / physical', `${snapshot.resources.length} / ${snapshot.physicalAllocations.length}`],\n\t\t\t\t['Texture views', snapshot.availability.textureViews ? String(snapshot.textureViewById.size) : 'Unknown'],\n\t\t\t\t['Access regions', snapshot.availability.accessRegions ? 'Available' : 'Unknown'],\n\t\t\t\t['Transient estimate', formatEstimatedBytes(metrics.transientEstimatedByteSize)],\n\t\t\t]),\n\t\t\tthis.createSummaryGroup('Pool', [\n\t\t\t\t['Retained', poolRetained],\n\t\t\t\t['Reuse', formatPoolHitRate(snapshot)],\n\t\t\t]),\n\t\t);\n\t}\n\n\tprivate createSummaryGroup(title: string, rows: readonly (readonly [string, string])[]): HTMLElement {\n\t\tconst group = document.createElement('section');\n\t\tconst heading = document.createElement('h2');\n\t\theading.textContent = title;\n\t\tgroup.appendChild(heading);\n\t\tfor (const [label, value] of rows) {\n\t\t\tconst row = document.createElement('div');\n\t\t\tconst term = document.createElement('span');\n\t\t\tterm.textContent = label;\n\t\t\tconst description = document.createElement('strong');\n\t\t\tdescription.textContent = value;\n\t\t\tdescription.title = value;\n\t\t\trow.append(term, description);\n\t\t\tgroup.appendChild(row);\n\t\t}\n\t\treturn group;\n\t}\n\n\tprivate setExportMenuOpen(open: boolean): void {\n\t\tthis.exportMenu.hidden = !open;\n\t\tthis.exportButton.setAttribute('aria-expanded', open ? 'true' : 'false');\n\t}\n\n\tprivate handleInspectorOpenChange(_open: boolean): void {\n\t\tthis.updateWorkspaceState();\n\t\tif (this.activeTab === 'graph') this.resizeGraph(false);\n\t}\n\n\tprivate updateWorkspaceState(): void {\n\t\tconst inspectorOpen = this.hasSnapshot && this.inspector.isOpen;\n\t\tthis.workspace.classList.toggle('has-capture', this.hasSnapshot);\n\t\tthis.workspace.classList.toggle('inspector-open', inspectorOpen);\n\t\tthis.inspector.root.classList.toggle('unavailable', !this.hasSnapshot);\n\t\tthis.inspectorOpenButton.hidden = !this.hasSnapshot || inspectorOpen;\n\t}\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /** Query-string flag recognized by {@link isZenFGInspectorRequested}. */
2
+ export declare const ZENFG_INSPECTOR_QUERY_PARAM = "fg";
3
+ /**
4
+ * Reports whether a URL contains the `fg` inspector opt-in parameter.
5
+ *
6
+ * @param href - Absolute URL accepted by `URL`; defaults to the current page
7
+ * URL when a browser location is available.
8
+ * @returns `false` when no URL is available or the supplied URL is invalid.
9
+ */
10
+ export declare function isZenFGInspectorRequested(href?: string): boolean;
11
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAEhD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,SAA4B,GAAG,OAAO,CAWnF"}
package/dist/query.js ADDED
@@ -0,0 +1,21 @@
1
+ /** Query-string flag recognized by {@link isZenFGInspectorRequested}. */
2
+ export const ZENFG_INSPECTOR_QUERY_PARAM = 'fg';
3
+ /**
4
+ * Reports whether a URL contains the `fg` inspector opt-in parameter.
5
+ *
6
+ * @param href - Absolute URL accepted by `URL`; defaults to the current page
7
+ * URL when a browser location is available.
8
+ * @returns `false` when no URL is available or the supplied URL is invalid.
9
+ */
10
+ export function isZenFGInspectorRequested(href = globalThis.location?.href) {
11
+ if (!href) {
12
+ return false;
13
+ }
14
+ try {
15
+ return new URL(href).searchParams.has(ZENFG_INSPECTOR_QUERY_PARAM);
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI;IACtE,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,IAAI,CAAC;QACD,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,CAAC;QACH,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC","sourcesContent":["/** Query-string flag recognized by {@link isZenFGInspectorRequested}. */\nexport const ZENFG_INSPECTOR_QUERY_PARAM = 'fg';\n\n/**\n * Reports whether a URL contains the `fg` inspector opt-in parameter.\n *\n * @param href - Absolute URL accepted by `URL`; defaults to the current page\n * URL when a browser location is available.\n * @returns `false` when no URL is available or the supplied URL is invalid.\n */\nexport function isZenFGInspectorRequested(href = globalThis.location?.href): boolean {\n if (!href) {\r\n return false;\r\n }\r\n\r\n try {\r\n return new URL(href).searchParams.has(ZENFG_INSPECTOR_QUERY_PARAM);\r\n }\r\n catch {\r\n return false;\r\n }\r\n}\r\n"]}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Installs the inspector's shared stylesheet in the current document once.
3
+ *
4
+ * @remarks This is safe to call repeatedly and is a no-op during server-side
5
+ * rendering. `FrameGraphInspector` calls it automatically.
6
+ */
7
+ export declare function ensureFrameGraphInspectorStyles(): void;
8
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAoiCA;;;;;GAKG;AACH,wBAAgB,+BAA+B,IAAI,IAAI,CAStD"}