@neta-art/cohub 9.0.1 → 11.0.0

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 (240) hide show
  1. package/README.md +108 -102
  2. package/dist/board/editor/align.d.ts +11 -0
  3. package/dist/board/editor/align.js +72 -0
  4. package/dist/board/editor/animation.d.ts +17 -0
  5. package/dist/board/editor/animation.js +187 -0
  6. package/dist/board/editor/camera.d.ts +32 -0
  7. package/dist/board/editor/camera.js +137 -0
  8. package/dist/board/editor/clipboard.d.ts +41 -0
  9. package/dist/board/editor/clipboard.js +129 -0
  10. package/dist/board/editor/connection-ports.d.ts +19 -0
  11. package/dist/board/editor/connection-ports.js +85 -0
  12. package/dist/board/editor/context.d.ts +111 -0
  13. package/dist/board/editor/context.js +30 -0
  14. package/dist/board/editor/copy.d.ts +17 -0
  15. package/dist/board/editor/copy.js +121 -0
  16. package/dist/board/editor/creation.d.ts +51 -0
  17. package/dist/board/editor/creation.js +225 -0
  18. package/dist/board/editor/deletion.d.ts +9 -0
  19. package/dist/board/editor/deletion.js +90 -0
  20. package/dist/board/editor/document-edits.d.ts +22 -0
  21. package/dist/board/editor/document-edits.js +193 -0
  22. package/dist/board/editor/document.d.ts +41 -0
  23. package/dist/board/editor/document.js +302 -0
  24. package/dist/board/editor/editor.d.ts +225 -0
  25. package/dist/board/editor/editor.js +439 -0
  26. package/dist/board/editor/index.d.ts +18 -0
  27. package/dist/board/editor/index.js +12 -0
  28. package/dist/board/editor/interaction.d.ts +115 -0
  29. package/dist/board/editor/interaction.js +584 -0
  30. package/dist/board/editor/query.d.ts +27 -0
  31. package/dist/board/editor/query.js +203 -0
  32. package/dist/board/editor/remote.d.ts +11 -0
  33. package/dist/board/editor/remote.js +55 -0
  34. package/dist/board/editor/selection-transform.d.ts +24 -0
  35. package/dist/board/editor/selection-transform.js +81 -0
  36. package/dist/board/editor/selection.d.ts +33 -0
  37. package/dist/board/editor/selection.js +197 -0
  38. package/dist/board/editor/snapping.d.ts +33 -0
  39. package/dist/board/editor/snapping.js +75 -0
  40. package/dist/board/editor/snapshots.d.ts +27 -0
  41. package/dist/board/editor/snapshots.js +132 -0
  42. package/dist/board/editor/spatial.d.ts +41 -0
  43. package/dist/board/editor/spatial.js +191 -0
  44. package/dist/board/editor/state.d.ts +12 -0
  45. package/dist/board/editor/state.js +49 -0
  46. package/dist/board/editor/tool.d.ts +10 -0
  47. package/dist/board/editor/tool.js +19 -0
  48. package/dist/board/editor/wheel.d.ts +5 -0
  49. package/dist/board/editor/wheel.js +17 -0
  50. package/dist/board/export/index.d.ts +28 -6
  51. package/dist/board/export/index.js +47 -13
  52. package/dist/board/export/node/index.d.ts +56 -0
  53. package/dist/board/{headless → export/node}/index.js +26 -21
  54. package/dist/board/export/node/scripts.d.ts +16 -0
  55. package/dist/board/export/node/scripts.js +258 -0
  56. package/dist/board/export/scene.d.ts +8 -5
  57. package/dist/board/export/scene.js +24 -9
  58. package/dist/board/{animation.d.ts → model/animation.d.ts} +8 -5
  59. package/dist/board/{animation.js → model/animation.js} +37 -10
  60. package/dist/board/{core → model}/arrow-geometry.d.ts +2 -2
  61. package/dist/board/{core → model}/arrow-geometry.js +2 -2
  62. package/dist/board/model/authoring.d.ts +20 -0
  63. package/dist/board/model/authoring.js +185 -0
  64. package/dist/board/{core → model}/draw-geometry.d.ts +2 -2
  65. package/dist/board/{core → model}/draw-geometry.js +1 -1
  66. package/dist/board/model/draw-input.d.ts +14 -0
  67. package/dist/board/model/draw-input.js +28 -0
  68. package/dist/board/{core → model}/export-assets.d.ts +1 -1
  69. package/dist/board/{core → model}/export-assets.js +1 -1
  70. package/dist/board/{core → model}/export-plan.d.ts +2 -2
  71. package/dist/board/{core → model}/export-plan.js +3 -2
  72. package/dist/board/{core → model}/file-preview.d.ts +1 -1
  73. package/dist/board/{core → model}/file-preview.js +2 -2
  74. package/dist/board/{core → model}/file-snapshot.d.ts +1 -1
  75. package/dist/board/{core → model}/file-snapshot.js +4 -3
  76. package/dist/board/{geometry.d.ts → model/geometry.d.ts} +3 -3
  77. package/dist/board/{geometry.js → model/geometry.js} +1 -1
  78. package/dist/board/{image-key.d.ts → model/image-key.d.ts} +2 -2
  79. package/dist/board/{image-key.js → model/image-key.js} +7 -3
  80. package/dist/board/model/index.d.ts +42 -0
  81. package/dist/board/model/index.js +39 -0
  82. package/dist/board/model/items/builtin.d.ts +5 -0
  83. package/dist/board/model/items/builtin.js +119 -0
  84. package/dist/board/model/items/create.d.ts +61 -0
  85. package/dist/board/model/items/create.js +272 -0
  86. package/dist/board/model/items/definition.d.ts +35 -0
  87. package/dist/board/model/items/definition.js +18 -0
  88. package/dist/board/model/items/id.d.ts +5 -0
  89. package/dist/board/model/items/id.js +11 -0
  90. package/dist/board/model/items/index.d.ts +6 -0
  91. package/dist/board/model/items/index.js +6 -0
  92. package/dist/board/model/items/registry.d.ts +35 -0
  93. package/dist/board/model/items/registry.js +84 -0
  94. package/dist/board/{media-playback.d.ts → model/media-playback.d.ts} +4 -3
  95. package/dist/board/{media-playback.js → model/media-playback.js} +15 -5
  96. package/dist/board/{media.d.ts → model/media.d.ts} +1 -1
  97. package/dist/board/{media.js → model/media.js} +8 -2
  98. package/dist/board/{core → model}/palette.d.ts +1 -1
  99. package/dist/board/{core → model}/palette.js +1 -1
  100. package/dist/board/{presets.d.ts → model/presets.d.ts} +3 -3
  101. package/dist/board/{presets.js → model/presets.js} +1 -1
  102. package/dist/board/{replay.d.ts → model/replay.d.ts} +5 -5
  103. package/dist/board/{replay.js → model/replay.js} +2 -2
  104. package/dist/board/model/sampling.d.ts +19 -0
  105. package/dist/board/model/sampling.js +96 -0
  106. package/dist/board/{core → model}/scene.d.ts +1 -1
  107. package/dist/board/{core → model}/scene.js +1 -1
  108. package/dist/board/model/script-example.d.ts +4 -0
  109. package/dist/board/model/script-example.js +21 -0
  110. package/dist/board/model/script-hit.d.ts +10 -0
  111. package/dist/board/model/script-hit.js +52 -0
  112. package/dist/board/model/script-index.d.ts +7 -0
  113. package/dist/board/model/script-index.js +15 -0
  114. package/dist/board/model/script-scene.d.ts +24 -0
  115. package/dist/board/model/script-scene.js +267 -0
  116. package/dist/board/model/script.d.ts +105 -0
  117. package/dist/board/model/script.js +1 -0
  118. package/dist/board/model/shape-types.d.ts +8 -0
  119. package/dist/board/model/shape-types.js +8 -0
  120. package/dist/board/{task.d.ts → model/task.d.ts} +4 -4
  121. package/dist/board/{task.js → model/task.js} +3 -3
  122. package/dist/board/{core → model}/text-metrics.d.ts +1 -1
  123. package/dist/board/{core → model}/text-metrics.js +1 -1
  124. package/dist/board/{core → model}/tool-styles.d.ts +1 -1
  125. package/dist/board/{core → model}/tool-styles.js +1 -1
  126. package/dist/board/{runtime/board-player.d.ts → player/index.d.ts} +2 -2
  127. package/dist/board/{runtime/board-player.js → player/index.js} +5 -4
  128. package/dist/board/render/board-background.d.ts +1 -1
  129. package/dist/board/render/clip.d.ts +1 -1
  130. package/dist/board/render/css-color.d.ts +6 -1
  131. package/dist/board/render/css-color.js +34 -20
  132. package/dist/board/render/diagnostics.d.ts +20 -0
  133. package/dist/board/render/diagnostics.js +117 -0
  134. package/dist/board/render/index.d.ts +9 -6
  135. package/dist/board/render/index.js +10 -7
  136. package/dist/board/render/media-interaction.d.ts +2 -2
  137. package/dist/board/render/media-interaction.js +1 -1
  138. package/dist/board/render/palette.d.ts +3 -2
  139. package/dist/board/render/palette.js +7 -3
  140. package/dist/board/render/renderers/arrow-card-renderer.js +4 -3
  141. package/dist/board/render/renderers/audio-card-renderer.js +2 -1
  142. package/dist/board/render/renderers/board-renderer-registry.d.ts +20 -10
  143. package/dist/board/render/renderers/board-renderer-registry.js +17 -17
  144. package/dist/board/render/renderers/custom-card-renderer.d.ts +5 -0
  145. package/dist/board/render/renderers/{sketch-card-renderer.js → custom-card-renderer.js} +16 -15
  146. package/dist/board/render/renderers/draw-card-renderer.js +4 -3
  147. package/dist/board/render/renderers/effect-card-renderer.js +22 -5
  148. package/dist/board/render/renderers/far-plate.js +1 -1
  149. package/dist/board/render/renderers/file-card-renderer.d.ts +1 -1
  150. package/dist/board/render/renderers/file-card-renderer.js +2 -2
  151. package/dist/board/render/renderers/frame-card-renderer.js +30 -14
  152. package/dist/board/render/renderers/image-card-renderer.d.ts +1 -1
  153. package/dist/board/render/renderers/image-card-renderer.js +43 -4
  154. package/dist/board/render/renderers/shape-card-renderer.js +11 -28
  155. package/dist/board/render/renderers/task-card-renderer.js +1 -1
  156. package/dist/board/render/renderers/text-card-renderer.js +6 -4
  157. package/dist/board/render/renderers/unknown-card-renderer.js +1 -0
  158. package/dist/board/render/renderers/video-card-renderer.d.ts +1 -1
  159. package/dist/board/render/renderers/video-card-renderer.js +2 -1
  160. package/dist/board/render/sampling.d.ts +22 -0
  161. package/dist/board/render/sampling.js +21 -0
  162. package/dist/board/render/script-export.d.ts +11 -0
  163. package/dist/board/render/script-export.js +86 -0
  164. package/dist/board/render/script-host.d.ts +31 -0
  165. package/dist/board/render/script-host.js +421 -0
  166. package/dist/board/render/script-modules.d.ts +2 -0
  167. package/dist/board/render/script-modules.js +2 -0
  168. package/dist/board/render/script-runtime.d.ts +29 -0
  169. package/dist/board/render/script-runtime.js +213 -0
  170. package/dist/board/render/script-sandbox.d.ts +4 -0
  171. package/dist/board/render/script-sandbox.js +173 -0
  172. package/dist/board/render/stroke.d.ts +3 -2
  173. package/dist/board/render/stroke.js +23 -2
  174. package/dist/board/render/text-measurement.js +2 -2
  175. package/dist/board/replica/index.d.ts +70 -0
  176. package/dist/board/replica/index.js +276 -0
  177. package/dist/board/stage/assets.d.ts +41 -0
  178. package/dist/board/stage/assets.js +355 -0
  179. package/dist/board/stage/index.d.ts +8 -0
  180. package/dist/board/stage/index.js +8 -0
  181. package/dist/board/stage/lru.d.ts +32 -0
  182. package/dist/board/stage/lru.js +29 -0
  183. package/dist/board/stage/maintenance.d.ts +5 -0
  184. package/dist/board/stage/maintenance.js +11 -0
  185. package/dist/board/stage/pointer.d.ts +8 -0
  186. package/dist/board/stage/pointer.js +33 -0
  187. package/dist/board/stage/scene.d.ts +85 -0
  188. package/dist/board/stage/scene.js +515 -0
  189. package/dist/board/stage/script-pointer.d.ts +19 -0
  190. package/dist/board/stage/script-pointer.js +35 -0
  191. package/dist/board/stage/stage.d.ts +76 -0
  192. package/dist/board/stage/stage.js +774 -0
  193. package/dist/board/stage/texture-pool.d.ts +24 -0
  194. package/dist/board/stage/texture-pool.js +153 -0
  195. package/dist/board/stage/views.d.ts +38 -0
  196. package/dist/board/stage/views.js +93 -0
  197. package/dist/chunks/environment.d.ts +289 -23
  198. package/dist/chunks/host-bridge.d.ts +2 -2
  199. package/dist/chunks/http.d.ts +185 -71
  200. package/dist/chunks/http.js +368 -269
  201. package/dist/chunks/transport.js +3 -1
  202. package/dist/chunks/websocket.d.ts +9 -1
  203. package/dist/chunks/websocket.js +16 -2
  204. package/dist/host-bridge.js +2 -1
  205. package/dist/http.d.ts +2 -2
  206. package/dist/index.d.ts +182 -4
  207. package/dist/index.js +1393 -129
  208. package/dist/media.d.ts +1 -10
  209. package/dist/media.js +16 -27
  210. package/dist/protocol/dist/board-assets.d.ts +1 -0
  211. package/dist/protocol/dist/board-constants.js +2 -2
  212. package/dist/protocol/dist/board-model.d.ts +201 -11
  213. package/dist/protocol/dist/board-model.js +33 -14
  214. package/dist/protocol/dist/board-patch.js +3 -2
  215. package/dist/protocol/dist/board-schema.d.ts +4 -2
  216. package/dist/protocol/dist/board-schema.js +18 -4
  217. package/dist/protocol/dist/board-script-modules.d.ts +25 -0
  218. package/dist/protocol/dist/board-script-modules.js +127 -0
  219. package/dist/protocol/dist/board.d.ts +28 -2
  220. package/dist/protocol/dist/board.js +3 -1
  221. package/dist/protocol/dist/core/media.d.ts +5 -0
  222. package/dist/protocol/dist/core/media.js +39 -0
  223. package/dist/protocol/dist/display/index.d.ts +1 -0
  224. package/dist/protocol/dist/index.d.ts +7 -5
  225. package/dist/protocol/dist/realtime/types.d.ts +1 -0
  226. package/dist/protocol/dist/rtc/index.d.ts +1 -0
  227. package/dist/types.d.ts +1 -1
  228. package/package.json +21 -8
  229. package/dist/board/core/shape-definition.d.ts +0 -23
  230. package/dist/board/core/shape-definition.js +0 -45
  231. package/dist/board/core/shape-types.d.ts +0 -38
  232. package/dist/board/core/shape-types.js +0 -22
  233. package/dist/board/headless/index.d.ts +0 -55
  234. package/dist/board/headless/sketch.d.ts +0 -19
  235. package/dist/board/headless/sketch.js +0 -146
  236. package/dist/board/index.d.ts +0 -30
  237. package/dist/board/index.js +0 -29
  238. package/dist/board/render/renderers/sketch-card-renderer.d.ts +0 -5
  239. package/dist/board/render/sketch-host.d.ts +0 -14
  240. package/dist/board/render/sketch-host.js +0 -216
