@neta-art/cohub 8.23.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 +7 -27
  30. package/dist/board/headless/index.js +20 -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 +2296 -3864
  91. package/dist/chunks/host-bridge.d.ts +253 -0
  92. package/dist/chunks/http.d.ts +238 -58
  93. package/dist/chunks/http.js +1061 -1034
  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 +76 -193
  101. package/dist/index.js +2037 -1191
  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,43 +1,14 @@
1
1
  import { BOARD_TEXT_FONT_FAMILY } from "../../protocol/dist/board-constants.js";
2
+ import { clampBoardFontSize } from "../../protocol/dist/board-layout.js";
2
3
  //#region src/board/core/text-metrics.ts
3
4
  const TEXT_FONT_FAMILY = BOARD_TEXT_FONT_FAMILY;
4
5
  const TEXT_FONT_SIZE = 24;
5
6
  const TEXT_LINE_HEIGHT = 32;
6
7
  const TEXT_MIN_FONT_SIZE = 2;
7
8
  const TEXT_MAX_FONT_SIZE = 512;
8
- const TEXT_LINE_HEIGHT_RATIO = TEXT_LINE_HEIGHT / TEXT_FONT_SIZE;
9
- const TEXT_MIN_WIDTH_RATIO = 16 / TEXT_FONT_SIZE;
10
- const TEXT_HORIZONTAL_PADDING_RATIO = 2 / TEXT_FONT_SIZE;
11
- const FALLBACK_CHARACTER_RATIO = .52;
12
- let textMeasurer;
13
- /** Install the renderer's text measurer, or clear it for environment-free fallback metrics. */
14
- function setBoardTextMeasurer(measurer) {
15
- textMeasurer = measurer;
16
- }
17
- function clampBoardTextFontSize(fontSize) {
18
- return Math.min(TEXT_MAX_FONT_SIZE, Math.max(TEXT_MIN_FONT_SIZE, fontSize));
19
- }
20
- function boardTextLineHeight(fontSize) {
21
- return clampBoardTextFontSize(fontSize) * TEXT_LINE_HEIGHT_RATIO;
22
- }
23
- /** Measure unwrapped plain text into scalable world-space bounds. */
24
- function measureBoardText(text, fontSize = TEXT_FONT_SIZE) {
25
- const size = clampBoardTextFontSize(fontSize);
26
- const lines = (text || " ").split("\n");
27
- const minWidth = size * TEXT_MIN_WIDTH_RATIO;
28
- const horizontalPadding = size * TEXT_HORIZONTAL_PADDING_RATIO;
29
- const lineHeight = boardTextLineHeight(size);
30
- const characterWidth = size * FALLBACK_CHARACTER_RATIO;
31
- let width = minWidth;
32
- for (const line of lines) {
33
- const value = line || " ";
34
- const measured = textMeasurer?.(value, size);
35
- width = Math.max(width, (measured ?? Math.max(1, value.length) * characterWidth) + horizontalPadding);
36
- }
37
- return {
38
- width,
39
- height: Math.max(lineHeight, lines.length * lineHeight)
40
- };
9
+ function boardFontFamily(font, stacks) {
10
+ if (font === "sans" || font === "serif" || font === "mono") return stacks[font];
11
+ return `"${font.replaceAll("\"", "")}", ${stacks.sans}`;
41
12
  }
42
13
  //#endregion
43
- export { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardTextLineHeight, clampBoardTextFontSize, measureBoardText, setBoardTextMeasurer };
14
+ export { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardFontFamily, clampBoardFontSize as clampBoardTextFontSize };
@@ -1,15 +1,14 @@
1
1
  import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../../protocol/dist/board-constants.js";
2
- import { BoardColorId } from "../../protocol/dist/board-node.js";
3
- import "./palette.js";
4
- import { GeoKind } from "./shape-types.js";
2
+ import { BoardColorId } from "./palette.js";
3
+ import { ShapeKind } from "./shape-types.js";
5
4
  //#region src/board/core/tool-styles.d.ts
6
5
  type BoardToolStyleMap = {
7
6
  text: {
8
7
  color: BoardColorId;
9
8
  };
10
- geo: {
9
+ shape: {
11
10
  color: BoardColorId;
12
- geo: GeoKind;
11
+ geometry: ShapeKind;
13
12
  };
14
13
  draw: {
15
14
  color: BoardColorId;
@@ -19,10 +18,6 @@ type BoardToolStyleMap = {
19
18
  color: BoardColorId;
20
19
  size: number;
21
20
  };
22
- connection: {
23
- color: BoardColorId;
24
- size: number;
25
- };
26
21
  frame: {
27
22
  color: BoardColorId;
28
23
  };
@@ -33,9 +28,9 @@ declare const DEFAULT_BOARD_TOOL_STYLES: {
33
28
  readonly text: {
34
29
  readonly color: "neutral";
35
30
  };
36
- readonly geo: {
31
+ readonly shape: {
37
32
  readonly color: "brand";
38
- readonly geo: "rectangle";
33
+ readonly geometry: "rectangle";
39
34
  };
40
35
  readonly draw: {
41
36
  readonly color: "brand";
@@ -45,15 +40,10 @@ declare const DEFAULT_BOARD_TOOL_STYLES: {
45
40
  readonly color: "brand";
46
41
  readonly size: 2.5;
47
42
  };
48
- readonly connection: {
49
- readonly color: "neutral";
50
- readonly size: 2.5;
51
- };
52
43
  readonly frame: {
53
44
  readonly color: "neutral";
54
45
  };
55
46
  };
56
- /** Return a mutable, validated style map for an editor or another Board client. */
57
47
  declare function createBoardToolStyles(patch?: BoardToolStylePatch): BoardToolStyleMap;
58
48
  //#endregion
59
49
  export { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardStyledToolId, BoardToolStyleMap, BoardToolStylePatch, DEFAULT_BOARD_TOOL_STYLES, clampBoardStrokeSize, createBoardToolStyles };
@@ -1,12 +1,12 @@
1
- import { BOARD_ARROW_STROKE_SIZE, BOARD_CONNECTION_STROKE_SIZE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../../protocol/dist/board-constants.js";
1
+ import { BOARD_ARROW_STROKE_SIZE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../../protocol/dist/board-constants.js";
2
2
  import { isBoardColorId } from "./palette.js";
3
- import { isGeoKind } from "./shape-types.js";
3
+ import { isShapeKind } from "./shape-types.js";
4
4
  //#region src/board/core/tool-styles.ts
5
5
  const DEFAULT_BOARD_TOOL_STYLES = {
6
6
  text: { color: "neutral" },
7
- geo: {
7
+ shape: {
8
8
  color: "brand",
9
- geo: "rectangle"
9
+ geometry: "rectangle"
10
10
  },
11
11
  draw: {
12
12
  color: "brand",
@@ -16,39 +16,31 @@ const DEFAULT_BOARD_TOOL_STYLES = {
16
16
  color: "brand",
17
17
  size: BOARD_ARROW_STROKE_SIZE
18
18
  },
19
- connection: {
20
- color: "neutral",
21
- size: BOARD_CONNECTION_STROKE_SIZE
22
- },
23
19
  frame: { color: "neutral" }
24
20
  };
25
21
  function finiteOr(value, fallback) {
26
22
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
27
23
  }
28
- /** Return a mutable, validated style map for an editor or another Board client. */
24
+ function colorOr(value, fallback) {
25
+ return isBoardColorId(value) ? value : fallback;
26
+ }
29
27
  function createBoardToolStyles(patch = {}) {
30
- const drawSize = clampBoardStrokeSize(finiteOr(patch.draw?.size, DEFAULT_BOARD_TOOL_STYLES.draw.size));
31
- const arrowSize = clampBoardStrokeSize(finiteOr(patch.arrow?.size, DEFAULT_BOARD_TOOL_STYLES.arrow.size));
32
- const connectionSize = clampBoardStrokeSize(finiteOr(patch.connection?.size, DEFAULT_BOARD_TOOL_STYLES.connection.size));
28
+ const defaults = DEFAULT_BOARD_TOOL_STYLES;
33
29
  return {
34
- text: { color: isBoardColorId(patch.text?.color) ? patch.text.color : DEFAULT_BOARD_TOOL_STYLES.text.color },
35
- geo: {
36
- color: isBoardColorId(patch.geo?.color) ? patch.geo.color : DEFAULT_BOARD_TOOL_STYLES.geo.color,
37
- geo: isGeoKind(patch.geo?.geo) ? patch.geo.geo : DEFAULT_BOARD_TOOL_STYLES.geo.geo
30
+ text: { color: colorOr(patch.text?.color, defaults.text.color) },
31
+ shape: {
32
+ color: colorOr(patch.shape?.color, defaults.shape.color),
33
+ geometry: isShapeKind(patch.shape?.geometry) ? patch.shape.geometry : defaults.shape.geometry
38
34
  },
39
35
  draw: {
40
- color: isBoardColorId(patch.draw?.color) ? patch.draw.color : DEFAULT_BOARD_TOOL_STYLES.draw.color,
41
- size: drawSize
36
+ color: colorOr(patch.draw?.color, defaults.draw.color),
37
+ size: clampBoardStrokeSize(finiteOr(patch.draw?.size, defaults.draw.size))
42
38
  },
43
39
  arrow: {
44
- color: isBoardColorId(patch.arrow?.color) ? patch.arrow.color : DEFAULT_BOARD_TOOL_STYLES.arrow.color,
45
- size: arrowSize
46
- },
47
- connection: {
48
- color: isBoardColorId(patch.connection?.color) ? patch.connection.color : DEFAULT_BOARD_TOOL_STYLES.connection.color,
49
- size: connectionSize
40
+ color: colorOr(patch.arrow?.color, defaults.arrow.color),
41
+ size: clampBoardStrokeSize(finiteOr(patch.arrow?.size, defaults.arrow.size))
50
42
  },
51
- frame: { color: isBoardColorId(patch.frame?.color) ? patch.frame.color : DEFAULT_BOARD_TOOL_STYLES.frame.color }
43
+ frame: { color: colorOr(patch.frame?.color, defaults.frame.color) }
52
44
  };
53
45
  }
54
46
  //#endregion
@@ -1,28 +1,29 @@
1
- import { BoardDocument, BoardItem } from "../../protocol/dist/board-document.js";
1
+ import { BoardDocument } from "../../protocol/dist/board-model.js";
2
+ import "../../protocol/dist/index.js";
3
+ import { BoardSceneItem } from "../core/scene.js";
2
4
  import { BoardExportPlan, BoardExportPlanInput, BoardExportRegion } from "../core/export-plan.js";
3
5
  import { BoardShapeColors } from "../core/palette.js";
4
- import { BoardRenderPalette } from "../render/renderers/board-renderer-registry.js";
6
+ import { BoardRenderPalette, BoardSketchHost } from "../render/renderers/board-renderer-registry.js";
5
7
  import "../render/index.js";
6
8
  import { BoardExportScene, BoardExportSceneInput, createBoardExportScene } from "./scene.js";
7
9
  import { ICanvas, Renderer, Texture } from "pixi.js";
8
10
  //#region src/board/export/index.d.ts
9
- /** Paper behind the content: the theme's page color, or none at all. */
10
11
  type BoardExportBackground = "paper" | "transparent" | number;
11
12
  type BoardExportOptions = {
12
13
  region?: BoardExportRegion;
13
- /** Output pixels per world unit. Defaults to 2. */
14
+ at?: {
15
+ animation?: string;
16
+ time: number;
17
+ };
14
18
  scale?: number;
15
- /** World-space padding. Frame and rect regions default to 0, others to 32. */
16
19
  padding?: number;
17
20
  colorScheme?: "dark" | "light";
18
- /** Defaults to "paper" — a transparent PNG surprises people who paste it. */
19
21
  background?: BoardExportBackground;
20
22
  palette?: Partial<BoardRenderPalette>;
21
23
  colors?: BoardShapeColors;
22
- /** Resolved textures by preview key; unresolved keys become placeholders. */
23
24
  textures?: Map<string, Texture>;
24
- /** Preview-key strategy supplied by the host; defaults to still images only. */
25
- assetKey?: (item: BoardItem) => string | null;
25
+ sketches?: BoardSketchHost;
26
+ assetKey?: (item: BoardSceneItem) => string | null;
26
27
  backgroundImage?: {
27
28
  texture: Texture;
28
29
  fit: "cover" | "contain" | "repeat";
@@ -48,15 +49,7 @@ type BoardExportResult = {
48
49
  plan: BoardExportPlan;
49
50
  warnings: BoardExportWarning[];
50
51
  };
51
- /**
52
- * Capture a board region as a canvas.
53
- *
54
- * Returns null when the region is empty — an empty selection is a no-op, not a
55
- * failure. The scene is always destroyed, so a throwing renderer cannot leak
56
- * GPU resources.
57
- */
58
52
  declare function renderBoardExport(renderer: Renderer, input: BoardDocument, options?: BoardExportOptions): BoardExportResult | null;
59
- /** Human-readable form of a warning, shared by the CLI and the web UI. */
60
53
  declare function describeBoardExportWarning(warning: BoardExportWarning): string;
61
54
  //#endregion
62
55
  export { BoardExportBackground, BoardExportOptions, type BoardExportPlan, type BoardExportPlanInput, type BoardExportRegion, BoardExportResult, type BoardExportScene, type BoardExportSceneInput, BoardExportWarning, createBoardExportScene, describeBoardExportWarning, renderBoardExport };
@@ -1,26 +1,26 @@
1
+ import { boardDocumentAt } from "../animation.js";
1
2
  import { normalizeBoardDocument, planBoardExport } from "../core/export-plan.js";
3
+ import { buildBoardScene } from "../core/scene.js";
2
4
  import { parseBoardCssColor } from "../render/css-color.js";
3
5
  import { defaultBoardPalette } from "../render/palette.js";
6
+ import { ensureBoardTextMeasurement } from "../render/text-measurement.js";
4
7
  import { createBoardExportScene } from "./scene.js";
5
8
  import { Rectangle } from "pixi.js";
6
9
  //#region src/board/export/index.ts
7
- function resolveBackground(background, palette, document) {
10
+ function resolveBackground(background, palette, document, colorScheme) {
8
11
  if (background === "transparent") return null;
9
12
  if (typeof background === "number") return background;
10
- const declared = document.appearance.background.color;
11
- return declared ? parseBoardCssColor(declared) ?? palette.bg : palette.bg;
13
+ const declared = document.board.background.color;
14
+ const css = typeof declared === "object" ? declared[colorScheme] : declared;
15
+ return css ? parseBoardCssColor(css) ?? palette.bg : palette.bg;
12
16
  }
13
- /**
14
- * Capture a board region as a canvas.
15
- *
16
- * Returns null when the region is empty — an empty selection is a no-op, not a
17
- * failure. The scene is always destroyed, so a throwing renderer cannot leak
18
- * GPU resources.
19
- */
20
17
  function renderBoardExport(renderer, input, options = {}) {
21
- const document = normalizeBoardDocument(input);
18
+ ensureBoardTextMeasurement();
19
+ const base = normalizeBoardDocument(input);
20
+ const document = options.at ? boardDocumentAt(base, options.at.animation ?? null, options.at.time).document : base;
21
+ const scene = buildBoardScene(document);
22
22
  const plan = planBoardExport({
23
- document,
23
+ scene,
24
24
  region: options.region ?? { kind: "all" },
25
25
  scale: options.scale,
26
26
  padding: options.padding,
@@ -33,23 +33,25 @@ function renderBoardExport(renderer, input, options = {}) {
33
33
  ...defaultBoardPalette(colorScheme),
34
34
  ...options.palette
35
35
  };
36
- const scene = createBoardExportScene({
37
- document,
36
+ const exportScene = createBoardExportScene({
37
+ settings: document.board,
38
+ scene,
38
39
  items: plan.items,
39
- connections: plan.connections,
40
+ time: options.at?.time ?? 0,
40
41
  world: plan.world,
41
42
  scale: plan.scale,
42
43
  colorScheme,
43
44
  palette,
44
45
  colors: options.colors,
45
46
  textures: options.textures,
47
+ sketches: options.sketches,
46
48
  assetKey: options.assetKey,
47
- background: resolveBackground(options.background, palette, document),
49
+ background: resolveBackground(options.background, palette, document, colorScheme),
48
50
  backgroundImage: options.backgroundImage
49
51
  });
50
52
  try {
51
53
  const canvas = renderer.extract.canvas({
52
- target: scene.root,
54
+ target: exportScene.root,
53
55
  frame: new Rectangle(0, 0, plan.width, plan.height),
54
56
  resolution: 1,
55
57
  antialias: true,
@@ -61,9 +63,9 @@ function renderBoardExport(renderer, input, options = {}) {
61
63
  requested: plan.requestedScale,
62
64
  applied: plan.scale
63
65
  });
64
- if (scene.missingImageKeys.length > 0) warnings.push({
66
+ if (exportScene.missingImageKeys.length > 0) warnings.push({
65
67
  kind: "images-missing",
66
- keys: scene.missingImageKeys
68
+ keys: exportScene.missingImageKeys
67
69
  });
68
70
  if (plan.items.length > 2e3) warnings.push({
69
71
  kind: "many-items",
@@ -75,10 +77,9 @@ function renderBoardExport(renderer, input, options = {}) {
75
77
  warnings
76
78
  };
77
79
  } finally {
78
- scene.destroy();
80
+ exportScene.destroy();
79
81
  }
80
82
  }
81
- /** Human-readable form of a warning, shared by the CLI and the web UI. */
82
83
  function describeBoardExportWarning(warning) {
83
84
  switch (warning.kind) {
84
85
  case "scale-clamped": return `Scale reduced from ${warning.requested}x to ${warning.applied.toFixed(2)}x to stay within the size limit.`;
@@ -1,29 +1,25 @@
1
- import { BoardConnection } from "../../protocol/dist/board-connection.js";
2
- import { BoardDocument, BoardItem } from "../../protocol/dist/board-document.js";
1
+ import { BoardSettings } from "../../protocol/dist/board-model.js";
2
+ import "../../protocol/dist/index.js";
3
3
  import { Rect } from "../geometry.js";
4
+ import { BoardScene, BoardSceneItem } from "../core/scene.js";
4
5
  import { BoardShapeColors } from "../core/palette.js";
5
- import { BoardRenderPalette } from "../render/renderers/board-renderer-registry.js";
6
+ import { BoardRenderContext, BoardRenderPalette } from "../render/renderers/board-renderer-registry.js";
6
7
  import "../render/index.js";
7
8
  import { Container, Texture } from "pixi.js";
8
9
  //#region src/board/export/scene.d.ts
9
10
  type BoardExportSceneInput = {
10
- document: BoardDocument;
11
- /** Items to draw, in document (z) order. */
12
- items: BoardItem[];
13
- /** Connections to draw. Rendered beneath the cards, as in the editor. */
14
- connections?: readonly BoardConnection[];
15
- /** World rect being captured; content is translated so it starts at 0,0. */
11
+ settings: BoardSettings;
12
+ scene: BoardScene;
13
+ items: readonly BoardSceneItem[];
14
+ time?: number;
16
15
  world: Rect;
17
- /** Output pixels per world unit. Drives text rasterisation resolution. */
18
16
  scale: number;
19
17
  colorScheme: "dark" | "light";
20
18
  palette?: Partial<BoardRenderPalette>;
21
19
  colors?: BoardShapeColors;
22
- /** Resolved textures by preview key. Missing keys render as placeholders. */
23
20
  textures?: Map<string, Texture>;
24
- /** Preview-key strategy supplied by the host; defaults to still images only. */
25
- assetKey?: (item: BoardItem) => string | null;
26
- /** Opaque paper behind the content, or null for transparency. */
21
+ sketches?: BoardRenderContext["sketches"];
22
+ assetKey?: (item: BoardSceneItem) => string | null;
27
23
  background?: number | null;
28
24
  backgroundImage?: {
29
25
  texture: Texture;
@@ -33,9 +29,7 @@ type BoardExportSceneInput = {
33
29
  };
34
30
  };
35
31
  type BoardExportScene = {
36
- /** Root to hand to the renderer; already positioned and scaled. */
37
32
  root: Container;
38
- /** Image keys the scene wanted but could not resolve. */
39
33
  missingImageKeys: string[];
40
34
  destroy: () => void;
41
35
  };
@@ -1,24 +1,18 @@
1
1
  import { imageAssetKey } from "../image-key.js";
2
2
  import { buildFallbackShapeColors } from "../core/palette.js";
3
- import { createConnectionLayer } from "../render/connection-layer.js";
3
+ import { clippingAncestor, isClippingFrame, syncClipGroup } from "../render/clip.js";
4
4
  import { defaultBoardPalette } from "../render/palette.js";
5
5
  import { getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
6
6
  import { Container, Graphics, Sprite, TilingSprite } from "pixi.js";
7
7
  //#region src/board/export/scene.ts
8
- /**
9
- * Render context for an export.
10
- *
11
- * Interaction state is empty by construction: nothing is selected, hovered or
12
- * resizing, so no editor chrome (outlines, handles) can leak into the image.
13
- */
14
8
  function buildContext(input) {
15
9
  const missing = /* @__PURE__ */ new Set();
16
- const byId = new Map(input.document.items.map((item) => [item.id, item]));
17
10
  const textures = input.textures ?? /* @__PURE__ */ new Map();
18
11
  return {
19
12
  context: {
20
- document: input.document,
21
- getItem: (id) => byId.get(id) ?? null,
13
+ settings: input.settings,
14
+ scene: input.scene,
15
+ time: input.time ?? 0,
22
16
  selectedIds: /* @__PURE__ */ new Set(),
23
17
  hoveredId: null,
24
18
  resizingIds: /* @__PURE__ */ new Set(),
@@ -30,6 +24,7 @@ function buildContext(input) {
30
24
  colorScheme: input.colorScheme,
31
25
  rendererType: "canvas",
32
26
  zoom: input.scale,
27
+ sketches: input.sketches,
33
28
  assetKey: input.assetKey ?? imageAssetKey,
34
29
  getTexture: (key) => textures.get(key) ?? null,
35
30
  hasError: (key) => {
@@ -80,32 +75,24 @@ function createBoardExportScene(input) {
80
75
  });
81
76
  world.scale.set(input.scale);
82
77
  world.position.set(-input.world.x * input.scale, -input.world.y * input.scale);
83
- const connections = input.connections ?? input.document.connections;
84
- let connectionLayer = null;
85
- if (connections.length > 0) {
86
- const frames = new Map(input.document.items.map((item) => [item.id, item.frame]));
87
- connectionLayer = createConnectionLayer({ parent: world });
88
- connectionLayer.sync({
89
- connections,
90
- getFrame: (id) => frames.get(id),
91
- colors: context.colors,
92
- colorScheme: input.colorScheme,
93
- zoom: input.scale,
94
- cullRect: input.world
95
- });
96
- }
78
+ const groups = /* @__PURE__ */ new Map();
97
79
  for (const item of input.items) {
98
- const renderer = getBoardCardRenderer(item, context);
99
- world.addChild(renderer.create(item, context));
80
+ const clip = clippingAncestor(input.scene, item);
81
+ const host = clip && groups.get(clip) || world;
82
+ const container = getBoardCardRenderer(item, context).create(item, context);
83
+ container.alpha = input.scene.opacity(item.id);
84
+ host.addChild(container);
85
+ if (isClippingFrame(item)) {
86
+ const { group } = syncClipGroup(void 0, item);
87
+ host.addChild(group);
88
+ groups.set(item.id, group);
89
+ }
100
90
  }
101
91
  root.addChild(world);
102
92
  return {
103
93
  root,
104
94
  missingImageKeys: [...missing],
105
- destroy: () => {
106
- connectionLayer?.destroy();
107
- root.destroy({ children: true });
108
- }
95
+ destroy: () => root.destroy({ children: true })
109
96
  };
110
97
  }
111
98
  //#endregion
@@ -1,7 +1,28 @@
1
- import { BoardCameraFocus, BoardCameraFocusParams, BoardCameraState } from "../protocol/dist/board.js";
2
- import { BoardFrame, BoardViewport } from "../protocol/dist/board-document.js";
1
+ import { BoardFrame } from "../protocol/dist/board-layout.js";
3
2
  import "../protocol/dist/index.js";
4
3
  //#region src/board/geometry.d.ts
4
+ type BoardViewport = {
5
+ x: number;
6
+ y: number;
7
+ zoom: number;
8
+ };
9
+ type BoardCameraState = {
10
+ centerX: number;
11
+ centerY: number;
12
+ zoom: number;
13
+ };
14
+ type BoardCameraFocus = string | {
15
+ x: number;
16
+ y: number;
17
+ width: number;
18
+ height: number;
19
+ };
20
+ type BoardCameraFit = {
21
+ fit?: "contain" | "cover";
22
+ padding?: number;
23
+ minZoom?: number;
24
+ maxZoom?: number;
25
+ };
5
26
  type Point = {
6
27
  x: number;
7
28
  y: number;
@@ -17,13 +38,11 @@ type Size = {
17
38
  height: number;
18
39
  };
19
40
  declare const coordBrand: unique symbol;
20
- /** Surface-relative screen coordinate, in CSS pixels. */
21
41
  type ScreenPoint = {
22
42
  x: number;
23
43
  y: number;
24
44
  readonly [coordBrand]: "screen";
25
45
  };
26
- /** Board world coordinate, in board units. */
27
46
  type WorldPoint = {
28
47
  x: number;
29
48
  y: number;
@@ -52,20 +71,11 @@ declare function normalizedPoint(x: number, y: number): BoardNormalizedPoint;
52
71
  declare function worldRect(x: number, y: number, width: number, height: number): BoardWorldRect;
53
72
  declare const MIN_BOARD_ZOOM = 0.05;
54
73
  declare const MAX_BOARD_ZOOM = 8;
55
- /** Smallest an item can be resized to, in world units. */
56
74
  declare const MIN_ITEM_SIZE = 24;
57
- /** Extra world-space padding applied when fitting content into view. */
58
75
  declare const FIT_PADDING = 64;
59
- /**
60
- * Fraction of the viewport's larger dimension used as an off-screen margin for
61
- * both card culling and texture preloading. Keeping them equal means a card's
62
- * texture is already requested before the card scrolls into view.
63
- */
64
76
  declare const VIEWPORT_MARGIN_RATIO = 0.5;
65
- /** Viewport plus margin, snapped to a grid so small pans return the same rect. */
66
77
  declare function stableCullRect(view: Rect): Rect;
67
78
  declare function clampZoom(zoom: number): number;
68
- /** Keep transient camera state finite without discarding its last valid axes. */
69
79
  declare function normalizeViewport(viewport: BoardViewport, fallback?: BoardViewport): BoardViewport;
70
80
  declare function clamp(value: number, min: number, max: number): number;
71
81
  declare function degToRad(degrees: number): number;
@@ -78,18 +88,12 @@ declare function expandRect(rect: Rect, amount: number): Rect;
78
88
  declare function pointsBounds(points: readonly Point[], minSize?: number): Rect | null;
79
89
  declare function unionRects(rects: Rect[]): Rect | null;
80
90
  declare function rotatePointAround<P extends Point>(point: P, center: Point, angleRad: number): P;
81
- /** Axis-aligned bounding box of a (possibly rotated) frame. */
82
91
  declare function itemBounds(frame: BoardFrame): Rect;
83
92
  declare function selectionBounds(frames: BoardFrame[]): Rect | null;
84
- /** Exact point-in-frame test, accounting for rotation. */
85
93
  declare function frameContainsPoint(frame: BoardFrame, point: WorldPoint): boolean;
86
- /** World position of a resize handle on a single (possibly rotated) frame. */
87
94
  declare function frameHandlePosition(frame: BoardFrame, handle: ResizeHandle): WorldPoint;
88
- /** Corners in clockwise order, following the frame's rotation. */
89
95
  declare function frameCorners(frame: BoardFrame): readonly WorldPoint[];
90
- /** Screen-space radius (px) within which a pointer grabs a handle. */
91
96
  declare const HANDLE_HIT_RADIUS = 8;
92
- /** Screen-space offset (px) from the selection's lower-facing edge. */
93
97
  declare const ROTATION_HANDLE_OFFSET = 28;
94
98
  declare function frameRayIntersection(frame: Rect & {
95
99
  rotation?: number;
@@ -104,64 +108,31 @@ type ResizeHandle = "nw" | "n" | "ne" | "e" | "se" | "s" | "sw" | "w";
104
108
  declare const CORNER_RESIZE_HANDLES: readonly ["nw", "ne", "se", "sw"];
105
109
  declare const EDGE_RESIZE_HANDLES: readonly ["n", "e", "s", "w"];
106
110
  type CornerResizeHandle = (typeof CORNER_RESIZE_HANDLES)[number];
107
- /** Screen-space depth of the rotation zone outside each resize corner. */
108
111
  declare const CORNER_ROTATION_ZONE_WIDTH = 16;
109
112
  declare const RESIZE_HANDLES: ResizeHandle[];
110
- /**
111
- * Hit-test the outward quadrant around each corner, outside its resize target.
112
- * This gives fine pointers Figma-style corner rotation without adding chrome.
113
- */
114
113
  declare function frameCornerRotationHandleAt(frame: BoardFrame, point: WorldPoint, zoom: number, screenRadius?: number): CornerResizeHandle | null;
115
- /**
116
- * Hit-test the continuous edge zones of a rotated frame. Corners are inset so
117
- * their resize handles retain priority even on small nodes.
118
- */
119
114
  declare function frameEdgeHandleAt(frame: BoardFrame, point: WorldPoint, zoom: number, screenRadius?: number): Extract<ResizeHandle, "n" | "e" | "s" | "w"> | null;
120
- /** Direction of a handle from the rect center: -1, 0, or 1 per axis. */
121
115
  declare const HANDLE_DIRECTION: Record<ResizeHandle, Point>;
122
- /** Position of a handle on an unrotated rect. */
123
116
  declare function handlePosition(rect: Rect, handle: ResizeHandle): WorldPoint;
124
- /** Resize a frame to exact dimensions while keeping the opposite handle fixed. */
125
117
  declare function resizeFrameToSize(frame: BoardFrame, handle: ResizeHandle, width: number, height: number): BoardFrame;
126
- /**
127
- * Resize a frame by dragging a handle to a world-space pointer position.
128
- * The edge/corner opposite the handle stays anchored. Works correctly for
129
- * rotated frames by performing the resize in the frame's local space.
130
- */
131
- declare function resizeFrame(frame: BoardFrame, handle: ResizeHandle, pointer: WorldPoint, minSize?: number,
132
- /** Keep the original aspect ratio (Shift). */
133
- keepAspect?: boolean): BoardFrame;
134
- /**
135
- * Proportionally scale a group of frames by dragging a corner handle of their
136
- * combined bounds. Individual rotations are preserved.
137
- */
118
+ declare function resizeFrame(frame: BoardFrame, handle: ResizeHandle, pointer: WorldPoint, minSize?: number, keepAspect?: boolean): BoardFrame;
138
119
  declare function scaleFrames(frames: BoardFrame[], bounds: Rect, handle: ResizeHandle, pointer: WorldPoint, minSize?: number, scaleRange?: {
139
120
  min?: number;
140
121
  max?: number;
141
122
  }): BoardFrame[];
142
- /** Angle (degrees) from a center to a world-space pointer. */
143
123
  declare function angleFromCenter(center: WorldPoint, pointer: WorldPoint): number;
144
- /**
145
- * Rotate a set of frames around a pivot by a delta (degrees). Each frame's
146
- * center orbits the pivot and its own rotation increases by the delta.
147
- */
148
124
  declare function rotateFrames(frames: BoardFrame[], pivot: WorldPoint, deltaDeg: number): BoardFrame[];
149
- /** Normalize a rotation into the [-180, 180] range for tidy persistence. */
150
125
  declare function normalizeRotation(degrees: number): number;
151
- /** Convert a surface-relative screen point into world space. */
152
126
  declare function pointToWorld(point: ScreenPoint, viewport: BoardViewport): WorldPoint;
153
127
  declare function worldToScreen(point: WorldPoint, viewport: BoardViewport): ScreenPoint;
154
128
  declare function screenToWorld(clientX: number, clientY: number, rect: DOMRect, viewport: BoardViewport): WorldPoint;
155
- /** Zoom while keeping a surface-relative screen point fixed under the cursor. */
156
129
  declare function zoomAround(viewport: BoardViewport, anchor: ScreenPoint, nextZoom: number): BoardViewport;
157
130
  declare function panBy(viewport: BoardViewport, dx: number, dy: number): BoardViewport;
158
131
  declare function cameraForState(state: BoardCameraState, surface: Size): BoardViewport;
159
- declare function cameraForRect(content: Rect, surface: Size, options?: Pick<BoardCameraFocusParams, "fit" | "padding" | "minZoom" | "maxZoom">): BoardViewport;
132
+ declare function cameraForRect(content: Rect, surface: Size, options?: BoardCameraFit): BoardViewport;
160
133
  declare function rectForCameraFocus(focus: BoardCameraFocus, getFrame: (id: string) => BoardFrame | null | undefined): Rect | null;
161
- declare function cameraForFocus(params: BoardCameraFocusParams, getFrame: (id: string) => BoardFrame | null | undefined, surface: Size): BoardViewport | null;
162
- /** Compute a viewport that frames the given world rect within the surface. */
134
+ declare function cameraForFocus(focus: BoardCameraFocus, getFrame: (id: string) => BoardFrame | null | undefined, surface: Size, options?: BoardCameraFit): BoardViewport | null;
163
135
  declare function fitToContent(content: Rect, surface: Size, padding?: number): BoardViewport;
164
- /** World-space rectangle currently visible in the board stage. */
165
136
  declare function visibleWorldRect(viewport: BoardViewport, surfaceWidth: number, surfaceHeight: number): Rect;
166
137
  //#endregion
167
- export { BoardNormalizedPoint, BoardScreenOffset, BoardScreenPoint, BoardWorldOffset, BoardWorldPoint, BoardWorldRect, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CornerResizeHandle, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, ResizeHandle, ScreenPoint, Size, VIEWPORT_MARGIN_RATIO, WorldPoint, angleFromCenter, cameraForFocus, cameraForRect, cameraForState, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, normalizedPoint, panBy, pointToWorld, pointsBounds, radToDeg, rectCenter, rectContainsPoint, rectForCameraFocus, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenOffset, screenPoint, screenToWorld, selectionBounds, stableCullRect, unionRects, visibleWorldRect, worldOffset, worldPoint, worldRect, worldToScreen, zoomAround };
138
+ export { BoardCameraFit, BoardCameraFocus, BoardCameraState, BoardNormalizedPoint, BoardScreenOffset, BoardScreenPoint, BoardViewport, BoardWorldOffset, BoardWorldPoint, BoardWorldRect, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CornerResizeHandle, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, ResizeHandle, ScreenPoint, Size, VIEWPORT_MARGIN_RATIO, WorldPoint, angleFromCenter, cameraForFocus, cameraForRect, cameraForState, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, normalizedPoint, panBy, pointToWorld, pointsBounds, radToDeg, rectCenter, rectContainsPoint, rectForCameraFocus, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenOffset, screenPoint, screenToWorld, selectionBounds, stableCullRect, unionRects, visibleWorldRect, worldOffset, worldPoint, worldRect, worldToScreen, zoomAround };