@neta-art/cohub 5.3.3 → 5.4.1

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 (43) hide show
  1. package/dist/board/codec.d.ts +2 -0
  2. package/dist/board/codec.js +18 -13
  3. package/dist/board/core/arrow-geometry.d.ts +23 -0
  4. package/dist/board/core/arrow-geometry.js +109 -0
  5. package/dist/board/core/connections.d.ts +91 -0
  6. package/dist/board/core/connections.js +414 -0
  7. package/dist/board/core/export-plan.d.ts +15 -4
  8. package/dist/board/core/export-plan.js +49 -16
  9. package/dist/board/core/shape-definition.js +1 -1
  10. package/dist/board/core/shape-types.d.ts +8 -2
  11. package/dist/board/core/shape-types.js +1 -1
  12. package/dist/board/core/tool-styles.d.ts +9 -3
  13. package/dist/board/core/tool-styles.js +10 -6
  14. package/dist/board/export/index.js +1 -0
  15. package/dist/board/export/scene.d.ts +3 -0
  16. package/dist/board/export/scene.js +18 -1
  17. package/dist/board/index.d.ts +8 -5
  18. package/dist/board/index.js +8 -5
  19. package/dist/board/render/connection-layer.d.ts +48 -0
  20. package/dist/board/render/connection-layer.js +223 -0
  21. package/dist/board/render/index.d.ts +2 -1
  22. package/dist/board/render/index.js +3 -2
  23. package/dist/board/render/renderers/arrow-card-renderer.js +35 -48
  24. package/dist/chunks/http.d.ts +53 -1
  25. package/dist/chunks/http.js +287 -1
  26. package/dist/chunks/websocket.d.ts +296 -57
  27. package/dist/http.d.ts +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +17 -56
  30. package/dist/protocol/dist/board-connection.d.ts +310 -0
  31. package/dist/protocol/dist/board-connection.js +215 -0
  32. package/dist/protocol/dist/board-constants.d.ts +11 -1
  33. package/dist/protocol/dist/board-constants.js +15 -1
  34. package/dist/protocol/dist/board-document.d.ts +106 -60
  35. package/dist/protocol/dist/board-document.js +57 -17
  36. package/dist/protocol/dist/board.d.ts +1 -0
  37. package/dist/protocol/dist/board.js +3 -0
  38. package/dist/protocol/dist/index.d.ts +2 -1
  39. package/dist/protocol/dist/index.js +2 -1
  40. package/dist/protocol/dist/realtime/board-awareness.js +15 -15
  41. package/package.json +1 -1
  42. package/dist/board/core/bindings.d.ts +0 -45
  43. package/dist/board/core/bindings.js +0 -162
@@ -1,9 +1,7 @@
1
- import { BOARD_ARROW_STROKE_SIZE } from "../../protocol/dist/board-constants.js";
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";
2
2
  import { isBoardColorId } from "./palette.js";
3
3
  import { isGeoKind } from "./shape-types.js";
4
4
  //#region src/board/core/tool-styles.ts
5
- const BOARD_STROKE_MIN_SIZE = 1;
6
- const BOARD_STROKE_MAX_SIZE = 64;
7
5
  const DEFAULT_BOARD_TOOL_STYLES = {
8
6
  text: { color: "neutral" },
9
7
  geo: {
@@ -18,18 +16,20 @@ const DEFAULT_BOARD_TOOL_STYLES = {
18
16
  color: "brand",
19
17
  size: BOARD_ARROW_STROKE_SIZE
20
18
  },
19
+ connection: {
20
+ color: "neutral",
21
+ size: BOARD_CONNECTION_STROKE_SIZE
22
+ },
21
23
  frame: { color: "neutral" }
22
24
  };
23
25
  function finiteOr(value, fallback) {
24
26
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
25
27
  }
26
- function clampBoardStrokeSize(size) {
27
- return Math.min(64, Math.max(1, size));
28
- }
29
28
  /** Return a mutable, validated style map for an editor or another Board client. */
30
29
  function createBoardToolStyles(patch = {}) {
31
30
  const drawSize = clampBoardStrokeSize(finiteOr(patch.draw?.size, DEFAULT_BOARD_TOOL_STYLES.draw.size));
32
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));
33
33
  return {
34
34
  text: { color: isBoardColorId(patch.text?.color) ? patch.text.color : DEFAULT_BOARD_TOOL_STYLES.text.color },
35
35
  geo: {
@@ -44,6 +44,10 @@ function createBoardToolStyles(patch = {}) {
44
44
  color: isBoardColorId(patch.arrow?.color) ? patch.arrow.color : DEFAULT_BOARD_TOOL_STYLES.arrow.color,
45
45
  size: arrowSize
46
46
  },
47
+ connection: {
48
+ color: isBoardColorId(patch.connection?.color) ? patch.connection.color : DEFAULT_BOARD_TOOL_STYLES.connection.color,
49
+ size: connectionSize
50
+ },
47
51
  frame: { color: isBoardColorId(patch.frame?.color) ? patch.frame.color : DEFAULT_BOARD_TOOL_STYLES.frame.color }
48
52
  };
49
53
  }
