@neta-art/cohub 11.0.0 → 11.2.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 (115) hide show
  1. package/README.md +31 -5
  2. package/dist/board/editor/context.d.ts +1 -0
  3. package/dist/board/editor/context.js +1 -0
  4. package/dist/board/editor/creation.d.ts +2 -2
  5. package/dist/board/editor/creation.js +3 -3
  6. package/dist/board/editor/editor.d.ts +5 -4
  7. package/dist/board/editor/editor.js +8 -1
  8. package/dist/board/editor/index.d.ts +2 -2
  9. package/dist/board/editor/interaction.d.ts +12 -2
  10. package/dist/board/editor/interaction.js +50 -8
  11. package/dist/board/editor/selection-transform.d.ts +1 -1
  12. package/dist/board/editor/selection-transform.js +13 -2
  13. package/dist/board/editor/snapshots.d.ts +0 -2
  14. package/dist/board/editor/snapshots.js +4 -20
  15. package/dist/board/export/index.d.ts +2 -0
  16. package/dist/board/export/index.js +1 -0
  17. package/dist/board/export/scene.d.ts +2 -0
  18. package/dist/board/export/scene.js +8 -1
  19. package/dist/board/model/file-preview.d.ts +0 -1
  20. package/dist/board/model/file-preview.js +10 -1
  21. package/dist/board/model/image-key.js +1 -1
  22. package/dist/board/model/index.d.ts +8 -7
  23. package/dist/board/model/index.js +6 -5
  24. package/dist/board/model/items/create.d.ts +16 -3
  25. package/dist/board/model/items/create.js +125 -5
  26. package/dist/board/model/items/index.d.ts +2 -2
  27. package/dist/board/model/items/index.js +2 -2
  28. package/dist/board/model/media-playback.js +1 -1
  29. package/dist/board/model/overlay-placement.d.ts +25 -0
  30. package/dist/board/model/overlay-placement.js +35 -0
  31. package/dist/board/model/replay.d.ts +1 -1
  32. package/dist/board/model/replay.js +1 -0
  33. package/dist/board/model/script-hit.d.ts +20 -3
  34. package/dist/board/model/script-hit.js +81 -24
  35. package/dist/board/model/script-observers.d.ts +18 -0
  36. package/dist/board/model/script-observers.js +92 -0
  37. package/dist/board/model/script-scene.d.ts +1 -1
  38. package/dist/board/model/script-scene.js +35 -8
  39. package/dist/board/model/script.d.ts +51 -7
  40. package/dist/board/render/audio-waveform.d.ts +1 -1
  41. package/dist/board/render/audio-waveform.js +8 -5
  42. package/dist/board/render/board-background.js +5 -4
  43. package/dist/board/render/card-tag.d.ts +24 -0
  44. package/dist/board/render/card-tag.js +205 -0
  45. package/dist/board/render/index.d.ts +8 -5
  46. package/dist/board/render/index.js +8 -5
  47. package/dist/board/render/media-interaction.d.ts +2 -1
  48. package/dist/board/render/media-interaction.js +15 -7
  49. package/dist/board/render/palette.js +2 -2
  50. package/dist/board/render/renderers/arrow-card-renderer.js +20 -16
  51. package/dist/board/render/renderers/audio-card-renderer.d.ts +8 -1
  52. package/dist/board/render/renderers/audio-card-renderer.js +64 -60
  53. package/dist/board/render/renderers/base-card-renderer.d.ts +1 -26
  54. package/dist/board/render/renderers/base-card-renderer.js +6 -92
  55. package/dist/board/render/renderers/board-renderer-registry.d.ts +25 -2
  56. package/dist/board/render/renderers/board-renderer-registry.js +11 -4
  57. package/dist/board/render/renderers/custom-card-renderer.js +6 -8
  58. package/dist/board/render/renderers/effect-card-renderer.js +0 -5
  59. package/dist/board/render/renderers/file-card-renderer.d.ts +1 -11
  60. package/dist/board/render/renderers/file-card-renderer.js +43 -105
  61. package/dist/board/render/renderers/frame-card-renderer.js +14 -15
  62. package/dist/board/render/renderers/image-card-renderer.js +62 -67
  63. package/dist/board/render/renderers/media-key.d.ts +6 -0
  64. package/dist/board/render/renderers/media-key.js +39 -0
  65. package/dist/board/render/renderers/shape-card-renderer.js +6 -12
  66. package/dist/board/render/renderers/task-card-renderer.d.ts +1 -8
  67. package/dist/board/render/renderers/task-card-renderer.js +286 -111
  68. package/dist/board/render/renderers/unknown-card-renderer.js +17 -16
  69. package/dist/board/render/renderers/video-card-renderer.js +73 -80
  70. package/dist/board/render/script-host.d.ts +1 -1
  71. package/dist/board/render/script-host.js +53 -28
  72. package/dist/board/render/script-runtime.js +13 -3
  73. package/dist/board/render/script-texture.d.ts +11 -0
  74. package/dist/board/render/script-texture.js +33 -0
  75. package/dist/board/render/stroke.d.ts +1 -1
  76. package/dist/board/render/stroke.js +5 -4
  77. package/dist/board/render/style.d.ts +29 -0
  78. package/dist/board/render/style.js +54 -0
  79. package/dist/board/render/surface.d.ts +34 -0
  80. package/dist/board/render/surface.js +132 -0
  81. package/dist/board/render/text-fit.d.ts +8 -0
  82. package/dist/board/render/text-fit.js +60 -0
  83. package/dist/board/render/text-resolution.d.ts +2 -1
  84. package/dist/board/render/text-resolution.js +4 -1
  85. package/dist/board/stage/assets.js +1 -1
  86. package/dist/board/stage/index.d.ts +3 -2
  87. package/dist/board/stage/index.js +2 -1
  88. package/dist/board/stage/overlay.d.ts +41 -0
  89. package/dist/board/stage/overlay.js +182 -0
  90. package/dist/board/stage/scene.d.ts +4 -43
  91. package/dist/board/stage/scene.js +38 -130
  92. package/dist/board/stage/script-pointer.d.ts +1 -0
  93. package/dist/board/stage/script-pointer.js +8 -2
  94. package/dist/board/stage/stage.d.ts +13 -3
  95. package/dist/board/stage/stage.js +217 -53
  96. package/dist/chunks/environment.d.ts +1037 -8
  97. package/dist/chunks/environment.js +12 -4
  98. package/dist/chunks/http.d.ts +51 -2
  99. package/dist/chunks/http.js +10 -1
  100. package/dist/chunks/transport.js +1 -1
  101. package/dist/chunks/websocket.d.ts +1 -1
  102. package/dist/http.d.ts +3 -3
  103. package/dist/index.d.ts +3 -3
  104. package/dist/index.js +151 -139
  105. package/dist/protocol/dist/board-model.d.ts +36 -1
  106. package/dist/protocol/dist/board-model.js +14 -4
  107. package/dist/protocol/dist/board-task.d.ts +22 -0
  108. package/dist/{board/model/task.js → protocol/dist/board-task.js} +34 -7
  109. package/dist/protocol/dist/generation/blocks.d.ts +8 -0
  110. package/dist/{generation-blocks.js → protocol/dist/generation/blocks.js} +14 -15
  111. package/dist/protocol/dist/index.d.ts +5 -2
  112. package/dist/protocol/dist/task/index.d.ts +4 -0
  113. package/package.json +2 -1
  114. package/dist/board/model/task.d.ts +0 -11
  115. package/dist/types.d.ts +0 -36
