@neta-art/cohub 11.5.1 → 12.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 (73) hide show
  1. package/dist/board/editor/animation.js +2 -1
  2. package/dist/board/editor/creation.js +1 -1
  3. package/dist/board/editor/document-edits.d.ts +1 -1
  4. package/dist/board/editor/document-edits.js +1 -19
  5. package/dist/board/editor/document.js +2 -1
  6. package/dist/board/editor/index.d.ts +2 -1
  7. package/dist/board/editor/index.js +2 -1
  8. package/dist/board/editor/snapshots.js +11 -13
  9. package/dist/board/export/index.js +1 -1
  10. package/dist/board/export/scene.js +1 -1
  11. package/dist/board/model/client-geometry.d.ts +22 -0
  12. package/dist/board/model/client-geometry.js +94 -0
  13. package/dist/board/model/document-share.d.ts +5 -0
  14. package/dist/board/model/document-share.js +27 -0
  15. package/dist/board/model/index.d.ts +5 -4
  16. package/dist/board/model/index.js +4 -3
  17. package/dist/board/model/items/create.d.ts +5 -1
  18. package/dist/board/model/items/create.js +29 -58
  19. package/dist/board/model/items/index.d.ts +2 -2
  20. package/dist/board/model/items/index.js +2 -2
  21. package/dist/board/model/items/registry.js +2 -5
  22. package/dist/board/model/json.d.ts +4 -0
  23. package/dist/board/model/json.js +22 -0
  24. package/dist/board/model/media-playback.d.ts +6 -3
  25. package/dist/board/player/index.d.ts +6 -2
  26. package/dist/board/player/index.js +33 -15
  27. package/dist/board/render/index.d.ts +2 -2
  28. package/dist/board/render/index.js +6 -6
  29. package/dist/board/render/renderers/arrow-card-renderer.js +5 -1
  30. package/dist/board/render/renderers/audio-card-renderer.js +4 -1
  31. package/dist/board/render/renderers/board-renderer-registry.d.ts +4 -2
  32. package/dist/board/render/renderers/custom-card-renderer.js +5 -2
  33. package/dist/board/render/renderers/file-card-renderer.js +4 -1
  34. package/dist/board/render/renderers/frame-card-renderer.js +5 -1
  35. package/dist/board/render/renderers/image-card-renderer.js +13 -49
  36. package/dist/board/render/renderers/model-card-renderer.js +4 -1
  37. package/dist/board/render/renderers/shape-card-renderer.js +5 -1
  38. package/dist/board/render/renderers/task-card-renderer.js +6 -3
  39. package/dist/board/render/renderers/text-card-renderer.js +6 -2
  40. package/dist/board/render/renderers/unknown-card-renderer.js +4 -0
  41. package/dist/board/render/renderers/video-card-renderer.js +19 -18
  42. package/dist/board/render/script-host.d.ts +2 -0
  43. package/dist/board/render/script-host.js +44 -9
  44. package/dist/board/render/script-resolution.d.ts +4 -0
  45. package/dist/board/render/script-resolution.js +18 -0
  46. package/dist/board/render/surface.d.ts +9 -2
  47. package/dist/board/render/surface.js +15 -1
  48. package/dist/board/replica/index.js +4 -1
  49. package/dist/board/stage/assets.d.ts +12 -8
  50. package/dist/board/stage/assets.js +173 -88
  51. package/dist/board/stage/index.d.ts +3 -3
  52. package/dist/board/stage/index.js +3 -3
  53. package/dist/board/stage/lru.d.ts +3 -2
  54. package/dist/board/stage/lru.js +8 -4
  55. package/dist/board/stage/pointer.d.ts +1 -1
  56. package/dist/board/stage/pointer.js +4 -5
  57. package/dist/board/stage/scene.d.ts +3 -0
  58. package/dist/board/stage/scene.js +44 -8
  59. package/dist/board/stage/stage.d.ts +1 -0
  60. package/dist/board/stage/stage.js +123 -56
  61. package/dist/board/stage/views.d.ts +7 -2
  62. package/dist/board/stage/views.js +50 -21
  63. package/dist/chunks/environment.d.ts +16 -2
  64. package/dist/index.js +65 -22
  65. package/dist/protocol/dist/board-constants.js +56 -1
  66. package/dist/protocol/dist/board-layout.d.ts +8 -1
  67. package/dist/protocol/dist/board-layout.js +16 -4
  68. package/dist/protocol/dist/board-model.js +13 -19
  69. package/dist/protocol/dist/board-schema.d.ts +52 -0
  70. package/dist/protocol/dist/board-schema.js +8 -0
  71. package/dist/protocol/dist/core/media.js +1 -0
  72. package/dist/protocol/dist/index.d.ts +2 -2
  73. package/package.json +1 -1
