@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,84 @@
1
+ import { hasAuthoredSize, parseBoardItem } from "../../../protocol/dist/board-model.js";
2
+ import { frameContainsPoint, itemBounds } from "../geometry.js";
3
+ import { FULL_CAPABILITIES } from "./definition.js";
4
+ import { builtinBoardItems } from "./builtin.js";
5
+ import { createBoardItemId } from "./id.js";
6
+ //#region src/board/model/items/registry.ts
7
+ const DEFAULT_ITEM_SIZE = {
8
+ width: 240,
9
+ height: 160
10
+ };
11
+ function createBoardRegistry(definitions = []) {
12
+ const byType = /* @__PURE__ */ new Map();
13
+ for (const definition of [...builtinBoardItems, ...definitions]) byType.set(definition.type, definition);
14
+ const capabilities = /* @__PURE__ */ new Map();
15
+ function capabilitiesOf(type) {
16
+ let value = capabilities.get(type);
17
+ if (!value) {
18
+ value = {
19
+ ...FULL_CAPABILITIES,
20
+ ...byType.get(type)?.capabilities
21
+ };
22
+ capabilities.set(type, value);
23
+ }
24
+ return value;
25
+ }
26
+ function validateProps(type, props) {
27
+ const schema = byType.get(type)?.props;
28
+ if (!schema) return { ok: true };
29
+ const parsed = schema.safeParse(props);
30
+ if (parsed.success) return { ok: true };
31
+ const issue = parsed.error.issues[0];
32
+ return {
33
+ ok: false,
34
+ message: `${type} props${issue?.path.length ? `.${issue.path.join(".")}` : ""}: ${issue?.message ?? "invalid"}`
35
+ };
36
+ }
37
+ return {
38
+ definitions: [...byType.values()],
39
+ get: (type) => byType.get(type),
40
+ capabilities: (item) => capabilitiesOf(item.type),
41
+ resizeMode(item) {
42
+ const value = capabilitiesOf(item.type);
43
+ if (!value.canResize) return "none";
44
+ return value.aspectLocked ? "uniform" : "free";
45
+ },
46
+ bounds: (item) => byType.get(item.type)?.bounds?.(item) ?? itemBounds(item.frame),
47
+ hitTest(item, point) {
48
+ const hitTest = byType.get(item.type)?.hitTest;
49
+ return hitTest ? hitTest(item, point) : frameContainsPoint(item.frame, point);
50
+ },
51
+ validateProps,
52
+ create(type, { props = {}, at, size, id = createBoardItemId() }) {
53
+ const valid = validateProps(type, props);
54
+ if (!valid.ok) throw new Error(valid.message);
55
+ const box = size ?? byType.get(type)?.size ?? DEFAULT_ITEM_SIZE;
56
+ const placement = hasAuthoredSize(type) ? {
57
+ position: {
58
+ x: at.x - box.width / 2,
59
+ y: at.y - box.height / 2
60
+ },
61
+ size: { ...box }
62
+ } : { position: {
63
+ x: at.x,
64
+ y: at.y
65
+ } };
66
+ const parsed = parseBoardItem({
67
+ type,
68
+ ...placement,
69
+ props
70
+ });
71
+ if (!parsed.ok) {
72
+ const diagnostic = parsed.diagnostics[0];
73
+ throw new Error(`Invalid ${type} item: ${diagnostic?.path}: ${diagnostic?.message}`);
74
+ }
75
+ return {
76
+ id,
77
+ item: parsed.item
78
+ };
79
+ }
80
+ };
81
+ }
82
+ const defaultBoardRegistry = createBoardRegistry();
83
+ //#endregion
84
+ export { createBoardRegistry, defaultBoardRegistry };
@@ -1,9 +1,10 @@
1
- import { BoardSceneItem } from "./core/scene.js";
2
- //#region src/board/media-playback.d.ts
1
+ import { BoardSceneItem } from "./scene.js";
2
+ //#region src/board/model/media-playback.d.ts
3
3
  type BoardAssetSource = {
4
4
  resolveFileUrl: (path: string) => Promise<string | null>;
5
5
  resolvePlaybackUrl?: (path: string) => Promise<string | null>;
6
6
  };