@@ -1,24 +1,27 @@
1
1
  import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
2
+ import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
2
3
  import { screenPoint, screenToWorld, stableCullRect, visibleWorldRect, worldPoint } from "../model/geometry.js";
3
4
  import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
4
5
  import { boardScriptTarget } from "../model/script-hit.js";
5
6
  import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "../model/sampling.js";
6
7
  import { resolveSceneArrow } from "../model/arrow-geometry.js";
7
8
  import { buildFallbackShapeColors, pickBoardColor, resolveItemColor } from "../model/palette.js";
8
- import { featuredTaskArtifact } from "../model/task.js";
9
9
  import { isCreationBoardTool } from "../editor/tool.js";
10
10
  import { resizeCursorForHandle } from "../editor/selection-transform.js";
11
11
  import { parseBoardCssColor } from "../render/css-color.js";
12
12
  import { defaultBoardPalette, itemAlpha } from "../render/palette.js";
13
13
  import { createBoardBackground, updateBoardBackground } from "../render/board-background.js";
14
14
  import { getBoardResolution, textZoomBucket } from "../render/text-resolution.js";
15
- import { getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
15
+ import { DEFAULT_BOARD_RENDER_LABELS, getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
16
16
  import { createBoardScriptHost } from "../render/script-host.js";
17
+ import { defaultBoardRenderStyle } from "../render/style.js";
18
+ import { createBoardScriptObservers } from "../model/script-observers.js";
17
19
  import { createBoardPlayer } from "../player/index.js";
18
20
  import { toBoardPointerEvent } from "./pointer.js";
19
21
  import { createBoardScene } from "./scene.js";
20
22
  import { scheduleBoardMaintenance } from "./maintenance.js";
21
23
  import { createBoardScriptPointerRouter } from "./script-pointer.js";
24
+ import { drawBoardOverlay } from "./overlay.js";
22
25
  import { createBoardItemViewLayer } from "./views.js";
23
26
  import { Application, Container, Graphics, RendererType } from "pixi.js";
24
27
  //#region src/board/stage/stage.ts
@@ -41,7 +44,19 @@ function defaultTheme() {
41
44
  colorScheme: "dark"
42
45
  };
43
46
  }
47
+ const NO_IDS = /* @__PURE__ */ new Set();
48
+ const MARCH_STEP_MS = 160;
49
+ const MARCH_SMOOTH_MS = 40;
44
50
  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`;
51
+ const defaultStyles = /* @__PURE__ */ new Map();
52
+ function styleOf(theme) {
53
+ if (theme.style) return theme.style;
54
+ const cached = defaultStyles.get(theme.colorScheme);
55
+ if (cached) return cached;
56
+ const style = defaultBoardRenderStyle(theme.colorScheme);
57
+ defaultStyles.set(theme.colorScheme, style);
58
+ return style;
59
+ }
45
60
  function mountBoardStage(host, options) {
46
61
  const { editor, assets } = options;
47
62
  const theme = options.theme ?? defaultTheme;
@@ -56,12 +71,26 @@ function mountBoardStage(host, options) {
56
71
  let scriptTime = 0;
57
72
  let scriptLastTick = performance.now();
58
73
  const scriptOutputs = /* @__PURE__ */ new Map();
74
+ const interactiveScripts = /* @__PURE__ */ new Set();
75
+ const screenScripts = /* @__PURE__ */ new Set();
76
+ const scriptObservers = createBoardScriptObservers((owner, event) => scripts?.event(owner, event));
77
+ let stopTransforms = null;
78
+ function syncTransformSubscription() {
79
+ if (scriptObservers.transforms && !stopTransforms) stopTransforms = editor.subscribeTransforms((event) => {
80
+ if (active && scriptMode !== "paused") scriptObservers.transform(editor.document, event);
81
+ });
82
+ else if (!scriptObservers.transforms && stopTransforms) {
83
+ stopTransforms();
84
+ stopTransforms = null;
85
+ }
86
+ }
59
87
  const scriptListeners = /* @__PURE__ */ new Set();
60
88
  let scriptVersion = 0;
61
89
  let composedVersion = -1;
62
90
  let composedZoom = 0;
63
91
  let composedPlayhead = "";
64
92
  let composedMoving = false;
93
+ let composedGesture = false;
65
94
  let composedDocument = null;
66
95
  let scriptHover = null;
67
96
  const scriptPointers = createBoardScriptPointerRouter();
@@ -70,6 +99,10 @@ function mountBoardStage(host, options) {
70
99
  let disposed = false;
71
100
  let renderFrame = 0;
72
101
  let tickFrame = 0;
102
+ let cardTickFrame = 0;
103
+ let cardTickTimer = null;
104
+ let cardTickDue = 0;
105
+ const staleIds = /* @__PURE__ */ new Set();
73
106
  let resizeFrame = 0;
74
107
  let cardEpoch = 0;
75
108
  let assetVersion = 0;
@@ -129,6 +162,19 @@ function mountBoardStage(host, options) {
129
162
  }
130
163
  if (sizes.length > 0) editor.adoptMediaNaturalSizes(sizes);
131
164
  }
165
+ let lifted = null;
166
+ function liftedIds() {
167
+ const interaction = editor.interaction;
168
+ if (interaction.type !== "translating" || !interaction.moved) {
169
+ lifted = null;
170
+ return NO_IDS;
171
+ }
172
+ if (lifted?.origin !== interaction.origin) lifted = {
173
+ origin: interaction.origin,
174
+ ids: new Set(interaction.origin.keys())
175
+ };
176
+ return lifted.ids;
177
+ }
132
178
  function renderContext(current, renderScene, time) {
133
179
  const interaction = editor.interaction;
134
180
  return {
@@ -139,11 +185,17 @@ function mountBoardStage(host, options) {
139
185
  selectedIds: new Set(editor.selection),
140
186
  hoveredId: editor.hoverId,
141
187
  resizingIds: interaction.type === "resizing" ? new Set(interaction.origin.keys()) : /* @__PURE__ */ new Set(),
188
+ liftedIds: liftedIds(),
142
189
  palette: current.palette,
143
190
  colors: current.colors,
144
191
  colorScheme: current.colorScheme,
192
+ style: styleOf(current),
193
+ themeKey: current.key,
145
194
  rendererType: app?.renderer.type === RendererType.CANVAS ? "canvas" : "gpu",
146
195
  zoom: renderCamera().zoom,
196
+ reducedMotion: options.reducedMotion?.() ?? false,
197
+ labels: options.labels?.() ?? DEFAULT_BOARD_RENDER_LABELS,
198
+ taskRun: options.taskRun ?? (() => null),
147
199
  assetKey: assets.assetKey,
148
200
  getTexture: (key) => assets.getTexture(key),
149
201
  hasError: (key) => assets.hasError(key),
@@ -253,6 +305,72 @@ function mountBoardStage(host, options) {
253
305
  });
254
306
  }
255
307
  }
308
+ let march = 0;
309
+ let marchTimer = null;
310
+ function stopMarch() {
311
+ if (marchTimer !== null) clearTimeout(marchTimer);
312
+ marchTimer = null;
313
+ }
314
+ function scheduleMarch(style) {
315
+ const stepped = style.motion === "stepped";
316
+ if (marchTimer !== null || !active || disposed) return;
317
+ marchTimer = setTimeout(() => {
318
+ marchTimer = null;
319
+ march += stepped ? 2 : 1;
320
+ drawInteraction();
321
+ scheduleRender();
322
+ }, stepped ? MARCH_STEP_MS : MARCH_SMOOTH_MS);
323
+ }
324
+ function drawInteraction() {
325
+ if (!overlay) return;
326
+ const current = theme();
327
+ const style = styleOf(current);
328
+ const renderScene = editor.scene;
329
+ const camera = renderCamera();
330
+ const interaction = editor.interaction;
331
+ const selected = editor.selection.flatMap((id) => renderScene.get(id) ?? []);
332
+ const single = selected.length === 1 ? selected[0] : void 0;
333
+ let arrowEndpoints;
334
+ if (single?.type === "arrow" && !single.locked) {
335
+ const resolved = resolveSceneArrow(single, renderScene);
336
+ arrowEndpoints = [
337
+ resolved.start.point,
338
+ resolved.mid,
339
+ resolved.end.point
340
+ ];
341
+ }
342
+ const hoverId = interaction.type === "idle" ? editor.hoverId : null;
343
+ const hovered = hoverId && !editor.selection.includes(hoverId) ? renderScene.get(hoverId) ?? null : null;
344
+ overlay.clear();
345
+ drawBoardOverlay(overlay, {
346
+ zoom: camera.zoom,
347
+ pointerType: editor.pointerType,
348
+ palette: current.palette,
349
+ style,
350
+ scene: renderScene,
351
+ hovered,
352
+ selected,
353
+ march,
354
+ marquee: editor.marquee,
355
+ transform: editor.selectionTransform,
356
+ controls: editor.tool === "select",
357
+ hoveredControl: editor.hoveredTransformControl,
358
+ rotationPointer: interaction.type === "rotating" ? interaction.current : null,
359
+ arrowEndpoints,
360
+ ports: editor.connectionPorts,
361
+ hoveredPort: editor.hoveredConnectionPort,
362
+ bindTarget: editor.bindTargetFrame ?? editor.arrowDraft?.targetFrame ?? null
363
+ });
364
+ options.drawOverlay?.(overlay, {
365
+ zoom: camera.zoom,
366
+ theme: current,
367
+ scene: renderScene
368
+ });
369
+ drawTransient(overlay, current);
370
+ editor.controlOutset = style.selection.outset;
371
+ if (style.selection.dash > 0 && selected.length > 0 && !(options.reducedMotion?.() ?? false)) scheduleMarch(style);
372
+ else stopMarch();
373
+ }
256
374
  function cursorFor() {
257
375
  if (scriptMode === "interact" && scriptHover) {
258
376
  const output = scriptOutputs.get(scriptHover.owner);
@@ -282,6 +400,28 @@ function mountBoardStage(host, options) {
282
400
  app?.render();
283
401
  });
284
402
  }
403
+ function scheduleCardTick(wait) {
404
+ if (!active || disposed) return;
405
+ const due = performance.now() + wait;
406
+ if (cardTickFrame || cardTickTimer !== null && cardTickDue <= due) return;
407
+ if (cardTickTimer !== null) clearTimeout(cardTickTimer);
408
+ cardTickTimer = null;
409
+ if (wait > 0) {
410
+ cardTickDue = due;
411
+ cardTickTimer = setTimeout(() => {
412
+ cardTickTimer = null;
413
+ scheduleCardTick(0);
414
+ }, wait);
415
+ return;
416
+ }
417
+ cardTickFrame = requestAnimationFrame(() => {
418
+ cardTickFrame = 0;
419
+ if (!scene) return;
420
+ const next = scene.tick(performance.now());
421
+ scheduleRender();
422
+ if (next !== null) scheduleCardTick(next);
423
+ });
424
+ }
285
425
  function scheduleTick() {
286
426
  if (tickFrame || !active || disposed) return;
287
427
  tickFrame = requestAnimationFrame(() => {
@@ -289,6 +429,16 @@ function mountBoardStage(host, options) {
289
429
  sync();
290
430
  });
291
431
  }
432
+ function cancelScriptPointers(owner, retained) {
433
+ scriptPointers.cancelScripts((pointerId, target) => {
434
+ scripts?.event(target.owner, {
435
+ type: "pointercancel",
436
+ target: target.target,
437
+ pointerId
438
+ });
439
+ }, owner, retained);
440
+ if (!retained || scriptHover && scriptHover.owner === owner && !Object.hasOwn(retained, scriptHover.target)) scriptHover = null;
441
+ }
292
442
  function createScripts() {
293
443
  return createBoardScriptHost({
294
444
  host,
@@ -310,8 +460,20 @@ function mountBoardStage(host, options) {
310
460
  onOutput: (id, output) => {
311
461
  if (output) {
312
462
  prepareBoardScriptOutput(editor.document, id, output);
463
+ cancelScriptPointers(id, output.hits);
313
464
  scriptOutputs.set(id, output);
314
- } else scriptOutputs.delete(id);
465
+ if (Object.keys(output.hits).length) interactiveScripts.add(id);
466
+ else interactiveScripts.delete(id);
467
+ if (output.space === "screen" && Object.keys(output.items).length) screenScripts.add(id);
468
+ else screenScripts.delete(id);
469
+ } else {
470
+ cancelScriptPointers(id);
471
+ scriptOutputs.delete(id);
472
+ interactiveScripts.delete(id);
473
+ screenScripts.delete(id);
474
+ }
475
+ scriptObservers.update(id, output);
476
+ syncTransformSubscription();
315
477
  scriptVersion++;
316
478
  scheduleTick();
317
479
  },
@@ -340,6 +502,10 @@ function mountBoardStage(host, options) {
340
502
  const previous = scripts;
341
503
  scripts = null;
342
504
  previous.destroy();
505
+ scriptObservers.clear();
506
+ syncTransformSubscription();
507
+ interactiveScripts.clear();
508
+ screenScripts.clear();
343
509
  scriptOutputs.clear();
344
510
  editor.setScriptItems(/* @__PURE__ */ new Map());
345
511
  scriptHover = null;
@@ -354,38 +520,48 @@ function mountBoardStage(host, options) {
354
520
  const moving = new Map(previews);
355
521
  for (const [id, item] of frame.items) moving.set(id, item);
356
522
  editor.setPlayedItems(moving);
523
+ const animationId = editor.playhead?.animationId ?? (frame.playbackTime !== null ? playback?.animationId : null) ?? null;
524
+ if (animationId && (effectDocument !== editor.document || effectAnimation !== animationId)) {
525
+ effectDocument = editor.document;
526
+ effectAnimation = animationId;
527
+ effectSampler = createBoardAnimationSampler(editor.document, animationId);
528
+ }
529
+ if (editor.playhead && effectSampler) {
530
+ frame.camera = effectSampler.at(editor.playhead.time).evaluation.camera;
531
+ frame.time = editor.playhead.time;
532
+ }
533
+ playbackCamera = editor.cameraPolicy === "follow" && Object.keys(frame.camera).length > 0 ? followCamera(frame, editor.scene) : null;
534
+ const camera = renderCamera();
357
535
  if (scripts && (scriptOutputs.size || composedVersion !== scriptVersion)) {
358
536
  const playheadKey = `${editor.playhead?.animationId ?? ""}:${editor.playhead?.time ?? ""}`;
359
- if (scriptVersion !== composedVersion || composedDocument !== editor.document || moving.size || composedMoving || composedZoom !== editor.camera.zoom || composedPlayhead !== playheadKey) {
537
+ if (scriptVersion !== composedVersion || composedDocument !== editor.document || screenScripts.size > 0 && editor.gestureActive || composedGesture || moving.size || composedMoving || composedZoom !== camera.zoom || composedPlayhead !== playheadKey) {
360
538
  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)));
539
+ const composed = composeBoardScriptItems(editor.document, editor.scene, scriptOutputs, animationItems, camera, (owner, error) => scripts?.fault(owner, error instanceof Error ? error.message : String(error)), editor.gestureActive ? editor.scene.layout : void 0);
362
540
  const scriptedIds = new Set([...scriptOutputs.values()].flatMap((output) => Object.keys(output.patches)));
363
541
  for (const id of animationItems.keys()) if (!scriptedIds.has(id)) composed.delete(id);
364
542
  editor.setScriptItems(composed);
365
543
  composedMoving = moving.size > 0;
366
544
  composedPlayhead = playheadKey;
367
- composedZoom = editor.camera.zoom;
545
+ composedZoom = camera.zoom;
546
+ composedGesture = screenScripts.size > 0 && editor.gestureActive;
368
547
  composedVersion = scriptVersion;
369
548
  composedDocument = editor.document;
370
549
  }
371
550
  }
372
551
  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
552
  if (scripts) {
386
553
  const now = performance.now();
387
554
  if (scriptMode !== "paused") scriptTime += Math.min(250, Math.max(0, now - scriptLastTick));
388
555
  scriptLastTick = now;
556
+ if (scriptMode !== "paused" && scriptObservers.size) scriptObservers.sync(editor.document, editor.selection, () => ({
557
+ camera: { ...camera },
558
+ ...surface,
559
+ safeRect: options.safeRect?.() ?? {
560
+ x: 0,
561
+ y: 0,
562
+ ...surface
563
+ }
564
+ }));
389
565
  scripts.sync(editor.document, renderScene, camera, scriptTime, scriptMode === "interact", visibleIds());
390
566
  }
391
567
  world.position.set(camera.x, camera.y);
@@ -420,42 +596,13 @@ function mountBoardStage(host, options) {
420
596
  current.key,
421
597
  textZoomBucket(camera.zoom)
422
598
  ].join("|"),
599
+ staleIds,
423
600
  structureVersion: editor.structureVersion,
424
601
  geometryVersion: editor.geometryVersion,
425
602
  gestureActive: editor.gestureActive && editor.interaction.type !== "panning"
426
603
  });
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);
604
+ staleIds.clear();
605
+ drawInteraction();
459
606
  views.sync({
460
607
  ids,
461
608
  scene: renderScene,
@@ -467,6 +614,8 @@ function mountBoardStage(host, options) {
467
614
  if (nextCursor !== cursor) host.style.cursor = cursor = nextCursor;
468
615
  scheduleRender();
469
616
  if (frame.running || scene.animated || scriptMode !== "paused" && scripts?.animated) scheduleTick();
617
+ const cardWait = scene.tick(performance.now());
618
+ if (cardWait !== null) scheduleCardTick(cardWait);
470
619
  }
471
620
  function resize() {
472
621
  cancelAnimationFrame(resizeFrame);
@@ -517,7 +666,7 @@ function mountBoardStage(host, options) {
517
666
  });
518
667
  }
519
668
  function scriptPointer(type, event, input) {
520
- if (!scriptPointers.needsRouting(event.pointerId, scripts !== null)) return false;
669
+ if (!scriptPointers.needsRouting(event.pointerId, interactiveScripts.size > 0)) return false;
521
670
  const enabled = scriptMode === "interact" && !editor.gestureActive && !editor.spaceHeld && event.button !== 1;
522
671
  const target = type === "leave" || !enabled || scriptPointers.owner(event.pointerId) === "editor" ? null : scriptTarget(input);
523
672
  if (target?.owner !== scriptHover?.owner || target?.target !== scriptHover?.target) {
@@ -525,6 +674,7 @@ function mountBoardStage(host, options) {
525
674
  if (target) sendScriptEvent(target, "pointerenter", event, input, scriptHover);
526
675
  scriptHover = target;
527
676
  }
677
+ const consumed = scriptPointers.owner(event.pointerId) === "script";
528
678
  const { recipient, click } = scriptPointers.route(type, event.pointerId, target, {
529
679
  x: event.clientX,
530
680
  y: event.clientY
@@ -535,10 +685,10 @@ function mountBoardStage(host, options) {
535
685
  }
536
686
  if (recipient && type !== "leave") sendScriptEvent(recipient, input.cancelled ? "pointercancel" : `pointer${type}`, event, input);
537
687
  if (click) sendScriptEvent(click, "click", event, input);
538
- return recipient !== null;
688
+ return consumed || recipient !== null;
539
689
  }
540
690
  function handleScriptKey(event) {
541
- if (scriptMode !== "interact" || !scriptHover || event.target !== host) return;
691
+ if (scriptMode !== "interact" || !scriptHover || event.target !== host || !scriptOutputs.get(scriptHover.owner)?.listens.includes(event.type)) return;
542
692
  const input = {
543
693
  type: event.type,
544
694
  target: scriptHover.target,
@@ -689,6 +839,7 @@ function mountBoardStage(host, options) {
689
839
  },
690
840
  setScriptMode(mode) {
691
841
  if (mode === scriptMode) return;
842
+ if (mode !== "interact") cancelScriptPointers();
692
843
  scriptMode = mode;
693
844
  scriptLastTick = performance.now();
694
845
  scheduleTick();
@@ -723,10 +874,16 @@ function mountBoardStage(host, options) {
723
874
  if (active === next) return;
724
875
  active = next;
725
876
  if (!active) {
877
+ stopMarch();
878
+ cancelScriptPointers();
726
879
  cancelAnimationFrame(renderFrame);
727
880
  cancelAnimationFrame(tickFrame);
881
+ cancelAnimationFrame(cardTickFrame);
882
+ if (cardTickTimer !== null) clearTimeout(cardTickTimer);
728
883
  renderFrame = 0;
729
884
  tickFrame = 0;
885
+ cardTickFrame = 0;
886
+ cardTickTimer = null;
730
887
  return;
731
888
  }
732
889
  player.reset();
@@ -738,13 +895,17 @@ function mountBoardStage(host, options) {
738
895
  cardEpoch += 1;
739
896
  requestAssets = true;
740
897
  }
898
+ for (const id of invalidation?.items ?? []) staleIds.add(id);
741
899
  scheduleTick();
742
900
  },
743
901
  isMaterialized: (id) => Boolean(scene?.getNode(id)),
744
902
  toWorld: (clientX, clientY) => screenToWorld(clientX, clientY, rectOf(), renderCamera()),
745
903
  destroy() {
746
904
  disposed = true;
905
+ stopMarch();
747
906
  scriptPointers.clear();
907
+ stopTransforms?.();
908
+ scriptObservers.clear();
748
909
  scriptListeners.clear();
749
910
  stopMaintenance?.();
750
911
  stopEditor();
@@ -753,6 +914,9 @@ function mountBoardStage(host, options) {
753
914
  cancelAnimationFrame(resizeFrame);
754
915
  cancelAnimationFrame(renderFrame);
755
916
  cancelAnimationFrame(tickFrame);
917
+ cancelAnimationFrame(cardTickFrame);
918
+ if (cardTickTimer !== null) clearTimeout(cardTickTimer);
919
+ cardTickTimer = null;
756
920
  for (const [type, listener] of listeners) host.removeEventListener(type, listener);
757
921
  editor.setPlayedItems(/* @__PURE__ */ new Map());
758
922
  editor.setScriptItems(/* @__PURE__ */ new Map());