@neta-art/cohub 8.24.0 → 9.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 (159) hide show
  1. package/dist/board/animation.d.ts +57 -181
  2. package/dist/board/animation.js +374 -220
  3. package/dist/board/core/arrow-geometry.d.ts +33 -18
  4. package/dist/board/core/arrow-geometry.js +283 -52
  5. package/dist/board/core/draw-geometry.d.ts +22 -36
  6. package/dist/board/core/draw-geometry.js +148 -85
  7. package/dist/board/core/export-assets.d.ts +3 -6
  8. package/dist/board/core/export-assets.js +0 -2
  9. package/dist/board/core/export-plan.d.ts +12 -63
  10. package/dist/board/core/export-plan.js +55 -94
  11. package/dist/board/core/palette.d.ts +4 -21
  12. package/dist/board/core/palette.js +8 -13
  13. package/dist/board/core/scene.d.ts +33 -0
  14. package/dist/board/core/scene.js +302 -0
  15. package/dist/board/core/shape-definition.d.ts +12 -24
  16. package/dist/board/core/shape-definition.js +0 -19
  17. package/dist/board/core/shape-types.d.ts +6 -120
  18. package/dist/board/core/shape-types.js +5 -5
  19. package/dist/board/core/text-metrics.d.ts +8 -11
  20. package/dist/board/core/text-metrics.js +5 -34
  21. package/dist/board/core/tool-styles.d.ts +6 -16
  22. package/dist/board/core/tool-styles.js +17 -25
  23. package/dist/board/export/index.d.ts +10 -17
  24. package/dist/board/export/index.js +22 -21
  25. package/dist/board/export/scene.d.ts +10 -16
  26. package/dist/board/export/scene.js +17 -30
  27. package/dist/board/geometry.d.ts +27 -56
  28. package/dist/board/geometry.js +7 -67
  29. package/dist/board/headless/index.d.ts +6 -27
  30. package/dist/board/headless/index.js +4 -19
  31. package/dist/board/headless/sketch.d.ts +19 -0
  32. package/dist/board/headless/sketch.js +146 -0
  33. package/dist/board/image-key.d.ts +2 -12
  34. package/dist/board/image-key.js +3 -13
  35. package/dist/board/index.d.ts +18 -20
  36. package/dist/board/index.js +17 -17
  37. package/dist/board/media-playback.d.ts +3 -6
  38. package/dist/board/media-playback.js +6 -6
  39. package/dist/board/presets.d.ts +150 -0
  40. package/dist/board/presets.js +226 -0
  41. package/dist/board/render/board-background.d.ts +5 -3
  42. package/dist/board/render/board-background.js +8 -7
  43. package/dist/board/render/clip.d.ts +14 -0
  44. package/dist/board/render/clip.js +47 -0
  45. package/dist/board/render/index.d.ts +8 -5
  46. package/dist/board/render/index.js +7 -4
  47. package/dist/board/render/media-interaction.d.ts +4 -5
  48. package/dist/board/render/media-interaction.js +1 -2
  49. package/dist/board/render/palette.d.ts +6 -2
  50. package/dist/board/render/palette.js +7 -1
  51. package/dist/board/render/renderers/arrow-card-renderer.js +69 -71
  52. package/dist/board/render/renderers/audio-card-renderer.js +3 -3
  53. package/dist/board/render/renderers/base-card-renderer.d.ts +6 -17
  54. package/dist/board/render/renderers/base-card-renderer.js +1 -24
  55. package/dist/board/render/renderers/board-renderer-registry.d.ts +20 -50
  56. package/dist/board/render/renderers/board-renderer-registry.js +6 -7
  57. package/dist/board/render/renderers/draw-card-renderer.js +89 -56
  58. package/dist/board/render/renderers/effect-card-renderer.d.ts +6 -0
  59. package/dist/board/render/renderers/effect-card-renderer.js +197 -0
  60. package/dist/board/render/renderers/far-plate.d.ts +4 -21
  61. package/dist/board/render/renderers/far-plate.js +15 -34
  62. package/dist/board/render/renderers/file-card-renderer.d.ts +4 -25
  63. package/dist/board/render/renderers/file-card-renderer.js +8 -58
  64. package/dist/board/render/renderers/frame-card-renderer.js +28 -28
  65. package/dist/board/render/renderers/image-card-renderer.d.ts +4 -3
  66. package/dist/board/render/renderers/image-card-renderer.js +0 -9
  67. package/dist/board/render/renderers/shape-card-renderer.d.ts +9 -0
  68. package/dist/board/render/renderers/shape-card-renderer.js +240 -0
  69. package/dist/board/render/renderers/sketch-card-renderer.d.ts +5 -0
  70. package/dist/board/render/renderers/sketch-card-renderer.js +98 -0
  71. package/dist/board/render/renderers/task-card-renderer.d.ts +0 -1
  72. package/dist/board/render/renderers/task-card-renderer.js +14 -16
  73. package/dist/board/render/renderers/text-card-renderer.d.ts +1 -3
  74. package/dist/board/render/renderers/text-card-renderer.js +56 -46
  75. package/dist/board/render/renderers/unknown-card-renderer.js +4 -10
  76. package/dist/board/render/renderers/video-card-renderer.d.ts +4 -2
  77. package/dist/board/render/renderers/video-card-renderer.js +2 -1
  78. package/dist/board/render/sketch-host.d.ts +14 -0
  79. package/dist/board/render/sketch-host.js +216 -0
  80. package/dist/board/render/stroke.d.ts +12 -0
  81. package/dist/board/render/stroke.js +90 -0
  82. package/dist/board/render/text-measurement.d.ts +6 -26
  83. package/dist/board/render/text-measurement.js +11 -30
  84. package/dist/board/replay.d.ts +6 -31
  85. package/dist/board/replay.js +45 -203
  86. package/dist/board/runtime/board-player.d.ts +24 -0
  87. package/dist/board/runtime/board-player.js +161 -0
  88. package/dist/board/task.d.ts +2 -10
  89. package/dist/board/task.js +1 -10
  90. package/dist/chunks/environment.d.ts +2291 -3864
  91. package/dist/chunks/host-bridge.d.ts +253 -0
  92. package/dist/chunks/http.d.ts +233 -58
  93. package/dist/chunks/http.js +1046 -1028
  94. package/dist/chunks/transport.js +113 -59
  95. package/dist/chunks/websocket.d.ts +1 -1
  96. package/dist/chunks/websocket.js +1 -1
  97. package/dist/host-bridge.d.ts +54 -0
  98. package/dist/host-bridge.js +322 -0
  99. package/dist/http.d.ts +3 -3
  100. package/dist/index.d.ts +74 -191
  101. package/dist/index.js +2032 -1186
  102. package/dist/protocol/dist/board-constants.d.ts +1 -29
  103. package/dist/protocol/dist/board-constants.js +2 -115
  104. package/dist/protocol/dist/board-layout.d.ts +59 -0
  105. package/dist/protocol/dist/board-layout.js +482 -0
  106. package/dist/protocol/dist/board-model.d.ts +2052 -0
  107. package/dist/protocol/dist/board-model.js +592 -0
  108. package/dist/protocol/dist/board-patch.d.ts +86 -0
  109. package/dist/protocol/dist/board-patch.js +734 -0
  110. package/dist/protocol/dist/board-schema.d.ts +33 -0
  111. package/dist/protocol/dist/board-schema.js +59 -0
  112. package/dist/protocol/dist/board-upgrade.d.ts +1 -0
  113. package/dist/protocol/dist/board-url.d.ts +1 -3
  114. package/dist/protocol/dist/board-url.js +2 -2
  115. package/dist/protocol/dist/board.d.ts +37 -232
  116. package/dist/protocol/dist/board.js +62 -160
  117. package/dist/protocol/dist/display/actions.d.ts +1 -0
  118. package/dist/protocol/dist/display/index.d.ts +2 -0
  119. package/dist/protocol/dist/index.d.ts +11 -12
  120. package/dist/protocol/dist/model/metrics.d.ts +2 -0
  121. package/dist/protocol/dist/model/session.d.ts +2 -1
  122. package/dist/protocol/dist/realtime/types.d.ts +2 -2
  123. package/dist/protocol/dist/runtime/index.d.ts +1 -0
  124. package/dist/space-picker.d.ts +1 -0
  125. package/dist/space-picker.js +1 -0
  126. package/dist/types.d.ts +2 -5
  127. package/package.json +9 -1
  128. package/dist/board/core/connections.d.ts +0 -108
  129. package/dist/board/core/connections.js +0 -455
  130. package/dist/board/mutation.d.ts +0 -6
  131. package/dist/board/mutation.js +0 -14
  132. package/dist/board/render/connection-layer.d.ts +0 -53
  133. package/dist/board/render/connection-layer.js +0 -375
  134. package/dist/board/render/renderers/geo-card-renderer.d.ts +0 -5
  135. package/dist/board/render/renderers/geo-card-renderer.js +0 -127
  136. package/dist/board/semantic-document.d.ts +0 -37
  137. package/dist/board/semantic-document.js +0 -288
  138. package/dist/board/semantic-mutation.d.ts +0 -10
  139. package/dist/board/semantic-mutation.js +0 -209
  140. package/dist/protocol/dist/board-animation.js +0 -34
  141. package/dist/protocol/dist/board-authoring.d.ts +0 -1326
  142. package/dist/protocol/dist/board-authoring.js +0 -302
  143. package/dist/protocol/dist/board-capability-registry.d.ts +0 -2
  144. package/dist/protocol/dist/board-capability-registry.js +0 -123
  145. package/dist/protocol/dist/board-codec.d.ts +0 -3
  146. package/dist/protocol/dist/board-codec.js +0 -383
  147. package/dist/protocol/dist/board-composition.d.ts +0 -383
  148. package/dist/protocol/dist/board-composition.js +0 -310
  149. package/dist/protocol/dist/board-connection.d.ts +0 -317
  150. package/dist/protocol/dist/board-connection.js +0 -219
  151. package/dist/protocol/dist/board-document.d.ts +0 -1566
  152. package/dist/protocol/dist/board-document.js +0 -456
  153. package/dist/protocol/dist/board-effect.d.ts +0 -96
  154. package/dist/protocol/dist/board-effect.js +0 -54
  155. package/dist/protocol/dist/board-geometry.d.ts +0 -15
  156. package/dist/protocol/dist/board-geometry.js +0 -137
  157. package/dist/protocol/dist/board-node.d.ts +0 -8
  158. package/dist/protocol/dist/board-node.js +0 -252
  159. /package/dist/protocol/dist/{board-animation.d.ts → host-bridge.d.ts} +0 -0
