@neta-art/cohub 8.24.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/board/animation.d.ts +57 -181
  2. package/dist/board/animation.js +374 -220
  3. package/dist/board/core/arrow-geometry.d.ts +33 -18
  4. package/dist/board/core/arrow-geometry.js +283 -52
  5. package/dist/board/core/draw-geometry.d.ts +22 -36
  6. package/dist/board/core/draw-geometry.js +148 -85
  7. package/dist/board/core/export-assets.d.ts +3 -6
  8. package/dist/board/core/export-assets.js +0 -2
  9. package/dist/board/core/export-plan.d.ts +12 -63
  10. package/dist/board/core/export-plan.js +55 -94
  11. package/dist/board/core/palette.d.ts +4 -21
  12. package/dist/board/core/palette.js +8 -13
  13. package/dist/board/core/scene.d.ts +33 -0
  14. package/dist/board/core/scene.js +302 -0
  15. package/dist/board/core/shape-definition.d.ts +12 -24
  16. package/dist/board/core/shape-definition.js +0 -19
  17. package/dist/board/core/shape-types.d.ts +6 -120
  18. package/dist/board/core/shape-types.js +5 -5
  19. package/dist/board/core/text-metrics.d.ts +8 -11
  20. package/dist/board/core/text-metrics.js +5 -34
  21. package/dist/board/core/tool-styles.d.ts +6 -16
  22. package/dist/board/core/tool-styles.js +17 -25
  23. package/dist/board/export/index.d.ts +10 -17
  24. package/dist/board/export/index.js +22 -21
  25. package/dist/board/export/scene.d.ts +10 -16
  26. package/dist/board/export/scene.js +17 -30
  27. package/dist/board/geometry.d.ts +27 -56
  28. package/dist/board/geometry.js +7 -67
  29. package/dist/board/headless/index.d.ts +6 -27
  30. package/dist/board/headless/index.js +4 -19
  31. package/dist/board/headless/sketch.d.ts +19 -0
  32. package/dist/board/headless/sketch.js +146 -0
  33. package/dist/board/image-key.d.ts +2 -12
  34. package/dist/board/image-key.js +3 -13
  35. package/dist/board/index.d.ts +18 -20
  36. package/dist/board/index.js +17 -17
  37. package/dist/board/media-playback.d.ts +3 -6
  38. package/dist/board/media-playback.js +6 -6
  39. package/dist/board/presets.d.ts +150 -0
  40. package/dist/board/presets.js +226 -0
  41. package/dist/board/render/board-background.d.ts +5 -3
  42. package/dist/board/render/board-background.js +8 -7
  43. package/dist/board/render/clip.d.ts +14 -0
  44. package/dist/board/render/clip.js +47 -0
  45. package/dist/board/render/index.d.ts +8 -5
  46. package/dist/board/render/index.js +7 -4
  47. package/dist/board/render/media-interaction.d.ts +4 -5
  48. package/dist/board/render/media-interaction.js +1 -2
  49. package/dist/board/render/palette.d.ts +6 -2
  50. package/dist/board/render/palette.js +7 -1
  51. package/dist/board/render/renderers/arrow-card-renderer.js +69 -71
  52. package/dist/board/render/renderers/audio-card-renderer.js +3 -3
  53. package/dist/board/render/renderers/base-card-renderer.d.ts +6 -17
  54. package/dist/board/render/renderers/base-card-renderer.js +1 -24
  55. package/dist/board/render/renderers/board-renderer-registry.d.ts +20 -50
  56. package/dist/board/render/renderers/board-renderer-registry.js +6 -7
  57. package/dist/board/render/renderers/draw-card-renderer.js +89 -56
  58. package/dist/board/render/renderers/effect-card-renderer.d.ts +6 -0
  59. package/dist/board/render/renderers/effect-card-renderer.js +197 -0
  60. package/dist/board/render/renderers/far-plate.d.ts +4 -21
  61. package/dist/board/render/renderers/far-plate.js +15 -34
  62. package/dist/board/render/renderers/file-card-renderer.d.ts +4 -25
  63. package/dist/board/render/renderers/file-card-renderer.js +8 -58
  64. package/dist/board/render/renderers/frame-card-renderer.js +28 -28
  65. package/dist/board/render/renderers/image-card-renderer.d.ts +4 -3
  66. package/dist/board/render/renderers/image-card-renderer.js +0 -9
  67. package/dist/board/render/renderers/shape-card-renderer.d.ts +9 -0
  68. package/dist/board/render/renderers/shape-card-renderer.js +240 -0
  69. package/dist/board/render/renderers/sketch-card-renderer.d.ts +5 -0
  70. package/dist/board/render/renderers/sketch-card-renderer.js +98 -0
  71. package/dist/board/render/renderers/task-card-renderer.d.ts +0 -1
  72. package/dist/board/render/renderers/task-card-renderer.js +14 -16
  73. package/dist/board/render/renderers/text-card-renderer.d.ts +1 -3
  74. package/dist/board/render/renderers/text-card-renderer.js +56 -46
  75. package/dist/board/render/renderers/unknown-card-renderer.js +4 -10
  76. package/dist/board/render/renderers/video-card-renderer.d.ts +4 -2
  77. package/dist/board/render/renderers/video-card-renderer.js +2 -1
  78. package/dist/board/render/sketch-host.d.ts +14 -0
  79. package/dist/board/render/sketch-host.js +216 -0
  80. package/dist/board/render/stroke.d.ts +12 -0
  81. package/dist/board/render/stroke.js +90 -0
  82. package/dist/board/render/text-measurement.d.ts +6 -26
  83. package/dist/board/render/text-measurement.js +11 -30
  84. package/dist/board/replay.d.ts +6 -31
  85. package/dist/board/replay.js +45 -203
  86. package/dist/board/runtime/board-player.d.ts +24 -0
  87. package/dist/board/runtime/board-player.js +161 -0
  88. package/dist/board/task.d.ts +2 -10
  89. package/dist/board/task.js +1 -10
  90. package/dist/chunks/environment.d.ts +2291 -3864
  91. package/dist/chunks/host-bridge.d.ts +253 -0
  92. package/dist/chunks/http.d.ts +233 -58
  93. package/dist/chunks/http.js +1046 -1028
  94. package/dist/chunks/transport.js +113 -59
  95. package/dist/chunks/websocket.d.ts +1 -1
  96. package/dist/chunks/websocket.js +1 -1
  97. package/dist/host-bridge.d.ts +54 -0
  98. package/dist/host-bridge.js +322 -0
  99. package/dist/http.d.ts +3 -3
  100. package/dist/index.d.ts +74 -191
  101. package/dist/index.js +2032 -1186
  102. package/dist/protocol/dist/board-constants.d.ts +1 -29
  103. package/dist/protocol/dist/board-constants.js +2 -115
  104. package/dist/protocol/dist/board-layout.d.ts +59 -0
  105. package/dist/protocol/dist/board-layout.js +482 -0
  106. package/dist/protocol/dist/board-model.d.ts +2052 -0
  107. package/dist/protocol/dist/board-model.js +592 -0
  108. package/dist/protocol/dist/board-patch.d.ts +86 -0
  109. package/dist/protocol/dist/board-patch.js +734 -0
  110. package/dist/protocol/dist/board-schema.d.ts +33 -0
  111. package/dist/protocol/dist/board-schema.js +59 -0
  112. package/dist/protocol/dist/board-upgrade.d.ts +1 -0
  113. package/dist/protocol/dist/board-url.d.ts +1 -3
  114. package/dist/protocol/dist/board-url.js +2 -2
  115. package/dist/protocol/dist/board.d.ts +37 -232
  116. package/dist/protocol/dist/board.js +62 -160
  117. package/dist/protocol/dist/display/actions.d.ts +1 -0
  118. package/dist/protocol/dist/display/index.d.ts +2 -0
  119. package/dist/protocol/dist/index.d.ts +11 -12
  120. package/dist/protocol/dist/model/metrics.d.ts +2 -0
  121. package/dist/protocol/dist/model/session.d.ts +2 -1
  122. package/dist/protocol/dist/realtime/types.d.ts +2 -2
  123. package/dist/protocol/dist/runtime/index.d.ts +1 -0
  124. package/dist/space-picker.d.ts +1 -0
  125. package/dist/space-picker.js +1 -0
  126. package/dist/types.d.ts +2 -5
  127. package/package.json +9 -1
  128. package/dist/board/core/connections.d.ts +0 -108
  129. package/dist/board/core/connections.js +0 -455
  130. package/dist/board/mutation.d.ts +0 -6
  131. package/dist/board/mutation.js +0 -14
  132. package/dist/board/render/connection-layer.d.ts +0 -53
  133. package/dist/board/render/connection-layer.js +0 -375
  134. package/dist/board/render/renderers/geo-card-renderer.d.ts +0 -5
  135. package/dist/board/render/renderers/geo-card-renderer.js +0 -127
  136. package/dist/board/semantic-document.d.ts +0 -37
  137. package/dist/board/semantic-document.js +0 -288
  138. package/dist/board/semantic-mutation.d.ts +0 -10
  139. package/dist/board/semantic-mutation.js +0 -209
  140. package/dist/protocol/dist/board-animation.js +0 -34
  141. package/dist/protocol/dist/board-authoring.d.ts +0 -1326
  142. package/dist/protocol/dist/board-authoring.js +0 -302
  143. package/dist/protocol/dist/board-capability-registry.d.ts +0 -2
  144. package/dist/protocol/dist/board-capability-registry.js +0 -123
  145. package/dist/protocol/dist/board-codec.d.ts +0 -3
  146. package/dist/protocol/dist/board-codec.js +0 -383
  147. package/dist/protocol/dist/board-composition.d.ts +0 -383
  148. package/dist/protocol/dist/board-composition.js +0 -310
  149. package/dist/protocol/dist/board-connection.d.ts +0 -317
  150. package/dist/protocol/dist/board-connection.js +0 -219
  151. package/dist/protocol/dist/board-document.d.ts +0 -1566
  152. package/dist/protocol/dist/board-document.js +0 -456
  153. package/dist/protocol/dist/board-effect.d.ts +0 -96
  154. package/dist/protocol/dist/board-effect.js +0 -54
  155. package/dist/protocol/dist/board-geometry.d.ts +0 -15
  156. package/dist/protocol/dist/board-geometry.js +0 -137
  157. package/dist/protocol/dist/board-node.d.ts +0 -8
  158. package/dist/protocol/dist/board-node.js +0 -252
  159. /package/dist/protocol/dist/{board-animation.d.ts → host-bridge.d.ts} +0 -0
