@volter/editor-game 0.5.65

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 (302) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +23 -0
  3. package/contributions/asset-budget-asset.menu.ts +26 -0
  4. package/contributions/asset-budget.action.ts +18 -0
  5. package/contributions/asset-budget.document.tsx +21 -0
  6. package/contributions/asset-budget.menu.ts +22 -0
  7. package/contributions/audio-unlock.service.ts +17 -0
  8. package/contributions/audio.utility.tsx +15 -0
  9. package/contributions/autoplay.service.ts +48 -0
  10. package/contributions/bridge.command.ts +172 -0
  11. package/contributions/build-profiles.document.tsx +21 -0
  12. package/contributions/build-progress.status.tsx +45 -0
  13. package/contributions/build.action.ts +26 -0
  14. package/contributions/build.command.ts +27 -0
  15. package/contributions/build.header.tsx +37 -0
  16. package/contributions/build.menu.ts +31 -0
  17. package/contributions/build.service.ts +31 -0
  18. package/contributions/connection.status.tsx +43 -0
  19. package/contributions/coverage.service.ts +118 -0
  20. package/contributions/edit-mode-audio.service.ts +23 -0
  21. package/contributions/edit-mode-networking.service.ts +30 -0
  22. package/contributions/game-document.service.ts +25 -0
  23. package/contributions/game-eval.command.ts +210 -0
  24. package/contributions/game.layout.ts +19 -0
  25. package/contributions/gameplay.command.ts +255 -0
  26. package/contributions/generation.service.ts +96 -0
  27. package/contributions/generations.status.tsx +53 -0
  28. package/contributions/ingest.service.ts +80 -0
  29. package/contributions/instances.command.ts +75 -0
  30. package/contributions/navmesh.menu.ts +39 -0
  31. package/contributions/navmesh.service.ts +19 -0
  32. package/contributions/network.utility.tsx +17 -0
  33. package/contributions/play.command.ts +355 -0
  34. package/contributions/profiler.action.ts +16 -0
  35. package/contributions/profiler.menu.ts +22 -0
  36. package/contributions/profiler.utility.tsx +17 -0
  37. package/contributions/react/component-board.service.ts +21 -0
  38. package/contributions/react/design-time-mount.service.ts +60 -0
  39. package/contributions/react/pasteboard.action.ts +41 -0
  40. package/contributions/react/react-inspector.service.ts +85 -0
  41. package/contributions/react/story-documents.service.ts +44 -0
  42. package/contributions/scene-document.service.ts +32 -0
  43. package/contributions/state-watch.action.ts +17 -0
  44. package/contributions/state-watch.menu.ts +23 -0
  45. package/contributions/state-watch.utility.tsx +20 -0
  46. package/contributions/team-playtest.service.ts +124 -0
  47. package/contributions/three/camera-runtime.inspector.tsx +34 -0
  48. package/contributions/three/component-board.service.ts +24 -0
  49. package/contributions/three/component-verbs.command.ts +110 -0
  50. package/contributions/three/component-verbs.service.ts +92 -0
  51. package/contributions/three/constraints.inspector.tsx +34 -0
  52. package/contributions/three/model-asset-sections.service.ts +26 -0
  53. package/contributions/three/reflection-probe-capture.inspector.tsx +32 -0
  54. package/contributions/three/story-documents.service.ts +31 -0
  55. package/contributions/three/three-authoring.service.ts +66 -0
  56. package/contributions/transport.header.tsx +19 -0
  57. package/contributions/xstate-behavior.action.ts +42 -0
  58. package/contributions/xstate-behavior.document.tsx +73 -0
  59. package/contributions/xstate-behavior.inspector.tsx +28 -0
  60. package/contributions/xstate-behavior.menu.ts +23 -0
  61. package/package.json +144 -0
  62. package/src/asset-budget/AssetBudgetPanel.tsx +1172 -0
  63. package/src/asset-budget/asset-budget-model.ts +799 -0
  64. package/src/asset-budget/basis-encoder.ts +165 -0
  65. package/src/asset-budget/gltf-io.ts +154 -0
  66. package/src/asset-budget/gltf-optimize.ts +384 -0
  67. package/src/asset-budget/image-dims.ts +78 -0
  68. package/src/asset-budget/optimize-apply.ts +221 -0
  69. package/src/audio/AudioDebuggerPanel.tsx +457 -0
  70. package/src/audio/audio-debugger-model.ts +87 -0
  71. package/src/bridge/call.ts +60 -0
  72. package/src/bridge/dispatch.ts +459 -0
  73. package/src/bridge/live-frames.ts +25 -0
  74. package/src/bridge/screenshot.ts +316 -0
  75. package/src/build/BuildProfilesPanel.tsx +476 -0
  76. package/src/build/build-session.ts +247 -0
  77. package/src/build/format-bytes.ts +14 -0
  78. package/src/command-results.ts +36 -0
  79. package/src/coverage/live-authoring-surface.ts +30 -0
  80. package/src/coverage/live-project-verbs.ts +162 -0
  81. package/src/coverage/native-system-coverage.ts +143 -0
  82. package/src/coverage/root-coverage.ts +79 -0
  83. package/src/coverage/session-coverage.ts +193 -0
  84. package/src/design-system-stories/ApplicationChrome.stories.tsx +100 -0
  85. package/src/design-system-stories/InspectorNarrowBodies.stories.tsx +406 -0
  86. package/src/edit-mode/edit-mode-audio.ts +56 -0
  87. package/src/edit-mode/edit-mode-networking.ts +112 -0
  88. package/src/game-document/DevicePresetPicker.tsx +84 -0
  89. package/src/game-document/GameCaptureFrameButton.tsx +45 -0
  90. package/src/game-document/GameDocument.tsx +215 -0
  91. package/src/game-document/GamePanel.tsx +662 -0
  92. package/src/game-document/InstanceInspectorPicker.tsx +183 -0
  93. package/src/game-document/crowd-debug.ts +183 -0
  94. package/src/game-document/device-preview.ts +336 -0
  95. package/src/game-document/game-view-store.ts +107 -0
  96. package/src/game-document/physics-debug.ts +187 -0
  97. package/src/generation/GenerationActivity.tsx +421 -0
  98. package/src/generation/GenerationGallery.css +231 -0
  99. package/src/generation/generation-documents.tsx +338 -0
  100. package/src/generation/generation-jobs.ts +128 -0
  101. package/src/generation/generation-presentation.ts +257 -0
  102. package/src/host/adapter-reach.ts +445 -0
  103. package/src/host/adapter-runtime-bindings.ts +303 -0
  104. package/src/host/after-paint.ts +112 -0
  105. package/src/host/api/configurations.ts +66 -0
  106. package/src/host/authoring/babylon-authoring-adapter.ts +703 -0
  107. package/src/host/authoring/canvas-runtime-recognition.ts +50 -0
  108. package/src/host/authoring/contract-hierarchy-authoring.ts +144 -0
  109. package/src/host/authoring/contract-scenes-stories.ts +204 -0
  110. package/src/host/authoring/creation-site-related.ts +55 -0
  111. package/src/host/authoring/ephemeral-persistence.ts +29 -0
  112. package/src/host/authoring/gesture-persist.ts +84 -0
  113. package/src/host/authoring/ingest-data-writer.ts +232 -0
  114. package/src/host/authoring/ingest-source-persistence.ts +826 -0
  115. package/src/host/authoring/mount-isolated-pixi-screen.ts +250 -0
  116. package/src/host/authoring/mounted-authoring.ts +41 -0
  117. package/src/host/authoring/owned-pixi-ticker-listeners.ts +96 -0
  118. package/src/host/authoring/phaser-live-authoring-adapter.ts +265 -0
  119. package/src/host/authoring/pixi-authoring-adapter.ts +1554 -0
  120. package/src/host/authoring/pixi-creation-site-write-target.ts +60 -0
  121. package/src/host/authoring/pixi-isolation-assets.ts +25 -0
  122. package/src/host/authoring/pixi-live-write-target.ts +979 -0
  123. package/src/host/authoring/pixi-source-identity.ts +141 -0
  124. package/src/host/authoring/pixi-still-presentation.ts +71 -0
  125. package/src/host/authoring/pixi-structure-history.ts +237 -0
  126. package/src/host/authoring/pixi-transform-channels.ts +205 -0
  127. package/src/host/authoring/selection-remount-handoff.ts +23 -0
  128. package/src/host/authoring/source-persistence-backend.ts +373 -0
  129. package/src/host/authoring/source-refresh-revisions.ts +81 -0
  130. package/src/host/authoring/struct-write-pipe.ts +143 -0
  131. package/src/host/auto-frame-window.ts +89 -0
  132. package/src/host/binding-resolver.ts +393 -0
  133. package/src/host/browser-transpile.ts +631 -0
  134. package/src/host/canvas-entry-runtime.ts +95 -0
  135. package/src/host/components/CameraAuthoringOverlay.tsx +216 -0
  136. package/src/host/components/HeaderTelemetry.tsx +341 -0
  137. package/src/host/components/PixiIsolationSceneContent.tsx +280 -0
  138. package/src/host/components/ResolutionPicker.tsx +89 -0
  139. package/src/host/components/ThreeIsolationSceneContent.tsx +180 -0
  140. package/src/host/components/frame-debugger-model.ts +579 -0
  141. package/src/host/components/header-telemetry-model.ts +74 -0
  142. package/src/host/components/scene-document.tsx +447 -0
  143. package/src/host/components/utility-view-state.ts +87 -0
  144. package/src/host/components/world-root-stage-binding.tsx +133 -0
  145. package/src/host/components/world-root-stage.ts +1046 -0
  146. package/src/host/coverage/authoring-read-probe.ts +583 -0
  147. package/src/host/coverage/capability-coverage.ts +1587 -0
  148. package/src/host/coverage/coverage-accounting.ts +261 -0
  149. package/src/host/coverage/game-contract-seam-evidence.ts +82 -0
  150. package/src/host/coverage/project-verb-coverage.ts +148 -0
  151. package/src/host/coverage/system-adapter-coverage.ts +373 -0
  152. package/src/host/design-system-stories/StoryLayout.tsx +104 -0
  153. package/src/host/design-system-stories/fixtures/authoring.ts +247 -0
  154. package/src/host/design-system-stories/fixtures/editor-runtime.tsx +115 -0
  155. package/src/host/document-preview-three.ts +110 -0
  156. package/src/host/entry-adjudication.ts +89 -0
  157. package/src/host/game-location-guard.ts +150 -0
  158. package/src/host/game-module-access.ts +196 -0
  159. package/src/host/game-realm-page.ts +358 -0
  160. package/src/host/game-realm-reclaim.ts +55 -0
  161. package/src/host/game-realm-storage.ts +104 -0
  162. package/src/host/gameplay-export.ts +288 -0
  163. package/src/host/gameplay-recording.ts +717 -0
  164. package/src/host/gated-globals.ts +1511 -0
  165. package/src/host/history/json-history-resource.ts +254 -0
  166. package/src/host/ingest/registry.ts +261 -0
  167. package/src/host/instance-extract-actions.ts +120 -0
  168. package/src/host/instance-fork-actions.ts +120 -0
  169. package/src/host/play-control-hook.ts +26 -0
  170. package/src/host/playwright-shim.ts +479 -0
  171. package/src/host/projection/dom.ts +295 -0
  172. package/src/host/projection/pixi.ts +288 -0
  173. package/src/host/r3f-entry-runtime.ts +77 -0
  174. package/src/host/react-mount-runtime.ts +162 -0
  175. package/src/host/realm-services.ts +148 -0
  176. package/src/host/recording-preview.ts +106 -0
  177. package/src/host/roots/module-root.ts +203 -0
  178. package/src/host/roots/react-root.ts +181 -0
  179. package/src/host/same-realm-loop-gate.ts +544 -0
  180. package/src/host/scene-view-drawability.ts +69 -0
  181. package/src/host/sdk/tools.ts +31 -0
  182. package/src/host/served-bundle-runtime-modules.ts +331 -0
  183. package/src/host/server-log-bridge.ts +60 -0
  184. package/src/host/staged-projects.ts +24 -0
  185. package/src/host/stories/mounted-story-viewport-source.ts +64 -0
  186. package/src/host/stories/story-arg-descriptors.ts +50 -0
  187. package/src/host/stories/story-media-presence.ts +152 -0
  188. package/src/host/surface-content.ts +87 -0
  189. package/src/host/take-named-export.ts +23 -0
  190. package/src/host/three-ingest-runtime.ts +76 -0
  191. package/src/host/types-fastnoise-lite.d.ts +7 -0
  192. package/src/host/types-mikktspace.d.ts +20 -0
  193. package/src/host/types-troika-three-text.d.ts +7 -0
  194. package/src/host/use-active-performance-source.ts +53 -0
  195. package/src/host/viewport-pose-memory.ts +48 -0
  196. package/src/host/viewport-root-presentation.ts +40 -0
  197. package/src/ingest/active-ingest.ts +251 -0
  198. package/src/ingest/active-scene-navigation.ts +43 -0
  199. package/src/ingest/authoring/ingest-dom-surface-authoring.ts +191 -0
  200. package/src/ingest/authoring/ingest-root-adapter.ts +897 -0
  201. package/src/ingest/capture-wait-report.ts +122 -0
  202. package/src/ingest/deferred-ingest-play.ts +216 -0
  203. package/src/ingest/deferred-ingest-session.ts +23 -0
  204. package/src/ingest/discovery-public-ingest.ts +242 -0
  205. package/src/ingest/dom-stub-mark.ts +7 -0
  206. package/src/ingest/entry-load.ts +56 -0
  207. package/src/ingest/game-contract-realm.ts +34 -0
  208. package/src/ingest/game-pointer-lock.ts +89 -0
  209. package/src/ingest/held-scene-repaint.ts +73 -0
  210. package/src/ingest/host-surface-box.ts +174 -0
  211. package/src/ingest/ingest-boot-viewport.ts +54 -0
  212. package/src/ingest/ingest-canvas-scene-document.tsx +177 -0
  213. package/src/ingest/ingest-canvas-scene.ts +50 -0
  214. package/src/ingest/ingest-evidence-hook.ts +131 -0
  215. package/src/ingest/ingest-frame-snapshot.ts +183 -0
  216. package/src/ingest/ingest-play-commands.ts +134 -0
  217. package/src/ingest/ingest-play-control.ts +299 -0
  218. package/src/ingest/ingest-render-debug.ts +320 -0
  219. package/src/ingest/ingest-siblings.ts +487 -0
  220. package/src/ingest/ingest-status.ts +62 -0
  221. package/src/ingest/live-ingest-facet.ts +46 -0
  222. package/src/ingest/module-mode.ts +229 -0
  223. package/src/ingest/mount-canvas-ingest-root.ts +899 -0
  224. package/src/ingest/mount-coverage.ts +296 -0
  225. package/src/ingest/mount-dom-ingest-root.ts +282 -0
  226. package/src/ingest/mount-ingest-root.ts +744 -0
  227. package/src/ingest/mount-three-ingest-root.ts +366 -0
  228. package/src/ingest/resolve-canvas.ts +47 -0
  229. package/src/ingest/resolve-three.ts +123 -0
  230. package/src/ingest/served-bundle.ts +109 -0
  231. package/src/ingest/served-html-boot.ts +292 -0
  232. package/src/ingest/surface-canvas.ts +84 -0
  233. package/src/ingest/surface-dom.ts +84 -0
  234. package/src/ingest/surface-three.ts +128 -0
  235. package/src/ingest/types.ts +76 -0
  236. package/src/ingest/unmount-ingest-root.ts +224 -0
  237. package/src/navmesh/navmesh-actions.ts +27 -0
  238. package/src/navmesh/navmesh-handler.ts +237 -0
  239. package/src/navmesh/navmesh-workflow-store.ts +78 -0
  240. package/src/network/NetworkInspectorPanel.tsx +644 -0
  241. package/src/network/network-inspector-model.ts +225 -0
  242. package/src/play/play-boot-stall.ts +118 -0
  243. package/src/play/play-log-events.ts +26 -0
  244. package/src/play/play-mode.ts +2553 -0
  245. package/src/play/play-recording.ts +335 -0
  246. package/src/play/react-play-live-authoring.ts +165 -0
  247. package/src/play-bar/PlayBar.tsx +488 -0
  248. package/src/play-bar/PlayerCountPicker.tsx +100 -0
  249. package/src/profiler/FrameDebuggerPanel.tsx +458 -0
  250. package/src/profiler/PerformancePanel.tsx +1068 -0
  251. package/src/profiler/ProfilerPanel.tsx +53 -0
  252. package/src/profiler/frame-debugger-store.ts +97 -0
  253. package/src/profiler/main-thread-busy.ts +90 -0
  254. package/src/react/design-time-react-mount.ts +782 -0
  255. package/src/react/dom-authoring-adapter.ts +764 -0
  256. package/src/react/pasteboard-materialize.ts +154 -0
  257. package/src/react/react-inspector-section.tsx +2496 -0
  258. package/src/react/react-world-authoring-adapter.ts +3795 -0
  259. package/src/react/story-documents/story-args-section.ts +19 -0
  260. package/src/react/story-documents/story-documents.tsx +1380 -0
  261. package/src/react/story-paint-bounds.ts +94 -0
  262. package/src/react/ui-board-document.tsx +101 -0
  263. package/src/react/ui-board-title.ts +9 -0
  264. package/src/react/ui-component-board.ts +72 -0
  265. package/src/services/audio-pose-guard.ts +81 -0
  266. package/src/services/game-audio-unlock.ts +48 -0
  267. package/src/state-watch/StateWatchPanel.tsx +535 -0
  268. package/src/three/authoring/camera-runtime-inspector-section.tsx +135 -0
  269. package/src/three/authoring/constraint-inspector-section.tsx +189 -0
  270. package/src/three/authoring/design-time-renderer.ts +189 -0
  271. package/src/three/authoring/model-asset-inspector-section.css +41 -0
  272. package/src/three/authoring/model-asset-inspector-section.tsx +869 -0
  273. package/src/three/authoring/oid-source-persistence.ts +557 -0
  274. package/src/three/authoring/r3f-design-session.ts +1174 -0
  275. package/src/three/authoring/r3f-source-authoring-adapter.ts +5949 -0
  276. package/src/three/authoring/reflection-probe-inspector-section.tsx +76 -0
  277. package/src/three/authoring/spatial-audio-handles.ts +215 -0
  278. package/src/three/authoring/spatial-collider-handles.ts +229 -0
  279. package/src/three/authoring/spatial-joint-handles.ts +114 -0
  280. package/src/three/authoring/spatial-light-handles.ts +178 -0
  281. package/src/three/authoring/spatial-lod-handles.ts +93 -0
  282. package/src/three/authoring/spatial-particle-handles.ts +368 -0
  283. package/src/three/authoring/three-authoring-adapter.ts +1953 -0
  284. package/src/three/authoring/three-scene-identity.ts +19 -0
  285. package/src/three/authoring/three-spatial-handles.ts +161 -0
  286. package/src/three/authoring/typed-three-inspector.ts +528 -0
  287. package/src/three/component-verbs/extract-menu.ts +71 -0
  288. package/src/three/component-verbs/fork-menu.ts +78 -0
  289. package/src/three/component-verbs/internals-menu.ts +91 -0
  290. package/src/three/story-documents/three-story-documents.tsx +607 -0
  291. package/src/three/three-board/ThreeBoardDocument.tsx +888 -0
  292. package/src/three/three-board/board-framing.ts +412 -0
  293. package/src/three/three-board/board-layout.ts +401 -0
  294. package/src/three/three-board/board-scene.ts +901 -0
  295. package/src/three/three-board/three-component-board.ts +62 -0
  296. package/src/xstate/XStateBehaviorSection.tsx +130 -0
  297. package/src/xstate/XStateMachineInspector.tsx +566 -0
  298. package/src/xstate/character-animation-machine.fixture.ts +74 -0
  299. package/src/xstate/live-behaviors.ts +106 -0
  300. package/src/xstate/use-live-actor-state.ts +44 -0
  301. package/src/xstate/xstate-graph.ts +235 -0
  302. package/src/xstate/xstate-layout.ts +76 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The compact `Capture frame` control in the Game document toolbar while play
