@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,6 +1,5 @@
1
1
  import { parseBoardItem } from "../../protocol/dist/board-model.js";
2
2
  import { drawPointsBounds } from "../../protocol/dist/board-layout.js";
3
- import { CORNER_RESIZE_HANDLES, frameCorners, frameHandlePosition, frameRayIntersection, rotationHandleAnchor, rotationHandlePosition } from "../model/geometry.js";
4
3
  import { clippingAncestor, isClippingFrame, syncClipGroup } from "../render/clip.js";
5
4
  import { Graphics } from "pixi.js";
6
5
  //#region src/board/stage/scene.ts
@@ -9,6 +8,7 @@ const FAR_LAYER_EXIT = 350;
9
8
  const FAR_PASS_BATCH = 240;
10
9
  const FAR_LIVE_LIMIT = 64;
11
10
  const Z_FAR_LAYER = -1;
11
+ const Z_LIFTED = 1e9;
12
12
  const Z_LIVE_STROKE = Number.MAX_SAFE_INTEGER - 1;
13
13
  const Z_OVERLAY = Number.MAX_SAFE_INTEGER;
14
14
  const POOL_LIMIT_PER_RENDERER = 48;
@@ -21,26 +21,6 @@ function idSetSignature(ids) {
21
21
  }
22
22
  return hash;
23
23
  }