@@ -1,455 +0,0 @@
1
- import { degToRad, frameRect, rectCenter, rotatePointAround, worldPoint } from "../geometry.js";
2
- //#region src/board/core/connections.ts
3
- /**
4
- * Connection geometry — pure resolution of a relation into a drawable path.
5
- *
6
- * A `BoardConnection` stores no coordinates: it names two nodes, how it attaches
7
- * to each, and how the line should travel. Everything spatial is derived here from
8
- * the live node frames, which is what makes a connection incapable of going stale.
9
- * No PixiJS, no DOM, no editor state — so the editor, the far-LOD batch, the
10
- * headless exporter and the tests all resolve a connection the same way.
11
- *
12
- * The `auto` anchor is the interesting part: rather than storing a side, it picks
13
- * one per resolve from the relative position of the two frames, so a connection
14
- * keeps its shortest sensible route through any layout change. A stored side is
15
- * honoured exactly, because a user who pinned one is stating intent that geometry
16
- * must not override.
17
- */
18
- /**
19
- * Gap between a node's edge and the line's endpoint, in world units.
20
- *
21
- * A connection that touches the border reads as part of the node; a small gap
22
- * makes the relation legible as its own object and keeps an arrowhead from being
23
- * swallowed by the card it points at.
24
- */
25
- const CONNECTION_ENDPOINT_GAP = 4;
26
- /** Perpendicular fraction of the span used for an `orthogonal` elbow. */
27
- const ORTHOGONAL_SNAP = .5;
28
- const SIDE_NORMALS = {
29
- top: {
30
- x: 0,
31
- y: -1
32
- },
33
- right: {
34
- x: 1,
35
- y: 0
36
- },
37
- bottom: {
38
- x: 0,
39
- y: 1
40
- },
41
- left: {
42
- x: -1,
43
- y: 0
44
- }
45
- };
46
- /** Normalized position of a point on a frame side, as (nx, ny). */
47
- function sideAnchorPoint(side, offset) {
48
- switch (side) {
49
- case "top": return {
50
- nx: offset,
51
- ny: 0
52
- };
53
- case "bottom": return {
54
- nx: offset,
55
- ny: 1
56
- };
57
- case "left": return {
58
- nx: 0,
59
- ny: offset
60
- };
61
- default: return {
62
- nx: 1,
63
- ny: offset
64
- };
65
- }
66
- }
67
- /** Denormalize a (nx, ny) anchor to a world point on a possibly rotated frame. */
68
- function anchorToWorld(frame, nx, ny) {
69
- const unrotated = worldPoint(frame.x + nx * frame.width, frame.y + ny * frame.height);
70
- if (!frame.rotation) return unrotated;
71
- return rotatePointAround(unrotated, rectCenter(frameRect(frame)), degToRad(frame.rotation));
72
- }
73
- /** Normalize a world point into a (nx, ny) anchor on a frame, clamped to it. */
74
- function worldToAnchor(frame, point) {
75
- const local = frame.rotation ? rotatePointAround(point, rectCenter(frameRect(frame)), -degToRad(frame.rotation)) : point;
76
- return {
77
- nx: clamp01((local.x - frame.x) / Math.max(frame.width, 1e-4)),
78
- ny: clamp01((local.y - frame.y) / Math.max(frame.height, 1e-4))
79
- };
80
- }
81
- function clamp01(value) {
82
- return Math.min(1, Math.max(0, value));
83
- }
84
- /**
85
- * Choose the side an `auto` anchor should use.
86
- *
87
- * The dominant axis of the center-to-center vector wins, weighted by the frame's
88
- * own proportions so a wide card prefers its long edges. Comparing raw dx/dy
89
- * instead would make a wide node attach to its short side for most angles, which
90
- * is the classic "line leaves from the corner" artifact.
91
- */
92
- function autoConnectionSide(from, to) {
93
- const a = rectCenter(frameRect(from));
94
- const b = rectCenter(frameRect(to));
95
- const dx = b.x - a.x;
96
- const dy = b.y - a.y;
97
- if (Math.abs(dx) / Math.max(from.width / 2, 1e-4) >= Math.abs(dy) / Math.max(from.height / 2, 1e-4)) return dx >= 0 ? "right" : "left";
98
- return dy >= 0 ? "bottom" : "top";
99
- }
100
- /**
101
- * World point of an anchor on a frame, ignoring the gap and the facing node.
102
- *
103
- * For a live drag the other end is the pointer, not a node, so `auto` has no
104
- * frame to face: it resolves to the node's centre, which is the only honest
105
- * answer while the relation has nowhere to point yet.
106
- */
107
- function anchorPointOnFrame(anchor, frame) {
108
- if (anchor.kind === "fixed") return anchorToWorld(frame, anchor.nx, anchor.ny);
109
- if (anchor.kind === "side") {
110
- const point = sideAnchorPoint(anchor.side, anchor.offset);
111
- return anchorToWorld(frame, point.nx, point.ny);
112
- }
113
- return anchorToWorld(frame, .5, .5);
114
- }
115
- /** Resolve one endpoint of a connection against its node frame. */
116
- function resolveEndpoint(anchor, frame, otherFrame, gap) {
117
- let side;
118
- let nx;
119
- let ny;
120
- if (anchor.kind === "fixed") {
121
- nx = anchor.nx;
122
- ny = anchor.ny;
123
- side = nearestSide(nx, ny);
124
- } else if (anchor.kind === "side") {
125
- side = anchor.side;
126
- const point = sideAnchorPoint(side, anchor.offset);
127
- nx = point.nx;
128
- ny = point.ny;
129
- } else {
130
- side = autoConnectionSide(frame, otherFrame);
131
- const point = sideAnchorPoint(side, .5);
132
- nx = point.nx;
133
- ny = point.ny;
134
- }
135
- const base = anchorToWorld(frame, nx, ny);
136
- const local = SIDE_NORMALS[side];
137
- const normal = frame.rotation ? rotateVector(local, degToRad(frame.rotation)) : worldPoint(local.x, local.y);
138
- return {
139
- point: worldPoint(base.x + normal.x * gap, base.y + normal.y * gap),
140
- normal,
141
- side
142
- };
143
- }
144
- function rotateVector(vector, angleRad) {
145
- const cos = Math.cos(angleRad);
146
- const sin = Math.sin(angleRad);
147
- return worldPoint(vector.x * cos - vector.y * sin, vector.x * sin + vector.y * cos);
148
- }
149
- function nearestSide(nx, ny) {
150
- const distances = [
151
- ["left", nx],
152
- ["right", 1 - nx],
153
- ["top", ny],
154
- ["bottom", 1 - ny]
155
- ];
156
- distances.sort((a, b) => a[1] - b[1]);
157
- return distances[0]?.[0] ?? "right";
158
- }
159
- /**
160
- * A self-loop's path: a lobe leaving and re-entering the same node.
161
- *
162
- * Handled separately because every straight/curve formula degenerates when both
163
- * endpoints coincide, and a self-relation is meaningful enough (a node that
164
- * depends on itself, a retry edge) that dropping it would lose real data.
165
- */
166
- function selfLoopPath(frame, gap) {
167
- const rect = frameRect(frame);
168
- const size = Math.max(Math.min(rect.width, rect.height) * .45, 24);
169
- const right = rect.x + rect.width + gap;
170
- const top = rect.y - gap;
171
- const midY = rect.y + rect.height * .3;
172
- const midX = rect.x + rect.width * .7;
173
- return [
174
- worldPoint(midX, top),
175
- worldPoint(midX, top - size),
176
- worldPoint(right + size, top - size),
177
- worldPoint(right + size, midY),
178
- worldPoint(right, midY)
179
- ];
180
- }
181
- function quadraticPoint(start, control, end, t) {
182
- const mt = 1 - t;
183
- return worldPoint(mt * mt * start.x + 2 * mt * t * control.x + t * t * end.x, mt * mt * start.y + 2 * mt * t * control.y + t * t * end.y);
184
- }
185
- /** Sample a quadratic curve into a polyline. */
186
- function sampleQuadratic(start, control, end, segments) {
187
- const out = [];
188
- for (let index = 0; index <= segments; index += 1) out.push(quadraticPoint(start, control, end, index / segments));
189
- return out;
190
- }
191
- /**
192
- * Build an orthogonal elbow between two endpoints, leaving each along its normal.
193
- *
194
- * The turn happens on the axis each endpoint exits by, so the line never starts
195
- * parallel to the edge it is attached to (which would read as touching the node
196
- * rather than leaving it).
197
- */
198
- function orthogonalPath(source, target) {
199
- const horizontalStart = Math.abs(source.normal.x) > Math.abs(source.normal.y);
200
- const horizontalEnd = Math.abs(target.normal.x) > Math.abs(target.normal.y);
201
- const a = source.point;
202
- const b = target.point;
203
- if (horizontalStart && horizontalEnd) {
204
- const midX = a.x + (b.x - a.x) * ORTHOGONAL_SNAP;
205
- return [
206
- a,
207
- worldPoint(midX, a.y),
208
- worldPoint(midX, b.y),
209
- b
210
- ];
211
- }
212
- if (!horizontalStart && !horizontalEnd) {
213
- const midY = a.y + (b.y - a.y) * ORTHOGONAL_SNAP;
214
- return [
215
- a,
216
- worldPoint(a.x, midY),
217
- worldPoint(b.x, midY),
218
- b
219
- ];
220
- }
221
- return horizontalStart ? [
222
- a,
223
- worldPoint(b.x, a.y),
224
- b
225
- ] : [
226
- a,
227
- worldPoint(a.x, b.y),
228
- b
229
- ];
230
- }
231
- /** Curve samples per connection. Enough to read as smooth at typical zoom. */
232
- const CURVE_SEGMENTS = 20;
233
- /**
234
- * Resolve a connection into world-space geometry, or null if either node is gone.
235
- *
236
- * A null result means "not drawable right now", never "delete this": the caller
237
- * may be looking at a viewport-culled read where an endpoint simply was not
238
- * fetched.
239
- */
240
- function resolveConnection(connection, getFrame, options = {}) {
241
- const sourceFrame = getFrame(connection.source.itemId);
242
- const targetFrame = getFrame(connection.target.itemId);
243
- if (!sourceFrame || !targetFrame) return null;
244
- const gap = options.gap ?? 4;
245
- if (connection.source.itemId === connection.target.itemId) {
246
- const path = selfLoopPath(sourceFrame, gap);
247
- const first = path[0];
248
- const last = path[path.length - 1];
249
- return {
250
- source: {
251
- point: first,
252
- normal: worldPoint(0, -1),
253
- side: "top"
254
- },
255
- target: {
256
- point: last,
257
- normal: worldPoint(1, 0),
258
- side: "right"
259
- },
260
- path,
261
- mid: path[Math.floor(path.length / 2)] ?? first
262
- };
263
- }
264
- const source = resolveEndpoint(connection.source.anchor, sourceFrame, targetFrame, gap);
265
- const target = resolveEndpoint(connection.target.anchor, targetFrame, sourceFrame, gap);
266
- const waypoints = connection.routing.waypoints;
267
- let path;
268
- if (waypoints.length > 0) path = [
269
- source.point,
270
- ...waypoints.map((point) => worldPoint(point.x, point.y)),
271
- target.point
272
- ];
273
- else if (connection.routing.kind === "orthogonal") path = orthogonalPath(source, target);
274
- else if (connection.routing.kind === "straight" && !connection.routing.bend) path = [source.point, target.point];
275
- else path = sampleQuadratic(source.point, curveControl(source, target, connection.routing.bend), target.point, CURVE_SEGMENTS);
276
- return {
277
- source,
278
- target,
279
- path,
280
- mid: pathMidpoint(path)
281
- };
282
- }
283
- /**
284
- * Control point for a curved connection.
285
- *
286
- * With no explicit bend the bow is derived from the endpoint normals, so the line
287
- * leaves each node perpendicular to its edge and reads as attached rather than
288
- * merely adjacent. An explicit bend is a user-set bow and takes over entirely.
289
- */
290
- function curveControl(source, target, bend) {
291
- const mid = worldPoint((source.point.x + target.point.x) / 2, (source.point.y + target.point.y) / 2);
292
- const dx = target.point.x - source.point.x;
293
- const dy = target.point.y - source.point.y;
294
- const length = Math.hypot(dx, dy) || 1;
295
- if (bend) {
296
- const offset = bend * length;
297
- return worldPoint(mid.x + -dy / length * offset, mid.y + dx / length * offset);
298
- }
299
- const nx = (source.normal.x + target.normal.x) / 2;
300
- const ny = (source.normal.y + target.normal.y) / 2;
301
- const magnitude = Math.hypot(nx, ny);
302
- if (magnitude < 1e-4) return mid;
303
- const strength = Math.min(length * .18, 96);
304
- return worldPoint(mid.x + nx / magnitude * strength, mid.y + ny / magnitude * strength);
305
- }
306
- /** Midpoint by arc length, so a label sits visually centered on the line. */
307
- function pathMidpoint(path) {
308
- if (path.length === 0) return worldPoint(0, 0);
309
- if (path.length === 1) return path[0];
310
- let total = 0;
311
- for (let index = 0; index < path.length - 1; index += 1) {
312
- const from = path[index];
313
- const to = path[index + 1];
314
- total += Math.hypot(to.x - from.x, to.y - from.y);
315
- }
316
- let travelled = 0;
317
- const half = total / 2;
318
- for (let index = 0; index < path.length - 1; index += 1) {
319
- const from = path[index];
320
- const to = path[index + 1];
321
- const segment = Math.hypot(to.x - from.x, to.y - from.y);
322
- if (travelled + segment >= half) {
323
- const t = segment > 0 ? (half - travelled) / segment : 0;
324
- return worldPoint(from.x + (to.x - from.x) * t, from.y + (to.y - from.y) * t);
325
- }
326
- travelled += segment;
327
- }
328
- return path[path.length - 1];
329
- }
330
- /** World bounds of a resolved connection, padded for its stroke. */
331
- function connectionBounds(resolved, strokeSize) {
332
- let minX = Number.POSITIVE_INFINITY;
333
- let minY = Number.POSITIVE_INFINITY;
334
- let maxX = Number.NEGATIVE_INFINITY;
335
- let maxY = Number.NEGATIVE_INFINITY;
336
- for (const point of resolved.path) {
337
- minX = Math.min(minX, point.x);
338
- minY = Math.min(minY, point.y);
339
- maxX = Math.max(maxX, point.x);
340
- maxY = Math.max(maxY, point.y);
341
- }
342
- const pad = Math.max(8, strokeSize * 2);
343
- return {
344
- x: minX - pad,
345
- y: minY - pad,
346
- width: Math.max(1, maxX - minX + pad * 2),
347
- height: Math.max(1, maxY - minY + pad * 2)
348
- };
349
- }
350
- function createConnectionGeometryCache() {
351
- const entries = /* @__PURE__ */ new Map();
352
- return {
353
- get(connection, getFrame) {
354
- const source = getFrame(connection.source.itemId);
355
- const target = getFrame(connection.target.itemId);
356
- if (!source || !target) {
357
- entries.delete(connection.id);
358
- return null;
359
- }
360
- const entry = entries.get(connection.id);
361
- if (entry && entry.geometry.connection === connection && entry.source === source && entry.target === target) return entry.geometry;
362
- const resolved = resolveConnection(connection, getFrame);
363
- if (!resolved) {
364
- entries.delete(connection.id);
365
- return null;
366
- }
367
- const geometry = {
368
- connection,
369
- resolved,
370
- bounds: connectionBounds(resolved, connection.style.size)
371
- };
372
- entries.set(connection.id, {
373
- source,
374
- target,
375
- geometry
376
- });
377
- return geometry;
378
- },
379
- peek: (connectionId) => entries.get(connectionId)?.geometry ?? null,
380
- retain(connections) {
381
- if (entries.size === 0) return;
382
- const live = new Set(connections.map((connection) => connection.id));
383
- for (const id of entries.keys()) if (!live.has(id)) entries.delete(id);
384
- },
385
- clear: () => entries.clear()
386
- };
387
- }
388
- /** Distance from a world point to a resolved connection's path. */
389
- function distanceToConnection(resolved, point) {
390
- let min = Number.POSITIVE_INFINITY;
391
- for (let index = 0; index < resolved.path.length - 1; index += 1) {
392
- const from = resolved.path[index];
393
- const to = resolved.path[index + 1];
394
- if (!from || !to) continue;
395
- const distance = segmentDistance(point, from, to);
396
- if (distance < min) min = distance;
397
- }
398
- return min;
399
- }
400
- function segmentDistance(p, a, b) {
401
- const dx = b.x - a.x;
402
- const dy = b.y - a.y;
403
- const lengthSq = dx * dx + dy * dy;
404
- if (lengthSq === 0) return Math.hypot(p.x - a.x, p.y - a.y);
405
- const t = Math.min(1, Math.max(0, ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSq));
406
- return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
407
- }
408
- /** Hit test a connection with a zoom-independent screen-space tolerance. */
409
- function connectionHitTest(resolved, point, strokeSize) {
410
- return distanceToConnection(resolved, point) <= connectionHitRadius(strokeSize);
411
- }
412
- function connectionHitRadius(strokeSize) {
413
- return Math.max(8, strokeSize * 2.5);
414
- }
415
- /** Whether the connection draws an arrowhead at its source / target. */
416
- function connectionArrowheads(connection) {
417
- switch (connection.direction) {
418
- case "forward": return {
419
- atSource: false,
420
- atTarget: true
421
- };
422
- case "backward": return {
423
- atSource: true,
424
- atTarget: false
425
- };
426
- case "both": return {
427
- atSource: true,
428
- atTarget: true
429
- };
430
- default: return {
431
- atSource: false,
432
- atTarget: false
433
- };
434
- }
435
- }
436
- const NO_CONNECTIONS = [];
437
- function createConnectionIndex(connections) {
438
- const byNode = /* @__PURE__ */ new Map();
439
- const byId = /* @__PURE__ */ new Map();
440
- for (const connection of connections) {
441
- byId.set(connection.id, connection);
442
- for (const nodeId of /* @__PURE__ */ new Set([connection.source.itemId, connection.target.itemId])) {
443
- const list = byNode.get(nodeId);
444
- if (list) list.push(connection.id);
445
- else byNode.set(nodeId, [connection.id]);
446
- }
447
- }
448
- return {
449
- byNode: (nodeId) => byNode.get(nodeId) ?? NO_CONNECTIONS,
450
- get: (connectionId) => byId.get(connectionId),
451
- all: connections
452
- };
453
- }
454
- //#endregion
455
- export { CONNECTION_ENDPOINT_GAP, anchorPointOnFrame, anchorToWorld, autoConnectionSide, connectionArrowheads, connectionBounds, connectionHitRadius, connectionHitTest, createConnectionGeometryCache, createConnectionIndex, distanceToConnection, pathMidpoint, resolveConnection, worldToAnchor };
@@ -1,6 +0,0 @@
1
- import { BoardAppearance } from "../protocol/dist/board-document.js";
2
- //#region src/board/mutation.d.ts
3
- /** Merge Board appearance fields while preserving nested background/grid defaults. */
4
- declare function patchBoardAppearance(current: BoardAppearance, patch: Partial<BoardAppearance>): BoardAppearance;
5
- //#endregion
6
- export { patchBoardAppearance };
@@ -1,14 +0,0 @@
1
- import { BoardAppearanceSchema } from "../protocol/dist/board-document.js";
2
- //#region src/board/mutation.ts
3
- /** Merge Board appearance fields while preserving nested background/grid defaults. */
4
- function patchBoardAppearance(current, patch) {
5
- return BoardAppearanceSchema.parse({
6
- ...current,
7
- ...patch,
8
- background: patch.background ?? current.background,
9
- grid: patch.grid ?? current.grid,
10
- ...Object.hasOwn(patch, "motion") ? { motion: patch.motion } : current.motion ? { motion: current.motion } : {}
11
- });
12
- }
13
- //#endregion
14
- export { patchBoardAppearance };
@@ -1,53 +0,0 @@
1
- import { BoardConnection } from "../../protocol/dist/board-connection.js";
2
- import { BoardFrame } from "../../protocol/dist/board-document.js";
3
- import { Rect } from "../geometry.js";
4
- import { FrameLookup, ResolvedConnection } from "../core/connections.js";
5
- import { BoardShapeColors } from "../core/palette.js";
6
- import { Container } from "pixi.js";
7
- //#region src/board/render/connection-layer.d.ts
8
- type ConnectionRenderInput = {
9
- connections: readonly BoardConnection[];
10
- getFrame: FrameLookup;
11
- colors: BoardShapeColors;
12
- colorScheme: "dark" | "light";
13
- zoom: number;
14
- /** Connections drawn in their selected state. */
15
- selectedIds?: ReadonlySet<string>;
16
- /** Connection under the pointer, if any. */
17
- hoveredId?: string | null;
18
- /**
19
- * Ids to skip because the host is drawing them itself this frame (e.g. a live
20
- * drag preview on the interaction overlay). Skipping avoids the doubled stroke
21
- * of a preview drawn over its own committed geometry.
22
- */
23
- skipIds?: ReadonlySet<string>;
24
- /** Cull and dash-clip rect; use `stableCullRect` so small pans keep the cache. */
25
- cullRect?: Rect | null;
26
- /** Nodes being manipulated; their relations are drawn on the live layer. */
27
- liveNodeIds?: ReadonlySet<string>;
28
- };
29
- type ConnectionLayer = {
30
- /** Draw the connection set; only changed layers re-tessellate. */
31
- sync: (input: ConnectionRenderInput) => void;
32
- /** Resolved geometry from the last sync, for hit testing and overlays. */
33
- resolved: (connectionId: string) => ResolvedConnection | null;
34
- /**
35
- * The display objects this layer owns, so a host can place them in its own
36
- * z-ordering scheme without the layer needing to know about it.
37
- */
38
- readonly children: readonly Container[];
39
- destroy: () => void;
40
- };
41
- declare function createConnectionLayer(options: {
42
- /** World-space container the layer attaches to. */
43
- parent: Container;
44
- /** zIndex applied to the layer's display objects once they exist. */
45
- zIndex?: number;
46
- }): ConnectionLayer;
47
- /** Frame lookup over a plain item list, for hosts without an index. */
48
- declare function framesFromItems(items: readonly {
49
- id: string;
50
- frame: BoardFrame;
51
- }[]): FrameLookup;
52
- //#endregion
53
- export { ConnectionLayer, ConnectionRenderInput, createConnectionLayer, framesFromItems };