7
+ declare function resolveBoardMediaUrl(src: string, source: BoardAssetSource, purpose?: "preview" | "playback"): Promise<string | null>;
7
8
  type BoardPlayableMedia = {
8
9
  id: string;
9
10
  kind: "video" | "audio";
@@ -16,4 +17,4 @@ declare function playableBoardMediaList(item: BoardSceneItem | null, assetSource
16
17
  declare function playableBoardMedia(item: BoardSceneItem | null, assetSource: BoardAssetSource, artifactId?: string | null): BoardPlayableMedia | null;
17
18
  declare function resetBoardPlaybackUrlCache(): void;
18
19
  //#endregion
19
- export { BoardAssetSource, BoardPlayableMedia, playableBoardMedia, playableBoardMediaList, resetBoardPlaybackUrlCache };
20
+ export { BoardAssetSource, BoardPlayableMedia, playableBoardMedia, playableBoardMediaList, resetBoardPlaybackUrlCache, resolveBoardMediaUrl };
@@ -1,5 +1,13 @@
1
+ import { parseBoardMediaSource } from "../../protocol/dist/board-model.js";
2
+ import { getMediaResourceTitle } from "./media.js";
1
3
  import { rankedTaskArtifacts } from "./task.js";
2
- //#region src/board/media-playback.ts
4
+ //#region src/board/model/media-playback.ts
5
+ function resolveBoardMediaUrl(src, source, purpose = "preview") {
6
+ const parsed = parseBoardMediaSource(src);
7
+ if (!parsed) return Promise.resolve(null);
8
+ if (parsed.kind === "url") return Promise.resolve(parsed.value);
9
+ return purpose === "playback" && source.resolvePlaybackUrl ? source.resolvePlaybackUrl(parsed.value) : source.resolveFileUrl(parsed.value);
10
+ }
3
11
  const resolvedUrls = /* @__PURE__ */ new Map();
4
12
  const sourceIds = /* @__PURE__ */ new WeakMap();
5
13
  const URL_CACHE_LIMIT = 64;
@@ -34,15 +42,17 @@ function cachedUrl(key, resolve) {
34
42
  function playableBoardMediaList(item, assetSource) {
35
43
  if (item?.type === "video" || item?.type === "audio") {
36
44
  const path = item.props.src;
45
+ const source = parseBoardMediaSource(path);
46
+ if (!source) return [];
37
47
  const version = item.props.snapshot?.mtimeMs ?? "unknown";
38
- const cacheKey = `${sourceId(assetSource)}:${item.type}:file:${path}:${version}`;
48
+ const cacheKey = `${sourceId(assetSource)}:${item.type}:${source.kind}:${path}:${version}`;
39
49
  const durationMs = item.type === "audio" ? item.props.snapshot?.durationMs : void 0;
40
50
  return [{
41
51
  id: item.id,
42
52
  kind: item.type,
43
- title: item.props.snapshot?.title ?? path.split("/").pop() ?? item.type,
53
+ title: item.props.snapshot?.title ?? getMediaResourceTitle(path),
44
54
  ...durationMs ? { durationMs } : {},
45
- resolveUrl: () => cachedUrl(cacheKey, () => (assetSource.resolvePlaybackUrl ?? assetSource.resolveFileUrl)(path)),
55
+ resolveUrl: () => cachedUrl(cacheKey, () => resolveBoardMediaUrl(path, assetSource, "playback")),
46
56
  invalidateUrl: () => invalidateCachedUrl(cacheKey)
47
57
  }];
48
58
  }
@@ -64,4 +74,4 @@ function resetBoardPlaybackUrlCache() {
64
74
  resolvedUrls.clear();
65
75
  }
66
76
  //#endregion
67
- export { playableBoardMedia, playableBoardMediaList, resetBoardPlaybackUrlCache };
77
+ export { playableBoardMedia, playableBoardMediaList, resetBoardPlaybackUrlCache, resolveBoardMediaUrl };
@@ -1,4 +1,4 @@
1
- //#region src/board/media.d.ts
1
+ //#region src/board/model/media.d.ts
2
2
  type BoardMediaKind = "image" | "video" | "audio" | "text" | "file";
3
3
  declare function getMediaExtension(value: string): string;
4
4
  declare function inferBoardMediaKind(value: string, mimeType?: string | null): BoardMediaKind;
@@ -1,4 +1,4 @@
1
- //#region src/board/media.ts
1
+ //#region src/board/model/media.ts
2
2
  const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
3
3
  "png",
4
4
  "jpg",
@@ -59,9 +59,15 @@ function inferBoardMediaKind(value, mimeType) {
59
59
  return "file";
60
60
  }
61
61
  function getMediaResourceTitle(value) {
62
+ if (!/^[a-z][a-z\d+.-]*:/i.test(value)) return value.split("/").filter(Boolean).pop() || value;
62
63
  try {
63
64
  const url = new URL(value);
64
- return decodeURIComponent(url.pathname.split("/").filter(Boolean).pop() || url.hostname);
65
+ const title = url.pathname.split("/").filter(Boolean).pop() || url.hostname;
66
+ try {
67
+ return decodeURIComponent(title);
68
+ } catch {
69
+ return title;
70
+ }
65
71
  } catch {
66
72
  return value.split("/").filter(Boolean).pop() || value;
67
73
  }
@@ -1,6 +1,6 @@
1
1
  import { BoardColor, BoardColorToken } from "../../protocol/dist/board-model.js";
2
2
  import "../../protocol/dist/index.js";
3
- //#region src/board/core/palette.d.ts
3
+ //#region src/board/model/palette.d.ts
4
4
  type BoardColorId = BoardColorToken;
5
5
  type BoardColorValue = {
6
6
  stroke: number;
@@ -1,4 +1,4 @@
1
- //#region src/board/core/palette.ts
1
+ //#region src/board/model/palette.ts
2
2
  const LABEL_DARK = 16053492;
3
3
  const LABEL_LIGHT = 1579035;
4
4
  const BOARD_COLORS = [
@@ -1,6 +1,6 @@
1
- import { BoardTrack } from "../protocol/dist/board-model.js";
2
- import "../protocol/dist/index.js";
3
- //#region src/board/presets.d.ts
1
+ import { BoardTrack } from "../../protocol/dist/board-model.js";
2
+ import "../../protocol/dist/index.js";
3
+ //#region src/board/model/presets.d.ts
4
4
  declare const PRESETS: {
5
5
  "fade-in": {
6
6
  description: string;
@@ -1,4 +1,4 @@
1
- //#region src/board/presets.ts
1
+ //#region src/board/model/presets.ts
2
2
  const OUT = "cubic-bezier(0.22, 1, 0.36, 1)";
3
3
  const IN_OUT = "ease-in-out";
4
4
  const PRESETS = {
@@ -1,8 +1,8 @@
1
- import { BoardDocument } from "../protocol/dist/board-model.js";
2
- import { RequestSource } from "../protocol/dist/provenance.js";
3
- import { BoardHistoryPage } from "../protocol/dist/board.js";
4
- import "../protocol/dist/index.js";
5
- //#region src/board/replay.d.ts
1
+ import { BoardDocument } from "../../protocol/dist/board-model.js";
2
+ import { RequestSource } from "../../protocol/dist/provenance.js";
3
+ import { BoardHistoryPage } from "../../protocol/dist/board.js";
4
+ import "../../protocol/dist/index.js";
5
+ //#region src/board/model/replay.d.ts
6
6
  type BoardReplayActorKind = "human" | "cli" | "agent";
7
7
  type BoardReplayEntry = {
8
8
  version: number;
@@ -1,5 +1,5 @@
1
- import { applyBoardDelta } from "../protocol/dist/board-patch.js";
2
- //#region src/board/replay.ts
1
+ import { applyBoardDelta } from "../../protocol/dist/board-patch.js";
2
+ //#region src/board/model/replay.ts
3
3
  function boardReplayActorKind(source) {
4
4
  if (!source) return "human";
5
5
  if (source.toolCallId) return "agent";
@@ -0,0 +1,19 @@
1
+ import { BoardDocument } from "../../protocol/dist/board-model.js";
2
+ import { BoardFrame } from "../../protocol/dist/board-layout.js";
3
+ import "../../protocol/dist/index.js";
4
+ import { BoardViewport, Size } from "./geometry.js";
5
+ import { BoardScene } from "./scene.js";
6
+ import { BoardCameraOverride, BoardEvaluateOptions, BoardEvaluation } from "./animation.js";
7
+ //#region src/board/model/sampling.d.ts
8
+ declare function createBoardAnimationSampler(document: BoardDocument, animation: string | null, options?: BoardEvaluateOptions): {
9
+ frameAt(id: string, time: number): BoardFrame | undefined;
10
+ at(time: number): {
11
+ document: BoardDocument;
12
+ evaluation: BoardEvaluation;
13
+ scene: BoardScene;
14
+ };
15
+ };
16
+ type BoardAnimationSampler = ReturnType<typeof createBoardAnimationSampler>;
17
+ declare function resolveBoardAnimationCamera(override: BoardCameraOverride, bounds: (id: string) => BoardFrame | undefined, surface: Size, time: number, base?: BoardViewport): BoardViewport;
18
+ //#endregion
19
+ export { BoardAnimationSampler, createBoardAnimationSampler, resolveBoardAnimationCamera };
@@ -0,0 +1,96 @@
1
+ import { arrowBindings } from "../../protocol/dist/board-layout.js";
2
+ import { cameraForFocus, cameraForState } from "./geometry.js";
3
+ import { applyBoardEvaluation, boardAnimationTime, compileBoardAnimations, evaluateBoardAnimations } from "./animation.js";
4
+ import { buildBoardScene } from "./scene.js";
5
+ //#region src/board/model/sampling.ts
6
+ function createBoardAnimationSampler(document, animation, options = {}) {
7
+ const selected = animation ? document.animations[animation] : void 0;
8
+ if (animation && !selected) throw new Error(`Animation ${animation} does not exist.`);
9
+ const compiled = compileBoardAnimations(document);
10
+ const cache = /* @__PURE__ */ new Map();
11
+ const geometry = /* @__PURE__ */ new Map();
12
+ function sample(time) {
13
+ const times = /* @__PURE__ */ new Map();
14
+ for (const [id, entry] of compiled.animations) if (entry.header.play === "always") times.set(id, boardAnimationTime(entry.header, time) ?? 0);
15
+ if (animation && selected) times.set(animation, Math.min(time, selected.duration));
16
+ const evaluation = evaluateBoardAnimations(compiled, times, options);
17
+ return {
18
+ document: applyBoardEvaluation(document, evaluation),
19
+ evaluation
20
+ };
21
+ }
22
+ function stateAt(time) {
23
+ if (!Number.isFinite(time) || time < 0) throw new Error("Animation time must be finite and non-negative.");
24
+ let value = cache.get(time);
25
+ if (!value) {
26
+ value = sample(time);
27
+ const oldest = cache.keys().next().value;
28
+ if (cache.size >= 64 && oldest !== void 0) cache.delete(oldest);
29
+ cache.set(time, value);
30
+ }
31
+ return value;
32
+ }
33
+ let current;
34
+ return {
35
+ frameAt(id, time) {
36
+ const key = `${time}:${id}`;
37
+ if (geometry.has(key)) return geometry.get(key);
38
+ const sampled = stateAt(time).document;
39
+ const items = {};
40
+ const pending = [id];
41
+ while (pending.length) {
42
+ const next = pending.pop();
43
+ if (!next || items[next]) continue;
44
+ const item = sampled.items[next];
45
+ if (!item) continue;
46
+ items[next] = item;
47
+ if (item.parent) pending.push(item.parent);
48
+ pending.push(...arrowBindings(item));
49
+ }
50
+ const frame = buildBoardScene({
51
+ ...sampled,
52
+ items
53
+ }).get(id)?.frame;
54
+ if (geometry.size >= 2048) geometry.clear();
55
+ geometry.set(key, frame);
56
+ return frame;
57
+ },
58
+ at(time) {
59
+ if (current?.time === time) return current.value;
60
+ const sampled = stateAt(time);
61
+ const value = {
62
+ ...sampled,
63
+ scene: buildBoardScene(sampled.document)
64
+ };
65
+ current = {
66
+ time,
67
+ value
68
+ };
69
+ return value;
70
+ }
71
+ };
72
+ }
73
+ function resolveBoardAnimationCamera(override, bounds, surface, time, base = {
74
+ x: 0,
75
+ y: 0,
76
+ zoom: 1
77
+ }) {
78
+ let camera = override.focus === void 0 ? base : cameraForFocus(override.focus, bounds, surface, { padding: 48 }) ?? base;
79
+ if (override.zoom !== void 0) camera = {
80
+ ...camera,
81
+ zoom: override.zoom
82
+ };
83
+ if (override.center) camera = cameraForState({
84
+ centerX: override.center.x,
85
+ centerY: override.center.y,
86
+ zoom: camera.zoom
87
+ }, surface);
88
+ if (override.shake) camera = {
89
+ ...camera,
90
+ x: camera.x + Math.sin(time / 1e3 * 91.3) * override.shake,
91
+ y: camera.y + Math.cos(time / 1e3 * 77.9) * override.shake
92
+ };
93
+ return camera;
94
+ }
95
+ //#endregion
96
+ export { createBoardAnimationSampler, resolveBoardAnimationCamera };
@@ -1,7 +1,7 @@
1
1
  import { BoardDocument, BoardItem } from "../../protocol/dist/board-model.js";
2
2
  import { BoardFrame, BoardItemLookup, BoardLayout, BoardMatrix, BoardRect } from "../../protocol/dist/board-layout.js";
3
3
  import "../../protocol/dist/index.js";
4
- //#region src/board/core/scene.d.ts
4
+ //#region src/board/model/scene.d.ts
5
5
  type SceneItem<T extends BoardItem = BoardItem> = T & {
6
6
  readonly id: string;
7
7
  readonly frame: BoardFrame;
@@ -1,5 +1,5 @@
1
1
  import { IDENTITY_MATRIX, applyMatrix, arrowBindings, clampBoardFontSize, createBoardLayout, drawPointsBounds, invertMatrix, layoutBoardText, scaleVector } from "../../protocol/dist/board-layout.js";
2
- //#region src/board/core/scene.ts
2
+ //#region src/board/model/scene.ts
3
3
  const EPSILON = 1e-6;
4
4
  function stripScene(item) {
5
5
  if (!("frame" in item) && !("id" in item)) return item;
@@ -0,0 +1,4 @@
1
+ //#region src/board/model/script-example.d.ts
2
+ declare const BOARD_SCRIPT_DRAWING_EXAMPLE = "export const animated = true;\n\nexport const parameters = {\n amplitude: { type: \"number\", label: \"Amplitude\", default: 40, min: 0, max: 120 }\n};\n\nexport function draw(ctx, { t, width, height, params }) {\n ctx.strokeStyle = \"#e67845\";\n ctx.lineWidth = 3;\n ctx.beginPath();\n for (let x = 0; x <= width; x += 2) {\n const y = height / 2 + Math.sin(x / 40 - t / 800) * params.amplitude;\n if (x === 0) ctx.moveTo(x, y);\n else ctx.lineTo(x, y);\n }\n ctx.stroke();\n}\n";
3
+ //#endregion
4
+ export { BOARD_SCRIPT_DRAWING_EXAMPLE };
@@ -0,0 +1,21 @@
1
+ //#region src/board/model/script-example.ts
2
+ const BOARD_SCRIPT_DRAWING_EXAMPLE = `export const animated = true;
3
+
4
+ export const parameters = {
5
+ amplitude: { type: "number", label: "Amplitude", default: 40, min: 0, max: 120 }
6
+ };
7
+
8
+ export function draw(ctx, { t, width, height, params }) {
9
+ ctx.strokeStyle = "#e67845";
10
+ ctx.lineWidth = 3;
11
+ ctx.beginPath();
12
+ for (let x = 0; x <= width; x += 2) {
13
+ const y = height / 2 + Math.sin(x / 40 - t / 800) * params.amplitude;
14
+ if (x === 0) ctx.moveTo(x, y);
15
+ else ctx.lineTo(x, y);
16
+ }
17
+ ctx.stroke();
18
+ }
19
+ `;
20
+ //#endregion
21
+ export { BOARD_SCRIPT_DRAWING_EXAMPLE };
@@ -0,0 +1,10 @@
1
+ import { BoardScriptOutput } from "./script.js";
2
+ import { WorldPoint } from "./geometry.js";
3
+ import { BoardScene, BoardSceneItem } from "./scene.js";
4
+ //#region src/board/model/script-hit.d.ts
5
+ declare function boardScriptTarget(scene: BoardScene, candidates: readonly string[], point: WorldPoint, outputs: ReadonlyMap<string, BoardScriptOutput>, hitTest: (item: BoardSceneItem, point: WorldPoint) => boolean): {
6
+ owner: string;
7
+ target: string;
8
+ } | null;
9
+ //#endregion
10
+ export { boardScriptTarget };
@@ -0,0 +1,52 @@
1
+ import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
2
+ import { frameContainsPoint } from "./geometry.js";
3
+ import { scriptTemporaryPrefix } from "./script-scene.js";
4
+ //#region src/board/model/script-hit.ts
5
+ function boardScriptTarget(scene, candidates, point, outputs, hitTest) {
6
+ const owners = new Map([...outputs.keys()].map((id) => [scriptTemporaryPrefix(id), id]));
7
+ for (const id of [...candidates].sort((a, b) => scene.indexOf(b) - scene.indexOf(a))) {
8
+ const item = scene.get(id);
9
+ if (!item || scene.opacity(id) <= 0 || id.endsWith("root") && owners.has(id.slice(0, -4))) continue;
10
+ let parent = item.parent;
11
+ let clipped = false;
12
+ for (let depth = 0; parent && depth < 64; depth++) {
13
+ const ancestor = scene.get(parent);
14
+ if (!ancestor) break;
15
+ if (ancestor.type === "frame" && ancestor.props.clip && !frameContainsPoint(ancestor.frame, point)) {
16
+ clipped = true;
17
+ break;
18
+ }
19
+ parent = ancestor.parent;
20
+ }
21
+ if (clipped) continue;
22
+ const output = outputs.get(id);
23
+ if (output) {
24
+ const local = applyMatrix(invertMatrix(scene.layout.matrix(id)), point);
25
+ for (const [target, region] of Object.entries(output.hits).reverse()) if (local.x >= region.x && local.y >= region.y && local.x <= region.x + region.width && local.y <= region.y + region.height) return {
26
+ owner: id,
27
+ target
28
+ };
29
+ }
30
+ if (!hitTest(item, point)) continue;
31
+ let current = item;
32
+ for (let depth = 0; current && depth < 64; depth++) {
33
+ if (outputs.has(current.id)) return {
34
+ owner: current.id,
35
+ target: id
36
+ };
37
+ for (const [prefix, owner] of owners) {
38
+ if (current.id === `${prefix}root`) break;
39
+ if (current.id.startsWith(prefix)) return {
40
+ owner,
41
+ target: current.id.slice(prefix.length)
42
+ };
43
+ }
44
+ current = current.parent ? scene.get(current.parent) : void 0;
45
+ }
46
+ if (item.type === "frame" && item.props.decoration === "none") continue;
47
+ return null;
48
+ }
49
+ return null;
50
+ }
51
+ //#endregion
52
+ export { boardScriptTarget };
@@ -0,0 +1,7 @@
1
+ import { BoardDocument, BoardItem } from "../../protocol/dist/board-model.js";
2
+ import "../../protocol/dist/index.js";
3
+ //#region src/board/model/script-index.d.ts
4
+ declare function boardScriptItems(document: Pick<BoardDocument, "items">): readonly (readonly [string, BoardItem])[];
5
+ declare function hasBoardScripts(document: Pick<BoardDocument, "items">): boolean;
6
+ //#endregion
7
+ export { boardScriptItems, hasBoardScripts };
@@ -0,0 +1,15 @@
1
+ //#region src/board/model/script-index.ts
2
+ const scriptsByItems = /* @__PURE__ */ new WeakMap();
3
+ function boardScriptItems(document) {
4
+ let scripts = scriptsByItems.get(document.items);
5
+ if (!scripts) {
6
+ scripts = Object.entries(document.items).filter(([, item]) => item.script?.enabled);
7
+ scriptsByItems.set(document.items, scripts);
8
+ }
9
+ return scripts;
10
+ }
11
+ function hasBoardScripts(document) {
12
+ return boardScriptItems(document).length > 0;
13
+ }
14
+ //#endregion
15
+ export { boardScriptItems, hasBoardScripts };
@@ -0,0 +1,24 @@
1
+ import { BoardDocument, BoardItem, BoardPatch } from "../../protocol/dist/board-model.js";
2
+ import { BoardScriptOutput } from "./script.js";
3
+ import { BoardScene } from "./scene.js";
4
+ //#region src/board/model/script-scene.d.ts
5
+ declare function boardScriptScope(document: Pick<BoardDocument, "items">, id: string): Set<string>;
6
+ declare function validateBoardScriptOutput(output: BoardScriptOutput, scope: ReadonlySet<string>): void;
7
+ declare function validateBoardScriptCommit(document: BoardDocument, id: string, patch: BoardPatch): void;
8
+ declare function scriptTemporaryPrefix(owner: string): string;
9
+ type PreparedOutput = {
10
+ document: BoardDocument;
11
+ owner: string;
12
+ rootId: string;
13
+ items: Map<string, BoardItem>;
14
+ presented: Map<string, {
15
+ base: BoardItem;
16
+ item: BoardItem;
17
+ }>;
18
+ };
19
+ declare function prepareBoardScriptOutput(document: BoardDocument, owner: string, output: BoardScriptOutput): PreparedOutput;
20
+ declare function composeBoardScriptItems(document: BoardDocument, scene: BoardScene, outputs: ReadonlyMap<string, BoardScriptOutput>, incoming?: ReadonlyMap<string, BoardItem>, screen?: {
21
+ zoom: number;
22
+ }, onError?: (owner: string, error: unknown) => void): Map<string, BoardItem>;
23
+ //#endregion
24
+ export { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, scriptTemporaryPrefix, validateBoardScriptCommit, validateBoardScriptOutput };