@@ -1,13 +1,15 @@
1
- import { BoardDocument, BoardViewport } from "../../protocol/dist/board-document.js";
1
+ import { BoardSettings } from "../../protocol/dist/board-model.js";
2
+ import "../../protocol/dist/index.js";
3
+ import { BoardViewport } from "../geometry.js";
2
4
  import { BoardRenderPalette } from "./renderers/board-renderer-registry.js";
3
5
  import { Application, Container } from "pixi.js";
4
6
  //#region src/board/render/board-background.d.ts
5
7
  type BoardBackgroundContext = {
6
8
  app: Application;
7
- document: BoardDocument;
9
+ settings: BoardSettings;
8
10
  viewport: BoardViewport;
11
+ colorScheme: "dark" | "light";
9
12
  palette: BoardRenderPalette;
10
- /** The host renders an image backdrop below the transparent Pixi canvas. */
11
13
  hasImageBackground?: boolean;
12
14
  };
13
15
  declare function createBoardBackground(context: BoardBackgroundContext): Container;
@@ -28,11 +28,12 @@ function buildGridTexture(context, size, color, opacity, kind) {
28
28
  return target;
29
29
  }
30
30
  function sync(parts, context) {
31
- const { app, document, viewport, palette } = context;
31
+ const { app, settings, viewport, palette } = context;
32
32
  const width = app.screen.width;
33
33
  const height = app.screen.height;
34
- const declaredBackground = document.appearance.background;
35
- const bgColor = declaredBackground.color ? parseBoardCssColor(declaredBackground.color) ?? palette.bg : palette.bg;
34
+ const declared = settings.background.color;
35
+ const cssColor = typeof declared === "object" ? declared[context.colorScheme] : declared;
36
+ const bgColor = cssColor ? parseBoardCssColor(cssColor) ?? palette.bg : palette.bg;
36
37
  const bgAlpha = context.hasImageBackground ? 0 : 1;
37
38
  if (parts.lastWidth !== width || parts.lastHeight !== height || parts.lastBg !== bgColor || parts.lastBgAlpha !== bgAlpha) {
38
39
  parts.fill.clear();
@@ -45,10 +46,10 @@ function sync(parts, context) {
45
46
  parts.lastBg = bgColor;
46
47
  parts.lastBgAlpha = bgAlpha;
47
48
  }
48
- const visible = document.appearance.grid?.visible === true;
49
- const size = Math.max(4, document.appearance.grid?.size ?? 24);
50
- const opacity = document.appearance.grid?.opacity ?? .12;
51
- const kind = document.appearance.background?.kind === "grid" ? "grid" : "dots";
49
+ const kind = settings.background.kind === "grid" ? "grid" : "dots";
50
+ const visible = settings.grid?.visible === true;
51
+ const size = Math.max(4, settings.grid?.size ?? 24);
52
+ const opacity = .12;
52
53
  const key = `${kind}|${size}|${palette.border}|${opacity}`;
53
54
  if (!visible) {
54
55
  if (parts.sprite) parts.sprite.visible = false;
@@ -0,0 +1,14 @@
1
+ import { BoardScene, BoardSceneItem } from "../core/scene.js";
2
+ import { Container, Graphics } from "pixi.js";
3
+ //#region src/board/render/clip.d.ts
4
+ declare function isClippingFrame(item: BoardSceneItem): boolean;
5
+ declare function clippingAncestor(scene: BoardScene, item: BoardSceneItem): string | undefined;
6
+ declare function traceFrameOutline(graphics: Graphics, item: BoardSceneItem): void;
7
+ type ClipGroup = {
8
+ group: Container;
9
+ mask: Graphics;
10
+ sig: string;
11
+ };
12
+ declare function syncClipGroup(entry: ClipGroup | undefined, item: BoardSceneItem): ClipGroup;
13
+ //#endregion
14
+ export { ClipGroup, clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline };
@@ -0,0 +1,47 @@
1
+ import { framePoint } from "../../protocol/dist/board-layout.js";
2
+ import { Container, Graphics } from "pixi.js";
3
+ //#region src/board/render/clip.ts
4
+ function isClippingFrame(item) {
5
+ return item.type === "frame" && item.props.clip !== false;
6
+ }
7
+ function clippingAncestor(scene, item) {
8
+ let cursor = item.parent;
9
+ for (let depth = 0; cursor && depth < 64; depth += 1) {
10
+ const parent = scene.get(cursor);
11
+ if (!parent) return void 0;
12
+ if (isClippingFrame(parent)) return cursor;
13
+ cursor = parent.parent;
14
+ }
15
+ }
16
+ function traceFrameOutline(graphics, item) {
17
+ const corners = [
18
+ framePoint(item.frame, 0, 0),
19
+ framePoint(item.frame, 1, 0),
20
+ framePoint(item.frame, 1, 1),
21
+ framePoint(item.frame, 0, 1)
22
+ ];
23
+ graphics.poly(corners.flatMap((point) => [point.x, point.y])).fill(16777215);
24
+ }
25
+ function syncClipGroup(entry, item) {
26
+ const next = entry ?? (() => {
27
+ const group = new Container({ label: `board-clip-${item.id}` });
28
+ const mask = new Graphics();
29
+ group.addChild(mask);
30
+ group.mask = mask;
31
+ return {
32
+ group,
33
+ mask,
34
+ sig: ""
35
+ };
36
+ })();
37
+ const { x, y, width, height, rotation } = item.frame;
38
+ const sig = `${x},${y},${width},${height},${rotation}`;
39
+ if (sig !== next.sig) {
40
+ next.sig = sig;
41
+ next.mask.clear();
42
+ traceFrameOutline(next.mask, item);
43
+ }
44
+ return next;
45
+ }
46
+ //#endregion
47
+ export { clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline };
@@ -1,11 +1,14 @@
1
- import { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
1
+ import { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, BoardSketchHost, boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
2
2
  import { BoardBackgroundContext, createBoardBackground, updateBoardBackground } from "./board-background.js";
3
- import { ConnectionLayer, ConnectionRenderInput, createConnectionLayer, framesFromItems } from "./connection-layer.js";
3
+ import { ClipGroup, clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline } from "./clip.js";
4
4
  import { parseBoardCssColor } from "./css-color.js";
5
5
  import { BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible } from "./media-interaction.js";
6
- import { defaultBoardPalette } from "./palette.js";
6
+ import { defaultBoardPalette, itemColor } from "./palette.js";
7
+ import { BoardSketchHostOptions, BrowserBoardSketchHost, createBoardSketchHost } from "./sketch-host.js";
8
+ import { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline } from "./stroke.js";
9
+ import { BOARD_EFFECT_MAX_PARTICLES } from "./renderers/effect-card-renderer.js";
7
10
  import { TASK_CARD_FULL_DETAIL_ZOOM } from "./renderers/task-card-renderer.js";
8
- import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
11
+ import { BOARD_FONT_STACKS, ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
9
12
  import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
10
13
  import { VIDEO_THUMBNAIL_MAX_EDGE, VideoNaturalSize, loadVideoThumbnailTexture, videoTextureNaturalSize, videoThumbnailSize } from "./video-thumbnail.js";
11
- export { BoardBackgroundContext, BoardCardRenderer, BoardMediaAction, BoardRenderContext, BoardRenderPalette, ConnectionLayer, ConnectionRenderInput, TASK_CARD_FULL_DETAIL_ZOOM, VIDEO_THUMBNAIL_MAX_EDGE, VideoNaturalSize, boardCardRenderersForTest, boardMediaActionAt, createBoardBackground, createConnectionLayer, defaultBoardPalette, ensureBoardTextMeasurement, framesFromItems, getBoardCardRenderer, getBoardResolution, installBoardTextMeasurement, loadVideoThumbnailTexture, mediaPlayBadgeHit, mediaPlayBadgeVisible, parseBoardCssColor, registerBoardCardRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize };
14
+ export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, BoardBackgroundContext, BoardCardRenderer, BoardMediaAction, BoardRenderContext, BoardRenderPalette, BoardSketchHost, BoardSketchHostOptions, BrowserBoardSketchHost, ClipGroup, TASK_CARD_FULL_DETAIL_ZOOM, VIDEO_THUMBNAIL_MAX_EDGE, VideoNaturalSize, boardCardRenderersForTest, boardMediaActionAt, clippingAncestor, createBoardBackground, createBoardSketchHost, dashPattern, defaultBoardPalette, endAngle, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, installBoardTextMeasurement, isClippingFrame, itemColor, loadVideoThumbnailTexture, mediaPlayBadgeHit, mediaPlayBadgeVisible, parseBoardCssColor, registerBoardCardRenderer, syncClipGroup, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, traceArrowhead, traceFrameOutline, tracePolyline, trimPolyline, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize };
@@ -1,11 +1,14 @@
1
1
  import { parseBoardCssColor } from "./css-color.js";
2
2
  import { createBoardBackground, updateBoardBackground } from "./board-background.js";
3
+ import { clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline } from "./clip.js";
3
4
  import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
4
- import { createConnectionLayer, framesFromItems } from "./connection-layer.js";
5
5
  import { TASK_CARD_FULL_DETAIL_ZOOM } from "./renderers/task-card-renderer.js";
6
6
  import { boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible } from "./media-interaction.js";
7
- import { defaultBoardPalette } from "./palette.js";
8
- import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
7
+ import { defaultBoardPalette, itemColor } from "./palette.js";
8
+ import { BOARD_FONT_STACKS, ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
9
+ import { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline } from "./stroke.js";
10
+ import { BOARD_EFFECT_MAX_PARTICLES } from "./renderers/effect-card-renderer.js";
9
11
  import { boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
12
+ import { createBoardSketchHost } from "./sketch-host.js";
10
13
  import { VIDEO_THUMBNAIL_MAX_EDGE, loadVideoThumbnailTexture, videoTextureNaturalSize, videoThumbnailSize } from "./video-thumbnail.js";
11
- export { TASK_CARD_FULL_DETAIL_ZOOM, VIDEO_THUMBNAIL_MAX_EDGE, boardCardRenderersForTest, boardMediaActionAt, createBoardBackground, createConnectionLayer, defaultBoardPalette, ensureBoardTextMeasurement, framesFromItems, getBoardCardRenderer, getBoardResolution, installBoardTextMeasurement, loadVideoThumbnailTexture, mediaPlayBadgeHit, mediaPlayBadgeVisible, parseBoardCssColor, registerBoardCardRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize };
14
+ export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, TASK_CARD_FULL_DETAIL_ZOOM, VIDEO_THUMBNAIL_MAX_EDGE, boardCardRenderersForTest, boardMediaActionAt, clippingAncestor, createBoardBackground, createBoardSketchHost, dashPattern, defaultBoardPalette, endAngle, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, installBoardTextMeasurement, isClippingFrame, itemColor, loadVideoThumbnailTexture, mediaPlayBadgeHit, mediaPlayBadgeVisible, parseBoardCssColor, registerBoardCardRenderer, syncClipGroup, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, traceArrowhead, traceFrameOutline, tracePolyline, trimPolyline, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize };
@@ -1,17 +1,16 @@
1
- import { BoardItem } from "../../protocol/dist/board-document.js";
2
1
  import { WorldPoint } from "../geometry.js";
2
+ import { BoardSceneItem } from "../core/scene.js";
3
3
  //#region src/board/render/media-interaction.d.ts
4
4
  type BoardMediaAction = {
5
5
  action: "play-media";
6
6
  itemId: string;
7
7
  };
8
- declare function mediaPlayBadgeVisible(item: BoardItem, zoom: number, options: {
8
+ declare function mediaPlayBadgeVisible(item: BoardSceneItem, zoom: number, options: {
9
9
  materialized: boolean;
10
10
  hasVideoPreview: boolean;
11
11
  }): boolean;
12
- /** The central badge is a fixed screen-space target, independent of Board zoom. */
13
- declare function mediaPlayBadgeHit(item: BoardItem, point: WorldPoint, zoom: number): boolean;
14
- declare function boardMediaActionAt(item: BoardItem, point: WorldPoint, zoom: number, options: {
12
+ declare function mediaPlayBadgeHit(item: BoardSceneItem, point: WorldPoint, zoom: number): boolean;
13
+ declare function boardMediaActionAt(item: BoardSceneItem, point: WorldPoint, zoom: number, options: {
15
14
  materialized: boolean;
16
15
  hasVideoPreview: boolean;
17
16
  }): BoardMediaAction | null;
@@ -5,11 +5,10 @@ function mediaPlayBadgeVisible(item, zoom, options) {
5
5
  if (!options.materialized) return false;
6
6
  if (item.type === "video" || item.type === "audio") return true;
7
7
  if (item.type !== "task" || zoom < .55) return false;
8
- const artifact = featuredTaskArtifact(item.snapshot.artifacts);
8
+ const artifact = featuredTaskArtifact(item.props.snapshot.artifacts);
9
9
  if (artifact?.type === "audio") return true;
10
10
  return artifact?.type === "video" && (Boolean(artifact.previewUrl) || options.hasVideoPreview);
11
11
  }
12
- /** The central badge is a fixed screen-space target, independent of Board zoom. */
13
12
  function mediaPlayBadgeHit(item, point, zoom) {
14
13
  const radius = 28 / Math.max(zoom, .05);
15
14
  const centerX = item.frame.x + item.frame.width / 2;
@@ -1,5 +1,9 @@
1
- import { BoardRenderPalette } from "./renderers/board-renderer-registry.js";
1
+ import { BoardColor } from "../../protocol/dist/board-model.js";
2
+ import "../../protocol/dist/index.js";
3
+ import { BoardColorId } from "../core/palette.js";
4
+ import { BoardRenderContext, BoardRenderPalette } from "./renderers/board-renderer-registry.js";
2
5
  //#region src/board/render/palette.d.ts
3
6
  declare function defaultBoardPalette(mode: "dark" | "light"): BoardRenderPalette;
7
+ declare function itemColor(context: Pick<BoardRenderContext, "colors" | "colorScheme" | "palette">, color: BoardColor | undefined, fallback: BoardColorId, part?: "stroke" | "fill" | "label"): number;
4
8
  //#endregion
5
- export { defaultBoardPalette };
9
+ export { defaultBoardPalette, itemColor };
@@ -1,3 +1,5 @@
1
+ import { resolveItemColor } from "../core/palette.js";
2
+ import { parseBoardCssColor } from "./css-color.js";
1
3
  //#region src/board/render/palette.ts
2
4
  const DARK = {
3
5
  bg: 1315860,
@@ -26,5 +28,9 @@ const LIGHT = {
26
28
  function defaultBoardPalette(mode) {
27
29
  return { ...mode === "light" ? LIGHT : DARK };
28
30
  }
31
+ function itemColor(context, color, fallback, part = "stroke") {
32
+ if (((typeof color === "object" && color ? color[context.colorScheme] : color) ?? fallback) === "neutral" && part !== "fill") return context.palette.text;
33
+ return resolveItemColor(color, fallback, context.colors, context.colorScheme, parseBoardCssColor, part);
34
+ }
29
35
  //#endregion
30
- export { defaultBoardPalette };
36
+ export { defaultBoardPalette, itemColor };
@@ -1,95 +1,91 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { resolveArrow, sampleArrow } from "../../core/arrow-geometry.js";
3
- import { pickBoardColor } from "../../core/palette.js";
2
+ import { pathPointAt, resolveSceneArrow } from "../../core/arrow-geometry.js";
4
3
  import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
5
4
  import { drawFarStroke } from "./far-plate.js";
5
+ import { itemColor } from "../palette.js";
6
+ import { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline } from "../stroke.js";
6
7
  import { Container, Graphics, Text } from "pixi.js";
7
8
  //#region src/board/render/renderers/arrow-card-renderer.ts
8
9
  const partsByContainer = /* @__PURE__ */ new WeakMap();
9
- /** Open chevron arrowhead — clearly directional, not a tiny filled nub. */
10
- function drawArrowhead(graphics, tip, angle, size, color, strokeWidth) {
11
- const spread = Math.PI / 6;
12
- const left = {
13
- x: tip.x - size * Math.cos(angle - spread),
14
- y: tip.y - size * Math.sin(angle - spread)
15
- };
16
- const right = {
17
- x: tip.x - size * Math.cos(angle + spread),
18
- y: tip.y - size * Math.sin(angle + spread)
19
- };
20
- graphics.moveTo(left.x, left.y).lineTo(tip.x, tip.y).lineTo(right.x, right.y).stroke({
21
- color,
22
- width: Math.max(1.5, strokeWidth),
23
- alpha: 1,
24
- cap: "round",
25
- join: "round"
26
- });
27
- }
28
10
  function sync(container, item, context) {
29
11
  const parts = partsByContainer.get(container);
30
12
  if (!parts) return;
31
13
  parts.root.position.set(0, 0);
32
14
  parts.root.rotation = 0;
15
+ parts.root.scale.set(1);
16
+ const { props, style } = item;
33
17
  const selected = context.selectedIds.has(item.id);
34
18
  const hovered = context.hoveredId === item.id;
35
- const color = pickBoardColor(context.colors, item.color, context.colorScheme);
19
+ const color = itemColor(context, style.stroke, "brand");
20
+ const size = style.strokeWidth ?? 2.5;
36
21
  syncTextResolution(parts.label, parts, context.zoom);
37
- const resolved = resolveArrow(item);
22
+ const resolved = resolveSceneArrow(item, context.scene);
23
+ const path = trimPolyline(resolved.path, style.trim);
38
24
  const lineSig = [
39
- resolved.start.x,
40
- resolved.start.y,
41
- resolved.end.x,
42
- resolved.end.y,
43
- resolved.control.x,
44
- resolved.control.y,
25
+ path.map((point) => `${point.x},${point.y}`).join(";"),
45
26
  selected,
46
27
  hovered,
47
- color.stroke,
48
- item.size,
49
- item.arrowStart,
50
- item.arrowEnd
28
+ color,
29
+ size,
30
+ style.dash,
31
+ props.arrowStart,
32
+ props.arrowEnd
51
33
  ].join("|");
52
34
  if (lineSig !== parts.lineSig) {
53
35
  parts.lineSig = lineSig;
54
36
  parts.line.clear();
55
- const strokeColor = color.stroke;
56
- const width = selected ? item.size + 1 : item.size;
57
- const samples = sampleArrow(resolved, 24);
58
- const head = samples[0];
59
- const tail = samples[samples.length - 1];
60
- if (head && tail) {
61
- parts.line.moveTo(head.x, head.y);
62
- for (let i = 1; i < samples.length; i += 1) {
63
- const point = samples[i];
64
- if (point) parts.line.lineTo(point.x, point.y);
65
- }
37
+ const width = selected ? size + 1 : size;
38
+ const stroke = {
39
+ color,
40
+ width,
41
+ alpha: selected || hovered ? 1 : .92,
42
+ cap: "round",
43
+ join: "round"
44
+ };
45
+ tracePolyline(parts.line, path, dashPattern(style.dash, width));
46
+ parts.line.stroke(stroke);
47
+ const first = path[0];
48
+ const last = path[path.length - 1];
49
+ if (first && last) {
50
+ const span = Math.hypot(last.x - first.x, last.y - first.y);
51
+ const headSize = Math.min(Math.max(14, size * 5.5), Math.max(10, span * .28));
52
+ const complete = style.trim === void 0 || style.trim >= 1;
53
+ const endDirection = endAngle(path, false);
54
+ const startDirection = endAngle(path, true);
55
+ if (props.arrowEnd && endDirection !== null && path.length > 1) traceArrowhead(parts.line, last, endDirection, headSize);
56
+ if (props.arrowStart && startDirection !== null && complete) traceArrowhead(parts.line, first, startDirection, headSize);
66
57
  parts.line.stroke({
67
- color: strokeColor,
68
- width,
69
- alpha: selected || hovered ? 1 : .92,
70
- cap: "round",
71
- join: "round"
58
+ ...stroke,
59
+ width: Math.max(1.5, width)
72
60
  });
73
- const span = Math.hypot(tail.x - head.x, tail.y - head.y);
74
- const headSize = Math.min(Math.max(14, item.size * 5.5), Math.max(10, span * .28));
75
- if (item.arrowEnd) {
76
- const prev = samples[samples.length - 2];
77
- if (prev) drawArrowhead(parts.line, tail, Math.atan2(tail.y - prev.y, tail.x - prev.x), headSize, strokeColor, width);
78
- }
79
- if (item.arrowStart) {
80
- const next = samples[1];
81
- if (next) drawArrowhead(parts.line, head, Math.atan2(head.y - next.y, head.x - next.x), headSize, strokeColor, width);
82
- }
83
61
  }
84
62
  }
85
- const labelSig = [item.label, color.label].join("|");
63
+ const labelSig = [
64
+ props.label,
65
+ context.palette.text,
66
+ context.palette.bg,
67
+ props.fontSize
68
+ ].join("|");
86
69
  if (labelSig !== parts.labelSig) {
87
70
  parts.labelSig = labelSig;
88
- parts.label.text = item.label;
89
- parts.label.style.fill = color.label;
71
+ parts.label.text = props.label;
72
+ parts.label.style.fill = context.palette.text;
73
+ parts.label.style.fontSize = props.fontSize;
74
+ const padX = props.fontSize * .4;
75
+ const padY = props.fontSize * .15;
76
+ const { width, height } = parts.label;
77
+ parts.backdrop.clear();
78
+ parts.backdrop.roundRect(-width / 2 - padX, -height / 2 - padY, width + padX * 2, height + padY * 2, props.fontSize * .3).fill({
79
+ color: context.palette.bg,
80
+ alpha: .92
81
+ });
90
82
  }
91
- parts.label.visible = item.label.length > 0;
92
- parts.label.position.copyFrom(resolved.control);
83
+ const visible = props.label.length > 0 && (style.trim === void 0 || style.trim >= .5);
84
+ parts.label.visible = visible;
85
+ parts.backdrop.visible = visible;
86
+ const mid = style.trim === void 0 ? resolved.mid : pathPointAt(resolved.path, .5);
87
+ parts.label.position.set(mid.x, mid.y);
88
+ parts.backdrop.position.set(mid.x, mid.y);
93
89
  }
94
90
  const arrowCardRenderer = {
95
91
  id: "arrow-card",
@@ -103,17 +99,19 @@ const arrowCardRenderer = {
103
99
  style: {
104
100
  fill: 16777215,
105
101
  fontFamily: BOARD_FONT_STACK,
106
- fontSize: 12,
102
+ fontSize: 14,
107
103
  fontWeight: "500"
108
104
  },
109
105
  resolution,
110
106
  roundPixels: true
111
107
  });
112
108
  label.anchor.set(.5);
113
- root.addChild(line, label);
109
+ const backdrop = new Graphics();
110
+ root.addChild(line, backdrop, label);
114
111
  partsByContainer.set(root, {
115
112
  root,
116
113
  line,
114
+ backdrop,
117
115
  label,
118
116
  lineSig: "",
119
117
  labelSig: "",
@@ -127,11 +125,11 @@ const arrowCardRenderer = {
127
125
  },
128
126
  renderFar: (graphics, item, context) => {
129
127
  if (item.type !== "arrow") return;
130
- const resolved = resolveArrow(item);
131
- const color = pickBoardColor(context.colors, item.color, context.colorScheme);
132
- drawFarStroke(graphics, sampleArrow(resolved, 12), {
133
- color: color.stroke,
134
- width: item.size,
128
+ const arrow = item;
129
+ const resolved = resolveSceneArrow(arrow, context.scene);
130
+ drawFarStroke(graphics, trimPolyline(resolved.path, arrow.style.trim), {
131
+ color: itemColor(context, arrow.style.stroke, "brand"),
132
+ width: arrow.style.strokeWidth ?? 2.5,
135
133
  alpha: .85
136
134
  });
137
135
  },
@@ -1,6 +1,6 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { syncTextResolution, syncTextWrapWidth, textResolutionForZoom } from "../text-resolution.js";
3
2
  import { drawAudioWaveform } from "../audio-waveform.js";
3
+ import { syncTextResolution, syncTextWrapWidth, textResolutionForZoom } from "../text-resolution.js";
4
4
  import { positionShell } from "./base-card-renderer.js";
5
5
  import { drawFarPlate } from "./far-plate.js";
6
6
  import { Container, Graphics, Text } from "pixi.js";
@@ -15,7 +15,7 @@ function sync(container, item, context) {
15
15
  const { width, height } = item.frame;
16
16
  const selected = context.selectedIds.has(item.id);
17
17
  const hovered = context.hoveredId === item.id;
18
- const title = item.snapshot?.title ?? item.ref.path.split("/").pop() ?? "Audio";
18
+ const title = item.props.snapshot?.title ?? item.props.src.split("/").pop() ?? "Audio";
19
19
  syncTextResolution(parts.label, parts, context.zoom);
20
20
  if (parts.label.text !== title) parts.label.text = title;
21
21
  syncTextWrapWidth(parts.label, parts, Math.max(1, width - 24), false);
@@ -46,7 +46,7 @@ function sync(container, item, context) {
46
46
  const labelBand = Math.min(height * .38, parts.label.height + 16);
47
47
  const waveformInset = Math.min(24, width * .08);
48
48
  parts.waveform.clear();
49
- drawAudioWaveform(parts.waveform, `${item.ref.path}:${item.snapshot?.mtimeMs ?? "unknown"}`, {
49
+ drawAudioWaveform(parts.waveform, `${item.props.src}:${item.props.snapshot?.mtimeMs ?? "unknown"}`, {
50
50
  x: waveformInset,
51
51
  y: 10,
52
52
  width: Math.max(1, width - waveformInset * 2),
@@ -1,11 +1,11 @@
1
- import { BoardItem } from "../../../protocol/dist/board-document.js";
1
+ import { BoardFrame } from "../../../protocol/dist/board-layout.js";
2
+ import "../../../protocol/dist/index.js";
2
3
  import { BoardRenderPalette } from "./board-renderer-registry.js";
3
4
  import { Container, Text } from "pixi.js";
4
5
  //#region src/board/render/renderers/base-card-renderer.d.ts
5
6
  declare const CARD_RADIUS = 10;
6
7
  declare const CARD_PADDING = 12;
7
8
  declare const FOOTER_HEIGHT = 34;
8
- declare function emphasisColor(item: BoardItem, palette: BoardRenderPalette): number;
9
9
  declare function createLabel(text: string, style: Record<string, unknown>): Text;
10
10
  type CardShellState = {
11
11
  width: number;
@@ -16,11 +16,8 @@ type CardShellState = {
16
16
  title: string;
17
17
  };
18
18
  type CardShell = {
19
- /** Root container positioned by the item frame. */
20
19
  root: Container;
21
- /** Masked container for renderer-specific content. */
22
20
  content: Container;
23
- /** Rectangle (local coords) available for content. */
24
21
  contentRect: () => {
25
22
  x: number;
26
23
  y: number;
@@ -30,17 +27,9 @@ type CardShell = {
30
27
  update: (state: CardShellState, palette: BoardRenderPalette, footer: boolean) => void;
31
28
  destroy: () => void;
32
29
  };
33
- /**
34
- * Shared card chrome: rounded background, selection/hover border, optional
35
- * footer with title, and a masked content region. Tracks the last rendered
36
- * state so unchanged attributes are not redrawn.
37
- */
38
30
  declare function createCardShell(): CardShell;
39
- /**
40
- * Position a shell root at an item frame. The container pivots around its
41
- * center so that Pixi's rotation matches the geometry model (which treats
42
- * `frame.rotation` as a rotation about the frame center).
43
- */
44
- declare function positionShell(root: Container, item: BoardItem): void;
31
+ declare function positionShell(root: Container, item: {
32
+ frame: BoardFrame;
33
+ }): void;
45
34
  //#endregion
46
- export { CARD_PADDING, CARD_RADIUS, CardShell, CardShellState, FOOTER_HEIGHT, createCardShell, createLabel, emphasisColor, positionShell };
35
+ export { CARD_PADDING, CARD_RADIUS, CardShell, CardShellState, FOOTER_HEIGHT, createCardShell, createLabel, positionShell };
@@ -1,5 +1,4 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { parseBoardCssColor } from "../css-color.js";
3
2
  import { getBoardResolution } from "../text-resolution.js";
4
3
  import { Container, Graphics, Text } from "pixi.js";
5
4
  //#region src/board/render/renderers/base-card-renderer.ts
@@ -10,18 +9,6 @@ const TEXT_OPTIONS = {
10
9
  resolution: getBoardResolution(),
11
10
  roundPixels: true
12
11
  };
13
- function emphasisColor(item, palette) {
14
- if (item.style?.accentColor) {
15
- const normalized = parseBoardCssColor(item.style.accentColor);
16
- if (normalized != null) return normalized;
17
- }
18
- switch (item.style?.emphasis) {
19
- case "rare": return palette.rare;
20
- case "epic": return palette.epic;
21
- case "legendary": return palette.legendary;
22
- default: return palette.brand;
23
- }
24
- }
25
12
  function createLabel(text, style) {
26
13
  return new Text({
27
14
  ...TEXT_OPTIONS,
@@ -29,11 +16,6 @@ function createLabel(text, style) {
29
16
  style
30
17
  });
31
18
  }
32
- /**
33
- * Shared card chrome: rounded background, selection/hover border, optional
34
- * footer with title, and a masked content region. Tracks the last rendered
35
- * state so unchanged attributes are not redrawn.
36
- */
37
19
  function createCardShell() {
38
20
  const root = new Container();
39
21
  const background = new Graphics();
@@ -120,11 +102,6 @@ function createCardShell() {
120
102
  destroy
121
103
  };
122
104
  }
123
- /**
124
- * Position a shell root at an item frame. The container pivots around its
125
- * center so that Pixi's rotation matches the geometry model (which treats
126
- * `frame.rotation` as a rotation about the frame center).
127
- */
128
105
  function positionShell(root, item) {
129
106
  const { x, y, width, height, rotation } = item.frame;
130
107
  root.pivot.set(width / 2, height / 2);
@@ -133,4 +110,4 @@ function positionShell(root, item) {
133
110
  root.rotation = (rotation || 0) * Math.PI / 180;
134
111
  }
135
112
  //#endregion
136
- export { CARD_PADDING, CARD_RADIUS, FOOTER_HEIGHT, createCardShell, createLabel, emphasisColor, positionShell };
113
+ export { CARD_PADDING, CARD_RADIUS, FOOTER_HEIGHT, createCardShell, createLabel, positionShell };