24
- function traceFrame(graphics, frame) {
25
- const corners = frameCorners(frame);
26
- const first = corners[0];
27
- if (!first) return graphics;
28
- graphics.moveTo(first.x, first.y);
29
- for (let index = 1; index < corners.length; index += 1) {
30
- const point = corners[index];
31
- if (point) graphics.lineTo(point.x, point.y);
32
- }
33
- return graphics.closePath();
34
- }
35
- function frameEdgePoints(frame, handle) {
36
- switch (handle) {
37
- case "n": return [frameHandlePosition(frame, "nw"), frameHandlePosition(frame, "ne")];
38
- case "e": return [frameHandlePosition(frame, "ne"), frameHandlePosition(frame, "se")];
39
- case "s": return [frameHandlePosition(frame, "sw"), frameHandlePosition(frame, "se")];
40
- case "w": return [frameHandlePosition(frame, "nw"), frameHandlePosition(frame, "sw")];
41
- default: return null;
42
- }
43
- }
44
24
  function createBoardScene(options) {
45
25
  const { world, overlay, getRenderer } = options;
46
26
  world.sortableChildren = true;
@@ -48,12 +28,15 @@ function createBoardScene(options) {
48
28
  const cards = /* @__PURE__ */ new Map();
49
29
  const clips = /* @__PURE__ */ new Map();
50
30
  const animatedIds = /* @__PURE__ */ new Set();
31
+ const tickingIds = /* @__PURE__ */ new Set();
51
32
  const pools = /* @__PURE__ */ new Map();
52
33
  const heldKeys = /* @__PURE__ */ new Map();
53
34
  let orderById = /* @__PURE__ */ new Map();
54
35
  let farSig = null;
55
36
  let farActive = false;
56
37
  let lastStructureVersion = -1;
38
+ let lastZoom = NaN;
39
+ let lifted = /* @__PURE__ */ new Set();
57
40
  const liveStrokes = /* @__PURE__ */ new Map();
58
41
  function setHeldKey(context, cardId, desiredKey) {
59
42
  const heldKey = heldKeys.get(cardId) ?? null;
@@ -72,6 +55,7 @@ function createBoardScene(options) {
72
55
  setHeldKey(context, id, null);
73
56
  cards.delete(id);
74
57
  animatedIds.delete(id);
58
+ tickingIds.delete(id);
75
59
  if (destroyed) return;
76
60
  entry.container.parent?.removeChild(entry.container);
77
61
  entry.container.visible = false;
@@ -123,6 +107,7 @@ function createBoardScene(options) {
123
107
  container.alpha = scene.opacity(item.id);
124
108
  hostFor(item, scene).addChild(container);
125
109
  if (renderer.animated) animatedIds.add(item.id);
110
+ if (renderer.tick) tickingIds.add(item.id);
126
111
  const entry = {
127
112
  item,
128
113
  container,
@@ -135,6 +120,7 @@ function createBoardScene(options) {
135
120
  };
136
121
  cards.set(item.id, entry);
137
122
  setHeldKey(context, item.id, context.assetKey(item));
123
+ renderer.zoom?.(container, context.zoom);
138
124
  return entry;
139
125
  }
140
126
  let farFront = createFarLayer();
@@ -352,7 +338,8 @@ function createBoardScene(options) {
352
338
  const hovered = context.hoveredId === id;
353
339
  const resizing = context.resizingIds.has(id);
354
340
  const scriptRevision = context.scripts?.revision?.(id) ?? 0;
355
- const changed = scriptRevision !== entry.scriptRevision || item !== entry.item || entry.renderer.animated || selected !== entry.selected || hovered !== entry.hovered || resizing !== entry.resizing || globalSig !== entry.globalSig;
341
+ const observed = entry.renderer.observesSelection === true && (selected !== entry.selected || hovered !== entry.hovered);
342
+ const changed = input.staleIds?.has(id) || scriptRevision !== entry.scriptRevision || item !== entry.item || entry.renderer.animated || observed || resizing !== entry.resizing || globalSig !== entry.globalSig;
356
343
  entry.scriptRevision = scriptRevision;
357
344
  entry.item = item;
358
345
  entry.selected = selected;
@@ -363,120 +350,39 @@ function createBoardScene(options) {
363
350
  if (changed) {
364
351
  entry.renderer.update(entry.container, item, context);
365
352
  entry.container.alpha = scene.opacity(id);
353
+ if (entry.renderer.tick) tickingIds.add(id);
366
354
  }
367
355
  }
368
356
  if (structureChanged || liveSetChanged) syncClips(scene);
369
- if (structureChanged || farModeChanged || liveSetChanged) applyChildOrder();
357
+ if (context.zoom !== lastZoom) {
358
+ lastZoom = context.zoom;
359
+ for (const entry of cards.values()) entry.renderer.zoom?.(entry.container, lastZoom);
360
+ }
361
+ const liftChanged = context.liftedIds !== lifted;
362
+ lifted = context.liftedIds;
363
+ if (structureChanged || farModeChanged || liveSetChanged || liftChanged) applyChildOrder(scene);
370
364
  syncLiveStrokes(input);
371
365
  }
372
- function applyChildOrder() {
373
- for (const [id, entry] of cards) entry.container.zIndex = orderById.get(id) ?? 0;
374
- world.sortableChildren = true;
375
- world.sortChildren();
376
- }
377
- function drawOverlay(input, palette) {
378
- overlay.clear();
379
- const { zoom, pointerType, marquee, selection, transform, controls, hoveredControl, rotationPointer, arrowEndpoints, ports, hoveredPort, arrowDraft, bindTarget } = input;
380
- const inv = 1 / zoom;
381
- const brand = palette.brand;
382
- if (marquee) {
383
- overlay.rect(marquee.x, marquee.y, marquee.width, marquee.height).fill({
384
- color: brand,
385
- alpha: .08
386
- });
387
- overlay.rect(marquee.x, marquee.y, marquee.width, marquee.height).stroke({
388
- color: brand,
389
- width: inv,
390
- alpha: .7
391
- });
392
- }
393
- if (bindTarget) traceFrame(overlay, bindTarget).stroke({
394
- color: brand,
395
- width: 2 * inv,
396
- alpha: .9
397
- });
398
- if (arrowDraft) {
399
- const { from, to, size, targetFrame } = arrowDraft;
400
- if (targetFrame) traceFrame(overlay, targetFrame).stroke({
401
- color: brand,
402
- width: 2 * inv,
403
- alpha: .9
404
- });
405
- overlay.moveTo(from.x, from.y).lineTo(to.x, to.y).stroke({
406
- color: brand,
407
- width: Math.max(size, 1.5) * inv,
408
- alpha: .85,
409
- cap: "round"
410
- });
411
- overlay.circle(to.x, to.y, 3.5 * inv).fill({
412
- color: brand,
413
- alpha: .95
414
- });
366
+ function tick(clock) {
367
+ let next = null;
368
+ for (const id of tickingIds) {
369
+ const entry = cards.get(id);
370
+ const wait = entry?.container.visible ? entry.renderer.tick?.(entry.container, clock) ?? null : null;
371
+ if (wait === null) tickingIds.delete(id);
372
+ else next = next === null ? wait : Math.min(next, wait);
415
373
  }
416
- if (ports && ports.length > 0) for (const port of ports) {
417
- const hovered = hoveredPort && Math.abs(hoveredPort.x - port.x) < .001 && Math.abs(hoveredPort.y - port.y) < .001;
418
- const r = (hovered ? port.radius * 1.5 : port.radius) * inv;
419
- overlay.circle(port.x, port.y, r).fill({
420
- color: palette.surface,
421
- alpha: 1
422
- }).stroke({
423
- color: brand,
424
- width: 1.5 * inv,
425
- alpha: hovered ? 1 : .8
426
- });
427
- }
428
- if (!transform || selection.length === 0) return;
429
- const source = transform.frame;
430
- traceFrame(overlay, source).stroke({
431
- color: brand,
432
- width: 1.5 * inv,
433
- alpha: .95
434
- });
435
- if (!controls) return;
436
- if (arrowEndpoints && arrowEndpoints.length > 0) {
437
- const r = 5 * inv;
438
- for (const point of arrowEndpoints) overlay.circle(point.x, point.y, r).fill({
439
- color: palette.surface,
440
- alpha: 1
441
- }).stroke({
442
- color: brand,
443
- width: 1.5 * inv
444
- });
445
- return;
446
- }
447
- if (hoveredControl?.kind === "resize" && transform.resizeMode === "free") {
448
- const edge = frameEdgePoints(source, hoveredControl.handle);
449
- if (edge) overlay.moveTo(edge[0].x, edge[0].y).lineTo(edge[1].x, edge[1].y).stroke({
450
- color: brand,
451
- width: 2.5 * inv,
452
- alpha: 1
453
- });
454
- }
455
- if (transform.resizeMode !== "none") for (const handle of CORNER_RESIZE_HANDLES) {
456
- const position = frameHandlePosition(source, handle);
457
- const hovered = hoveredControl?.kind === "resize" && hoveredControl.handle === handle;
458
- overlay.circle(position.x, position.y, (hovered ? 5 : 4) * inv).fill({
459
- color: hovered ? brand : palette.surface,
460
- alpha: 1
461
- }).stroke({
462
- color: brand,
463
- width: 1.5 * inv
464
- });
465
- }
466
- if (transform.canRotate && (pointerType === "touch" || transform.resizeMode === "none")) {
467
- const rotation = rotationPointer ?? rotationHandlePosition(source, zoom);
468
- const anchor = rotationPointer ? frameRayIntersection(source, rotationPointer) : rotationHandleAnchor(source);
469
- const hovered = rotationPointer !== null || hoveredControl?.kind === "rotate";
470
- overlay.moveTo(anchor.x, anchor.y).lineTo(rotation.x, rotation.y).stroke({
471
- color: brand,
472
- width: inv,
473
- alpha: .8
474
- });
475
- overlay.circle(rotation.x, rotation.y, (hovered ? 6 : 5) * inv).fill({ color: hovered ? brand : palette.surface }).stroke({
476
- color: brand,
477
- width: 1.5 * inv
478
- });
374
+ return next;
375
+ }
376
+ function applyChildOrder(scene) {
377
+ const raised = new Set(lifted);
378
+ for (const id of lifted) if (scene.get(id)?.type === "frame") for (const child of scene.descendants(id)) raised.add(child);
379
+ const order = (id) => (orderById.get(id) ?? 0) + (raised.has(id) ? Z_LIFTED : 0);
380
+ for (const [id, entry] of cards) entry.container.zIndex = order(id);
381
+ for (const [id, entry] of clips) {
382
+ entry.group.zIndex = order(id) + .5;
383
+ entry.group.sortChildren();
479
384
  }
385
+ world.sortChildren();
480
386
  }
481
387
  function destroy(context) {
482
388
  for (const entry of cards.values()) entry.renderer.destroy?.(entry.container, context);
@@ -489,11 +395,13 @@ function createBoardScene(options) {
489
395
  for (const entry of clips.values()) entry.group.destroy({ children: true });
490
396
  clips.clear();
491
397
  animatedIds.clear();
398
+ tickingIds.clear();
492
399
  for (const id of [...liveStrokes.keys()]) removeLiveStroke(id, context);
493
400
  resetFarLayer();
494
401
  farActive = false;
495
402
  visibleMemo = null;
496
403
  lastStructureVersion = -1;
404
+ lastZoom = NaN;
497
405
  }
498
406
  return {
499
407
  sync,
@@ -507,7 +415,7 @@ function createBoardScene(options) {
507
415
  get animated() {
508
416
  return animatedIds.size > 0;
509
417
  },
510
- drawOverlay,
418
+ tick,
511
419
  destroy
512
420
  };
513
421
  }
@@ -13,6 +13,7 @@ declare function createBoardScriptPointerRouter(): {
13
13
  recipient: BoardScriptPointerTarget | null;
14
14
  click: BoardScriptPointerTarget | null;
15
15
  };
16
+ cancelScripts(cancel: (pointerId: number, target: BoardScriptPointerTarget) => void, owner?: string, retained?: Readonly<Record<string, unknown>>): void;
16
17
  clear(): void;
17
18
  };
18
19
  //#endregion
@@ -15,17 +15,23 @@ function createBoardScriptPointerRouter() {
15
15
  ...point
16
16
  });
17
17
  const gesture = gestures.get(pointerId);
18
- const recipient = gesture ? gesture.target : phase === "move" ? target : null;
18
+ const recipient = gesture ? gesture.cancelled ? null : gesture.target : phase === "move" ? target : null;
19
19
  let click = null;
20
20
  if (phase === "up") {
21
21
  gestures.delete(pointerId);
22
- if (!cancelled && gesture?.target && target?.owner === gesture.target.owner && target.target === gesture.target.target && Math.hypot(point.x - gesture.x, point.y - gesture.y) < 5) click = gesture.target;
22
+ if (!cancelled && !gesture?.cancelled && gesture?.target && target?.owner === gesture.target.owner && target.target === gesture.target.target && Math.hypot(point.x - gesture.x, point.y - gesture.y) < 5) click = gesture.target;
23
23
  }
24
24
  return {
25
25
  recipient,
26
26
  click
27
27
  };
28
28
  },
29
+ cancelScripts(cancel, owner, retained) {
30
+ for (const [pointerId, gesture] of gestures) if (!gesture.cancelled && gesture.target && (!owner || gesture.target.owner === owner) && (!retained || !Object.hasOwn(retained, gesture.target.target))) {
31
+ gesture.cancelled = true;
32
+ cancel(pointerId, gesture.target);
33
+ }
34
+ },
29
35
  clear() {
30
36
  gestures.clear();
31
37
  }
@@ -1,8 +1,8 @@
1
- import { BoardItem } from "../../protocol/dist/board-model.js";
1
+ import { BoardItem, BoardTaskItem } from "../../protocol/dist/board-model.js";
2
2
  import { BoardPlaybackSnapshot } from "../../protocol/dist/board.js";
3
3
  import "../../protocol/dist/index.js";
4
+ import { BoardViewport, Rect, WorldPoint } from "../model/geometry.js";
4
5
  import { BoardScriptOutput, BoardScriptSnapshot } from "../model/script.js";
5
- import { BoardViewport, WorldPoint } from "../model/geometry.js";
6
6
  import { BoardScene, BoardSceneItem } from "../model/scene.js";
7
7
  import { BoardShapeColors } from "../model/palette.js";
8
8
  import { BoardAssetSource } from "../model/media-playback.js";
@@ -10,7 +10,8 @@ import "../model/index.js";
10
10
  import { BoardPointerEvent } from "../editor/interaction.js";
11
11
  import { BoardEditor } from "../editor/editor.js";
12
12
  import "../editor/index.js";
13
- import { BoardCardRendererResolver, BoardRenderPalette } from "../render/renderers/board-renderer-registry.js";
13
+ import { BoardRenderStyle } from "../render/style.js";
14
+ import { BoardCardRendererResolver, BoardRenderLabels, BoardRenderPalette } from "../render/renderers/board-renderer-registry.js";
14
15
  import "../render/index.js";
15
16
  import { BoardAssetManager } from "./assets.js";
16
17
  import { BoardLiveStroke } from "./scene.js";
@@ -22,6 +23,7 @@ type BoardStageTheme = {
22
23
  palette: BoardRenderPalette;
23
24
  colors: BoardShapeColors;
24
25
  colorScheme: "dark" | "light";
26
+ style?: BoardRenderStyle;
25
27
  imageBackground?: boolean;
26
28
  };
27
29
  type BoardStagePointerPhase = "down" | "move" | "up" | "leave";
@@ -32,6 +34,12 @@ type BoardStageOptions = {
32
34
  renderers?: BoardCardRendererResolver;
33
35
  views?: readonly BoardItemView[];
34
36
  theme?: () => BoardStageTheme;
37
+ labels?: () => BoardRenderLabels;
38
+ taskRun?: (taskRunId: string) => {
39
+ status: BoardTaskItem["props"]["snapshot"]["status"];
40
+ startedAt?: string;
41
+ } | null;
42
+ reducedMotion?: () => boolean;
35
43
  playback?: () => BoardPlaybackSnapshot | null;
36
44
  fileState?: (path: string) => "ok" | "missing" | "unavailable";
37
45
  previews?: () => ReadonlyMap<string, BoardItem>;
@@ -48,6 +56,7 @@ type BoardStageOptions = {
48
56
  height: number;
49
57
  }) => void;
50
58
  onVisibleChange?: (ids: ReadonlySet<string> | null) => void;
59
+ safeRect?: () => Rect;
51
60
  scriptCapabilities?: Record<string, (id: string, input: unknown) => Promise<unknown>>;
52
61
  };
53
62
  type BoardStage = {
@@ -66,6 +75,7 @@ type BoardStage = {
66
75
  subscribeScripts(listener: () => void): () => void;
67
76
  invalidate(options?: {
68
77
  cards?: boolean;
78
+ items?: Iterable<string>;
69
79
  }): void;
70
80
  isMaterialized(id: string): boolean;
71
81
  toWorld(clientX: number, clientY: number): WorldPoint;