3
+ * runs (`GameDocumentToolbar`, CenterDocuments.tsx). Captures one frame into
4
+ * the shared ring (`frame-debugger-store.ts`) and opens the Frame view of the
5
+ * Profiler utility. Disabled — with honest title text — when the world
6
+ * registered no render-debug adapter.
7
+ *
8
+ * It sits HERE rather than beside the panel it opens because the panel moved
9
+ * to `@volter/editor-game` (the game skew as a package) and this button's caller is a
10
+ * host module: the host imports no package (WORKBENCH.md §The invariants), so
11
+ * the button stays on this side of the line with the store and model it reads.
12
+ */
13
+ import { getInspectedRenderDebug } from '@volter/editor-core/authoring/active-systems';
14
+ import { useAvailabilitySelector } from '@volter/editor-core/availability-tick';
15
+ import { deriveRenderDebugCapabilities } from '../host/components/frame-debugger-model';
16
+ import { profilerView } from '../host/components/utility-view-state';
17
+ import { Button } from '@volter/editor-sdk/widgets';
18
+ import { captureFrame } from '../profiler/frame-debugger-store';
19
+
20
+ export function GameCaptureFrameButton() {
21
+ const adapter = useAvailabilitySelector(() => getInspectedRenderDebug() ?? null);
22
+ const caps = deriveRenderDebugCapabilities(adapter);
23
+ const available = caps?.capture === true;
24
+ return (
25
+ <Button
26
+ type="button"
27
+ size="compact"
28
+ variant="ghost"
29
+ data-testid="game-capture-frame"
30
+ className="vgai-frame-capture-game-button"
31
+ disabled={!available}
32
+ title={
33
+ available
34
+ ? 'Capture one rendered frame and open the Frame debugger'
35
+ : 'No render-debug adapter registered for this world — frame capture is unavailable'
36
+ }
37
+ onClick={() => {
38
+ void captureFrame(adapter);
39
+ profilerView.open('frame');
40
+ }}
41
+ >
42
+ Capture frame
43
+ </Button>
44
+ );
45
+ }
@@ -0,0 +1,215 @@
1
+ import { HeaderTelemetry } from '../host/components/HeaderTelemetry';
2
+ import { PlayBar } from '../play-bar/PlayBar';
3
+ /**
4
+ * THE GAME DOCUMENT's CONTENT AND TOOLBAR — what the host's live document
5
+ * (`workspace:game`) draws while a runtime is live. Registered through
6
+ * `workspace.liveDocument.register` by `contributions/game-document.service.ts`.
7
+ *
8
+ * It moved out of `components/CenterDocuments.tsx` when Play left the host
9
+ * (WORK.md §The workbench, P3b). `ResolutionPicker` stayed behind — the
10
+ * host's story documents read it — so it is reached through the `@editor/*`
11
+ * alias, like every other editor internal this document still holds.
12
+ */
13
+
14
+ import { ResolutionPicker } from '../host/components/ResolutionPicker';
15
+ import { useEditorStore } from '@volter/editor-core/editor-runtime';
16
+ import { getCurrentProject, onProjectChange } from '@volter/editor-core/project-manager';
17
+ import type { LiveDocumentContentProps } from '@volter/editor-sdk/host';
18
+ import {
19
+ AnchoredMenu,
20
+ Button,
21
+ DisclosureIcon,
22
+ MenuItem,
23
+ themeVars,
24
+ } from '@volter/editor-sdk/widgets';
25
+ import { useRef, useState, useSyncExternalStore } from 'react';
26
+ import { crowdDebugEnabled, setCrowdDebugEnabled } from './crowd-debug';
27
+ import { DevicePresetPicker } from './DevicePresetPicker';
28
+ import {
29
+ devicePreviewVersion,
30
+ FIT_PRESET_ID,
31
+ setDevicePreset,
32
+ subscribeDevicePreview,
33
+ } from './device-preview';
34
+ import { GameCaptureFrameButton } from './GameCaptureFrameButton';
35
+ import { GamePanel } from './GamePanel';
36
+ import {
37
+ applyGameDevicePreset,
38
+ displayedGameResolution,
39
+ gameDocumentResolution,
40
+ gameDocumentScale,
41
+ gameResolutionOptions,
42
+ gameViewVersion,
43
+ notifyGameView,
44
+ setGameDocumentResolution,
45
+ subscribeGameView,
46
+ } from './game-view-store';
47
+ import { InstanceInspectorPicker } from './InstanceInspectorPicker';
48
+ import { physicsDebugEnabled, setPhysicsDebugEnabled } from './physics-debug';
49
+
50
+ function GameDebugMenu() {
51
+ const [open, setOpen] = useState(false);
52
+ const ref = useRef<HTMLButtonElement>(null);
53
+ return (
54
+ <div style={{ position: 'relative' }}>
55
+ <Button
56
+ ref={ref}
57
+ type="button"
58
+ variant="outline"
59
+ size="compact"
60
+ data-testid="game-debug-menu"
61
+ aria-haspopup="menu"
62
+ aria-expanded={open}
63
+ aria-controls={open ? 'vgai-game-debug-menu' : undefined}
64
+ onClick={() => setOpen((value) => !value)}
65
+ >
66
+ <span>Debug</span>
67
+ <DisclosureIcon direction="down" />
68
+ </Button>
69
+ {open && (
70
+ <AnchoredMenu
71
+ id="vgai-game-debug-menu"
72
+ anchorRef={ref}
73
+ gap={3}
74
+ onDismiss={() => setOpen(false)}
75
+ style={{
76
+ minWidth: 190,
77
+ }}
78
+ >
79
+ <MenuItem
80
+ onClick={() => {
81
+ setCrowdDebugEnabled(!crowdDebugEnabled());
82
+ notifyGameView();
83
+ }}
84
+ >
85
+ {crowdDebugEnabled() ? '✓ ' : ' '}Crowd debug draw
86
+ </MenuItem>
87
+ <MenuItem
88
+ onClick={() => {
89
+ setPhysicsDebugEnabled(!physicsDebugEnabled());
90
+ notifyGameView();
91
+ }}
92
+ >
93
+ {physicsDebugEnabled() ? '✓ ' : ' '}Physics debug draw
94
+ </MenuItem>
95
+ </AnchoredMenu>
96
+ )}
97
+ </div>
98
+ );
99
+ }
100
+
101
+ /**
102
+ * The Game document's LOCAL toolbar (§7.1 toolbar contribution, drawn in the
103
+ * document's own header strip while it is active): resolution picker + mute — the V4 remainder deferred from W1.
104
+ * The global header keeps the launcher; running-session transport and telemetry belong here.
105
+ */
106
+ export function GameDocumentToolbar(_props: LiveDocumentContentProps) {
107
+ const project = useSyncExternalStore(onProjectChange, getCurrentProject);
108
+ const store = useEditorStore();
109
+ useSyncExternalStore(store.subscribe, store.getShellSnapshot ?? store.getSnapshot);
110
+ useSyncExternalStore(subscribeGameView, gameViewVersion);
111
+ useSyncExternalStore(subscribeDevicePreview, devicePreviewVersion);
112
+ return (
113
+ <div
114
+ data-testid="game-doc-toolbar"
115
+ style={{
116
+ display: 'grid',
117
+ alignItems: 'center',
118
+ gridTemplateColumns: 'minmax(0, 1fr) auto minmax(0, 1fr)',
119
+ width: '100%',
120
+ gap: 6,
121
+ padding: '2px 8px',
122
+ }}
123
+ >
124
+ <div style={{ display: 'flex', alignItems: 'center', minWidth: 0, overflow: 'auto' }}>
125
+ <InstanceInspectorPicker />
126
+ <DevicePresetPicker
127
+ onPresetChange={(preset) => {
128
+ applyGameDevicePreset(preset);
129
+ notifyGameView();
130
+ }}
131
+ />
132
+ <ResolutionPicker
133
+ resolution={displayedGameResolution(gameDocumentResolution(), project?.config.resolution)}
134
+ options={gameResolutionOptions(project?.config.resolution)}
135
+ onResolutionChange={(resolution) => {
136
+ // A plain resolution pick is a deliberate exit from device
137
+ // emulation: keep the chosen dimensions, drop DPR/safe-area/touch.
138
+ setDevicePreset(FIT_PRESET_ID);
139
+ setGameDocumentResolution(resolution);
140
+ }}
141
+ scale={gameDocumentScale()}
142
+ title="Change game resolution"
143
+ />
144
+ <GameDebugMenu />
145
+ {/* F11: capture one rendered frame into the Frame debugger.
146
+ Play-gated; honestly disabled when the world registered no
147
+ render-debug adapter (headless/non-real-context). Lives in the
148
+ toolbar (not floating over the panel) so it tiles with the rest of
149
+ the chrome when paused Play reveals the editor. */}
150
+ {store.playState !== 'stopped' && <GameCaptureFrameButton />}
151
+ </div>
152
+ <PlayBar placement="runtime" />
153
+ <div style={{ display: 'flex', justifyContent: 'flex-end', minWidth: 0 }}>
154
+ <HeaderTelemetry />
155
+ </div>
156
+ </div>
157
+ );
158
+ }
159
+
160
+ /** The Game document's content host. It exists only while a runtime is live —
161
+ * see this file's header. */
162
+ export function GameDocumentContent(_props: LiveDocumentContentProps) {
163
+ const store = useEditorStore();
164
+ useSyncExternalStore(store.subscribe, store.getShellSnapshot ?? store.getSnapshot);
165
+ const isPlaying = store.playState !== 'stopped';
166
+ return (
167
+ <div style={{ flex: 1, position: 'relative', display: 'flex', flexDirection: 'column' }}>
168
+ <GamePanel
169
+ style={{
170
+ flex: 1,
171
+ position: 'relative',
172
+ display: 'flex',
173
+ flexDirection: 'column',
174
+ pointerEvents: 'auto',
175
+ // L-20 — playing/paused edge treatment from the shared themeVars.semantic.success/themeVars.semantic.warning
176
+ // tokens (same "healthy"/"attention" semantic SaveStatus uses).
177
+ ...(store.playState === 'playing'
178
+ ? { outline: `2px solid ${themeVars.semantic.success}`, outlineOffset: -2 }
179
+ : isPlaying
180
+ ? { outline: `2px solid ${themeVars.semantic.warning}`, outlineOffset: -2 }
181
+ : {}),
182
+ }}
183
+ />
184
+ {store.playState === 'paused' && (
185
+ // THE EDITOR PAUSED THE GAME, AND SAYS SO ON THE GAME. Escape belongs
186
+ // to play-mode while playing (pause on Escape), so a player who
187
+ // pressed it — once to free the mouse, once more by habit — froze the
188
+ // game with input gated off while the game's own card still read
189
+ // PRESS ENTER TO REDEPLOY; two testers in a row reported "Enter ain't
190
+ // working" from exactly that sequence (runhuman passes 124, 125). The
191
+ // yellow outline alone did not read as "paused". This label sits over
192
+ // the game and points at the one control that resumes it.
193
+ <div
194
+ data-testid="game-paused-notice"
195
+ style={{
196
+ position: 'absolute',
197
+ left: '50%',
198
+ top: 12,
199
+ transform: 'translateX(-50%)',
200
+ padding: '6px 12px',
201
+ borderRadius: 6,
202
+ background: 'rgba(0,0,0,.72)',
203
+ color: themeVars.content.primary,
204
+ fontSize: 12,
205
+ letterSpacing: '.04em',
206
+ pointerEvents: 'none',
207
+ zIndex: 2,
208
+ }}
209
+ >
210
+ Paused by the editor — press ▶ Play to resume (Escape pauses)
211
+ </div>
212
+ )}
213
+ </div>
214
+ );
215
+ }