aurasu 0.1.0 → 0.1.2

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.
@@ -0,0 +1,14 @@
1
+ function hasMethod(obj, method) {
2
+ return Boolean(obj) && typeof obj[method] === 'function';
3
+ }
4
+
5
+ export function assertRuntimeCapabilities() {
6
+ const missing = [];
7
+ if (!hasMethod(aura.draw2d, 'clear')) missing.push('aura.draw2d.clear');
8
+ if (!hasMethod(aura.draw2d, 'rect')) missing.push('aura.draw2d.rect');
9
+ if (typeof aura.rgba !== 'function') missing.push('aura.rgba');
10
+
11
+ if (missing.length > 0) {
12
+ throw new Error(`[authored-project] runtime missing required APIs: ${missing.join(', ')} [reason:missing_runtime_api]`);
13
+ }
14
+ }
@@ -0,0 +1,615 @@
1
+ // Project Inspector overlay for registry-backed authored projects.
2
+ import projectRegistry from './project-registry.js';
3
+ import { ensureUiState } from './app-state.js';
4
+
5
+ const PROJECT_INSPECTOR_SCHEMA = "aurajs.project-inspector.v1";
6
+ const PROJECT_INSPECTOR_TOGGLE_KEY = 'F1';
7
+ const HUD_MARGIN = 12;
8
+ const HUD_PADDING = 10;
9
+ const HUD_ROW_GAP = 8;
10
+ const HUD_SCENE_ROW_HEIGHT = 28;
11
+ const HUD_TOOLBAR_ROW_HEIGHT = 28;
12
+ const HUD_CHIP_GAP = 8;
13
+ const HUD_MINIMIZED_HEIGHT = 30;
14
+ const HUD_MINIMIZED_WIDTH = 260;
15
+ const HUD_MINIMIZED_MAX_WIDTH = 420;
16
+
17
+ function summarizeEntries(entries, formatter) {
18
+ const list = Array.isArray(entries) ? entries : [];
19
+ if (list.length === 0) return '(none)';
20
+ return list.map((entry) => formatter(entry)).join(', ');
21
+ }
22
+
23
+ function hasMethod(obj, method) {
24
+ return Boolean(obj) && typeof obj[method] === 'function';
25
+ }
26
+
27
+ function getRuntime() {
28
+ return globalThis.aura || null;
29
+ }
30
+
31
+ function getWindowSize() {
32
+ const runtime = getRuntime();
33
+ if (hasMethod(runtime?.window, 'getSize')) {
34
+ return runtime.window.getSize();
35
+ }
36
+ return { width: 1280, height: 720 };
37
+ }
38
+
39
+ function inputIsKeyPressed(input, key) {
40
+ return hasMethod(input, 'isKeyPressed') && input.isKeyPressed(String(key || '').toLowerCase());
41
+ }
42
+
43
+ function mousePressed(input, name = 'left', fallbackIndex = 0) {
44
+ if (hasMethod(input?.mouse, 'isPressed')) {
45
+ return input.mouse.isPressed(name);
46
+ }
47
+ if (hasMethod(input, 'isMousePressed')) {
48
+ return input.isMousePressed(fallbackIndex);
49
+ }
50
+ return false;
51
+ }
52
+
53
+ function mousePosition(input) {
54
+ if (hasMethod(input, 'getMousePosition')) {
55
+ const point = input.getMousePosition();
56
+ return {
57
+ x: Number.isFinite(point?.x) ? Number(point.x) : 0,
58
+ y: Number.isFinite(point?.y) ? Number(point.y) : 0,
59
+ };
60
+ }
61
+ return {
62
+ x: Number.isFinite(input?.mouse?.x) ? Number(input.mouse.x) : 0,
63
+ y: Number.isFinite(input?.mouse?.y) ? Number(input.mouse.y) : 0,
64
+ };
65
+ }
66
+
67
+ function pointInRect(point, rect) {
68
+ if (!point || !rect) return false;
69
+ return point.x >= rect.x
70
+ && point.x <= rect.x + rect.width
71
+ && point.y >= rect.y
72
+ && point.y <= rect.y + rect.height;
73
+ }
74
+
75
+ function approximateChipWidth(label) {
76
+ return Math.max(76, 18 + (String(label || '').length * 8));
77
+ }
78
+
79
+ function hudStatusFlags(snapshot) {
80
+ const flags = [];
81
+ if (snapshot.recording?.active === true) {
82
+ flags.push('REC');
83
+ }
84
+ if (snapshot.paused === true) {
85
+ flags.push('PAUSED');
86
+ }
87
+ return flags;
88
+ }
89
+
90
+ function buildMinimizedHudLabel(snapshot) {
91
+ const parts = [
92
+ `${PROJECT_INSPECTOR_TOGGLE_KEY} Play HUD`,
93
+ snapshot.activeSceneId || '(none)',
94
+ ...hudStatusFlags(snapshot),
95
+ ];
96
+ return parts.join(' • ');
97
+ }
98
+
99
+ function buildExpandedHudStatusLabel(snapshot) {
100
+ const parts = [
101
+ `Scene ${snapshot.activeSceneId || '(none)'}`,
102
+ snapshot.theme?.presetId ? `Theme ${snapshot.theme.presetId}` : null,
103
+ ...hudStatusFlags(snapshot),
104
+ ].filter(Boolean);
105
+ return parts.join(' • ');
106
+ }
107
+
108
+ function buildToolbarActions({
109
+ canRecord = false,
110
+ recordingActive = false,
111
+ canScreenshot = false,
112
+ canRestartScene = false,
113
+ canRestartApp = false,
114
+ canPause = false,
115
+ paused = false,
116
+ } = {}) {
117
+ return [
118
+ {
119
+ id: 'record',
120
+ label: recordingActive ? 'Stop Rec' : 'Record',
121
+ enabled: canRecord,
122
+ active: recordingActive,
123
+ },
124
+ {
125
+ id: 'screenshot',
126
+ label: 'Screenshot',
127
+ enabled: canScreenshot,
128
+ active: false,
129
+ },
130
+ {
131
+ id: 'restart-scene',
132
+ label: 'Restart Scene',
133
+ enabled: canRestartScene,
134
+ active: false,
135
+ },
136
+ {
137
+ id: 'restart-app',
138
+ label: 'Restart App',
139
+ enabled: canRestartApp,
140
+ active: false,
141
+ },
142
+ {
143
+ id: 'pause',
144
+ label: paused ? 'Resume' : 'Pause',
145
+ enabled: canPause,
146
+ active: paused,
147
+ },
148
+ {
149
+ id: 'minimize',
150
+ label: 'Minimize',
151
+ enabled: true,
152
+ active: false,
153
+ },
154
+ ];
155
+ }
156
+
157
+ function drawChip(draw2d, colorFactory, chip, options = {}) {
158
+ const enabled = chip.enabled !== false;
159
+ const active = options.active === true;
160
+ const background = !enabled
161
+ ? colorFactory(0.18, 0.2, 0.24, 0.72)
162
+ : active
163
+ ? colorFactory(0.28, 0.54, 0.92, 0.94)
164
+ : colorFactory(0.11, 0.15, 0.2, 0.92);
165
+ const border = !enabled
166
+ ? colorFactory(0.28, 0.3, 0.34, 0.94)
167
+ : active
168
+ ? colorFactory(0.94, 0.82, 0.32, 0.96)
169
+ : colorFactory(0.38, 0.76, 1, 0.82);
170
+ const textColor = !enabled
171
+ ? colorFactory(0.62, 0.66, 0.72, 0.92)
172
+ : colorFactory(0.96, 0.98, 1, 1);
173
+
174
+ draw2d.rect(chip.x, chip.y, chip.width, chip.height, background);
175
+ draw2d.rect(chip.x, chip.y, chip.width, 2, border);
176
+ draw2d.text(chip.label, chip.x + 10, chip.y + 7, {
177
+ size: 12,
178
+ color: textColor,
179
+ });
180
+ }
181
+
182
+ function drawSceneStrip(draw2d, colorFactory, snapshot, panelX, panelY, panelWidth, uiState = null) {
183
+ const chips = [];
184
+ let x = panelX + HUD_PADDING;
185
+ const y = panelY + 22;
186
+ const maxX = panelX + panelWidth - HUD_PADDING;
187
+ const scenes = Array.isArray(snapshot.scenes) ? snapshot.scenes : [];
188
+ for (const scene of scenes) {
189
+ const label = scene.id || '(scene)';
190
+ const width = approximateChipWidth(label);
191
+ if (x + width > maxX) {
192
+ const remaining = scenes.length - chips.length;
193
+ if (remaining > 0) {
194
+ const overflowLabel = '+' + String(remaining);
195
+ const overflowWidth = approximateChipWidth(overflowLabel);
196
+ chips.push({
197
+ id: '__overflow__',
198
+ label: overflowLabel,
199
+ x,
200
+ y,
201
+ width: Math.min(overflowWidth, Math.max(60, maxX - x)),
202
+ height: HUD_SCENE_ROW_HEIGHT,
203
+ enabled: false,
204
+ active: false,
205
+ });
206
+ }
207
+ break;
208
+ }
209
+ chips.push({
210
+ id: scene.id,
211
+ label,
212
+ x,
213
+ y,
214
+ width,
215
+ height: HUD_SCENE_ROW_HEIGHT,
216
+ enabled: true,
217
+ active: scene.active === true,
218
+ });
219
+ x += width + HUD_CHIP_GAP;
220
+ }
221
+
222
+ for (const chip of chips) {
223
+ drawChip(draw2d, colorFactory, chip, { active: chip.active });
224
+ }
225
+ if (uiState) {
226
+ uiState.sceneChips = chips.map((chip) => ({ ...chip }));
227
+ }
228
+ }
229
+
230
+ function layoutToolbar(snapshot, panelX, panelY, panelWidth) {
231
+ const buttons = [];
232
+ let x = panelX + HUD_PADDING;
233
+ const y = panelY + 22 + HUD_SCENE_ROW_HEIGHT + HUD_ROW_GAP;
234
+ const maxX = panelX + panelWidth - HUD_PADDING;
235
+ const actions = Array.isArray(snapshot.toolbarActions) ? snapshot.toolbarActions : [];
236
+ for (const action of actions) {
237
+ const width = approximateChipWidth(action.label);
238
+ if (x + width > maxX) break;
239
+ buttons.push({
240
+ id: action.id,
241
+ label: action.label,
242
+ enabled: action.enabled !== false,
243
+ active: action.active === true,
244
+ x,
245
+ y,
246
+ width,
247
+ height: HUD_TOOLBAR_ROW_HEIGHT,
248
+ });
249
+ x += width + HUD_CHIP_GAP;
250
+ }
251
+ return buttons;
252
+ }
253
+
254
+ function drawProjectInspectorOverlay(snapshot, uiState) {
255
+ const runtime = getRuntime();
256
+ if (!runtime?.draw2d || typeof runtime.draw2d.rect !== 'function' || typeof runtime.draw2d.text !== 'function' || typeof runtime.rgba !== 'function') {
257
+ return;
258
+ }
259
+
260
+ const windowSize = getWindowSize();
261
+ const panelX = HUD_MARGIN;
262
+ const panelY = HUD_MARGIN;
263
+ const panelWidth = Math.max(420, Math.min(1240, Number(windowSize?.width || 1280) - (HUD_MARGIN * 2)));
264
+
265
+ if (snapshot.presentation === 'minimized') {
266
+ const label = buildMinimizedHudLabel(snapshot);
267
+ const chip = {
268
+ x: panelX,
269
+ y: panelY,
270
+ width: Math.min(HUD_MINIMIZED_MAX_WIDTH, Math.max(HUD_MINIMIZED_WIDTH, approximateChipWidth(label) + 22)),
271
+ height: HUD_MINIMIZED_HEIGHT,
272
+ label,
273
+ enabled: true,
274
+ active: snapshot.paused === true || snapshot.recording?.active === true,
275
+ };
276
+ drawChip(runtime.draw2d, runtime.rgba, chip, { active: chip.active });
277
+ uiState.minimizedChip = chip;
278
+ uiState.toolbarButtons = [];
279
+ uiState.sceneChips = [];
280
+ return;
281
+ }
282
+
283
+ const panelHeight = 22 + HUD_SCENE_ROW_HEIGHT + HUD_ROW_GAP + HUD_TOOLBAR_ROW_HEIGHT + HUD_PADDING;
284
+
285
+ runtime.draw2d.rect(panelX, panelY, panelWidth, panelHeight, runtime.rgba(0.03, 0.05, 0.08, 0.92));
286
+ runtime.draw2d.rect(panelX, panelY, panelWidth, 3, runtime.rgba(0.38, 0.76, 1.0, 0.92));
287
+ runtime.draw2d.text(`${PROJECT_INSPECTOR_TOGGLE_KEY} Play HUD`, panelX + HUD_PADDING, panelY + 6, {
288
+ size: 13,
289
+ color: runtime.rgba(1, 0.97, 0.86, 1),
290
+ });
291
+ runtime.draw2d.text(buildExpandedHudStatusLabel(snapshot), panelX + panelWidth - 240, panelY + 6, {
292
+ size: 12,
293
+ color: runtime.rgba(0.88, 0.94, 1, 1),
294
+ });
295
+
296
+ drawSceneStrip(runtime.draw2d, runtime.rgba, snapshot, panelX, panelY, panelWidth, uiState);
297
+ uiState.toolbarButtons = layoutToolbar(snapshot, panelX, panelY, panelWidth);
298
+ for (const button of uiState.toolbarButtons) {
299
+ drawChip(runtime.draw2d, runtime.rgba, button, { active: button.active });
300
+ }
301
+ uiState.minimizedChip = null;
302
+ }
303
+
304
+ export function buildProjectInspectorSnapshot({
305
+ projectTitle = null,
306
+ sceneRegistry = null,
307
+ getActiveSceneId = null,
308
+ appState = null,
309
+ getUiThemeState = null,
310
+ enabled = false,
311
+ minimized = false,
312
+ paused = false,
313
+ recording = null,
314
+ actions = null,
315
+ } = {}) {
316
+ const activeSceneId = typeof getActiveSceneId === 'function' ? getActiveSceneId() : null;
317
+ const registryScenes = Array.isArray(projectRegistry.scenes) ? projectRegistry.scenes : [];
318
+ const registryScreens = Array.isArray(projectRegistry.screens) ? projectRegistry.screens : [];
319
+ const registryPrefabs = Array.isArray(projectRegistry.prefabs) ? projectRegistry.prefabs : [];
320
+ const registryDataFiles = Array.isArray(projectRegistry.dataFiles) ? projectRegistry.dataFiles : [];
321
+ const runtimeSceneIds = sceneRegistry && typeof sceneRegistry === 'object' && sceneRegistry.scenes
322
+ ? Object.keys(sceneRegistry.scenes)
323
+ : [];
324
+ const sessionState = appState && typeof appState?.session === 'object' && !Array.isArray(appState.session)
325
+ ? appState.session
326
+ : {};
327
+ const uiState = appState && typeof appState?.ui === 'object' && !Array.isArray(appState.ui)
328
+ ? appState.ui
329
+ : {};
330
+ const runtimeState = appState && typeof appState?.runtime === 'object' && !Array.isArray(appState.runtime)
331
+ ? appState.runtime
332
+ : {};
333
+ const themeState = typeof getUiThemeState === 'function' ? getUiThemeState() : null;
334
+ const uiPreferences = uiState.preferences && typeof uiState.preferences === 'object' && !Array.isArray(uiState.preferences)
335
+ ? cloneProjectValue(uiState.preferences)
336
+ : null;
337
+
338
+ return {
339
+ schema: PROJECT_INSPECTOR_SCHEMA,
340
+ template: projectRegistry.template || 'blank',
341
+ projectTitle: projectTitle || projectRegistry.projectTitle || 'AuraJS Game',
342
+ enabled: enabled === true,
343
+ presentation: minimized === true ? 'minimized' : 'expanded',
344
+ toggleKey: PROJECT_INSPECTOR_TOGGLE_KEY,
345
+ sourceOfTruth: 'src/runtime/project-registry.js',
346
+ startSceneId: projectRegistry.startSceneId || null,
347
+ activeSceneId: activeSceneId || null,
348
+ paused: paused === true,
349
+ recording: recording && typeof recording === 'object'
350
+ ? {
351
+ supported: recording.supported === true,
352
+ active: recording.active === true,
353
+ }
354
+ : {
355
+ supported: false,
356
+ active: false,
357
+ },
358
+ runtimeSceneIds,
359
+ appStateKeys: appState && typeof appState === 'object' && !Array.isArray(appState)
360
+ ? Object.keys(appState).sort()
361
+ : [],
362
+ appStateBuckets: ['session', 'ui', 'runtime'],
363
+ sessionKeys: Object.keys(sessionState).sort(),
364
+ uiKeys: Object.keys(uiState).sort(),
365
+ runtimeKeys: Object.keys(runtimeState).sort(),
366
+ uiPreferencesPath: 'appState.ui.preferences',
367
+ uiPreferences,
368
+ theme: themeState && typeof themeState === 'object'
369
+ ? {
370
+ presetId: typeof themeState.presetId === 'string' ? themeState.presetId : null,
371
+ presetLabel: typeof themeState.presetLabel === 'string' ? themeState.presetLabel : null,
372
+ density: typeof themeState.density === 'string' ? themeState.density : null,
373
+ contrast: typeof themeState.contrast === 'string' ? themeState.contrast : null,
374
+ availableThemeIds: Array.isArray(themeState.availableThemeIds) ? [...themeState.availableThemeIds] : [],
375
+ }
376
+ : null,
377
+ mountedScreens: {
378
+ hud: typeof runtimeState.hudScreenId === 'string' ? runtimeState.hudScreenId : null,
379
+ overlay: typeof runtimeState.overlayScreenId === 'string' ? runtimeState.overlayScreenId : null,
380
+ modals: Array.isArray(runtimeState.modalScreenIds) ? [...runtimeState.modalScreenIds] : [],
381
+ },
382
+ stateOwnership: {
383
+ engineApi: 'aura',
384
+ sharedSession: 'appState.session',
385
+ sharedUi: 'appState.ui',
386
+ sharedUiPreferences: 'appState.ui.preferences',
387
+ runtimeFacts: 'appState.runtime',
388
+ sceneLocal: 'sceneState',
389
+ sceneEntryPayload: 'sceneFlow.current.data',
390
+ screenPayloads: 'screenShell.hud|overlay|modals[].data',
391
+ themeModule: 'src/runtime/ui-theme.js',
392
+ retainedSettingsHelpers: 'src/runtime/ui-settings.js',
393
+ authoredInput: 'config/* and content/*',
394
+ },
395
+ scenes: registryScenes.map((entry) => ({
396
+ id: entry.id,
397
+ path: entry.path,
398
+ active: entry.id === activeSceneId,
399
+ })),
400
+ screens: registryScreens.map((entry) => ({
401
+ id: entry.id,
402
+ path: entry.path,
403
+ })),
404
+ prefabs: registryPrefabs.map((entry) => ({
405
+ id: entry.id,
406
+ role: entry.role || null,
407
+ path: entry.path,
408
+ })),
409
+ dataFiles: [...registryDataFiles],
410
+ toolbarActions: Array.isArray(actions) ? actions.map((entry) => ({ ...entry })) : [],
411
+ };
412
+ }
413
+
414
+ export function createProjectInspector({
415
+ projectTitle = null,
416
+ sceneRegistry = null,
417
+ getActiveSceneId = null,
418
+ appState = null,
419
+ getUiThemeState = null,
420
+ onSelectScene = null,
421
+ onRestartScene = null,
422
+ onRestartApp = null,
423
+ getPaused = null,
424
+ togglePaused = null,
425
+ getRecordingState = null,
426
+ toggleRecording = null,
427
+ } = {}) {
428
+ const playHudState = ensureUiState(appState, 'playHud', {
429
+ enabled: false,
430
+ minimized: false,
431
+ });
432
+ let enabled = playHudState.enabled === true;
433
+ let minimized = playHudState.minimized === true;
434
+ let pointerPressedLastFrame = false;
435
+ const uiState = {
436
+ sceneChips: [],
437
+ toolbarButtons: [],
438
+ minimizedChip: null,
439
+ };
440
+
441
+ function syncPlayHudState() {
442
+ playHudState.enabled = enabled === true;
443
+ playHudState.minimized = minimized === true;
444
+ }
445
+
446
+ function recordingState() {
447
+ if (typeof getRecordingState !== 'function') {
448
+ return { supported: false, active: false };
449
+ }
450
+ const state = getRecordingState();
451
+ return {
452
+ supported: state?.supported === true,
453
+ active: state?.active === true,
454
+ };
455
+ }
456
+
457
+ function currentActions() {
458
+ const runtime = getRuntime();
459
+ return buildToolbarActions({
460
+ canRecord: typeof toggleRecording === 'function' && recordingState().supported === true,
461
+ recordingActive: recordingState().active === true,
462
+ canScreenshot: hasMethod(runtime?.window, 'screenshot'),
463
+ canRestartScene: typeof onRestartScene === 'function',
464
+ canRestartApp: typeof onRestartApp === 'function',
465
+ canPause: typeof togglePaused === 'function',
466
+ paused: typeof getPaused === 'function' ? getPaused() === true : false,
467
+ });
468
+ }
469
+
470
+ function runToolbarAction(actionId) {
471
+ const runtime = getRuntime();
472
+ switch (actionId) {
473
+ case 'record':
474
+ if (typeof toggleRecording === 'function') {
475
+ toggleRecording();
476
+ }
477
+ return true;
478
+ case 'screenshot':
479
+ if (hasMethod(runtime?.window, 'screenshot')) {
480
+ runtime.window.screenshot();
481
+ return true;
482
+ }
483
+ return false;
484
+ case 'restart-scene':
485
+ if (typeof onRestartScene === 'function') {
486
+ onRestartScene();
487
+ return true;
488
+ }
489
+ return false;
490
+ case 'restart-app':
491
+ if (typeof onRestartApp === 'function') {
492
+ onRestartApp();
493
+ return true;
494
+ }
495
+ return false;
496
+ case 'pause':
497
+ if (typeof togglePaused === 'function') {
498
+ togglePaused();
499
+ return true;
500
+ }
501
+ return false;
502
+ case 'minimize':
503
+ minimized = !minimized;
504
+ syncPlayHudState();
505
+ return true;
506
+ default:
507
+ return false;
508
+ }
509
+ }
510
+
511
+ function runSceneSelection(sceneId) {
512
+ if (typeof onSelectScene !== 'function' || sceneId === '__overflow__') {
513
+ return false;
514
+ }
515
+ const result = onSelectScene(sceneId);
516
+ return result !== false && result?.ok !== false;
517
+ }
518
+
519
+ return {
520
+ get enabled() {
521
+ return enabled;
522
+ },
523
+ get minimized() {
524
+ return minimized;
525
+ },
526
+ show() {
527
+ enabled = true;
528
+ syncPlayHudState();
529
+ return enabled;
530
+ },
531
+ hide() {
532
+ enabled = false;
533
+ syncPlayHudState();
534
+ return enabled;
535
+ },
536
+ setEnabled(nextValue) {
537
+ enabled = nextValue === true;
538
+ syncPlayHudState();
539
+ return enabled;
540
+ },
541
+ toggle() {
542
+ enabled = !enabled;
543
+ syncPlayHudState();
544
+ return enabled;
545
+ },
546
+ setMinimized(nextValue) {
547
+ minimized = nextValue === true;
548
+ syncPlayHudState();
549
+ return minimized;
550
+ },
551
+ toggleMinimized() {
552
+ minimized = !minimized;
553
+ syncPlayHudState();
554
+ return minimized;
555
+ },
556
+ update(input = getRuntime()?.input || null) {
557
+ const pointerPressed = mousePressed(input, 'left', 0);
558
+ const pointerJustPressed = pointerPressed && !pointerPressedLastFrame;
559
+ pointerPressedLastFrame = pointerPressed;
560
+ if (inputIsKeyPressed(input, 'f1')) {
561
+ enabled = !enabled;
562
+ syncPlayHudState();
563
+ return enabled;
564
+ }
565
+ if (!enabled) {
566
+ return enabled;
567
+ }
568
+ if (inputIsKeyPressed(input, 'f2')) {
569
+ runToolbarAction('screenshot');
570
+ }
571
+ if (inputIsKeyPressed(input, 'p')) {
572
+ runToolbarAction('pause');
573
+ }
574
+ if (pointerJustPressed) {
575
+ const point = mousePosition(input);
576
+ if (minimized && pointInRect(point, uiState.minimizedChip)) {
577
+ minimized = false;
578
+ syncPlayHudState();
579
+ return enabled;
580
+ }
581
+ for (const chip of uiState.sceneChips) {
582
+ if (chip.enabled !== false && chip.active !== true && pointInRect(point, chip)) {
583
+ runSceneSelection(chip.id);
584
+ return enabled;
585
+ }
586
+ }
587
+ for (const button of uiState.toolbarButtons) {
588
+ if (button.enabled !== false && pointInRect(point, button)) {
589
+ runToolbarAction(button.id);
590
+ break;
591
+ }
592
+ }
593
+ }
594
+ return enabled;
595
+ },
596
+ snapshot() {
597
+ return buildProjectInspectorSnapshot({
598
+ projectTitle,
599
+ sceneRegistry,
600
+ getActiveSceneId,
601
+ appState,
602
+ getUiThemeState,
603
+ enabled,
604
+ minimized,
605
+ paused: typeof getPaused === 'function' ? getPaused() === true : false,
606
+ recording: recordingState(),
607
+ actions: currentActions(),
608
+ });
609
+ },
610
+ draw() {
611
+ if (!enabled) return;
612
+ drawProjectInspectorOverlay(this.snapshot(), uiState);
613
+ },
614
+ };
615
+ }