@@ -34,6 +34,7 @@ function renderBoardExport(renderer, input, options = {}) {
34
34
  const scene = createBoardExportScene({
35
35
  document,
36
36
  items: plan.items,
37
+ connections: plan.connections,
37
38
  world: plan.world,
38
39
  scale: plan.scale,
39
40
  colorScheme,
@@ -1,3 +1,4 @@
1
+ import { BoardConnection } from "../../protocol/dist/board-connection.js";
1
2
  import { BoardDocument, BoardItem } from "../../protocol/dist/board-document.js";
2
3
  import { Rect } from "../geometry.js";
3
4
  import { BoardShapeColors } from "../core/palette.js";
@@ -9,6 +10,8 @@ type BoardExportSceneInput = {
9
10
  document: BoardDocument;
10
11
  /** Items to draw, in document (z) order. */
11
12
  items: BoardItem[];
13
+ /** Connections to draw. Rendered beneath the cards, as in the editor. */
14
+ connections?: readonly BoardConnection[];
12
15
  /** World rect being captured; content is translated so it starts at 0,0. */
13
16
  world: Rect;
14
17
  /** Output pixels per world unit. Drives text rasterisation resolution. */
@@ -1,5 +1,6 @@
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
4
  import { defaultBoardPalette } from "../render/palette.js";
4
5
  import { getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
5
6
  import { Container, Graphics } from "pixi.js";
@@ -54,6 +55,19 @@ function createBoardExportScene(input) {
54
55
  });
55
56
  world.scale.set(input.scale);
56
57
  world.position.set(-input.world.x * input.scale, -input.world.y * input.scale);
58
+ const connections = input.connections ?? input.document.connections;
59
+ let connectionLayer = null;
60
+ if (connections.length > 0) {
61
+ const frames = new Map(input.document.items.map((item) => [item.id, item.frame]));
62
+ connectionLayer = createConnectionLayer({ parent: world });
63
+ connectionLayer.sync({
64
+ connections,
65
+ getFrame: (id) => frames.get(id),
66
+ colors: context.colors,
67
+ colorScheme: input.colorScheme,
68
+ zoom: input.scale
69
+ });
70
+ }
57
71
  for (const item of input.items) {
58
72
  const renderer = getBoardCardRenderer(item, context);
59
73
  world.addChild(renderer.create(item, context));
@@ -62,7 +76,10 @@ function createBoardExportScene(input) {
62
76
  return {
63
77
  root,
64
78
  missingImageKeys: [...missing],
65
- destroy: () => root.destroy({ children: true })
79
+ destroy: () => {
80
+ connectionLayer?.destroy();
81
+ root.destroy({ children: true });
82
+ }
66
83
  };
67
84
  }
68
85
  //#endregion
@@ -1,17 +1,20 @@
1
+ import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../protocol/dist/board-constants.js";
2
+ import { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BoardConnection, BoardConnectionAnchor, BoardConnectionAnchorSchema, BoardConnectionDirection, BoardConnectionEndpoint, BoardConnectionEndpointSchema, BoardConnectionInput, BoardConnectionLine, BoardConnectionPatch, BoardConnectionPatchSchema, BoardConnectionRecord, BoardConnectionRouting, BoardConnectionRoutingConfig, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionSide, BoardConnectionStyle, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardRelationSchema, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_RELATION, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, flipBoardConnection, normalizeBoardConnectionStyle } from "../protocol/dist/board-connection.js";
1
3
  import { BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardManifest, BoardNodeRecord, BoardRecord, InvalidBoardFileError, isBoardPath, parseBoardManifest, serializeBoardManifest } from "../protocol/dist/board.js";
2
4
  import { BoardExtensionDefinition, BoardExtensionRegistry, BoardPresetDefinition, CompiledSequence, DEFAULT_BOARD_LIMITS, QualityProfile, RenderBounds, TimelineClipInput, TimelineInput, clip, compileSequence, createBoardExtensionRegistry, timeline } from "./animation.js";
3
- import { ArrowEndpoint, ArrowEndpointSchema, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardTextItem, BoardTextItemSchema, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, DrawPoint, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, SpaceFileRef, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardItemLoose, unknownRealType } from "../protocol/dist/board-document.js";
5
+ import { BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardPoint, BoardPointSchema, BoardTextItem, BoardTextItemSchema, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, DrawPoint, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, SpaceFileRef, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardDocument, parseBoardItemLoose, unknownRealType, withResolvedConnections } from "../protocol/dist/board-document.js";
4
6
  import { BOARD_NODE_SOURCE, DEFAULT_BOARD_APPEARANCE, ITEM_BASE_KEYS, WireBackedBoardItem, boardBootstrapToDocument, boardNodeToItem, isRecord, nodeInputFromRecord, sourceForItem } from "./codec.js";
5
7
  import { 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, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, panBy, pointToWorld, radToDeg, rectCenter, rectContainsPoint, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenPoint, screenToWorld, selectionBounds, unionRects, visibleWorldRect, worldPoint, worldToScreen, zoomAround } from "./geometry.js";
6
- import { FrameLookup, ResolvedArrow, anchorToWorld, arrowBounds, bindEndpointAt, distanceToArrow, resolveArrow, resolveEndpoint, sampleQuadratic, translateArrow, worldToAnchor } from "./core/bindings.js";
8
+ import { ResolvedArrow, arrowBounds, arrowFrame, distanceToArrow, resolveArrow, sampleArrow, translateArrow } from "./core/arrow-geometry.js";
9
+ import { CONNECTION_ENDPOINT_GAP, ConnectionIndex, FrameLookup, ResolvedConnection, ResolvedConnectionEndpoint, anchorPointOnFrame, anchorToWorld, autoConnectionSide, connectionArrowheads, connectionBounds, connectionHitTest, createConnectionIndex, distanceToConnection, pathMidpoint, resolveConnection, worldToAnchor } from "./core/connections.js";
7
10
  import { buildStrokeOutline, computeDrawBounds, distanceToStroke, sampleRadius, simplifyDrawIndices } from "./core/draw-geometry.js";
8
11
  import { BOARD_EXPORT_MAX_TEXTURES, BoardExportAssetSelection, selectBoardExportAssets } from "./core/export-assets.js";
9
- import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, boardFrameLookup, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
12
+ import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, boardFrameLookup, exportConnectionBounds, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
10
13
  import { BoardFileSnapshotFacts, BuildSnapshotInput, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FileAvailability, FilePreviewKind, ResolvedCover, availabilityFromError, buildFileExcerpt, buildFileSnapshot, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot, readCoverFromFrontmatter, readTitleFromFrontmatter, resolveCoverRef, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./core/file-preview.js";
11
14
  import { BOARD_COLORS, BoardColorEntry, BoardColorId, BoardColorValue, BoardShapeColors, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor } from "./core/palette.js";
12
15
  import { ArrowShapeProps, DrawShapeProps, FULL_CAPABILITIES, GEO_KINDS, GeoKind, GeoShapeProps, HandleDragResult, ImageShapeProps, ShapeCapabilities, ShapeGeometry, ShapeHandle, ShapeHandleId, ShapeResizeMode, TextShapeProps, VideoShapeProps, isGeoKind, resizeModeForCapabilities } from "./core/shape-types.js";
13
16
  import { ShapeDefinition, definitionForItem, getShapeDefinition, registerShapeDefinition, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, unknownShapeDefinition } from "./core/shape-definition.js";
14
17
  import { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardTextLineHeight, clampBoardTextFontSize, measureBoardText, setBoardTextMeasurer } from "./core/text-metrics.js";
15
- import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardStyledToolId, BoardToolStyleMap, BoardToolStylePatch, DEFAULT_BOARD_TOOL_STYLES, clampBoardStrokeSize, createBoardToolStyles } from "./core/tool-styles.js";
18
+ import { BoardStyledToolId, BoardToolStyleMap, BoardToolStylePatch, DEFAULT_BOARD_TOOL_STYLES, createBoardToolStyles } from "./core/tool-styles.js";
16
19
  import { boardImageKeySource, imageAssetKey } from "./image-key.js";
17
- export { ArrowEndpoint, ArrowEndpointSchema, type ArrowShapeProps, BOARD_COLORS, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardColorEntry, BoardColorId, BoardColorValue, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardExportAssetSelection, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, BoardExtensionDefinition, BoardExtensionRegistry, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotFacts, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, type BoardManifest, BoardMediaSnapshot, BoardMediaSnapshotSchema, type BoardNodeRecord, BoardPresetDefinition, type BoardRecord, BoardShapeColors, BoardStyledToolId, BoardTextItem, BoardTextItemSchema, BoardToolStyleMap, BoardToolStylePatch, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, BuildSnapshotInput, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CompiledSequence, CornerResizeHandle, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_TOOL_STYLES, DrawPoint, DrawPointSchema, type DrawShapeProps, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, FileAvailability, FilePreviewKind, FrameLookup, GEO_KINDS, type GeoKind, type GeoShapeProps, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, type HandleDragResult, ITEM_BASE_KEYS, type ImageShapeProps, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, QualityProfile, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, RenderBounds, ResizeHandle, ResolvedArrow, ResolvedCover, ScreenPoint, type ShapeCapabilities, ShapeDefinition, type ShapeGeometry, type ShapeHandle, type ShapeHandleId, type ShapeResizeMode, Size, SpaceFileRef, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, type TextShapeProps, TimelineClipInput, TimelineInput, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, type VideoShapeProps, WireBackedBoardItem, WorldPoint, anchorToWorld, angleFromCenter, arrowBounds, availabilityFromError, bindEndpointAt, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, createBoardExtensionRegistry, createBoardToolStyles, definitionForItem, degToRad, distanceToArrow, distanceToStroke, expandRect, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardItemLoose, parseBoardManifest, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveCoverRef, resolveEndpoint, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleQuadratic, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, worldPoint, worldToAnchor, worldToScreen, zoomAround };
20
+ export { AUTO_BOARD_CONNECTION_ANCHOR, type ArrowShapeProps, BOARD_COLORS, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardColorEntry, BoardColorId, BoardColorValue, BoardConnection, BoardConnectionAnchor, BoardConnectionAnchorSchema, BoardConnectionDirection, BoardConnectionEndpoint, BoardConnectionEndpointSchema, BoardConnectionInput, BoardConnectionLine, BoardConnectionPatch, BoardConnectionPatchSchema, BoardConnectionRecord, BoardConnectionRouting, BoardConnectionRoutingConfig, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionSide, BoardConnectionStyle, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardExportAssetSelection, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, BoardExtensionDefinition, BoardExtensionRegistry, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotFacts, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, type BoardManifest, BoardMediaSnapshot, BoardMediaSnapshotSchema, type BoardNodeRecord, BoardPoint, BoardPointSchema, BoardPresetDefinition, type BoardRecord, BoardRelationSchema, BoardShapeColors, BoardStyledToolId, BoardTextItem, BoardTextItemSchema, BoardToolStyleMap, BoardToolStylePatch, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, BuildSnapshotInput, CONNECTION_ENDPOINT_GAP, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CompiledSequence, ConnectionIndex, CornerResizeHandle, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_RELATION, DEFAULT_BOARD_TOOL_STYLES, DrawPoint, DrawPointSchema, type DrawShapeProps, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, FileAvailability, FilePreviewKind, FrameLookup, GEO_KINDS, type GeoKind, type GeoShapeProps, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, type HandleDragResult, ITEM_BASE_KEYS, type ImageShapeProps, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, QualityProfile, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, RenderBounds, ResizeHandle, ResolvedArrow, ResolvedConnection, ResolvedConnectionEndpoint, ResolvedCover, ScreenPoint, type ShapeCapabilities, ShapeDefinition, type ShapeGeometry, type ShapeHandle, type ShapeHandleId, type ShapeResizeMode, Size, SpaceFileRef, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, type TextShapeProps, TimelineClipInput, TimelineInput, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, type VideoShapeProps, WireBackedBoardItem, WorldPoint, anchorPointOnFrame, anchorToWorld, angleFromCenter, arrowBounds, arrowFrame, autoConnectionSide, availabilityFromError, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, connectionArrowheads, connectionBounds, connectionHitTest, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, createBoardExtensionRegistry, createBoardToolStyles, createConnectionIndex, definitionForItem, degToRad, distanceToArrow, distanceToConnection, distanceToStroke, expandRect, exportConnectionBounds, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, flipBoardConnection, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardConnectionStyle, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardDocument, parseBoardItemLoose, parseBoardManifest, pathMidpoint, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveConnection, resolveCoverRef, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleArrow, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, withResolvedConnections, worldPoint, worldToAnchor, worldToScreen, zoomAround };
@@ -1,17 +1,20 @@
1
+ import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../protocol/dist/board-constants.js";
1
2
  import { BoardExtensionRegistry, DEFAULT_BOARD_LIMITS, clip, compileSequence, createBoardExtensionRegistry, timeline } from "./animation.js";
3
+ import { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BoardConnectionAnchorSchema, BoardConnectionEndpointSchema, BoardConnectionPatchSchema, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardRelationSchema, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_RELATION, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, flipBoardConnection, normalizeBoardConnectionStyle } from "../protocol/dist/board-connection.js";
2
4
  import { BOARD_DOCUMENT_KIND, BOARD_EXTENSION, InvalidBoardFileError, isBoardPath, parseBoardManifest, serializeBoardManifest } from "../protocol/dist/board.js";
3
- import { ArrowEndpointSchema, BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardItemLoose, unknownRealType } from "../protocol/dist/board-document.js";
5
+ import { BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardPointSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardDocument, parseBoardItemLoose, unknownRealType, withResolvedConnections } from "../protocol/dist/board-document.js";
4
6
  import { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardTextLineHeight, clampBoardTextFontSize, measureBoardText, setBoardTextMeasurer } from "./core/text-metrics.js";
5
7
  import { BOARD_NODE_SOURCE, DEFAULT_BOARD_APPEARANCE, ITEM_BASE_KEYS, boardBootstrapToDocument, boardNodeToItem, isRecord, nodeInputFromRecord, sourceForItem } from "./codec.js";
6
8
  import { CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, VIEWPORT_MARGIN_RATIO, angleFromCenter, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, panBy, pointToWorld, radToDeg, rectCenter, rectContainsPoint, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenPoint, screenToWorld, selectionBounds, unionRects, visibleWorldRect, worldPoint, worldToScreen, zoomAround } from "./geometry.js";
7
9
  import { boardImageKeySource, imageAssetKey } from "./image-key.js";
8
- import { anchorToWorld, arrowBounds, bindEndpointAt, distanceToArrow, resolveArrow, resolveEndpoint, sampleQuadratic, translateArrow, worldToAnchor } from "./core/bindings.js";
10
+ import { arrowBounds, arrowFrame, distanceToArrow, resolveArrow, sampleArrow, translateArrow } from "./core/arrow-geometry.js";
11
+ import { CONNECTION_ENDPOINT_GAP, anchorPointOnFrame, anchorToWorld, autoConnectionSide, connectionArrowheads, connectionBounds, connectionHitTest, createConnectionIndex, distanceToConnection, pathMidpoint, resolveConnection, worldToAnchor } from "./core/connections.js";
9
12
  import { buildStrokeOutline, computeDrawBounds, distanceToStroke, sampleRadius, simplifyDrawIndices } from "./core/draw-geometry.js";
10
13
  import { BOARD_EXPORT_MAX_TEXTURES, selectBoardExportAssets } from "./core/export-assets.js";
11
- import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, boardFrameLookup, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
14
+ import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, boardFrameLookup, exportConnectionBounds, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
12
15
  import { FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, availabilityFromError, buildFileExcerpt, buildFileSnapshot, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot, readCoverFromFrontmatter, readTitleFromFrontmatter, resolveCoverRef, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./core/file-preview.js";
13
16
  import { BOARD_COLORS, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor } from "./core/palette.js";
14
17
  import { FULL_CAPABILITIES, GEO_KINDS, isGeoKind, resizeModeForCapabilities } from "./core/shape-types.js";
15
18
  import { definitionForItem, getShapeDefinition, registerShapeDefinition, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, unknownShapeDefinition } from "./core/shape-definition.js";
16
- import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, DEFAULT_BOARD_TOOL_STYLES, clampBoardStrokeSize, createBoardToolStyles } from "./core/tool-styles.js";
17
- export { ArrowEndpointSchema, BOARD_COLORS, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardExtensionRegistry, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_TOOL_STYLES, DrawPointSchema, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, GEO_KINDS, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, ITEM_BASE_KEYS, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, anchorToWorld, angleFromCenter, arrowBounds, availabilityFromError, bindEndpointAt, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, createBoardExtensionRegistry, createBoardToolStyles, definitionForItem, degToRad, distanceToArrow, distanceToStroke, expandRect, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardItemLoose, parseBoardManifest, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveCoverRef, resolveEndpoint, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleQuadratic, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, worldPoint, worldToAnchor, worldToScreen, zoomAround };
19
+ import { DEFAULT_BOARD_TOOL_STYLES, createBoardToolStyles } from "./core/tool-styles.js";
20
+ export { AUTO_BOARD_CONNECTION_ANCHOR, BOARD_COLORS, BOARD_CONNECTION_DIRECTIONS, BOARD_CONNECTION_LINES, BOARD_CONNECTION_ROUTINGS, BOARD_CONNECTION_SIDES, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearanceSchema, BoardArrowItemSchema, BoardConnectionAnchorSchema, BoardConnectionEndpointSchema, BoardConnectionPatchSchema, BoardConnectionRoutingSchema, BoardConnectionSchema, BoardConnectionStyleSchema, BoardConnectionWaypointSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardExtensionRegistry, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardPointSchema, BoardRelationSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, CONNECTION_ENDPOINT_GAP, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_CONNECTION_ROUTING, DEFAULT_BOARD_CONNECTION_STYLE, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_RELATION, DEFAULT_BOARD_TOOL_STYLES, DrawPointSchema, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, GEO_KINDS, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, ITEM_BASE_KEYS, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, anchorPointOnFrame, anchorToWorld, angleFromCenter, arrowBounds, arrowFrame, autoConnectionSide, availabilityFromError, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, connectionArrowheads, connectionBounds, connectionHitTest, connectionNodeIds, connectionOtherNodeId, connectionTouchesNode, createBoardConnection, createBoardExtensionRegistry, createBoardToolStyles, createConnectionIndex, definitionForItem, degToRad, distanceToArrow, distanceToConnection, distanceToStroke, expandRect, exportConnectionBounds, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, flipBoardConnection, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardConnectionStyle, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardDocument, parseBoardItemLoose, parseBoardManifest, pathMidpoint, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveConnection, resolveCoverRef, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleArrow, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, withResolvedConnections, worldPoint, worldToAnchor, worldToScreen, zoomAround };
@@ -0,0 +1,48 @@
1
+ import { BoardConnection } from "../../protocol/dist/board-connection.js";
2
+ import { BoardFrame } from "../../protocol/dist/board-document.js";
3
+ import { FrameLookup, ResolvedConnection } from "../core/connections.js";
4
+ import { BoardShapeColors } from "../core/palette.js";
5
+ import { Container } from "pixi.js";
6
+ //#region src/board/render/connection-layer.d.ts
7
+ type ConnectionRenderInput = {
8
+ connections: readonly BoardConnection[];
9
+ getFrame: FrameLookup;
10
+ colors: BoardShapeColors;
11
+ colorScheme: "dark" | "light";
12
+ zoom: number;
13
+ /** Connections drawn in their selected state. */
14
+ selectedIds?: ReadonlySet<string>;
15
+ /** Connection under the pointer, if any. */
16
+ hoveredId?: string | null;
17
+ /**
18
+ * Ids to skip because the host is drawing them itself this frame (e.g. a live
19
+ * drag preview on the interaction overlay). Skipping avoids the doubled stroke
20
+ * of a preview drawn over its own committed geometry.
21
+ */
22
+ skipIds?: ReadonlySet<string>;
23
+ };
24
+ type ConnectionLayer = {
25
+ /** Redraw every connection. Cheap: one Graphics, batched. */
26
+ sync: (input: ConnectionRenderInput) => void;
27
+ /** Resolved geometry from the last sync, for hit testing and overlays. */
28
+ resolved: (connectionId: string) => ResolvedConnection | null;
29
+ /**
30
+ * The display objects this layer owns, so a host can place them in its own
31
+ * z-ordering scheme without the layer needing to know about it.
32
+ */
33
+ readonly children: readonly Container[];
34
+ destroy: () => void;
35
+ };
36
+ declare function createConnectionLayer(options: {
37
+ /** World-space container the layer attaches to. */
38
+ parent: Container;
39
+ /** zIndex applied to the layer's display objects once they exist. */
40
+ zIndex?: number;
41
+ }): ConnectionLayer;
42
+ /** Frame lookup over a plain item list, for hosts without an index. */
43
+ declare function framesFromItems(items: readonly {
44
+ id: string;
45
+ frame: BoardFrame;
46
+ }[]): FrameLookup;
47
+ //#endregion
48
+ export { ConnectionLayer, ConnectionRenderInput, createConnectionLayer, framesFromItems };
@@ -0,0 +1,223 @@
1
+ import { BOARD_FONT_STACK } from "../../protocol/dist/board-constants.js";
2
+ import { connectionArrowheads, resolveConnection } from "../core/connections.js";
3
+ import { pickBoardColor } from "../core/palette.js";
4
+ import { syncTextResolution, textResolutionForZoom } from "./text-resolution.js";
5
+ import { Container, Graphics, Text } from "pixi.js";
6
+ //#region src/board/render/connection-layer.ts
7
+ /**
8
+ * Connection drawing.
9
+ *
10
+ * Connections render into one shared layer beneath the cards rather than as a
11
+ * container per relation. A connection is a thin stroke with no texture and no
12
+ * interactive chrome of its own, so a per-connection container would add a
13
+ * transform, a render group and a draw call each for geometry that batches
14
+ * perfectly — on a densely connected board that is the difference between a few
15
+ * draw calls and a few thousand.
16
+ *
17
+ * Labels are the exception: text needs its own object to rasterise, so a `Text`
18
+ * is materialised only for connections that actually carry one and is pooled by
19
+ * connection id.
20
+ */
21
+ /** Arrowhead length relative to stroke width, and its floor in world units. */
22
+ const HEAD_SCALE = 5.5;
23
+ const HEAD_MIN = 11;
24
+ const HEAD_SPREAD = Math.PI / 6;
25
+ /** Dash pattern for `dashed` connections, in world units. */
26
+ const DASH_LENGTH = 10;
27
+ const DASH_GAP = 7;
28
+ /** Draw an open chevron arrowhead aimed along `angle`. */
29
+ function drawArrowhead(graphics, tip, angle, size, color, width, alpha) {
30
+ graphics.moveTo(tip.x - size * Math.cos(angle - HEAD_SPREAD), tip.y - size * Math.sin(angle - HEAD_SPREAD)).lineTo(tip.x, tip.y).lineTo(tip.x - size * Math.cos(angle + HEAD_SPREAD), tip.y - size * Math.sin(angle + HEAD_SPREAD)).stroke({
31
+ color,
32
+ width,
33
+ alpha,
34
+ cap: "round",
35
+ join: "round"
36
+ });
37
+ }
38
+ /** Trace a polyline as a dashed path, walking segment by segment. */
39
+ function traceDashed(graphics, path) {
40
+ let penDown = true;
41
+ let remaining = DASH_LENGTH;
42
+ let current = path[0];
43
+ if (!current) return;
44
+ graphics.moveTo(current.x, current.y);
45
+ for (let index = 1; index < path.length; index += 1) {
46
+ const next = path[index];
47
+ if (!next) continue;
48
+ let segmentRemaining = Math.hypot(next.x - current.x, next.y - current.y);
49
+ let from = current;
50
+ while (segmentRemaining > 1e-4) {
51
+ const step = Math.min(segmentRemaining, remaining);
52
+ const ratio = step / segmentRemaining;
53
+ const to = {
54
+ x: from.x + (next.x - from.x) * ratio,
55
+ y: from.y + (next.y - from.y) * ratio
56
+ };
57
+ if (penDown) graphics.lineTo(to.x, to.y);
58
+ else graphics.moveTo(to.x, to.y);
59
+ remaining -= step;
60
+ segmentRemaining -= step;
61
+ from = to;
62
+ if (remaining <= 1e-4) {
63
+ penDown = !penDown;
64
+ remaining = penDown ? DASH_LENGTH : DASH_GAP;
65
+ }
66
+ }
67
+ current = next;
68
+ }
69
+ }
70
+ function createConnectionLayer(options) {
71
+ let graphics = null;
72
+ let labelLayer = null;
73
+ const labels = /* @__PURE__ */ new Map();
74
+ let resolvedById = /* @__PURE__ */ new Map();
75
+ function ensureAttached() {
76
+ if (graphics && labelLayer) return {
77
+ graphics,
78
+ labelLayer
79
+ };
80
+ const nextGraphics = new Graphics({ label: "board-connections" });
81
+ const nextLabels = new Container({ label: "board-connection-labels" });
82
+ if (options.zIndex !== void 0) {
83
+ nextGraphics.zIndex = options.zIndex;
84
+ nextLabels.zIndex = options.zIndex;
85
+ }
86
+ options.parent.addChild(nextGraphics, nextLabels);
87
+ graphics = nextGraphics;
88
+ labelLayer = nextLabels;
89
+ return {
90
+ graphics: nextGraphics,
91
+ labelLayer: nextLabels
92
+ };
93
+ }
94
+ function releaseLabel(connectionId) {
95
+ const entry = labels.get(connectionId);
96
+ if (!entry) return;
97
+ labelLayer?.removeChild(entry.text);
98
+ entry.text.destroy();
99
+ labels.delete(connectionId);
100
+ }
101
+ function syncLabel(connection, resolved, input, color, host) {
102
+ const value = connection.label.trim();
103
+ if (!value) {
104
+ releaseLabel(connection.id);
105
+ return;
106
+ }
107
+ let entry = labels.get(connection.id);
108
+ if (!entry) {
109
+ const resolution = textResolutionForZoom(input.zoom);
110
+ const text = new Text({
111
+ text: value,
112
+ style: {
113
+ fill: color,
114
+ fontFamily: BOARD_FONT_STACK,
115
+ fontSize: 12,
116
+ fontWeight: "500"
117
+ },
118
+ resolution,
119
+ roundPixels: true
120
+ });
121
+ text.anchor.set(.5);
122
+ host.addChild(text);
123
+ entry = {
124
+ text,
125
+ resolution,
126
+ sig: ""
127
+ };
128
+ labels.set(connection.id, entry);
129
+ }
130
+ syncTextResolution(entry.text, entry, input.zoom);
131
+ const sig = `${value}|${color}`;
132
+ if (sig !== entry.sig) {
133
+ entry.sig = sig;
134
+ entry.text.text = value;
135
+ entry.text.style.fill = color;
136
+ }
137
+ entry.text.position.set(resolved.mid.x, resolved.mid.y);
138
+ }
139
+ function sync(input) {
140
+ if (input.connections.length === 0 && !graphics) {
141
+ resolvedById = /* @__PURE__ */ new Map();
142
+ return;
143
+ }
144
+ const host = ensureAttached();
145
+ host.graphics.clear();
146
+ const next = /* @__PURE__ */ new Map();
147
+ const selected = input.selectedIds ?? /* @__PURE__ */ new Set();
148
+ const skip = input.skipIds;
149
+ const minWidth = 1 / Math.max(input.zoom, 1e-4);
150
+ for (const connection of input.connections) {
151
+ const resolved = resolveConnection(connection, input.getFrame);
152
+ if (!resolved) continue;
153
+ next.set(connection.id, resolved);
154
+ if (skip?.has(connection.id)) {
155
+ releaseLabel(connection.id);
156
+ continue;
157
+ }
158
+ const isSelected = selected.has(connection.id);
159
+ const isHovered = input.hoveredId === connection.id;
160
+ const color = pickBoardColor(input.colors, connection.style.color, input.colorScheme);
161
+ const width = Math.max(connection.style.size + (isSelected ? 1 : 0), minWidth);
162
+ const alpha = isSelected || isHovered ? 1 : .9;
163
+ if (connection.style.line === "dashed") traceDashed(host.graphics, resolved.path);
164
+ else {
165
+ const first = resolved.path[0];
166
+ if (!first) continue;
167
+ host.graphics.moveTo(first.x, first.y);
168
+ for (let index = 1; index < resolved.path.length; index += 1) {
169
+ const point = resolved.path[index];
170
+ if (point) host.graphics.lineTo(point.x, point.y);
171
+ }
172
+ }
173
+ host.graphics.stroke({
174
+ color: color.stroke,
175
+ width,
176
+ alpha,
177
+ cap: "round",
178
+ join: "round"
179
+ });
180
+ const heads = connectionArrowheads(connection);
181
+ const headSize = Math.max(HEAD_MIN, connection.style.size * HEAD_SCALE);
182
+ if (heads.atTarget) {
183
+ const tip = resolved.path[resolved.path.length - 1];
184
+ const previous = resolved.path[resolved.path.length - 2];
185
+ if (tip && previous) drawArrowhead(host.graphics, tip, Math.atan2(tip.y - previous.y, tip.x - previous.x), headSize, color.stroke, width, alpha);
186
+ }
187
+ if (heads.atSource) {
188
+ const tip = resolved.path[0];
189
+ const next2 = resolved.path[1];
190
+ if (tip && next2) drawArrowhead(host.graphics, tip, Math.atan2(tip.y - next2.y, tip.x - next2.x), headSize, color.stroke, width, alpha);
191
+ }
192
+ syncLabel(connection, resolved, input, color.label, host.labelLayer);
193
+ }
194
+ for (const connectionId of [...labels.keys()]) if (!next.has(connectionId)) releaseLabel(connectionId);
195
+ resolvedById = next;
196
+ }
197
+ return {
198
+ sync,
199
+ resolved: (connectionId) => resolvedById.get(connectionId) ?? null,
200
+ get children() {
201
+ const list = [];
202
+ if (graphics) list.push(graphics);
203
+ if (labelLayer) list.push(labelLayer);
204
+ return list;
205
+ },
206
+ destroy: () => {
207
+ for (const entry of labels.values()) entry.text.destroy();
208
+ labels.clear();
209
+ graphics?.destroy();
210
+ labelLayer?.destroy({ children: true });
211
+ graphics = null;
212
+ labelLayer = null;
213
+ resolvedById = /* @__PURE__ */ new Map();
214
+ }
215
+ };
216
+ }
217
+ /** Frame lookup over a plain item list, for hosts without an index. */
218
+ function framesFromItems(items) {
219
+ const frames = new Map(items.map((item) => [item.id, item.frame]));
220
+ return (id) => frames.get(id);
221
+ }
222
+ //#endregion
223
+ export { createConnectionLayer, framesFromItems };
@@ -1,6 +1,7 @@
1
+ import { ConnectionLayer, ConnectionRenderInput, createConnectionLayer, framesFromItems } from "./connection-layer.js";
1
2
  import { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
2
3
  import { defaultBoardPalette } from "./palette.js";
3
4
  import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
4
5
  import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
5
6
  import { BoardThemeContext, BoardThemeRenderer, getBoardThemeRenderer, registerBoardThemeRenderer } from "./themes/board-theme-registry.js";
6
- export { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, BoardThemeContext, BoardThemeRenderer, boardCardRenderersForTest, defaultBoardPalette, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
7
+ export { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, BoardThemeContext, BoardThemeRenderer, ConnectionLayer, ConnectionRenderInput, boardCardRenderersForTest, createConnectionLayer, defaultBoardPalette, ensureBoardTextMeasurement, framesFromItems, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
@@ -1,6 +1,7 @@
1
+ import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
2
+ import { createConnectionLayer, framesFromItems } from "./connection-layer.js";
1
3
  import { defaultBoardPalette } from "./palette.js";
2
4
  import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
3
- import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
4
5
  import { boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
5
6
  import { getBoardThemeRenderer, registerBoardThemeRenderer } from "./themes/board-theme-registry.js";
6
- export { boardCardRenderersForTest, defaultBoardPalette, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
7
+ export { boardCardRenderersForTest, createConnectionLayer, defaultBoardPalette, ensureBoardTextMeasurement, framesFromItems, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
@@ -1,21 +1,11 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { resolveArrow, sampleQuadratic } from "../../core/bindings.js";
2
+ import { resolveArrow, sampleArrow } from "../../core/arrow-geometry.js";
3
3
  import { pickBoardColor } from "../../core/palette.js";
4
4
  import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
5
5
  import { drawFarStroke } from "./far-plate.js";
6
6
  import { Container, Graphics, Text } from "pixi.js";
7
7
  //#region src/board/render/renderers/arrow-card-renderer.ts
8
8
  const partsByContainer = /* @__PURE__ */ new WeakMap();
9
- /**
10
- * Frame lookup for resolving bindings.
11
- *
12
- * Routed through the context's id index rather than scanning the document: an
13
- * arrow re-resolves its endpoints on every sync, and a per-arrow O(items) scan
14
- * would make a board with many arrows quadratic per frame.
15
- */
16
- function frameLookup(context) {
17
- return (id) => context.getItem(id)?.frame;
18
- }
19
9
  /** Open chevron arrowhead — clearly directional, not a tiny filled nub. */
20
10
  function drawArrowhead(graphics, tip, angle, size, color, strokeWidth) {
21
11
  const spread = Math.PI / 6;
@@ -44,8 +34,8 @@ function sync(container, item, context) {
44
34
  const hovered = context.hoveredId === item.id;
45
35
  const color = pickBoardColor(context.colors, item.color, context.colorScheme);
46
36
  syncTextResolution(parts.label, parts, context.zoom);
47
- const resolved = resolveArrow(item, frameLookup(context));
48
- const lineSig = resolved ? [
37
+ const resolved = resolveArrow(item);
38
+ const lineSig = [
49
39
  resolved.start.x,
50
40
  resolved.start.y,
51
41
  resolved.end.x,
@@ -58,39 +48,37 @@ function sync(container, item, context) {
58
48
  item.size,
59
49
  item.arrowStart,
60
50
  item.arrowEnd
61
- ].join("|") : `empty|${item.id}`;
51
+ ].join("|");
62
52
  if (lineSig !== parts.lineSig) {
63
53
  parts.lineSig = lineSig;
64
54
  parts.line.clear();
65
- if (resolved) {
66
- const strokeColor = color.stroke;
67
- const width = selected ? item.size + 1 : item.size;
68
- const samples = sampleQuadratic(resolved, 24);
69
- const head = samples[0];
70
- const tail = samples[samples.length - 1];
71
- if (head && tail) {
72
- parts.line.moveTo(head.x, head.y);
73
- for (let i = 1; i < samples.length; i += 1) {
74
- const point = samples[i];
75
- if (point) parts.line.lineTo(point.x, point.y);
76
- }
77
- parts.line.stroke({
78
- color: strokeColor,
79
- width,
80
- alpha: selected || hovered ? 1 : .92,
81
- cap: "round",
82
- join: "round"
83
- });
84
- const span = Math.hypot(tail.x - head.x, tail.y - head.y);
85
- const headSize = Math.min(Math.max(14, item.size * 5.5), Math.max(10, span * .28));
86
- if (item.arrowEnd) {
87
- const prev = samples[samples.length - 2];
88
- if (prev) drawArrowhead(parts.line, tail, Math.atan2(tail.y - prev.y, tail.x - prev.x), headSize, strokeColor, width);
89
- }
90
- if (item.arrowStart) {
91
- const next = samples[1];
92
- if (next) drawArrowhead(parts.line, head, Math.atan2(head.y - next.y, head.x - next.x), headSize, strokeColor, width);
93
- }
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
+ }
66
+ parts.line.stroke({
67
+ color: strokeColor,
68
+ width,
69
+ alpha: selected || hovered ? 1 : .92,
70
+ cap: "round",
71
+ join: "round"
72
+ });
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);
94
82
  }
95
83
  }
96
84
  }
@@ -100,8 +88,8 @@ function sync(container, item, context) {
100
88
  parts.label.text = item.label;
101
89
  parts.label.style.fill = color.label;
102
90
  }
103
- parts.label.visible = Boolean(resolved && item.label.length > 0);
104
- if (resolved) parts.label.position.copyFrom(resolved.control);
91
+ parts.label.visible = item.label.length > 0;
92
+ parts.label.position.copyFrom(resolved.control);
105
93
  }
106
94
  const arrowCardRenderer = {
107
95
  id: "arrow-card",
@@ -139,10 +127,9 @@ const arrowCardRenderer = {
139
127
  },
140
128
  renderFar: (graphics, item, context) => {
141
129
  if (item.type !== "arrow") return;
142
- const resolved = resolveArrow(item, frameLookup(context));
143
- if (!resolved) return;
130
+ const resolved = resolveArrow(item);
144
131
  const color = pickBoardColor(context.colors, item.color, context.colorScheme);
145
- drawFarStroke(graphics, sampleQuadratic(resolved, 12), {
132
+ drawFarStroke(graphics, sampleArrow(resolved, 12), {
146
133
  color: color.stroke,
147
134
  width: item.size,
148
135
  alpha: .85