@@ -0,0 +1,774 @@
1
+ import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
2
+ import { screenPoint, screenToWorld, stableCullRect, visibleWorldRect, worldPoint } from "../model/geometry.js";
3
+ import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
4
+ import { boardScriptTarget } from "../model/script-hit.js";
5
+ import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "../model/sampling.js";
6
+ import { resolveSceneArrow } from "../model/arrow-geometry.js";
7
+ import { buildFallbackShapeColors, pickBoardColor, resolveItemColor } from "../model/palette.js";
8
+ import { featuredTaskArtifact } from "../model/task.js";
9
+ import { isCreationBoardTool } from "../editor/tool.js";
10
+ import { resizeCursorForHandle } from "../editor/selection-transform.js";
11
+ import { parseBoardCssColor } from "../render/css-color.js";
12
+ import { defaultBoardPalette, itemAlpha } from "../render/palette.js";
13
+ import { createBoardBackground, updateBoardBackground } from "../render/board-background.js";
14
+ import { getBoardResolution, textZoomBucket } from "../render/text-resolution.js";
15
+ import { getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
16
+ import { createBoardScriptHost } from "../render/script-host.js";
17
+ import { createBoardPlayer } from "../player/index.js";
18
+ import { toBoardPointerEvent } from "./pointer.js";
19
+ import { createBoardScene } from "./scene.js";
20
+ import { scheduleBoardMaintenance } from "./maintenance.js";
21
+ import { createBoardScriptPointerRouter } from "./script-pointer.js";
22
+ import { createBoardItemViewLayer } from "./views.js";
23
+ import { Application, Container, Graphics, RendererType } from "pixi.js";
24
+ //#region src/board/stage/stage.ts
25
+ const LIVE_CHANNELS = [
26
+ "document",
27
+ "scene",
28
+ "selection",
29
+ "camera",
30
+ "tool",
31
+ "interaction",
32
+ "hover",
33
+ "editing",
34
+ "playback"
35
+ ];
36
+ function defaultTheme() {
37
+ return {
38
+ key: "dark",
39
+ palette: defaultBoardPalette("dark"),
40
+ colors: buildFallbackShapeColors("dark"),
41
+ colorScheme: "dark"
42
+ };
43
+ }
44
+ const ROTATE_CURSOR = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M21 12a9 9 0 1 1-2.64-6.36L21 8M21 3v5h-5' fill='none' stroke='%23fff' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M21 12a9 9 0 1 1-2.64-6.36L21 8M21 3v5h-5' fill='none' stroke='%231d1d1f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12, crosshair`;
45
+ function mountBoardStage(host, options) {
46
+ const { editor, assets } = options;
47
+ const theme = options.theme ?? defaultTheme;
48
+ const resolveRenderer = options.renderers ?? getBoardCardRenderer;
49
+ let app = null;
50
+ let world = null;
51
+ let overlay = null;
52
+ let background = null;
53
+ let scene = null;
54
+ let scripts = null;
55
+ let scriptMode = editor.readonly ? "interact" : "edit";
56
+ let scriptTime = 0;
57
+ let scriptLastTick = performance.now();
58
+ const scriptOutputs = /* @__PURE__ */ new Map();
59
+ const scriptListeners = /* @__PURE__ */ new Set();
60
+ let scriptVersion = 0;
61
+ let composedVersion = -1;
62
+ let composedZoom = 0;
63
+ let composedPlayhead = "";
64
+ let composedMoving = false;
65
+ let composedDocument = null;
66
+ let scriptHover = null;
67
+ const scriptPointers = createBoardScriptPointerRouter();
68
+ let stopMaintenance = null;
69
+ let active = true;
70
+ let disposed = false;
71
+ let renderFrame = 0;
72
+ let tickFrame = 0;
73
+ let resizeFrame = 0;
74
+ let cardEpoch = 0;
75
+ let assetVersion = 0;
76
+ let surface = {
77
+ width: 0,
78
+ height: 0
79
+ };
80
+ let playbackCamera = null;
81
+ let cursor = "";
82
+ const renderCamera = () => playbackCamera ?? editor.camera;
83
+ const views = createBoardItemViewLayer(host, editor, options.views ?? [], renderCamera);
84
+ const player = createBoardPlayer({ resolveColor: (color) => {
85
+ const current = theme();
86
+ return {
87
+ color: resolveItemColor(color, "brand", current.colors, current.colorScheme, parseBoardCssColor),
88
+ alpha: itemAlpha(current, color)
89
+ };
90
+ } });
91
+ let cull = {
92
+ rect: null,
93
+ ids: null,
94
+ scene: null
95
+ };
96
+ function visibleIds() {
97
+ if (surface.width === 0 || surface.height === 0) return null;
98
+ const rect = stableCullRect(visibleWorldRect(renderCamera(), surface.width, surface.height));
99
+ const same = cull.rect && cull.rect.x === rect.x && cull.rect.y === rect.y && cull.rect.width === rect.width && cull.rect.height === rect.height;
100
+ if (same && cull.scene === editor.scene) return cull.ids;
101
+ cull = {
102
+ rect: same ? cull.rect : rect,
103
+ ids: new Set(editor.idsInRect(rect, true)),
104
+ scene: editor.scene
105
+ };
106
+ options.onVisibleChange?.(cull.ids);
107
+ requestAssets = true;
108
+ return cull.ids;
109
+ }
110
+ let requestAssets = true;
111
+ function syncAssets(ids) {
112
+ if (!requestAssets || !ids) return;
113
+ requestAssets = false;
114
+ const sizes = [];
115
+ for (const id of ids) {
116
+ const item = editor.itemById(id);
117
+ if (!item) continue;
118
+ const key = assets.assetKey(item);
119
+ if (!key) continue;
120
+ assets.requestItem(item);
121
+ const artifact = item.type === "task" ? featuredTaskArtifact(item.props.snapshot.artifacts) : null;
122
+ const recorded = artifact?.type === "image" || artifact?.type === "video" ? artifact : item.type === "image" || item.type === "video" ? item.props.snapshot : null;
123
+ if (!recorded || recorded.naturalWidth && recorded.naturalHeight) continue;
124
+ const natural = assets.getNaturalSize(key);
125
+ if (natural?.width && natural.height) sizes.push({
126
+ id: item.id,
127
+ ...natural
128
+ });
129
+ }
130
+ if (sizes.length > 0) editor.adoptMediaNaturalSizes(sizes);
131
+ }
132
+ function renderContext(current, renderScene, time) {
133
+ const interaction = editor.interaction;
134
+ return {
135
+ settings: editor.settings,
136
+ scene: renderScene,
137
+ time,
138
+ ...scripts ? { scripts } : {},
139
+ selectedIds: new Set(editor.selection),
140
+ hoveredId: editor.hoverId,
141
+ resizingIds: interaction.type === "resizing" ? new Set(interaction.origin.keys()) : /* @__PURE__ */ new Set(),
142
+ palette: current.palette,
143
+ colors: current.colors,
144
+ colorScheme: current.colorScheme,
145
+ rendererType: app?.renderer.type === RendererType.CANVAS ? "canvas" : "gpu",
146
+ zoom: renderCamera().zoom,
147
+ assetKey: assets.assetKey,
148
+ getTexture: (key) => assets.getTexture(key),
149
+ hasError: (key) => assets.hasError(key),
150
+ fileState: (path) => options.fileState?.(path) ?? "ok",
151
+ acquireTexture: (key) => assets.acquire(key),
152
+ releaseTexture: (key) => assets.release(key)
153
+ };
154
+ }
155
+ function syncBackground(current) {
156
+ if (!app) return;
157
+ const context = {
158
+ app,
159
+ settings: editor.settings,
160
+ viewport: editor.camera,
161
+ colorScheme: current.colorScheme,
162
+ palette: current.palette,
163
+ hasImageBackground: current.imageBackground === true
164
+ };
165
+ if (background) updateBoardBackground(background, context);
166
+ else {
167
+ background = createBoardBackground(context);
168
+ app.stage.addChildAt(background, 0);
169
+ }
170
+ }
171
+ function localGestureItemIds() {
172
+ const interaction = editor.interaction;
173
+ switch (interaction.type) {
174
+ case "translating":
175
+ case "resizing":
176
+ case "rotating": return new Set(interaction.origin.keys());
177
+ case "draggingArrowHandle": return /* @__PURE__ */ new Set([interaction.arrowId]);
178
+ default: return /* @__PURE__ */ new Set();
179
+ }
180
+ }
181
+ function previewItems() {
182
+ const previews = /* @__PURE__ */ new Map();
183
+ const remote = options.previews?.();
184
+ if (!remote?.size) return previews;
185
+ const local = localGestureItemIds();
186
+ for (const [id, item] of remote) if (!local.has(id)) previews.set(id, item);
187
+ return previews;
188
+ }
189
+ function liveStrokes() {
190
+ const strokes = [...options.strokes?.() ?? []];
191
+ const interaction = editor.interaction;
192
+ if (interaction.type === "drawing") strokes.push({
193
+ id: interaction.id,
194
+ points: interaction.points,
195
+ color: interaction.color,
196
+ size: interaction.size
197
+ });
198
+ return strokes;
199
+ }
200
+ function followCamera(frame, renderScene) {
201
+ return resolveBoardAnimationCamera(frame.camera, (id) => renderScene.get(id)?.frame, surface, frame.time, editor.camera);
202
+ }
203
+ let effectSampler;
204
+ let effectDocument;
205
+ let effectAnimation = null;
206
+ function arrowHead(target, from, to, color, width, inv, alpha) {
207
+ const angle = Math.atan2(to.y - from.y, to.x - from.x);
208
+ const head = Math.max(14, 16 * inv);
209
+ const spread = Math.PI / 6;
210
+ target.moveTo(to.x - head * Math.cos(angle - spread), to.y - head * Math.sin(angle - spread)).lineTo(to.x, to.y).lineTo(to.x - head * Math.cos(angle + spread), to.y - head * Math.sin(angle + spread)).stroke({
211
+ color,
212
+ width,
213
+ alpha,
214
+ cap: "round",
215
+ join: "round"
216
+ });
217
+ }
218
+ function drawTransient(target, current) {
219
+ const inv = 1 / Math.max(editor.camera.zoom, 1e-4);
220
+ const interaction = editor.interaction;
221
+ for (const guide of editor.snapGuides) {
222
+ const vertical = guide.axis === "x";
223
+ target.moveTo(vertical ? guide.at : guide.from, vertical ? guide.from : guide.at).lineTo(vertical ? guide.at : guide.to, vertical ? guide.to : guide.at).stroke({
224
+ color: current.palette.brand,
225
+ width: inv,
226
+ alpha: .9
227
+ });
228
+ }
229
+ if (interaction.type === "creatingArrow") {
230
+ const color = pickBoardColor(current.colors, interaction.color, current.colorScheme);
231
+ const target_ = interaction.targetItemId ? editor.itemById(interaction.targetItemId) : null;
232
+ const end = target_ ? worldPoint(target_.frame.x + target_.frame.width / 2, target_.frame.y + target_.frame.height / 2) : interaction.current;
233
+ const width = Math.max(interaction.size, 1.5 * inv);
234
+ target.moveTo(interaction.start.x, interaction.start.y).lineTo(end.x, end.y).stroke({
235
+ color: color.stroke,
236
+ width,
237
+ alpha: .9
238
+ });
239
+ arrowHead(target, interaction.start, end, color.stroke, width, inv, .95);
240
+ }
241
+ if (interaction.type === "creatingBox") {
242
+ const color = pickBoardColor(current.colors, interaction.color, current.colorScheme);
243
+ const { start, current: corner } = interaction;
244
+ const w = Math.abs(corner.x - start.x);
245
+ const h = Math.abs(corner.y - start.y);
246
+ if (w > 1 || h > 1) target.roundRect(Math.min(start.x, corner.x), Math.min(start.y, corner.y), Math.max(w, 1), Math.max(h, 1), 4).fill({
247
+ color: color.fill,
248
+ alpha: .04
249
+ }).stroke({
250
+ color: color.stroke,
251
+ width: 1.5 * inv,
252
+ alpha: .85
253
+ });
254
+ }
255
+ }
256
+ function cursorFor() {
257
+ if (scriptMode === "interact" && scriptHover) {
258
+ const output = scriptOutputs.get(scriptHover.owner);
259
+ return output?.hits[scriptHover.target]?.cursor ?? (output?.listens.includes("click") ? "pointer" : "default");
260
+ }
261
+ const interaction = editor.interaction;
262
+ switch (interaction.type) {
263
+ case "panning":
264
+ case "translating": return "grabbing";
265
+ case "resizing": return resizeCursorForHandle(interaction.handle, interaction.single?.rotation ?? 0);
266
+ case "rotating": return ROTATE_CURSOR;
267
+ case "draggingArrowHandle":
268
+ case "brushing": return "crosshair";
269
+ }
270
+ if (editor.spaceHeld || editor.tool === "hand") return "grab";
271
+ const control = editor.hoveredTransformControl;
272
+ if (control?.kind === "resize") return resizeCursorForHandle(control.handle, editor.selectionTransform?.frame.rotation ?? 0);
273
+ if (control?.kind === "rotate") return ROTATE_CURSOR;
274
+ if (isCreationBoardTool(editor.tool)) return "crosshair";
275
+ const hovered = editor.hoverId ? editor.itemById(editor.hoverId) : null;
276
+ return hovered && !hovered.locked && editor.registry.capabilities(hovered).canMove ? "move" : "default";
277
+ }
278
+ function scheduleRender() {
279
+ if (renderFrame || !app || !active) return;
280
+ renderFrame = requestAnimationFrame(() => {
281
+ renderFrame = 0;
282
+ app?.render();
283
+ });
284
+ }
285
+ function scheduleTick() {
286
+ if (tickFrame || !active || disposed) return;
287
+ tickFrame = requestAnimationFrame(() => {
288
+ tickFrame = 0;
289
+ sync();
290
+ });
291
+ }
292
+ function createScripts() {
293
+ return createBoardScriptHost({
294
+ host,
295
+ capabilities: {
296
+ ...options.scriptCapabilities,
297
+ "board.emit": async (id, value) => {
298
+ const message = value;
299
+ if (!message || typeof message.target !== "string" || typeof message.type !== "string" || !boardScriptScope(editor.document, id).has(message.target)) throw new Error("Invalid script event target.");
300
+ scripts?.event(message.target, {
301
+ type: message.type,
302
+ data: message.data
303
+ });
304
+ },
305
+ ...!editor.readonly ? { "board.commit": async (id, value) => {
306
+ validateBoardScriptCommit(editor.document, id, value);
307
+ await editor.commitPatch(value);
308
+ } } : {}
309
+ },
310
+ onOutput: (id, output) => {
311
+ if (output) {
312
+ prepareBoardScriptOutput(editor.document, id, output);
313
+ scriptOutputs.set(id, output);
314
+ } else scriptOutputs.delete(id);
315
+ scriptVersion++;
316
+ scheduleTick();
317
+ },
318
+ readModule: async (src) => {
319
+ const url = await options.source.resolveFileUrl(src);
320
+ if (!url) throw new Error(`${src} is not available.`);
321
+ const response = await fetch(url, { signal: AbortSignal.timeout(15e3) });
322
+ if (!response.ok) throw new Error(`${src} could not be read.`);
323
+ return response.text();
324
+ },
325
+ onFrame: () => {
326
+ scheduleTick();
327
+ for (const listener of scriptListeners) listener();
328
+ }
329
+ });
330
+ }
331
+ function sync() {
332
+ if (!app || !world || !scene || !overlay) return;
333
+ const current = theme();
334
+ const hasScripts = editor.hasScripts;
335
+ if (hasScripts && !scripts) {
336
+ scripts = createScripts();
337
+ scriptTime = 0;
338
+ scriptLastTick = performance.now();
339
+ } else if (!hasScripts && scripts) {
340
+ const previous = scripts;
341
+ scripts = null;
342
+ previous.destroy();
343
+ scriptOutputs.clear();
344
+ editor.setScriptItems(/* @__PURE__ */ new Map());
345
+ scriptHover = null;
346
+ composedVersion = -1;
347
+ composedDocument = null;
348
+ }
349
+ syncBackground(current);
350
+ player.enter(editor.consumeRecentlyAdded(), editor.document);
351
+ const playback = options.playback?.() ?? null;
352
+ const frame = player.frame(editor.document, playback, performance.now(), Date.now(), editor.playhead?.animationId ?? null);
353
+ const previews = previewItems();
354
+ const moving = new Map(previews);
355
+ for (const [id, item] of frame.items) moving.set(id, item);
356
+ editor.setPlayedItems(moving);
357
+ if (scripts && (scriptOutputs.size || composedVersion !== scriptVersion)) {
358
+ const playheadKey = `${editor.playhead?.animationId ?? ""}:${editor.playhead?.time ?? ""}`;
359
+ if (scriptVersion !== composedVersion || composedDocument !== editor.document || moving.size || composedMoving || composedZoom !== editor.camera.zoom || composedPlayhead !== playheadKey) {
360
+ const animationItems = editor.animationItems();
361
+ const composed = composeBoardScriptItems(editor.document, editor.scene, scriptOutputs, animationItems, editor.camera, (owner, error) => scripts?.fault(owner, error instanceof Error ? error.message : String(error)));
362
+ const scriptedIds = new Set([...scriptOutputs.values()].flatMap((output) => Object.keys(output.patches)));
363
+ for (const id of animationItems.keys()) if (!scriptedIds.has(id)) composed.delete(id);
364
+ editor.setScriptItems(composed);
365
+ composedMoving = moving.size > 0;
366
+ composedPlayhead = playheadKey;
367
+ composedZoom = editor.camera.zoom;
368
+ composedVersion = scriptVersion;
369
+ composedDocument = editor.document;
370
+ }
371
+ }
372
+ const renderScene = editor.scene;
373
+ const animationId = editor.playhead?.animationId ?? (frame.playbackTime !== null ? playback?.animationId : null) ?? null;
374
+ if (animationId && (effectDocument !== editor.document || effectAnimation !== animationId)) {
375
+ effectDocument = editor.document;
376
+ effectAnimation = animationId;
377
+ effectSampler = createBoardAnimationSampler(editor.document, animationId);
378
+ }
379
+ if (editor.playhead && effectSampler) {
380
+ frame.camera = effectSampler.at(editor.playhead.time).evaluation.camera;
381
+ frame.time = editor.playhead.time;
382
+ }
383
+ playbackCamera = editor.cameraPolicy === "follow" && Object.keys(frame.camera).length > 0 ? followCamera(frame, renderScene) : null;
384
+ const camera = renderCamera();
385
+ if (scripts) {
386
+ const now = performance.now();
387
+ if (scriptMode !== "paused") scriptTime += Math.min(250, Math.max(0, now - scriptLastTick));
388
+ scriptLastTick = now;
389
+ scripts.sync(editor.document, renderScene, camera, scriptTime, scriptMode === "interact", visibleIds());
390
+ }
391
+ world.position.set(camera.x, camera.y);
392
+ world.scale.set(camera.zoom);
393
+ const ids = visibleIds();
394
+ syncAssets(ids);
395
+ const context = renderContext(current, renderScene, frame.time);
396
+ if (animationId && effectSampler) {
397
+ context.time = editor.playhead?.time ?? frame.time;
398
+ context.frameAt = effectSampler.frameAt;
399
+ }
400
+ const pinnedIds = new Set(editor.selection);
401
+ for (const item of renderScene.items) if (item.type === "effect" && item.props.kind === "trail" && renderScene.opacity(item.id) > 0) pinnedIds.add(item.id);
402
+ for (const id of previews.keys()) pinnedIds.add(id);
403
+ if (editor.editingId) pinnedIds.add(editor.editingId);
404
+ for (const id of frame.items.keys()) {
405
+ pinnedIds.add(id);
406
+ for (const child of renderScene.descendants(id)) pinnedIds.add(child);
407
+ for (const binder of renderScene.binders(id)) pinnedIds.add(binder);
408
+ }
409
+ scene.sync({
410
+ items: renderScene.items,
411
+ strokes: liveStrokes(),
412
+ scene: renderScene,
413
+ context,
414
+ getItem: (id) => renderScene.get(id) ?? null,
415
+ visibleIds: ids,
416
+ pinnedIds,
417
+ globalSig: [
418
+ assetVersion,
419
+ cardEpoch,
420
+ current.key,
421
+ textZoomBucket(camera.zoom)
422
+ ].join("|"),
423
+ structureVersion: editor.structureVersion,
424
+ geometryVersion: editor.geometryVersion,
425
+ gestureActive: editor.gestureActive && editor.interaction.type !== "panning"
426
+ });
427
+ const single = editor.selection.length === 1 ? renderScene.get(editor.selection[0]) : null;
428
+ let arrowEndpoints;
429
+ if (single?.type === "arrow" && !single.locked) {
430
+ const resolved = resolveSceneArrow(single, renderScene);
431
+ arrowEndpoints = [
432
+ resolved.start.point,
433
+ resolved.mid,
434
+ resolved.end.point
435
+ ];
436
+ }
437
+ const interaction = editor.interaction;
438
+ scene.drawOverlay({
439
+ zoom: camera.zoom,
440
+ pointerType: editor.pointerType,
441
+ marquee: editor.marquee,
442
+ selection: editor.selection,
443
+ transform: editor.selectionTransform,
444
+ controls: editor.tool === "select",
445
+ hoveredControl: editor.hoveredTransformControl,
446
+ rotationPointer: interaction.type === "rotating" ? interaction.current : null,
447
+ arrowEndpoints,
448
+ ports: editor.connectionPorts,
449
+ hoveredPort: editor.hoveredConnectionPort,
450
+ arrowDraft: null,
451
+ bindTarget: editor.bindTargetFrame ?? editor.arrowDraft?.targetFrame ?? null
452
+ }, current.palette);
453
+ options.drawOverlay?.(overlay, {
454
+ zoom: camera.zoom,
455
+ theme: current,
456
+ scene: renderScene
457
+ });
458
+ drawTransient(overlay, current);
459
+ views.sync({
460
+ ids,
461
+ scene: renderScene,
462
+ camera,
463
+ surface,
464
+ selection: context.selectedIds
465
+ });
466
+ const nextCursor = cursorFor();
467
+ if (nextCursor !== cursor) host.style.cursor = cursor = nextCursor;
468
+ scheduleRender();
469
+ if (frame.running || scene.animated || scriptMode !== "paused" && scripts?.animated) scheduleTick();
470
+ }
471
+ function resize() {
472
+ cancelAnimationFrame(resizeFrame);
473
+ resizeFrame = requestAnimationFrame(() => {
474
+ if (!app) return;
475
+ app.resize();
476
+ surface = {
477
+ width: app.screen.width,
478
+ height: app.screen.height
479
+ };
480
+ editor.surfaceSize = surface;
481
+ options.onSurfaceChange?.(surface);
482
+ sync();
483
+ });
484
+ }
485
+ const rectOf = () => host.getBoundingClientRect();
486
+ const inViews = (event) => event.target instanceof Node && views.element.contains(event.target);
487
+ function toInput(event) {
488
+ return toBoardPointerEvent(event, rectOf(), renderCamera(), event.type === "pointermove" && editor.interaction.type === "drawing");
489
+ }
490
+ function scriptTarget(input) {
491
+ if (!scriptOutputs.size) return null;
492
+ const point = input.world;
493
+ const candidates = editor.idsInRect({
494
+ x: point.x - .01,
495
+ y: point.y - .01,
496
+ width: .02,
497
+ height: .02
498
+ }, true);
499
+ return boardScriptTarget(editor.scene, candidates, point, scriptOutputs, editor.registry.hitTest);
500
+ }
501
+ function sendScriptEvent(target, type, event, input, related) {
502
+ if (!scripts) return;
503
+ const point = applyMatrix(invertMatrix(editor.scene.layout.matrix(target.owner)), input.world);
504
+ scripts?.event(target.owner, {
505
+ type,
506
+ target: target.target,
507
+ relatedTarget: related?.target,
508
+ relatedOwner: related?.owner,
509
+ point,
510
+ pointerId: event.pointerId,
511
+ pointerType: event.pointerType,
512
+ buttons: event.buttons,
513
+ shiftKey: event.shiftKey,
514
+ altKey: event.altKey,
515
+ ctrlKey: event.ctrlKey,
516
+ metaKey: event.metaKey
517
+ });
518
+ }
519
+ function scriptPointer(type, event, input) {
520
+ if (!scriptPointers.needsRouting(event.pointerId, scripts !== null)) return false;
521
+ const enabled = scriptMode === "interact" && !editor.gestureActive && !editor.spaceHeld && event.button !== 1;
522
+ const target = type === "leave" || !enabled || scriptPointers.owner(event.pointerId) === "editor" ? null : scriptTarget(input);
523
+ if (target?.owner !== scriptHover?.owner || target?.target !== scriptHover?.target) {
524
+ if (scriptHover) sendScriptEvent(scriptHover, "pointerleave", event, input, target);
525
+ if (target) sendScriptEvent(target, "pointerenter", event, input, scriptHover);
526
+ scriptHover = target;
527
+ }
528
+ const { recipient, click } = scriptPointers.route(type, event.pointerId, target, {
529
+ x: event.clientX,
530
+ y: event.clientY
531
+ }, event.type !== "pointerup");
532
+ if (type === "down" && recipient) {
533
+ host.setPointerCapture(event.pointerId);
534
+ host.focus({ preventScroll: true });
535
+ }
536
+ if (recipient && type !== "leave") sendScriptEvent(recipient, input.cancelled ? "pointercancel" : `pointer${type}`, event, input);
537
+ if (click) sendScriptEvent(click, "click", event, input);
538
+ return recipient !== null;
539
+ }
540
+ function handleScriptKey(event) {
541
+ if (scriptMode !== "interact" || !scriptHover || event.target !== host) return;
542
+ const input = {
543
+ type: event.type,
544
+ target: scriptHover.target,
545
+ key: event.key,
546
+ shiftKey: event.shiftKey,
547
+ altKey: event.altKey,
548
+ ctrlKey: event.ctrlKey,
549
+ metaKey: event.metaKey
550
+ };
551
+ scripts?.event(scriptHover.owner, input);
552
+ event.stopPropagation();
553
+ }
554
+ function handlePointerDown(event) {
555
+ if (inViews(event)) return;
556
+ editor.takeCameraControl();
557
+ const input = toInput(event);
558
+ if (scriptPointer("down", event, input)) return;
559
+ if (options.onPointer?.("down", event, input) === false) return;
560
+ host.setPointerCapture(event.pointerId);
561
+ editor.pointerDown(input);
562
+ }
563
+ function handlePointerMove(event) {
564
+ if (inViews(event)) return;
565
+ const input = toInput(event);
566
+ if (scriptPointer("move", event, input)) return;
567
+ if (options.onPointer?.("move", event, input) === false) return;
568
+ editor.pointerMove(input);
569
+ }
570
+ function handlePointerUp(event) {
571
+ if (inViews(event)) return;
572
+ const input = toInput(event);
573
+ if (scriptPointer("up", event, input)) return;
574
+ if (options.onPointer?.("up", event, input) === false) return;
575
+ editor.pointerUp(input);
576
+ if (event.type === "pointercancel" || event.pointerType !== "mouse") editor.pointerLeave();
577
+ }
578
+ function handlePointerLeave(event) {
579
+ if (event.buttons !== 0) return;
580
+ scriptPointer("leave", event, toInput(event));
581
+ if (options.onPointer?.("leave", event, toInput(event)) === false) return;
582
+ editor.pointerLeave();
583
+ }
584
+ function handleWheel(event) {
585
+ if (inViews(event)) return;
586
+ event.preventDefault();
587
+ editor.takeCameraControl();
588
+ const rect = rectOf();
589
+ const point = screenPoint(event.clientX - rect.left, event.clientY - rect.top);
590
+ editor.wheel(point, event.deltaX, event.deltaY, event.ctrlKey || event.metaKey, event.deltaMode);
591
+ }
592
+ function handleDoubleClick(event) {
593
+ if (inViews(event)) return;
594
+ const point = screenToWorld(event.clientX, event.clientY, rectOf(), renderCamera());
595
+ const item = editor.itemAt(point);
596
+ if (options.onDoubleClick?.(item, point) === true || editor.readonly) return;
597
+ if (item && !item.locked && editor.registry.capabilities(item).canEdit) {
598
+ editor.editingId = item.id;
599
+ return;
600
+ }
601
+ if (item && item.type !== "frame" && item.type !== "arrow") return;
602
+ const label = editor.labelItemAt(point);
603
+ if (label) editor.editingId = label.id;
604
+ else if (!item) editor.beginTextDraft(point);
605
+ }
606
+ const listeners = [
607
+ ["keydown", handleScriptKey],
608
+ ["keyup", handleScriptKey],
609
+ ["pointerdown", handlePointerDown],
610
+ ["pointermove", handlePointerMove],
611
+ ["pointerup", handlePointerUp],
612
+ ["pointercancel", handlePointerUp],
613
+ ["lostpointercapture", handlePointerUp],
614
+ ["pointerleave", handlePointerLeave],
615
+ [
616
+ "wheel",
617
+ handleWheel,
618
+ { passive: false }
619
+ ],
620
+ ["dblclick", handleDoubleClick]
621
+ ];
622
+ const stopEditor = editor.subscribe(LIVE_CHANNELS, scheduleTick);
623
+ const stopAssets = assets.subscribe(() => {
624
+ assetVersion += 1;
625
+ requestAssets = true;
626
+ scheduleTick();
627
+ });
628
+ const resizeObserver = new ResizeObserver(resize);
629
+ return {
630
+ ready: (async () => {
631
+ const instance = new Application();
632
+ try {
633
+ await instance.init({
634
+ antialias: true,
635
+ autoDensity: true,
636
+ backgroundAlpha: 0,
637
+ resizeTo: host,
638
+ resolution: getBoardResolution(),
639
+ autoStart: false
640
+ });
641
+ } catch (error) {
642
+ console.error("Board canvas failed to start", error);
643
+ instance.destroy({ removeView: true });
644
+ return false;
645
+ }
646
+ if (disposed) {
647
+ instance.destroy({ removeView: true });
648
+ return false;
649
+ }
650
+ app = instance;
651
+ stopMaintenance = scheduleBoardMaintenance(instance.renderer);
652
+ Object.assign(instance.canvas.style, {
653
+ position: "relative",
654
+ zIndex: "1",
655
+ display: "block",
656
+ touchAction: "none"
657
+ });
658
+ host.insertBefore(instance.canvas, views.element);
659
+ world = new Container({
660
+ isRenderGroup: true,
661
+ label: "board-world"
662
+ });
663
+ const nodes = new Container({
664
+ isRenderGroup: true,
665
+ label: "board-nodes"
666
+ });
667
+ overlay = new Graphics({ label: "board-interaction-overlay" });
668
+ world.addChild(nodes, overlay);
669
+ instance.stage.addChild(world);
670
+ scene = createBoardScene({
671
+ world: nodes,
672
+ overlay,
673
+ getRenderer: resolveRenderer,
674
+ onFarLayerFrame: scheduleTick
675
+ });
676
+ for (const [type, listener, listenerOptions] of listeners) host.addEventListener(type, listener, listenerOptions);
677
+ resizeObserver.observe(host);
678
+ resize();
679
+ return true;
680
+ })(),
681
+ get renderer() {
682
+ return app ? app.renderer : null;
683
+ },
684
+ get camera() {
685
+ return renderCamera();
686
+ },
687
+ get theme() {
688
+ return theme();
689
+ },
690
+ setScriptMode(mode) {
691
+ if (mode === scriptMode) return;
692
+ scriptMode = mode;
693
+ scriptLastTick = performance.now();
694
+ scheduleTick();
695
+ },
696
+ resetScripts() {
697
+ scriptTime = 0;
698
+ scripts?.invalidate();
699
+ },
700
+ invalidateScript(path) {
701
+ scripts?.invalidate(path);
702
+ },
703
+ scriptOutput: (id) => scripts?.output(id) ?? null,
704
+ async snapshotScripts() {
705
+ const result = {};
706
+ await Promise.all([...scriptOutputs.keys()].map(async (id) => {
707
+ const snapshot = await scripts?.snapshot(id);
708
+ if (snapshot) result[id] = snapshot;
709
+ }));
710
+ return result;
711
+ },
712
+ restoreScript(id, snapshot) {
713
+ scripts?.restore(id, snapshot);
714
+ },
715
+ subscribeScripts(listener) {
716
+ scriptListeners.add(listener);
717
+ return () => {
718
+ scriptListeners.delete(listener);
719
+ };
720
+ },
721
+ scriptError: (id) => scripts?.error(id) ?? null,
722
+ setActive(next) {
723
+ if (active === next) return;
724
+ active = next;
725
+ if (!active) {
726
+ cancelAnimationFrame(renderFrame);
727
+ cancelAnimationFrame(tickFrame);
728
+ renderFrame = 0;
729
+ tickFrame = 0;
730
+ return;
731
+ }
732
+ player.reset();
733
+ scriptLastTick = performance.now();
734
+ resize();
735
+ },
736
+ invalidate(invalidation) {
737
+ if (invalidation?.cards) {
738
+ cardEpoch += 1;
739
+ requestAssets = true;
740
+ }
741
+ scheduleTick();
742
+ },
743
+ isMaterialized: (id) => Boolean(scene?.getNode(id)),
744
+ toWorld: (clientX, clientY) => screenToWorld(clientX, clientY, rectOf(), renderCamera()),
745
+ destroy() {
746
+ disposed = true;
747
+ scriptPointers.clear();
748
+ scriptListeners.clear();
749
+ stopMaintenance?.();
750
+ stopEditor();
751
+ stopAssets();
752
+ resizeObserver.disconnect();
753
+ cancelAnimationFrame(resizeFrame);
754
+ cancelAnimationFrame(renderFrame);
755
+ cancelAnimationFrame(tickFrame);
756
+ for (const [type, listener] of listeners) host.removeEventListener(type, listener);
757
+ editor.setPlayedItems(/* @__PURE__ */ new Map());
758
+ editor.setScriptItems(/* @__PURE__ */ new Map());
759
+ scene?.destroy(renderContext(theme(), editor.scene, 0));
760
+ scene = null;
761
+ scripts?.destroy();
762
+ scripts = null;
763
+ background?.destroy({ children: true });
764
+ background = null;
765
+ views.destroy();
766
+ world = null;
767
+ overlay = null;
768
+ app?.destroy({ removeView: true });
769
+ app = null;
770
+ }
771
+ };
772
+ }
773
+ //#endregion
774
+ export { mountBoardStage };