@@ -1,22 +1,24 @@
1
1
  import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
2
2
  import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
3
- import { screenPoint, screenToWorld, stableCullRect, visibleWorldRect, worldPoint } from "../model/geometry.js";
3
+ import { pointToWorld, stableCullRect, visibleWorldRect, worldPoint } from "../model/geometry.js";
4
4
  import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
5
5
  import { boardScriptTarget } from "../model/script-hit.js";
6
6
  import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "../model/sampling.js";
7
7
  import { resolveSceneArrow } from "../model/arrow-geometry.js";
8
8
  import { buildFallbackShapeColors, pickBoardColor, resolveItemColor } from "../model/palette.js";
9
+ import { elementClientToLocal } from "../model/client-geometry.js";
9
10
  import { isCreationBoardTool } from "../editor/tool.js";
10
11
  import { resizeCursorForHandle } from "../editor/selection-transform.js";
12
+ import { createBoardPlayer } from "../player/index.js";
13
+ import { createBoardScriptObservers } from "../model/script-observers.js";
11
14
  import { parseBoardCssColor } from "../render/css-color.js";
12
- import { defaultBoardPalette, itemAlpha } from "../render/palette.js";
13
15
  import { createBoardBackground, updateBoardBackground } from "../render/board-background.js";
14
- import { getBoardResolution, textZoomBucket } from "../render/text-resolution.js";
16
+ import { getBoardResolution } from "../render/text-resolution.js";
17
+ import { defaultBoardPalette, itemAlpha } from "../render/palette.js";
15
18
  import { DEFAULT_BOARD_RENDER_LABELS, getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
16
19
  import { createBoardScriptHost } from "../render/script-host.js";
17
20
  import { defaultBoardRenderStyle } from "../render/style.js";
18
- import { createBoardScriptObservers } from "../model/script-observers.js";
19
- import { createBoardPlayer } from "../player/index.js";
21
+ import { boardTextureEdge } from "./assets.js";
20
22
  import { observeDisplayDensity } from "./display-density.js";
21
23
  import { toBoardPointerEvent } from "./pointer.js";
22
24
  import { createBoardPointerGestures } from "./pointer-gestures.js";
@@ -49,6 +51,7 @@ function defaultTheme() {
49
51
  const NO_IDS = /* @__PURE__ */ new Set();
50
52
  const MARCH_STEP_MS = 160;
51
53
  const MARCH_SMOOTH_MS = 40;
54
+ const TEXTURE_SETTLE_MS = 150;
52
55
  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`;
53
56
  const defaultStyles = /* @__PURE__ */ new Map();
54
57
  function styleOf(theme) {
@@ -102,13 +105,13 @@ function mountBoardStage(host, options) {
102
105
  let disposed = false;
103
106
  let renderFrame = 0;
104
107
  let tickFrame = 0;
108
+ let scriptTickFrame = 0;
105
109
  let cardTickFrame = 0;
106
110
  let cardTickTimer = null;
107
111
  let cardTickDue = 0;
108
112
  const staleIds = /* @__PURE__ */ new Set();
109
113
  let resizeFrame = 0;
110
114
  let cardEpoch = 0;
111
- let assetVersion = 0;
112
115
  let surface = {
113
116
  width: 0,
114
117
  height: 0
@@ -116,7 +119,7 @@ function mountBoardStage(host, options) {
116
119
  let playbackCamera = null;
117
120
  let cursor = "";
118
121
  const renderCamera = () => playbackCamera ?? editor.camera;
119
- const views = createBoardItemViewLayer(host, editor, options.views ?? [], renderCamera);
122
+ const views = createBoardItemViewLayer(host, editor, options.views ?? [], renderCamera, scheduleTick);
120
123
  const player = createBoardPlayer({ resolveColor: (color) => {
121
124
  const current = theme();
122
125
  return {
@@ -140,29 +143,70 @@ function mountBoardStage(host, options) {
140
143
  scene: editor.scene
141
144
  };
142
145
  options.onVisibleChange?.(cull.ids);
143
- requestAssets = true;
144
146
  return cull.ids;
145
147
  }
146
- let requestAssets = true;
147
- function syncAssets(ids) {
148
- if (!requestAssets || !ids) return;
149
- requestAssets = false;
148
+ const textureScale = () => renderCamera().zoom * (app?.renderer.resolution ?? 1);
149
+ let refined = {
150
+ scale: 0,
151
+ geometry: 0
152
+ };
153
+ let pendingRefine = "";
154
+ let refineTimer = null;
155
+ function stopRefine() {
156
+ if (refineTimer !== null) clearTimeout(refineTimer);
157
+ refineTimer = null;
158
+ refined = {
159
+ scale: 0,
160
+ geometry: 0
161
+ };
162
+ pendingRefine = "";
163
+ }
164
+ function scheduleRefine() {
165
+ const scale = textureScale();
166
+ const geometry = editor.geometryVersion;
167
+ const key = `${scale}:${geometry}`;
168
+ if (key === pendingRefine) return;
169
+ pendingRefine = key;
170
+ if (refineTimer !== null) clearTimeout(refineTimer);
171
+ refineTimer = null;
172
+ if (refined.scale === 0 || scale <= refined.scale && geometry === refined.geometry) {
173
+ refined = {
174
+ scale,
175
+ geometry
176
+ };
177
+ return;
178
+ }
179
+ refineTimer = setTimeout(() => {
180
+ refineTimer = null;
181
+ refined = {
182
+ scale,
183
+ geometry
184
+ };
185
+ for (const id of scene?.liveIds() ?? []) {
186
+ const item = editor.scene.get(id);
187
+ if (item) assets.requestItem(item, boardTextureEdge(item, scale));
188
+ }
189
+ }, TEXTURE_SETTLE_MS);
190
+ }
191
+ const naturalIds = /* @__PURE__ */ new Set();
192
+ let liveVersion = -1;
193
+ function adoptNaturalSizes() {
194
+ if (naturalIds.size === 0) return;
150
195
  const sizes = [];
151
- for (const id of ids) {
196
+ for (const id of naturalIds) {
152
197
  const item = editor.itemById(id);
153
- if (!item) continue;
154
- const key = assets.assetKey(item);
155
- if (!key) continue;
156
- assets.requestItem(item);
198
+ const key = item && assets.assetKey(item);
199
+ if (!item || !key) continue;
157
200
  const artifact = item.type === "task" ? featuredTaskArtifact(item.props.snapshot.artifacts) : null;
158
201
  const recorded = artifact?.type === "image" || artifact?.type === "video" ? artifact : item.type === "image" || item.type === "video" ? item.props.snapshot : null;
159
202
  if (!recorded || recorded.naturalWidth && recorded.naturalHeight) continue;
160
203
  const natural = assets.getNaturalSize(key);
161
204
  if (natural?.width && natural.height) sizes.push({
162
- id: item.id,
205
+ id,
163
206
  ...natural
164
207
  });
165
208
  }
209
+ naturalIds.clear();
166
210
  if (sizes.length > 0) editor.adoptMediaNaturalSizes(sizes);
167
211
  }
168
212
  let lifted = null;
@@ -203,7 +247,11 @@ function mountBoardStage(host, options) {
203
247
  getTexture: (key) => assets.getTexture(key),
204
248
  hasError: (key) => assets.hasError(key),
205
249
  fileState: (path) => options.fileState?.(path) ?? "ok",
206
- acquireTexture: (key) => assets.acquire(key),
250
+ acquireTexture: (key, item) => {
251
+ assets.acquire(key);
252
+ assets.requestItem(item, boardTextureEdge(item, textureScale()));
253
+ if (assets.getTexture(key)) naturalIds.add(item.id);
254
+ },
207
255
  releaseTexture: (key) => assets.release(key)
208
256
  };
209
257
  }
@@ -442,9 +490,37 @@ function mountBoardStage(host, options) {
442
490
  }, owner, retained);
443
491
  if (!retained || scriptHover && scriptHover.owner === owner && !Object.hasOwn(retained, scriptHover.target)) scriptHover = null;
444
492
  }
493
+ function syncScripts() {
494
+ if (!scripts) return;
495
+ const now = performance.now();
496
+ if (scriptMode !== "paused") scriptTime += Math.min(250, Math.max(0, now - scriptLastTick));
497
+ scriptLastTick = now;
498
+ const camera = renderCamera();
499
+ if (scriptMode !== "paused" && scriptObservers.size) scriptObservers.sync(editor.document, editor.selection, () => ({
500
+ camera: { ...camera },
501
+ ...surface,
502
+ safeRect: options.safeRect?.() ?? {
503
+ x: 0,
504
+ y: 0,
505
+ ...surface
506
+ }
507
+ }));
508
+ scripts.sync(editor.document, editor.scene, camera, scriptTime, scriptMode === "interact", visibleIds());
509
+ }
510
+ function scheduleScriptTick() {
511
+ if (scriptTickFrame || !active || disposed) return;
512
+ scriptTickFrame = requestAnimationFrame(() => {
513
+ scriptTickFrame = 0;
514
+ if (tickFrame) return;
515
+ syncScripts();
516
+ if (scriptMode !== "paused" && scripts?.animated) scheduleScriptTick();
517
+ });
518
+ }
445
519
  function createScripts() {
446
520
  return createBoardScriptHost({
447
521
  host,
522
+ isMaterialized: (id) => Boolean(scene?.getNode(id)),
523
+ onSchedule: scheduleScriptTick,
448
524
  capabilities: {
449
525
  ...options.scriptCapabilities,
450
526
  "board.emit": async (id, value) => {
@@ -552,25 +628,9 @@ function mountBoardStage(host, options) {
552
628
  }
553
629
  }
554
630
  const renderScene = editor.scene;
555
- if (scripts) {
556
- const now = performance.now();
557
- if (scriptMode !== "paused") scriptTime += Math.min(250, Math.max(0, now - scriptLastTick));
558
- scriptLastTick = now;
559
- if (scriptMode !== "paused" && scriptObservers.size) scriptObservers.sync(editor.document, editor.selection, () => ({
560
- camera: { ...camera },
561
- ...surface,
562
- safeRect: options.safeRect?.() ?? {
563
- x: 0,
564
- y: 0,
565
- ...surface
566
- }
567
- }));
568
- scripts.sync(editor.document, renderScene, camera, scriptTime, scriptMode === "interact", visibleIds());
569
- }
570
631
  world.position.set(camera.x, camera.y);
571
632
  world.scale.set(camera.zoom);
572
633
  const ids = visibleIds();
573
- syncAssets(ids);
574
634
  const context = renderContext(current, renderScene, frame.time);
575
635
  if (animationId && effectSampler) {
576
636
  context.time = editor.playhead?.time ?? frame.time;
@@ -593,19 +653,20 @@ function mountBoardStage(host, options) {
593
653
  getItem: (id) => renderScene.get(id) ?? null,
594
654
  visibleIds: ids,
595
655
  pinnedIds,
596
- globalSig: [
597
- assetVersion,
598
- cardEpoch,
599
- current.key,
600
- textZoomBucket(camera.zoom),
601
- getBoardResolution()
602
- ].join("|"),
656
+ globalSig: [cardEpoch, current.key].join("|"),
603
657
  staleIds,
604
658
  structureVersion: editor.structureVersion,
605
659
  geometryVersion: editor.geometryVersion,
606
660
  gestureActive: editor.gestureActive && editor.interaction.type !== "panning"
607
661
  });
608
662
  staleIds.clear();
663
+ if (scene.liveVersion !== liveVersion) {
664
+ liveVersion = scene.liveVersion;
665
+ options.onLiveChange?.(scene.liveIds());
666
+ }
667
+ adoptNaturalSizes();
668
+ scheduleRefine();
669
+ syncScripts();
609
670
  drawInteraction();
610
671
  views.sync({
611
672
  ids,
@@ -617,7 +678,8 @@ function mountBoardStage(host, options) {
617
678
  const nextCursor = cursorFor();
618
679
  if (nextCursor !== cursor) host.style.cursor = cursor = nextCursor;
619
680
  scheduleRender();
620
- if (frame.running || scene.animated || scriptMode !== "paused" && scripts?.animated) scheduleTick();
681
+ if (frame.running || scene.animated) scheduleTick();
682
+ if (scriptMode !== "paused" && scripts?.animated) scheduleScriptTick();
621
683
  const cardWait = scene.tick(performance.now());
622
684
  if (cardWait !== null) scheduleCardTick(cardWait);
623
685
  }
@@ -641,10 +703,10 @@ function mountBoardStage(host, options) {
641
703
  sync();
642
704
  });
643
705
  }
644
- const rectOf = () => host.getBoundingClientRect();
706
+ const localPoint = (x, y) => elementClientToLocal(host)(x, y);
645
707
  const inViews = (event) => event.target instanceof Node && views.element.contains(event.target);
646
708
  function toInput(event) {
647
- return toBoardPointerEvent(event, rectOf(), renderCamera(), event.type === "pointermove" && editor.interaction.type === "drawing");
709
+ return toBoardPointerEvent(event, host, renderCamera(), event.type === "pointermove" && editor.interaction.type === "drawing");
648
710
  }
649
711
  function scriptTarget(input) {
650
712
  if (!scriptOutputs.size) return null;
@@ -751,13 +813,12 @@ function mountBoardStage(host, options) {
751
813
  if (inViews(event)) return;
752
814
  event.preventDefault();
753
815
  editor.takeCameraControl();
754
- const rect = rectOf();
755
- const point = screenPoint(event.clientX - rect.left, event.clientY - rect.top);
816
+ const point = localPoint(event.clientX, event.clientY);
756
817
  editor.wheel(point, event.deltaX, event.deltaY, event.ctrlKey || event.metaKey, event.deltaMode);
757
818
  }
758
819
  function handleDoubleClick(event) {
759
820
  if (inViews(event)) return;
760
- const point = screenToWorld(event.clientX, event.clientY, rectOf(), renderCamera());
821
+ const point = pointToWorld(localPoint(event.clientX, event.clientY), renderCamera());
761
822
  const item = editor.itemAt(point);
762
823
  if (options.onDoubleClick?.(item, point) === true || editor.readonly) return;
763
824
  if (item && !item.locked && editor.registry.capabilities(item).canEdit) {
@@ -783,9 +844,13 @@ function mountBoardStage(host, options) {
783
844
  ["dblclick", handleDoubleClick]
784
845
  ];
785
846
  const stopEditor = editor.subscribe(LIVE_CHANNELS, scheduleTick);
786
- const stopAssets = assets.subscribe(() => {
787
- assetVersion += 1;
788
- requestAssets = true;
847
+ const stopAssets = assets.subscribe((key) => {
848
+ const ids = scene?.holders(key);
849
+ if (!ids?.size) return;
850
+ for (const id of ids) {
851
+ staleIds.add(id);
852
+ naturalIds.add(id);
853
+ }
789
854
  scheduleTick();
790
855
  });
791
856
  const resizeObserver = new ResizeObserver(resize);
@@ -895,7 +960,10 @@ function mountBoardStage(host, options) {
895
960
  if (!active) {
896
961
  pointers.cancel();
897
962
  stopMarch();
963
+ stopRefine();
898
964
  cancelScriptPointers();
965
+ cancelAnimationFrame(scriptTickFrame);
966
+ scriptTickFrame = 0;
899
967
  cancelAnimationFrame(renderFrame);
900
968
  cancelAnimationFrame(tickFrame);
901
969
  cancelAnimationFrame(cardTickFrame);
@@ -911,19 +979,17 @@ function mountBoardStage(host, options) {
911
979
  resize();
912
980
  },
913
981
  invalidate(invalidation) {
914
- if (invalidation?.cards) {
915
- cardEpoch += 1;
916
- requestAssets = true;
917
- }
982
+ if (invalidation?.cards) cardEpoch += 1;
918
983
  for (const id of invalidation?.items ?? []) staleIds.add(id);
919
984
  scheduleTick();
920
985
  },
921
986
  isMaterialized: (id) => Boolean(scene?.getNode(id)),
922
- toWorld: (clientX, clientY) => screenToWorld(clientX, clientY, rectOf(), renderCamera()),
987
+ toWorld: (clientX, clientY) => pointToWorld(localPoint(clientX, clientY), renderCamera()),
923
988
  destroy() {
924
989
  disposed = true;
925
990
  pointers.cancel();
926
991
  stopMarch();
992
+ stopRefine();
927
993
  scriptPointers.clear();
928
994
  stopTransforms?.();
929
995
  scriptObservers.clear();
@@ -933,6 +999,7 @@ function mountBoardStage(host, options) {
933
999
  stopEditor();
934
1000
  stopAssets();
935
1001
  resizeObserver.disconnect();
1002
+ cancelAnimationFrame(scriptTickFrame);
936
1003
  cancelAnimationFrame(resizeFrame);
937
1004
  cancelAnimationFrame(renderFrame);
938
1005
  cancelAnimationFrame(tickFrame);
@@ -7,7 +7,7 @@ import "../editor/index.js";
7
7
  //#region src/board/stage/views.d.ts
8
8
  type BoardItemViewContext = {
9
9
  editor: BoardEditor;
10
- zoom: number;
10
+ detailed: boolean;
11
11
  selected: boolean;
12
12
  toPointerEvent(event: PointerEvent): BoardPointerEvent;
13
13
  };
@@ -17,6 +17,11 @@ type BoardItemViewInstance = {
17
17
  };
18
18
  type BoardItemView = {
19
19
  type: string | ((item: BoardSceneItem) => boolean);
20
+ /** Optional screen-pixel threshold for expensive content, with built-in hysteresis. */
21
+ contentSize?: {
22
+ width: number;
23
+ height: number;
24
+ };
20
25
  mount(element: HTMLElement, item: BoardSceneItem, context: BoardItemViewContext): BoardItemViewInstance;
21
26
  };
22
27
  type BoardItemViewLayer = {
@@ -33,6 +38,6 @@ type BoardItemViewLayer = {
33
38
  }): void;
34
39
  destroy(): void;
35
40
  };
36
- declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport): BoardItemViewLayer;
41
+ declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport, onInvalidate?: () => void): BoardItemViewLayer;
37
42
  //#endregion
38
43
  export { BoardItemView, BoardItemViewContext, BoardItemViewInstance, BoardItemViewLayer, createBoardItemViewLayer };
@@ -1,55 +1,80 @@
1
+ import { itemBounds } from "../model/geometry.js";
1
2
  import { toBoardPointerEvent } from "./pointer.js";
2
3
  //#region src/board/stage/views.ts
3
4
  const VISIBLE_MARGIN = 240;
4
- function screenStyle(frame, camera, order) {
5
- const { zoom } = camera;
5
+ function worldStyle(frame, order) {
6
6
  return [
7
7
  `z-index:${order}`,
8
- `left:${frame.x * zoom + camera.x}px`,
9
- `top:${frame.y * zoom + camera.y}px`,
10
- `width:${frame.width * zoom}px`,
11
- `height:${frame.height * zoom}px`,
12
- `--board-zoom:${zoom}`,
8
+ `left:${frame.x}px`,
9
+ `top:${frame.y}px`,
10
+ `width:${frame.width}px`,
11
+ `height:${frame.height}px`,
13
12
  `transform:rotate(${frame.rotation}deg)`
14
13
  ].join(";");
15
14
  }
16
15
  function onScreen(frame, camera, surface) {
17
- const left = frame.x * camera.zoom + camera.x;
18
- const top = frame.y * camera.zoom + camera.y;
19
- return left + frame.width * camera.zoom >= -240 && top + frame.height * camera.zoom >= -240 && left <= surface.width + VISIBLE_MARGIN && top <= surface.height + VISIBLE_MARGIN;
16
+ const bounds = itemBounds(frame);
17
+ const left = bounds.x * camera.zoom + camera.x;
18
+ const top = bounds.y * camera.zoom + camera.y;
19
+ return left + bounds.width * camera.zoom >= -240 && top + bounds.height * camera.zoom >= -240 && left <= surface.width + VISIBLE_MARGIN && top <= surface.height + VISIBLE_MARGIN;
20
20
  }
21
- function createBoardItemViewLayer(host, editor, views, camera) {
21
+ function createBoardItemViewLayer(host, editor, views, camera, onInvalidate = () => {}) {
22
22
  const element = host.ownerDocument.createElement("div");
23
23
  element.dataset.boardViews = "";
24
24
  element.style.cssText = "position:absolute;inset:0;z-index:2;overflow:hidden;pointer-events:none";
25
25
  host.appendChild(element);
26
+ const world = host.ownerDocument.createElement("div");
27
+ world.style.cssText = "position:absolute;inset:0;transform-origin:0 0;pointer-events:none";
28
+ element.appendChild(world);
29
+ let cameraStyle = "";
26
30
  const mounted = /* @__PURE__ */ new Map();
27
- const toPointerEvent = (event) => toBoardPointerEvent(event, host.getBoundingClientRect(), camera());
31
+ const pointers = /* @__PURE__ */ new Map();
32
+ const retained = (id, entry) => entry.element.contains(host.ownerDocument.activeElement) || [...pointers.values()].includes(id);
33
+ const pointerDown = (event) => {
34
+ const id = event.target?.closest("[data-board-item]")?.dataset.boardItem;
35
+ if (id && mounted.has(id)) pointers.set(event.pointerId, id);
36
+ };
37
+ const pointerEnd = (event) => {
38
+ if (pointers.delete(event.pointerId)) onInvalidate();
39
+ };
40
+ element.addEventListener("pointerdown", pointerDown, true);
41
+ element.addEventListener("focusout", onInvalidate);
42
+ host.ownerDocument.addEventListener("pointerup", pointerEnd, true);
43
+ host.ownerDocument.addEventListener("pointercancel", pointerEnd, true);
44
+ const toPointerEvent = (event) => toBoardPointerEvent(event, host, camera());
28
45
  const viewFor = (item) => views.find((view) => typeof view.type === "string" ? view.type === item.type : view.type(item));
29
46
  function unmount(id, entry) {
30
47
  entry.instance.destroy?.();
31
48
  entry.element.remove();
32
49
  mounted.delete(id);
50
+ for (const [pointer, owner] of pointers) if (owner === id) pointers.delete(pointer);
33
51
  }
34
52
  return {
35
53
  element,
36
54
  sync({ ids, scene, camera: view, surface, selection }) {
37
55
  if (views.length === 0) return;
56
+ const transform = `translate(${view.x}px,${view.y}px) scale(${view.zoom})`;
57
+ if (transform !== cameraStyle) world.style.transform = cameraStyle = transform;
38
58
  const live = /* @__PURE__ */ new Set();
39
- for (const id of ids ?? scene.items.map((item) => item.id)) {
59
+ const candidates = new Set(ids ?? scene.items.map((item) => item.id));
60
+ for (const [id, entry] of mounted) if (retained(id, entry)) candidates.add(id);
61
+ for (const id of candidates) {
40
62
  const item = scene.get(id);
41
63
  if (!item) continue;
42
64
  const itemView = viewFor(item);
43
- if (!itemView || !onScreen(item.frame, view, surface)) continue;
65
+ let entry = mounted.get(item.id);
66
+ const held = entry ? retained(id, entry) : false;
67
+ if (!itemView || !held && !onScreen(item.frame, view, surface)) continue;
44
68
  live.add(item.id);
69
+ const style = worldStyle(item.frame, scene.indexOf(item.id));
70
+ const minimum = itemView.contentSize;
71
+ const threshold = entry?.detailed ? .85 : 1;
45
72
  const context = {
46
73
  editor,
47
- zoom: view.zoom,
74
+ detailed: held || !minimum || item.frame.width * view.zoom >= minimum.width * threshold && item.frame.height * view.zoom >= minimum.height * threshold,
48
75
  selected: selection.has(item.id),
49
76
  toPointerEvent
50
77
  };
51
- const style = screenStyle(item.frame, view, scene.indexOf(item.id));
52
- let entry = mounted.get(item.id);
53
78
  if (entry && entry.view !== itemView) {
54
79
  unmount(item.id, entry);
55
80
  entry = void 0;
@@ -58,13 +83,13 @@ function createBoardItemViewLayer(host, editor, views, camera) {
58
83
  const node = host.ownerDocument.createElement("div");
59
84
  node.dataset.boardItem = item.id;
60
85
  node.style.cssText = `position:absolute;pointer-events:none;transform-origin:center;${style}`;
61
- element.appendChild(node);
86
+ world.appendChild(node);
62
87
  mounted.set(item.id, {
63
88
  view: itemView,
64
89
  element: node,
65
90
  instance: itemView.mount(node, item, context),
66
91
  item,
67
- zoom: context.zoom,
92
+ detailed: context.detailed,
68
93
  selected: context.selected,
69
94
  style
70
95
  });
@@ -74,9 +99,9 @@ function createBoardItemViewLayer(host, editor, views, camera) {
74
99
  entry.element.style.cssText = `position:absolute;pointer-events:none;transform-origin:center;${style}`;
75
100
  entry.style = style;
76
101
  }
77
- if (entry.item !== item || entry.zoom !== context.zoom || entry.selected !== context.selected) {
102
+ if (entry.item !== item || entry.detailed !== context.detailed || entry.selected !== context.selected) {
78
103
  entry.item = item;
79
- entry.zoom = context.zoom;
104
+ entry.detailed = context.detailed;
80
105
  entry.selected = context.selected;
81
106
  entry.instance.update?.(item, context);
82
107
  }
@@ -84,6 +109,10 @@ function createBoardItemViewLayer(host, editor, views, camera) {
84
109
  for (const [id, entry] of mounted) if (!live.has(id)) unmount(id, entry);
85
110
  },
86
111
  destroy() {
112
+ element.removeEventListener("pointerdown", pointerDown, true);
113
+ element.removeEventListener("focusout", onInvalidate);
114
+ host.ownerDocument.removeEventListener("pointerup", pointerEnd, true);
115
+ host.ownerDocument.removeEventListener("pointercancel", pointerEnd, true);
87
116
  for (const [id, entry] of mounted) unmount(id, entry);
88
117
  element.remove();
89
118
  }
@@ -2767,6 +2767,7 @@ declare const harnessArchiveSchema: z.ZodObject<{
2767
2767
  harness: z.ZodEnum<{
2768
2768
  claude: "claude";
2769
2769
  codex: "codex";
2770
+ cursor: "cursor";
2770
2771
  pi: "pi";
2771
2772
  workbuddy: "workbuddy";
2772
2773
  }>;
@@ -2777,6 +2778,7 @@ declare const harnessArchiveIndexSchema: z.ZodObject<{
2777
2778
  harness: z.ZodEnum<{
2778
2779
  claude: "claude";
2779
2780
  codex: "codex";
2781
+ cursor: "cursor";
2780
2782
  pi: "pi";
2781
2783
  workbuddy: "workbuddy";
2782
2784
  }>;
@@ -2814,7 +2816,7 @@ declare function validateArchiveBoundary(index: HarnessArchiveIndex, parent: Har
2814
2816
  //#endregion
2815
2817
  //#region ../protocol/dist/runtime/harnesses.d.ts
2816
2818
  /** Single source of truth for local Harness identities. Adding a Harness starts here. */
2817
- declare const LOCAL_HARNESSES: readonly ["pi", "codex", "claude", "workbuddy"];
2819
+ declare const LOCAL_HARNESSES: readonly ["pi", "codex", "claude", "workbuddy", "cursor"];
2818
2820
  type LocalHarness = typeof LOCAL_HARNESSES[number];
2819
2821
  type LocalHarnessSpec = {
2820
2822
  label: string;
@@ -2827,6 +2829,7 @@ declare const LOCAL_HARNESS_SPECS: Readonly<Record<LocalHarness, LocalHarnessSpe
2827
2829
  declare const localHarnessSchema: z.ZodEnum<{
2828
2830
  claude: "claude";
2829
2831
  codex: "codex";
2832
+ cursor: "cursor";
2830
2833
  pi: "pi";
2831
2834
  workbuddy: "workbuddy";
2832
2835
  }>;
@@ -2834,6 +2837,7 @@ declare const harnessSchema: z.ZodEnum<{
2834
2837
  claude: "claude";
2835
2838
  codex: "codex";
2836
2839
  cohub: "cohub";
2840
+ cursor: "cursor";
2837
2841
  pi: "pi";
2838
2842
  workbuddy: "workbuddy";
2839
2843
  }>;
@@ -2973,6 +2977,7 @@ declare const nativeIngestSchema: z.ZodObject<{
2973
2977
  harness: z.ZodEnum<{
2974
2978
  claude: "claude";
2975
2979
  codex: "codex";
2980
+ cursor: "cursor";
2976
2981
  pi: "pi";
2977
2982
  workbuddy: "workbuddy";
2978
2983
  }>;
@@ -3023,6 +3028,7 @@ declare const nativeRuntimeEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3023
3028
  harness: z.ZodEnum<{
3024
3029
  claude: "claude";
3025
3030
  codex: "codex";
3031
+ cursor: "cursor";
3026
3032
  pi: "pi";
3027
3033
  workbuddy: "workbuddy";
3028
3034
  }>;
@@ -3271,6 +3277,7 @@ declare const runtimeCapabilitiesSchema: z.ZodObject<{
3271
3277
  harnesses: z.ZodArray<z.ZodEnum<{
3272
3278
  claude: "claude";
3273
3279
  codex: "codex";
3280
+ cursor: "cursor";
3274
3281
  pi: "pi";
3275
3282
  workbuddy: "workbuddy";
3276
3283
  }>>;
@@ -3278,6 +3285,7 @@ declare const runtimeCapabilitiesSchema: z.ZodObject<{
3278
3285
  harness: z.ZodEnum<{
3279
3286
  claude: "claude";
3280
3287
  codex: "codex";
3288
+ cursor: "cursor";
3281
3289
  pi: "pi";
3282
3290
  workbuddy: "workbuddy";
3283
3291
  }>;
@@ -3313,6 +3321,7 @@ declare const runtimePendingExecutionSchema: z.ZodObject<{
3313
3321
  harness: z.ZodEnum<{
3314
3322
  claude: "claude";
3315
3323
  codex: "codex";
3324
+ cursor: "cursor";
3316
3325
  pi: "pi";
3317
3326
  workbuddy: "workbuddy";
3318
3327
  }>;
@@ -3503,6 +3512,7 @@ declare const runtimeEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3503
3512
  harness: z.ZodEnum<{
3504
3513
  claude: "claude";
3505
3514
  codex: "codex";
3515
+ cursor: "cursor";
3506
3516
  pi: "pi";
3507
3517
  workbuddy: "workbuddy";
3508
3518
  }>;
@@ -3533,6 +3543,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3533
3543
  harness: z.ZodEnum<{
3534
3544
  claude: "claude";
3535
3545
  codex: "codex";
3546
+ cursor: "cursor";
3536
3547
  pi: "pi";
3537
3548
  workbuddy: "workbuddy";
3538
3549
  }>;
@@ -3555,6 +3566,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3555
3566
  harness: z.ZodEnum<{
3556
3567
  claude: "claude";
3557
3568
  codex: "codex";
3569
+ cursor: "cursor";
3558
3570
  pi: "pi";
3559
3571
  workbuddy: "workbuddy";
3560
3572
  }>;
@@ -3603,6 +3615,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3603
3615
  harness: z.ZodEnum<{
3604
3616
  claude: "claude";
3605
3617
  codex: "codex";
3618
+ cursor: "cursor";
3606
3619
  pi: "pi";
3607
3620
  workbuddy: "workbuddy";
3608
3621
  }>;
@@ -3667,6 +3680,7 @@ declare const runtimeCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3667
3680
  harness: z.ZodEnum<{
3668
3681
  claude: "claude";
3669
3682
  codex: "codex";
3683
+ cursor: "cursor";
3670
3684
  pi: "pi";
3671
3685
  workbuddy: "workbuddy";
3672
3686
  }>;
@@ -6536,7 +6550,7 @@ interface SystemOneRequest<Q extends Questions = Questions> {
6536
6550
  model?: string;
6537
6551
  }
6538
6552
  //#endregion
6539
- //#region ../../node_modules/.pnpm/@neta-art+generation@0.1.39/node_modules/@neta-art/generation/dist/builtins-BYR-8YTe.d.ts
6553
+ //#region ../../node_modules/.pnpm/@neta-art+generation@0.1.40/node_modules/@neta-art/generation/dist/builtins-BYR-8YTe.d.ts
6540
6554
  //#region src/types.d.ts
6541
6555
  declare const MODEL_SCHEMA: "neta.generation.model.v1";
6542
6556
  declare const GENERATION_MODEL_CATEGORIES: readonly ["image", "video", "audio", "3d", "decision"];