@neta-art/cohub 5.3.2 → 5.4.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.
- package/dist/board/codec.d.ts +2 -0
- package/dist/board/codec.js +18 -13
- package/dist/board/core/arrow-geometry.d.ts +23 -0
- package/dist/board/core/arrow-geometry.js +109 -0
- package/dist/board/core/connections.d.ts +83 -0
- package/dist/board/core/connections.js +399 -0
- package/dist/board/core/export-plan.d.ts +15 -4
- package/dist/board/core/export-plan.js +49 -16
- package/dist/board/core/shape-definition.js +1 -1
- package/dist/board/core/shape-types.d.ts +8 -2
- package/dist/board/core/shape-types.js +1 -1
- package/dist/board/core/tool-styles.d.ts +9 -3
- package/dist/board/core/tool-styles.js +10 -6
- package/dist/board/export/index.js +1 -0
- package/dist/board/export/scene.d.ts +3 -0
- package/dist/board/export/scene.js +18 -1
- package/dist/board/index.d.ts +8 -5
- package/dist/board/index.js +8 -5
- package/dist/board/render/connection-layer.d.ts +48 -0
- package/dist/board/render/connection-layer.js +223 -0
- package/dist/board/render/index.d.ts +2 -1
- package/dist/board/render/index.js +3 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +35 -48
- package/dist/chunks/http.d.ts +53 -1
- package/dist/chunks/http.js +287 -1
- package/dist/chunks/websocket.d.ts +296 -57
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.js +22 -58
- package/dist/protocol/dist/board-connection.d.ts +310 -0
- package/dist/protocol/dist/board-connection.js +215 -0
- package/dist/protocol/dist/board-constants.d.ts +11 -1
- package/dist/protocol/dist/board-constants.js +15 -1
- package/dist/protocol/dist/board-document.d.ts +106 -60
- package/dist/protocol/dist/board-document.js +57 -17
- package/dist/protocol/dist/board.d.ts +1 -0
- package/dist/protocol/dist/board.js +3 -0
- package/dist/protocol/dist/index.d.ts +2 -1
- package/dist/protocol/dist/index.js +2 -1
- package/dist/protocol/dist/realtime/board-awareness.js +15 -15
- package/docs/work-runtime-guide.md +1 -1
- package/package.json +1 -1
- package/dist/board/core/bindings.d.ts +0 -45
- package/dist/board/core/bindings.js +0 -162
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BOARD_ARROW_STROKE_SIZE } from "../board-constants.js";
|
|
1
|
+
import { BOARD_ARROW_STROKE_SIZE, BOARD_CONNECTION_STROKE_SIZE } from "../board-constants.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region ../protocol/dist/realtime/board-awareness.js
|
|
4
4
|
const idSchema = z.string().min(1).max(160);
|
|
@@ -15,23 +15,13 @@ const BoardAwarenessFrameSchema = z.object({
|
|
|
15
15
|
height: finiteSchema.positive(),
|
|
16
16
|
rotation: finiteSchema
|
|
17
17
|
});
|
|
18
|
-
const arrowEndpointSchema = z.union([z.object({
|
|
19
|
-
kind: z.literal("point"),
|
|
20
|
-
x: finiteSchema,
|
|
21
|
-
y: finiteSchema
|
|
22
|
-
}), z.object({
|
|
23
|
-
kind: z.literal("binding"),
|
|
24
|
-
target: idSchema,
|
|
25
|
-
nx: finiteSchema,
|
|
26
|
-
ny: finiteSchema,
|
|
27
|
-
precise: z.boolean()
|
|
28
|
-
})]);
|
|
29
18
|
const BoardAwarenessNodePreviewSchema = z.object({
|
|
30
19
|
nodeId: idSchema,
|
|
31
20
|
frame: BoardAwarenessFrameSchema,
|
|
21
|
+
/** Live endpoints of a free arrow being dragged. */
|
|
32
22
|
arrow: z.object({
|
|
33
|
-
start:
|
|
34
|
-
end:
|
|
23
|
+
start: BoardAwarenessPointSchema,
|
|
24
|
+
end: BoardAwarenessPointSchema,
|
|
35
25
|
bend: finiteSchema
|
|
36
26
|
}).optional()
|
|
37
27
|
});
|
|
@@ -80,6 +70,15 @@ const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
|
|
|
80
70
|
color: z.string().min(1).max(64),
|
|
81
71
|
geo: z.string().min(1).max(40)
|
|
82
72
|
}),
|
|
73
|
+
z.object({
|
|
74
|
+
kind: z.literal("connection"),
|
|
75
|
+
id: idSchema,
|
|
76
|
+
sourceNodeId: idSchema,
|
|
77
|
+
targetNodeId: idSchema.nullable(),
|
|
78
|
+
current: BoardAwarenessPointSchema,
|
|
79
|
+
color: z.string().min(1).max(64),
|
|
80
|
+
size: finiteSchema.positive().max(256).default(BOARD_CONNECTION_STROKE_SIZE)
|
|
81
|
+
}),
|
|
83
82
|
z.object({
|
|
84
83
|
kind: z.literal("transform"),
|
|
85
84
|
id: idSchema,
|
|
@@ -87,7 +86,8 @@ const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
|
|
|
87
86
|
"translate",
|
|
88
87
|
"resize",
|
|
89
88
|
"rotate",
|
|
90
|
-
"arrow"
|
|
89
|
+
"arrow",
|
|
90
|
+
"connection"
|
|
91
91
|
]),
|
|
92
92
|
nodes: z.array(BoardAwarenessNodePreviewSchema).max(64),
|
|
93
93
|
bounds: BoardAwarenessFrameSchema.nullable()
|
|
@@ -61,7 +61,7 @@ Four runtime-only APIs form the foundation; everything else is standard SDK:
|
|
|
61
61
|
| API | What it does | Returns |
|
|
62
62
|
|---|---|---|
|
|
63
63
|
| `client.context()` | Asks the host for the Work's identity | `{ work, space, viewer?, permissions }` or `null` |
|
|
64
|
-
| `client.auth.request({ scopes, reason })` |
|
|
64
|
+
| `client.auth.request({ scopes, reason })` | Requests viewer authorization and caches a scoped token; Cohub may silently approve the publisher's own workspace preview or background | `true` / `false` |
|
|
65
65
|
| `client.work.commerce.*` | Entitlement checks, credit consumption, purchases | (see Commerce section) |
|
|
66
66
|
| `client.work.realtime.*` | Temporary rooms, events, presence, and membership | (see Realtime rooms section) |
|
|
67
67
|
|
package/package.json
CHANGED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { ArrowEndpoint, BoardArrowItem, BoardFrame } from "../../protocol/dist/board-document.js";
|
|
2
|
-
import { Rect, WorldPoint } from "../geometry.js";
|
|
3
|
-
//#region src/board/core/bindings.d.ts
|
|
4
|
-
type FrameLookup = (id: string) => BoardFrame | undefined;
|
|
5
|
-
/** Denormalize a binding anchor to a world point on the (rotated) frame. */
|
|
6
|
-
declare function anchorToWorld(frame: BoardFrame, nx: number, ny: number): WorldPoint;
|
|
7
|
-
/** Normalize a world point to a binding anchor on the (rotated) frame, clamped. */
|
|
8
|
-
declare function worldToAnchor(frame: BoardFrame, point: WorldPoint): {
|
|
9
|
-
nx: number;
|
|
10
|
-
ny: number;
|
|
11
|
-
};
|
|
12
|
-
/** Resolve an endpoint to a world point, or null if a binding target is gone. */
|
|
13
|
-
declare function resolveEndpoint(endpoint: ArrowEndpoint, getFrame: FrameLookup): WorldPoint | null;
|
|
14
|
-
type ResolvedArrow = {
|
|
15
|
-
start: WorldPoint;
|
|
16
|
-
end: WorldPoint;
|
|
17
|
-
/** Quadratic control point (already bent); equals midpoint when bend is 0. */
|
|
18
|
-
control: WorldPoint;
|
|
19
|
-
};
|
|
20
|
-
/** Resolve both endpoints and compute the bent control point. */
|
|
21
|
-
declare function resolveArrow(item: BoardArrowItem, getFrame: FrameLookup): ResolvedArrow | null;
|
|
22
|
-
/** World-space bounds of an arrow, sampling the curve for accuracy. */
|
|
23
|
-
declare function arrowBounds(item: BoardArrowItem, getFrame: FrameLookup): Rect | null;
|
|
24
|
-
/** Sample the arrow's quadratic curve into world points (for render/hit-test). */
|
|
25
|
-
declare function sampleQuadratic(resolved: ResolvedArrow, segments: number): WorldPoint[];
|
|
26
|
-
/** Distance from a world point to the arrow curve (hit testing). */
|
|
27
|
-
declare function distanceToArrow(item: BoardArrowItem, getFrame: FrameLookup, point: WorldPoint): number;
|
|
28
|
-
/**
|
|
29
|
-
* Turn a free endpoint into a binding if a candidate target frame contains the
|
|
30
|
-
* point; otherwise keep it free. Used while dragging an arrow handle so the
|
|
31
|
-
* arrow "connects" to shapes it lands on.
|
|
32
|
-
*/
|
|
33
|
-
declare function bindEndpointAt(point: WorldPoint, target: {
|
|
34
|
-
id: string;
|
|
35
|
-
frame: BoardFrame;
|
|
36
|
-
} | null): ArrowEndpoint;
|
|
37
|
-
/**
|
|
38
|
-
* Translate an arrow by a delta: free endpoints move; bindings stay attached to
|
|
39
|
-
* their targets (so a bound end anchors while the rest of the arrow moves). The
|
|
40
|
-
* frame — a derived bounding box, not a transform — is recomputed from the new
|
|
41
|
-
* endpoint geometry.
|
|
42
|
-
*/
|
|
43
|
-
declare function translateArrow(item: BoardArrowItem, dx: number, dy: number, getFrame: FrameLookup): BoardArrowItem;
|
|
44
|
-
//#endregion
|
|
45
|
-
export { FrameLookup, ResolvedArrow, anchorToWorld, arrowBounds, bindEndpointAt, distanceToArrow, resolveArrow, resolveEndpoint, sampleQuadratic, translateArrow, worldToAnchor };
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { degToRad, rectCenter, rotatePointAround, worldPoint } from "../geometry.js";
|
|
2
|
-
//#region src/board/core/bindings.ts
|
|
3
|
-
/**
|
|
4
|
-
* Arrow bindings — pure geometry for connecting arrows to shapes.
|
|
5
|
-
*
|
|
6
|
-
* An arrow endpoint is either a free world point or a *binding*: a normalized
|
|
7
|
-
* anchor (0..1) on a target shape's frame. Because the anchor is relative, the
|
|
8
|
-
* arrow tracks the target through move and resize with no stored absolute
|
|
9
|
-
* coordinates — the binding never goes stale. Resolution to world space happens
|
|
10
|
-
* here, given a frame lookup, so it is fully testable and renderer-independent.
|
|
11
|
-
*/
|
|
12
|
-
/** Denormalize a binding anchor to a world point on the (rotated) frame. */
|
|
13
|
-
function anchorToWorld(frame, nx, ny) {
|
|
14
|
-
const unrotated = worldPoint(frame.x + nx * frame.width, frame.y + ny * frame.height);
|
|
15
|
-
if (!frame.rotation) return unrotated;
|
|
16
|
-
return rotatePointAround(unrotated, rectCenter(frame), degToRad(frame.rotation));
|
|
17
|
-
}
|
|
18
|
-
/** Normalize a world point to a binding anchor on the (rotated) frame, clamped. */
|
|
19
|
-
function worldToAnchor(frame, point) {
|
|
20
|
-
let local = point;
|
|
21
|
-
if (frame.rotation) local = rotatePointAround(point, rectCenter(frame), -degToRad(frame.rotation));
|
|
22
|
-
return {
|
|
23
|
-
nx: clamp01((local.x - frame.x) / frame.width),
|
|
24
|
-
ny: clamp01((local.y - frame.y) / frame.height)
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function clamp01(value) {
|
|
28
|
-
return Math.min(1, Math.max(0, value));
|
|
29
|
-
}
|
|
30
|
-
/** Resolve an endpoint to a world point, or null if a binding target is gone. */
|
|
31
|
-
function resolveEndpoint(endpoint, getFrame) {
|
|
32
|
-
if (endpoint.kind === "point") return worldPoint(endpoint.x, endpoint.y);
|
|
33
|
-
const frame = getFrame(endpoint.target);
|
|
34
|
-
if (!frame) return null;
|
|
35
|
-
return anchorToWorld(frame, endpoint.nx, endpoint.ny);
|
|
36
|
-
}
|
|
37
|
-
/** Resolve both endpoints and compute the bent control point. */
|
|
38
|
-
function resolveArrow(item, getFrame) {
|
|
39
|
-
const start = resolveEndpoint(item.start, getFrame);
|
|
40
|
-
const end = resolveEndpoint(item.end, getFrame);
|
|
41
|
-
if (!start || !end) return null;
|
|
42
|
-
const mid = worldPoint((start.x + end.x) / 2, (start.y + end.y) / 2);
|
|
43
|
-
if (!item.bend) return {
|
|
44
|
-
start,
|
|
45
|
-
end,
|
|
46
|
-
control: mid
|
|
47
|
-
};
|
|
48
|
-
const dx = end.x - start.x;
|
|
49
|
-
const dy = end.y - start.y;
|
|
50
|
-
const length = Math.hypot(dx, dy) || 1;
|
|
51
|
-
const offset = item.bend * length;
|
|
52
|
-
return {
|
|
53
|
-
start,
|
|
54
|
-
end,
|
|
55
|
-
control: worldPoint(mid.x + -dy / length * offset, mid.y + dx / length * offset)
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
/** World-space bounds of an arrow, sampling the curve for accuracy. */
|
|
59
|
-
function arrowBounds(item, getFrame) {
|
|
60
|
-
const resolved = resolveArrow(item, getFrame);
|
|
61
|
-
if (!resolved) return null;
|
|
62
|
-
const samples = sampleQuadratic(resolved, 12);
|
|
63
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
64
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
65
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
66
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
67
|
-
for (const p of samples) {
|
|
68
|
-
minX = Math.min(minX, p.x);
|
|
69
|
-
minY = Math.min(minY, p.y);
|
|
70
|
-
maxX = Math.max(maxX, p.x);
|
|
71
|
-
maxY = Math.max(maxY, p.y);
|
|
72
|
-
}
|
|
73
|
-
const pad = Math.max(8, item.size * 2);
|
|
74
|
-
return {
|
|
75
|
-
x: minX - pad,
|
|
76
|
-
y: minY - pad,
|
|
77
|
-
width: Math.max(1, maxX - minX + pad * 2),
|
|
78
|
-
height: Math.max(1, maxY - minY + pad * 2)
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
/** Sample the arrow's quadratic curve into world points (for render/hit-test). */
|
|
82
|
-
function sampleQuadratic(resolved, segments) {
|
|
83
|
-
const { start, control, end } = resolved;
|
|
84
|
-
const out = [];
|
|
85
|
-
for (let i = 0; i <= segments; i += 1) {
|
|
86
|
-
const t = i / segments;
|
|
87
|
-
const mt = 1 - t;
|
|
88
|
-
out.push(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));
|
|
89
|
-
}
|
|
90
|
-
return out;
|
|
91
|
-
}
|
|
92
|
-
/** Distance from a world point to the arrow curve (hit testing). */
|
|
93
|
-
function distanceToArrow(item, getFrame, point) {
|
|
94
|
-
const resolved = resolveArrow(item, getFrame);
|
|
95
|
-
if (!resolved) return Number.POSITIVE_INFINITY;
|
|
96
|
-
const samples = sampleQuadratic(resolved, 16);
|
|
97
|
-
let min = Number.POSITIVE_INFINITY;
|
|
98
|
-
for (let i = 0; i < samples.length - 1; i += 1) {
|
|
99
|
-
const from = samples[i];
|
|
100
|
-
const to = samples[i + 1];
|
|
101
|
-
if (!from || !to) continue;
|
|
102
|
-
const d = segmentDistance(point, from, to);
|
|
103
|
-
if (d < min) min = d;
|
|
104
|
-
}
|
|
105
|
-
return min;
|
|
106
|
-
}
|
|
107
|
-
function segmentDistance(p, a, b) {
|
|
108
|
-
const dx = b.x - a.x;
|
|
109
|
-
const dy = b.y - a.y;
|
|
110
|
-
const lengthSq = dx * dx + dy * dy;
|
|
111
|
-
if (lengthSq === 0) return Math.hypot(p.x - a.x, p.y - a.y);
|
|
112
|
-
const t = Math.min(1, Math.max(0, ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSq));
|
|
113
|
-
return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Turn a free endpoint into a binding if a candidate target frame contains the
|
|
117
|
-
* point; otherwise keep it free. Used while dragging an arrow handle so the
|
|
118
|
-
* arrow "connects" to shapes it lands on.
|
|
119
|
-
*/
|
|
120
|
-
function bindEndpointAt(point, target) {
|
|
121
|
-
if (!target) return {
|
|
122
|
-
kind: "point",
|
|
123
|
-
x: point.x,
|
|
124
|
-
y: point.y
|
|
125
|
-
};
|
|
126
|
-
const { nx, ny } = worldToAnchor(target.frame, point);
|
|
127
|
-
return {
|
|
128
|
-
kind: "binding",
|
|
129
|
-
target: target.id,
|
|
130
|
-
nx,
|
|
131
|
-
ny,
|
|
132
|
-
precise: true
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Translate an arrow by a delta: free endpoints move; bindings stay attached to
|
|
137
|
-
* their targets (so a bound end anchors while the rest of the arrow moves). The
|
|
138
|
-
* frame — a derived bounding box, not a transform — is recomputed from the new
|
|
139
|
-
* endpoint geometry.
|
|
140
|
-
*/
|
|
141
|
-
function translateArrow(item, dx, dy, getFrame) {
|
|
142
|
-
const move = (endpoint) => endpoint.kind === "point" ? {
|
|
143
|
-
kind: "point",
|
|
144
|
-
x: endpoint.x + dx,
|
|
145
|
-
y: endpoint.y + dy
|
|
146
|
-
} : endpoint;
|
|
147
|
-
const next = {
|
|
148
|
-
...item,
|
|
149
|
-
start: move(item.start),
|
|
150
|
-
end: move(item.end)
|
|
151
|
-
};
|
|
152
|
-
const bounds = arrowBounds(next, getFrame);
|
|
153
|
-
return bounds ? {
|
|
154
|
-
...next,
|
|
155
|
-
frame: {
|
|
156
|
-
...bounds,
|
|
157
|
-
rotation: 0
|
|
158
|
-
}
|
|
159
|
-
} : next;
|
|
160
|
-
}
|
|
161
|
-
//#endregion
|
|
162
|
-
export { anchorToWorld, arrowBounds, bindEndpointAt, distanceToArrow, resolveArrow, resolveEndpoint, sampleQuadratic, translateArrow, worldToAnchor };
|