@neta-art/cohub 5.10.0 → 6.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.
- package/README.md +42 -46
- package/dist/board/animation.d.ts +156 -67
- package/dist/board/animation.js +161 -305
- package/dist/board/geometry.js +4 -4
- package/dist/board/index.d.ts +4 -4
- package/dist/board/index.js +3 -4
- package/dist/board/mutation.d.ts +5 -11
- package/dist/board/mutation.js +9 -46
- package/dist/chunks/http.d.ts +23 -12
- package/dist/chunks/http.js +674 -316
- package/dist/chunks/websocket.d.ts +2623 -201
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +158 -299
- package/dist/index.js +164 -306
- package/dist/protocol/dist/board-authoring.d.ts +1 -0
- package/dist/protocol/dist/board-authoring.js +217 -0
- package/dist/protocol/dist/board-capability-registry.d.ts +2 -0
- package/dist/protocol/dist/board-capability-registry.js +74 -0
- package/dist/protocol/dist/board-codec.d.ts +2 -0
- package/dist/protocol/dist/board-codec.js +4 -0
- package/dist/protocol/dist/board-composition.d.ts +258 -0
- package/dist/protocol/dist/board-composition.js +318 -0
- package/dist/protocol/dist/board-constants.js +0 -25
- package/dist/protocol/dist/board-node.d.ts +1 -12
- package/dist/protocol/dist/board-node.js +1 -81
- package/dist/protocol/dist/board-upgrade.d.ts +1 -0
- package/dist/protocol/dist/board-upgrade.js +2 -0
- package/dist/protocol/dist/board.d.ts +19 -92
- package/dist/protocol/dist/board.js +18 -78
- package/dist/protocol/dist/index.d.ts +8 -3
- package/dist/protocol/dist/index.js +9 -4
- package/dist/types.d.ts +2 -1
- package/docs/work-runtime-guide.md +19 -3
- package/package.json +3 -2
- package/dist/board/nodes.d.ts +0 -113
- package/dist/board/nodes.js +0 -154
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region ../protocol/dist/board-composition.js
|
|
3
|
+
const idSchema = z.string().min(1).max(160);
|
|
4
|
+
const finiteSchema = z.number().finite();
|
|
5
|
+
const jsonObjectSchema = z.record(z.string(), z.unknown());
|
|
6
|
+
const BOARD_EASINGS = [
|
|
7
|
+
"linear",
|
|
8
|
+
"ease-in-quad",
|
|
9
|
+
"ease-out-quad",
|
|
10
|
+
"ease-in-out-quad",
|
|
11
|
+
"ease-in-cubic",
|
|
12
|
+
"ease-out-cubic",
|
|
13
|
+
"ease-in-out-cubic",
|
|
14
|
+
"ease-out-quart",
|
|
15
|
+
"ease-out-expo"
|
|
16
|
+
];
|
|
17
|
+
const BoardEasingSchema = z.enum(BOARD_EASINGS);
|
|
18
|
+
const BoardAnimationTargetSchema = z.discriminatedUnion("type", [
|
|
19
|
+
z.object({
|
|
20
|
+
type: z.literal("item"),
|
|
21
|
+
itemId: idSchema
|
|
22
|
+
}).strict(),
|
|
23
|
+
z.object({
|
|
24
|
+
type: z.literal("effect"),
|
|
25
|
+
effectId: idSchema
|
|
26
|
+
}).strict(),
|
|
27
|
+
z.object({ type: z.literal("camera") }).strict(),
|
|
28
|
+
z.object({ type: z.literal("board") }).strict()
|
|
29
|
+
]);
|
|
30
|
+
const vector2Schema = z.object({
|
|
31
|
+
x: finiteSchema,
|
|
32
|
+
y: finiteSchema
|
|
33
|
+
}).strict();
|
|
34
|
+
const scaleSchema = z.union([finiteSchema.positive(), z.object({
|
|
35
|
+
x: finiteSchema.positive(),
|
|
36
|
+
y: finiteSchema.positive()
|
|
37
|
+
}).strict()]);
|
|
38
|
+
const BOARD_ANIMATION_CHANNELS = {
|
|
39
|
+
"transform.translation": {
|
|
40
|
+
targets: ["item"],
|
|
41
|
+
value: vector2Schema,
|
|
42
|
+
interpolations: ["linear", "step"],
|
|
43
|
+
coordinateSpace: "world-offset",
|
|
44
|
+
unit: "board"
|
|
45
|
+
},
|
|
46
|
+
"transform.rotation": {
|
|
47
|
+
targets: ["item"],
|
|
48
|
+
value: finiteSchema,
|
|
49
|
+
interpolations: ["linear", "step"],
|
|
50
|
+
unit: "radian"
|
|
51
|
+
},
|
|
52
|
+
"transform.scale": {
|
|
53
|
+
targets: ["item"],
|
|
54
|
+
value: scaleSchema,
|
|
55
|
+
interpolations: ["linear", "step"],
|
|
56
|
+
unit: "ratio"
|
|
57
|
+
},
|
|
58
|
+
"style.opacity": {
|
|
59
|
+
targets: ["item"],
|
|
60
|
+
value: finiteSchema.min(0).max(1),
|
|
61
|
+
interpolations: ["linear", "step"],
|
|
62
|
+
unit: "ratio"
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const BoardTrackKeyframeSchema = z.object({
|
|
66
|
+
time: finiteSchema.nonnegative(),
|
|
67
|
+
value: z.unknown(),
|
|
68
|
+
easing: BoardEasingSchema.optional()
|
|
69
|
+
}).strict();
|
|
70
|
+
const BoardTrackSchema = z.object({
|
|
71
|
+
id: idSchema,
|
|
72
|
+
target: BoardAnimationTargetSchema,
|
|
73
|
+
channel: z.string().min(1).max(160),
|
|
74
|
+
channelVersion: z.number().int().positive().default(1),
|
|
75
|
+
interpolation: z.enum(["linear", "step"]).default("linear"),
|
|
76
|
+
fill: z.enum([
|
|
77
|
+
"none",
|
|
78
|
+
"backwards",
|
|
79
|
+
"forwards",
|
|
80
|
+
"both"
|
|
81
|
+
]).default("none"),
|
|
82
|
+
keyframes: z.array(BoardTrackKeyframeSchema).min(1).max(1e5),
|
|
83
|
+
metadata: jsonObjectSchema.default({})
|
|
84
|
+
}).strict().superRefine((track, context) => {
|
|
85
|
+
let previous = -1;
|
|
86
|
+
for (const [index, keyframe] of track.keyframes.entries()) {
|
|
87
|
+
if (keyframe.time <= previous) context.addIssue({
|
|
88
|
+
code: "custom",
|
|
89
|
+
message: "keyframe times must be strictly increasing",
|
|
90
|
+
path: [
|
|
91
|
+
"keyframes",
|
|
92
|
+
index,
|
|
93
|
+
"time"
|
|
94
|
+
]
|
|
95
|
+
});
|
|
96
|
+
previous = keyframe.time;
|
|
97
|
+
}
|
|
98
|
+
const channel = BOARD_ANIMATION_CHANNELS[track.channel];
|
|
99
|
+
if (!channel) {
|
|
100
|
+
if (!/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+){2,}$/.test(track.channel)) context.addIssue({
|
|
101
|
+
code: "custom",
|
|
102
|
+
message: `unknown channel: ${track.channel}`,
|
|
103
|
+
path: ["channel"]
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!channel.targets.includes(track.target.type)) context.addIssue({
|
|
108
|
+
code: "custom",
|
|
109
|
+
message: `${track.channel} cannot target ${track.target.type}`,
|
|
110
|
+
path: ["target"]
|
|
111
|
+
});
|
|
112
|
+
if (!channel.interpolations.includes(track.interpolation)) context.addIssue({
|
|
113
|
+
code: "custom",
|
|
114
|
+
message: `${track.channel} does not support ${track.interpolation} interpolation`,
|
|
115
|
+
path: ["interpolation"]
|
|
116
|
+
});
|
|
117
|
+
for (const [index, keyframe] of track.keyframes.entries()) {
|
|
118
|
+
const parsed = channel.value.safeParse(keyframe.value);
|
|
119
|
+
if (!parsed.success) context.addIssue({
|
|
120
|
+
code: "custom",
|
|
121
|
+
message: parsed.error.issues[0]?.message ?? `invalid value for ${track.channel}`,
|
|
122
|
+
path: [
|
|
123
|
+
"keyframes",
|
|
124
|
+
index,
|
|
125
|
+
"value"
|
|
126
|
+
]
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
const extensionKindSchema = z.string().regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/).max(160);
|
|
131
|
+
const BoardProceduralClipSchema = z.object({
|
|
132
|
+
id: idSchema,
|
|
133
|
+
kind: extensionKindSchema,
|
|
134
|
+
kindVersion: z.number().int().positive(),
|
|
135
|
+
target: BoardAnimationTargetSchema,
|
|
136
|
+
start: finiteSchema.nonnegative(),
|
|
137
|
+
duration: finiteSchema.positive(),
|
|
138
|
+
layer: z.enum([
|
|
139
|
+
"behind",
|
|
140
|
+
"content",
|
|
141
|
+
"front",
|
|
142
|
+
"screen"
|
|
143
|
+
]).default("content"),
|
|
144
|
+
fill: z.enum([
|
|
145
|
+
"none",
|
|
146
|
+
"backwards",
|
|
147
|
+
"forwards",
|
|
148
|
+
"both"
|
|
149
|
+
]).default("none"),
|
|
150
|
+
easing: BoardEasingSchema.default("linear"),
|
|
151
|
+
params: jsonObjectSchema.default({}),
|
|
152
|
+
assetRefs: z.array(z.object({
|
|
153
|
+
type: z.enum(["space-file", "extension"]),
|
|
154
|
+
ref: z.string().min(1).max(4096),
|
|
155
|
+
digest: z.string().min(16).max(160).optional()
|
|
156
|
+
}).strict()).default([]),
|
|
157
|
+
seed: idSchema,
|
|
158
|
+
metadata: jsonObjectSchema.default({})
|
|
159
|
+
}).strict();
|
|
160
|
+
const BoardTimelineMarkerSchema = z.object({
|
|
161
|
+
id: idSchema,
|
|
162
|
+
time: finiteSchema.nonnegative(),
|
|
163
|
+
duration: finiteSchema.nonnegative().optional(),
|
|
164
|
+
metadata: jsonObjectSchema.default({})
|
|
165
|
+
}).strict();
|
|
166
|
+
const BoardTimelineSchema = z.object({
|
|
167
|
+
duration: finiteSchema.nonnegative(),
|
|
168
|
+
tracks: z.array(BoardTrackSchema).max(5e4).default([]),
|
|
169
|
+
clips: z.array(BoardProceduralClipSchema).max(5e4).default([]),
|
|
170
|
+
markers: z.array(BoardTimelineMarkerSchema).max(1e4).default([])
|
|
171
|
+
}).strict().superRefine((timeline, context) => {
|
|
172
|
+
const ids = /* @__PURE__ */ new Set();
|
|
173
|
+
const channels = /* @__PURE__ */ new Set();
|
|
174
|
+
for (const [index, track] of timeline.tracks.entries()) {
|
|
175
|
+
if (ids.has(track.id)) context.addIssue({
|
|
176
|
+
code: "custom",
|
|
177
|
+
message: `duplicate timeline id: ${track.id}`,
|
|
178
|
+
path: [
|
|
179
|
+
"tracks",
|
|
180
|
+
index,
|
|
181
|
+
"id"
|
|
182
|
+
]
|
|
183
|
+
});
|
|
184
|
+
ids.add(track.id);
|
|
185
|
+
const targetId = track.target.type === "item" ? track.target.itemId : track.target.type === "effect" ? track.target.effectId : track.target.type;
|
|
186
|
+
const key = `${track.target.type}:${targetId}:${track.channel}`;
|
|
187
|
+
if (channels.has(key)) context.addIssue({
|
|
188
|
+
code: "custom",
|
|
189
|
+
message: `multiple tracks control ${key}`,
|
|
190
|
+
path: [
|
|
191
|
+
"tracks",
|
|
192
|
+
index,
|
|
193
|
+
"channel"
|
|
194
|
+
]
|
|
195
|
+
});
|
|
196
|
+
channels.add(key);
|
|
197
|
+
for (const [keyframeIndex, keyframe] of track.keyframes.entries()) if (keyframe.time > timeline.duration) context.addIssue({
|
|
198
|
+
code: "custom",
|
|
199
|
+
message: "keyframe exceeds timeline duration",
|
|
200
|
+
path: [
|
|
201
|
+
"tracks",
|
|
202
|
+
index,
|
|
203
|
+
"keyframes",
|
|
204
|
+
keyframeIndex,
|
|
205
|
+
"time"
|
|
206
|
+
]
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
for (const [index, clip] of timeline.clips.entries()) {
|
|
210
|
+
if (ids.has(clip.id)) context.addIssue({
|
|
211
|
+
code: "custom",
|
|
212
|
+
message: `duplicate timeline id: ${clip.id}`,
|
|
213
|
+
path: [
|
|
214
|
+
"clips",
|
|
215
|
+
index,
|
|
216
|
+
"id"
|
|
217
|
+
]
|
|
218
|
+
});
|
|
219
|
+
ids.add(clip.id);
|
|
220
|
+
if (clip.start + clip.duration > timeline.duration) context.addIssue({
|
|
221
|
+
code: "custom",
|
|
222
|
+
message: "clip exceeds timeline duration",
|
|
223
|
+
path: [
|
|
224
|
+
"clips",
|
|
225
|
+
index,
|
|
226
|
+
"duration"
|
|
227
|
+
]
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
for (const [index, marker] of timeline.markers.entries()) {
|
|
231
|
+
if (ids.has(marker.id)) context.addIssue({
|
|
232
|
+
code: "custom",
|
|
233
|
+
message: `duplicate timeline id: ${marker.id}`,
|
|
234
|
+
path: [
|
|
235
|
+
"markers",
|
|
236
|
+
index,
|
|
237
|
+
"id"
|
|
238
|
+
]
|
|
239
|
+
});
|
|
240
|
+
ids.add(marker.id);
|
|
241
|
+
if (marker.time + (marker.duration ?? 0) > timeline.duration) context.addIssue({
|
|
242
|
+
code: "custom",
|
|
243
|
+
message: "marker exceeds timeline duration",
|
|
244
|
+
path: ["markers", index]
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
const BoardCompositionPlaybackSchema = z.object({
|
|
249
|
+
loop: z.boolean().default(false),
|
|
250
|
+
endBehavior: z.enum(["hold", "reset"]).default("hold"),
|
|
251
|
+
reducedMotion: z.discriminatedUnion("mode", [
|
|
252
|
+
z.object({ mode: z.literal("base") }).strict(),
|
|
253
|
+
z.object({
|
|
254
|
+
mode: z.literal("time"),
|
|
255
|
+
time: finiteSchema.nonnegative()
|
|
256
|
+
}).strict(),
|
|
257
|
+
z.object({
|
|
258
|
+
mode: z.literal("marker"),
|
|
259
|
+
markerId: idSchema
|
|
260
|
+
}).strict()
|
|
261
|
+
]).default({ mode: "base" })
|
|
262
|
+
}).strict();
|
|
263
|
+
const compositionFields = {
|
|
264
|
+
id: idSchema,
|
|
265
|
+
name: z.string().min(1).max(255),
|
|
266
|
+
timeline: BoardTimelineSchema,
|
|
267
|
+
playback: BoardCompositionPlaybackSchema.default({
|
|
268
|
+
loop: false,
|
|
269
|
+
endBehavior: "hold",
|
|
270
|
+
reducedMotion: { mode: "base" }
|
|
271
|
+
}),
|
|
272
|
+
metadata: jsonObjectSchema.default({})
|
|
273
|
+
};
|
|
274
|
+
function validateCompositionFallback(composition, context) {
|
|
275
|
+
const fallback = composition.playback.reducedMotion;
|
|
276
|
+
if (fallback.mode === "time" && fallback.time > composition.timeline.duration) context.addIssue({
|
|
277
|
+
code: "custom",
|
|
278
|
+
message: "reduced-motion time exceeds timeline duration",
|
|
279
|
+
path: [
|
|
280
|
+
"playback",
|
|
281
|
+
"reducedMotion",
|
|
282
|
+
"time"
|
|
283
|
+
]
|
|
284
|
+
});
|
|
285
|
+
if (fallback.mode === "marker" && !composition.timeline.markers.some((marker) => marker.id === fallback.markerId)) context.addIssue({
|
|
286
|
+
code: "custom",
|
|
287
|
+
message: `marker does not exist: ${fallback.markerId}`,
|
|
288
|
+
path: [
|
|
289
|
+
"playback",
|
|
290
|
+
"reducedMotion",
|
|
291
|
+
"markerId"
|
|
292
|
+
]
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
const BoardCompositionInputSchema = z.object(compositionFields).strict().superRefine(validateCompositionFallback);
|
|
296
|
+
const BoardCompositionSchema = z.object({
|
|
297
|
+
...compositionFields,
|
|
298
|
+
revision: z.number().int().nonnegative().default(0)
|
|
299
|
+
}).strict().superRefine(validateCompositionFallback);
|
|
300
|
+
/** Accept inspect/get output as apply input while stripping server-owned revision. */
|
|
301
|
+
function parseBoardCompositionInput(value) {
|
|
302
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
303
|
+
const { revision: _revision, ...input } = value;
|
|
304
|
+
return BoardCompositionInputSchema.parse(input);
|
|
305
|
+
}
|
|
306
|
+
return BoardCompositionInputSchema.parse(value);
|
|
307
|
+
}
|
|
308
|
+
Object.entries(BOARD_ANIMATION_CHANNELS).map(([id, definition]) => ({
|
|
309
|
+
id,
|
|
310
|
+
version: 1,
|
|
311
|
+
targets: definition.targets,
|
|
312
|
+
interpolations: definition.interpolations,
|
|
313
|
+
..."coordinateSpace" in definition ? { coordinateSpace: definition.coordinateSpace } : {},
|
|
314
|
+
..."unit" in definition ? { unit: definition.unit } : {},
|
|
315
|
+
valueSchema: z.toJSONSchema(definition.value)
|
|
316
|
+
}));
|
|
317
|
+
//#endregion
|
|
318
|
+
export { BOARD_ANIMATION_CHANNELS, BOARD_EASINGS, BoardAnimationTargetSchema, BoardCompositionInputSchema, BoardCompositionPlaybackSchema, BoardCompositionSchema, BoardEasingSchema, BoardProceduralClipSchema, BoardTimelineMarkerSchema, BoardTimelineSchema, BoardTrackSchema, parseBoardCompositionInput };
|
|
@@ -11,7 +11,6 @@ const DEFAULT_BOARD_RENDER_LIMITS = {
|
|
|
11
11
|
simulationSteps: 1e5
|
|
12
12
|
};
|
|
13
13
|
const BOARD_BUILTIN_CLIP_KINDS = [
|
|
14
|
-
"motion.keyframes",
|
|
15
14
|
"motion.path",
|
|
16
15
|
"draw.reveal",
|
|
17
16
|
"draw.handwrite",
|
|
@@ -20,9 +19,6 @@ const BOARD_BUILTIN_CLIP_KINDS = [
|
|
|
20
19
|
"effects.trail",
|
|
21
20
|
"effects.impact",
|
|
22
21
|
"effects.flash",
|
|
23
|
-
"effects.color",
|
|
24
|
-
"camera.pan",
|
|
25
|
-
"camera.zoom",
|
|
26
22
|
"camera.focus",
|
|
27
23
|
"camera.shake"
|
|
28
24
|
];
|
|
@@ -63,16 +59,6 @@ const BOARD_FONT_STACK = "\"Geist\", system-ui, -apple-system, \"Noto Sans CJK S
|
|
|
63
59
|
const BOARD_MONO_FONT_STACK = "\"Geist Mono\", \"Fira Code\", ui-monospace, \"Noto Sans Mono CJK SC\", monospace";
|
|
64
60
|
function clipSchema(id) {
|
|
65
61
|
switch (id) {
|
|
66
|
-
case "motion.keyframes": return { params: {
|
|
67
|
-
x: {
|
|
68
|
-
coordinateSpace: "world-offset",
|
|
69
|
-
unit: "board"
|
|
70
|
-
},
|
|
71
|
-
y: {
|
|
72
|
-
coordinateSpace: "world-offset",
|
|
73
|
-
unit: "board"
|
|
74
|
-
}
|
|
75
|
-
} };
|
|
76
62
|
case "motion.path": return { params: { points: {
|
|
77
63
|
coordinateSpace: "world-offset",
|
|
78
64
|
unit: "board"
|
|
@@ -81,17 +67,6 @@ function clipSchema(id) {
|
|
|
81
67
|
coordinateSpace: "world",
|
|
82
68
|
unit: "board"
|
|
83
69
|
} } };
|
|
84
|
-
case "camera.pan": return { params: {
|
|
85
|
-
x: {
|
|
86
|
-
coordinateSpace: "screen-offset",
|
|
87
|
-
unit: "css-px"
|
|
88
|
-
},
|
|
89
|
-
y: {
|
|
90
|
-
coordinateSpace: "screen-offset",
|
|
91
|
-
unit: "css-px"
|
|
92
|
-
}
|
|
93
|
-
} };
|
|
94
|
-
case "camera.zoom": return { params: { scale: { unit: "ratio" } } };
|
|
95
70
|
case "camera.focus": return { params: {
|
|
96
71
|
focus: {
|
|
97
72
|
coordinateSpace: "world",
|
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
import { BoardCoordinateSpace } from "./board-constants.js";
|
|
2
1
|
import { z } from "zod";
|
|
3
2
|
//#region ../protocol/dist/board-node.d.ts
|
|
4
3
|
declare const BOARD_COLOR_IDS: readonly ["brand", "neutral", "black", "white", "blue", "green", "amber", "violet", "rose"];
|
|
5
4
|
type BoardColorId = (typeof BOARD_COLOR_IDS)[number];
|
|
6
5
|
declare const BOARD_GEO_KINDS: readonly ["rectangle", "rounded", "ellipse", "diamond", "triangle"];
|
|
7
6
|
type BoardGeoKind = (typeof BOARD_GEO_KINDS)[number];
|
|
8
|
-
type BoardNodeValidationDiagnostic = {
|
|
9
|
-
severity: "error";
|
|
10
|
-
code: "INVALID_BOARD_NODE" | "INVALID_BOARD_GEOMETRY";
|
|
11
|
-
message: string;
|
|
12
|
-
path: string;
|
|
13
|
-
expected?: string;
|
|
14
|
-
received?: unknown;
|
|
15
|
-
allowedValues?: readonly string[];
|
|
16
|
-
coordinateSpace?: BoardCoordinateSpace;
|
|
17
|
-
};
|
|
18
7
|
//#endregion
|
|
19
|
-
export { BOARD_COLOR_IDS, BOARD_GEO_KINDS, BoardColorId, BoardGeoKind
|
|
8
|
+
export { BOARD_COLOR_IDS, BOARD_GEO_KINDS, BoardColorId, BoardGeoKind };
|
|
@@ -155,85 +155,5 @@ function jsonSchema(schema) {
|
|
|
155
155
|
return z.toJSONSchema(schema);
|
|
156
156
|
}
|
|
157
157
|
jsonSchema(nodeEnvelopeSchema), Object.fromEntries(BOARD_NATIVE_NODE_TYPES.map((type) => [type, jsonSchema(dataSchemas[type])])), Object.fromEntries(BOARD_NATIVE_NODE_TYPES.map((type) => [type, jsonSchema(viewSchemas[type])]));
|
|
158
|
-
function issueDiagnostic(issue, path) {
|
|
159
|
-
const fullPath = [path, ...issue.path].join(".");
|
|
160
|
-
const values = "values" in issue && Array.isArray(issue.values) ? issue.values.filter((value) => typeof value === "string") : void 0;
|
|
161
|
-
return {
|
|
162
|
-
severity: "error",
|
|
163
|
-
code: "INVALID_BOARD_NODE",
|
|
164
|
-
message: `${fullPath}: ${issue.message}`,
|
|
165
|
-
path: fullPath,
|
|
166
|
-
...values?.length ? { allowedValues: values } : {}
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
function drawGeometryDiagnostic(node, data, path) {
|
|
170
|
-
let minX = Number.POSITIVE_INFINITY;
|
|
171
|
-
let minY = Number.POSITIVE_INFINITY;
|
|
172
|
-
let maxX = Number.NEGATIVE_INFINITY;
|
|
173
|
-
let maxY = Number.NEGATIVE_INFINITY;
|
|
174
|
-
for (const point of data.points) {
|
|
175
|
-
const radius = Math.max(.5, data.size / 2 * (.5 + point.p));
|
|
176
|
-
minX = Math.min(minX, point.x - radius);
|
|
177
|
-
minY = Math.min(minY, point.y - radius);
|
|
178
|
-
maxX = Math.max(maxX, point.x + radius);
|
|
179
|
-
maxY = Math.max(maxY, point.y + radius);
|
|
180
|
-
}
|
|
181
|
-
const width = Math.max(1, maxX - minX);
|
|
182
|
-
const height = Math.max(1, maxY - minY);
|
|
183
|
-
const tolerance = Math.max(.01, node.width * 1e-6, node.height * 1e-6);
|
|
184
|
-
if (Math.abs(minX) <= tolerance && Math.abs(minY) <= tolerance && Math.abs(width - node.width) <= tolerance && Math.abs(height - node.height) <= tolerance) return null;
|
|
185
|
-
return {
|
|
186
|
-
severity: "error",
|
|
187
|
-
code: "INVALID_BOARD_GEOMETRY",
|
|
188
|
-
message: `${path}.data.points must use frame-local coordinates and match the node frame`,
|
|
189
|
-
path: `${path}.data.points`,
|
|
190
|
-
expected: "frame-local points with bounds matching width and height",
|
|
191
|
-
coordinateSpace: "frame-local"
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
function validateBoardNodeInput(node, path = "node") {
|
|
195
|
-
const envelopeResult = nodeEnvelopeSchema.safeParse(node);
|
|
196
|
-
if (!envelopeResult.success) return envelopeResult.error.issues.map((issue) => issueDiagnostic(issue, path));
|
|
197
|
-
if (typeof node.type !== "string" || !BOARD_NATIVE_NODE_TYPES.includes(node.type)) return [{
|
|
198
|
-
severity: "error",
|
|
199
|
-
code: "INVALID_BOARD_NODE",
|
|
200
|
-
message: `${path}.type is not supported`,
|
|
201
|
-
path: `${path}.type`,
|
|
202
|
-
expected: "BoardNativeNodeType",
|
|
203
|
-
received: node.type,
|
|
204
|
-
allowedValues: BOARD_NATIVE_NODE_TYPES
|
|
205
|
-
}];
|
|
206
|
-
const type = node.type;
|
|
207
|
-
const dataResult = dataSchemas[type].safeParse(node.data ?? {});
|
|
208
|
-
if (!dataResult.success) return dataResult.error.issues.map((issue) => issueDiagnostic(issue, `${path}.data`));
|
|
209
|
-
const viewResult = viewSchemas[type].safeParse(node.view ?? {});
|
|
210
|
-
if (!viewResult.success) return viewResult.error.issues.map((issue) => issueDiagnostic(issue, `${path}.view`));
|
|
211
|
-
if (type === "image" || type === "video" || type === "audio" || type === "file") {
|
|
212
|
-
if (node.refKind !== "space_file" || typeof node.refPath !== "string" || !node.refPath) return [{
|
|
213
|
-
severity: "error",
|
|
214
|
-
code: "INVALID_BOARD_NODE",
|
|
215
|
-
message: `${path} requires a space file reference`,
|
|
216
|
-
path: `${path}.refPath`,
|
|
217
|
-
expected: "non-empty refPath with refKind space_file"
|
|
218
|
-
}];
|
|
219
|
-
}
|
|
220
|
-
if (type === "draw") {
|
|
221
|
-
const diagnostic = drawGeometryDiagnostic(node, dataResult.data, path);
|
|
222
|
-
return diagnostic ? [diagnostic] : [];
|
|
223
|
-
}
|
|
224
|
-
if (type === "arrow") {
|
|
225
|
-
const data = dataResult.data;
|
|
226
|
-
const inside = (point) => point.x >= node.x && point.x <= node.x + node.width && point.y >= node.y && point.y <= node.y + node.height;
|
|
227
|
-
if (!inside(data.start) || !inside(data.end)) return [{
|
|
228
|
-
severity: "error",
|
|
229
|
-
code: "INVALID_BOARD_GEOMETRY",
|
|
230
|
-
message: `${path}.data endpoints must be covered by the node frame`,
|
|
231
|
-
path: `${path}.data`,
|
|
232
|
-
expected: "world-space endpoints inside the node frame",
|
|
233
|
-
coordinateSpace: "world"
|
|
234
|
-
}];
|
|
235
|
-
}
|
|
236
|
-
return [];
|
|
237
|
-
}
|
|
238
158
|
//#endregion
|
|
239
|
-
export { BOARD_COLOR_IDS, BOARD_GEO_KINDS, BOARD_NATIVE_NODE_TYPES, BoardColorIdSchema, BoardGeoKindSchema
|
|
159
|
+
export { BOARD_COLOR_IDS, BOARD_GEO_KINDS, BOARD_NATIVE_NODE_TYPES, BoardColorIdSchema, BoardGeoKindSchema };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./board.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BoardCapability, BoardCoordinateSpace, BoardRenderCost } from "./board-constants.js";
|
|
2
2
|
import { BoardConnectionInput, BoardConnectionPatch } from "./board-connection.js";
|
|
3
|
+
import { BoardComposition } from "./board-composition.js";
|
|
3
4
|
import "./board-node.js";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
//#region ../protocol/dist/board.d.ts
|
|
@@ -18,17 +19,6 @@ declare class InvalidBoardFileError extends Error {
|
|
|
18
19
|
}
|
|
19
20
|
declare function parseBoardManifest(input: string | unknown): BoardManifest;
|
|
20
21
|
declare function serializeBoardManifest(manifest: BoardManifest): string;
|
|
21
|
-
declare const BoardTargetSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
22
|
-
type: z.ZodLiteral<"node">;
|
|
23
|
-
nodeId: z.ZodString;
|
|
24
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
25
|
-
type: z.ZodLiteral<"effect">;
|
|
26
|
-
effectId: z.ZodString;
|
|
27
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
28
|
-
type: z.ZodLiteral<"board">;
|
|
29
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
30
|
-
type: z.ZodLiteral<"camera">;
|
|
31
|
-
}, z.core.$strip>], "type">;
|
|
32
22
|
declare const BoardCameraStateSchema: z.ZodObject<{
|
|
33
23
|
centerX: z.ZodNumber;
|
|
34
24
|
centerY: z.ZodNumber;
|
|
@@ -43,11 +33,11 @@ declare const BoardCameraFocusSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
43
33
|
height: z.ZodNumber;
|
|
44
34
|
}, z.core.$strip>;
|
|
45
35
|
}, z.core.$strip>, z.ZodObject<{
|
|
46
|
-
type: z.ZodLiteral<"
|
|
47
|
-
|
|
36
|
+
type: z.ZodLiteral<"item">;
|
|
37
|
+
itemId: z.ZodString;
|
|
48
38
|
}, z.core.$strip>, z.ZodObject<{
|
|
49
|
-
type: z.ZodLiteral<"
|
|
50
|
-
|
|
39
|
+
type: z.ZodLiteral<"items">;
|
|
40
|
+
itemIds: z.ZodArray<z.ZodString>;
|
|
51
41
|
}, z.core.$strip>, z.ZodObject<{
|
|
52
42
|
type: z.ZodLiteral<"frame">;
|
|
53
43
|
frameId: z.ZodString;
|
|
@@ -62,11 +52,11 @@ declare const BoardCameraFocusParamsSchema: z.ZodObject<{
|
|
|
62
52
|
height: z.ZodNumber;
|
|
63
53
|
}, z.core.$strip>;
|
|
64
54
|
}, z.core.$strip>, z.ZodObject<{
|
|
65
|
-
type: z.ZodLiteral<"
|
|
66
|
-
|
|
55
|
+
type: z.ZodLiteral<"item">;
|
|
56
|
+
itemId: z.ZodString;
|
|
67
57
|
}, z.core.$strip>, z.ZodObject<{
|
|
68
|
-
type: z.ZodLiteral<"
|
|
69
|
-
|
|
58
|
+
type: z.ZodLiteral<"items">;
|
|
59
|
+
itemIds: z.ZodArray<z.ZodString>;
|
|
70
60
|
}, z.core.$strip>, z.ZodObject<{
|
|
71
61
|
type: z.ZodLiteral<"frame">;
|
|
72
62
|
frameId: z.ZodString;
|
|
@@ -87,63 +77,15 @@ declare const BoardAssetRefSchema: z.ZodObject<{
|
|
|
87
77
|
ref: z.ZodString;
|
|
88
78
|
digest: z.ZodOptional<z.ZodString>;
|
|
89
79
|
}, z.core.$strip>;
|
|
90
|
-
declare const BoardClipSchema: z.ZodObject<{
|
|
91
|
-
id: z.ZodString;
|
|
92
|
-
sequenceId: z.ZodString;
|
|
93
|
-
kind: z.ZodString;
|
|
94
|
-
kindVersion: z.ZodNumber;
|
|
95
|
-
target: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
96
|
-
type: z.ZodLiteral<"node">;
|
|
97
|
-
nodeId: z.ZodString;
|
|
98
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
99
|
-
type: z.ZodLiteral<"effect">;
|
|
100
|
-
effectId: z.ZodString;
|
|
101
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
102
|
-
type: z.ZodLiteral<"board">;
|
|
103
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
104
|
-
type: z.ZodLiteral<"camera">;
|
|
105
|
-
}, z.core.$strip>], "type">;
|
|
106
|
-
start: z.ZodNumber;
|
|
107
|
-
duration: z.ZodNumber;
|
|
108
|
-
layer: z.ZodDefault<z.ZodEnum<{
|
|
109
|
-
behind: "behind";
|
|
110
|
-
content: "content";
|
|
111
|
-
front: "front";
|
|
112
|
-
screen: "screen";
|
|
113
|
-
}>>;
|
|
114
|
-
fill: z.ZodDefault<z.ZodEnum<{
|
|
115
|
-
backwards: "backwards";
|
|
116
|
-
both: "both";
|
|
117
|
-
forwards: "forwards";
|
|
118
|
-
none: "none";
|
|
119
|
-
}>>;
|
|
120
|
-
easing: z.ZodDefault<z.ZodString>;
|
|
121
|
-
params: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
122
|
-
keyframes: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
123
|
-
at: z.ZodNumber;
|
|
124
|
-
value: z.ZodUnknown;
|
|
125
|
-
easing: z.ZodOptional<z.ZodString>;
|
|
126
|
-
}, z.core.$strip>>>;
|
|
127
|
-
assetRefs: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
128
|
-
type: z.ZodEnum<{
|
|
129
|
-
extension: "extension";
|
|
130
|
-
"space-file": "space-file";
|
|
131
|
-
}>;
|
|
132
|
-
ref: z.ZodString;
|
|
133
|
-
digest: z.ZodOptional<z.ZodString>;
|
|
134
|
-
}, z.core.$strip>>>;
|
|
135
|
-
seed: z.ZodString;
|
|
136
|
-
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
137
|
-
}, z.core.$strip>;
|
|
138
80
|
declare const BoardEffectSchema: z.ZodObject<{
|
|
139
81
|
id: z.ZodString;
|
|
140
82
|
boardId: z.ZodString;
|
|
141
83
|
target: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
142
|
-
type: z.ZodLiteral<"
|
|
143
|
-
|
|
144
|
-
}, z.core.$
|
|
84
|
+
type: z.ZodLiteral<"item">;
|
|
85
|
+
itemId: z.ZodString;
|
|
86
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
145
87
|
type: z.ZodLiteral<"board">;
|
|
146
|
-
}, z.core.$
|
|
88
|
+
}, z.core.$strict>], "type">;
|
|
147
89
|
kind: z.ZodString;
|
|
148
90
|
kindVersion: z.ZodNumber;
|
|
149
91
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -175,24 +117,11 @@ declare const BoardEffectSchema: z.ZodObject<{
|
|
|
175
117
|
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
176
118
|
revision: z.ZodNumber;
|
|
177
119
|
}, z.core.$strip>;
|
|
178
|
-
declare const BoardSequenceSchema: z.ZodObject<{
|
|
179
|
-
id: z.ZodString;
|
|
180
|
-
boardId: z.ZodString;
|
|
181
|
-
name: z.ZodString;
|
|
182
|
-
duration: z.ZodNumber;
|
|
183
|
-
seed: z.ZodString;
|
|
184
|
-
restPose: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
185
|
-
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
186
|
-
revision: z.ZodNumber;
|
|
187
|
-
}, z.core.$strip>;
|
|
188
|
-
type BoardTarget = z.infer<typeof BoardTargetSchema>;
|
|
189
120
|
type BoardCameraState = z.infer<typeof BoardCameraStateSchema>;
|
|
190
121
|
type BoardCameraFocus = z.infer<typeof BoardCameraFocusSchema>;
|
|
191
122
|
type BoardCameraFocusParams = z.infer<typeof BoardCameraFocusParamsSchema>;
|
|
192
123
|
type BoardAssetRef = z.infer<typeof BoardAssetRefSchema>;
|
|
193
|
-
type BoardClip = z.infer<typeof BoardClipSchema>;
|
|
194
124
|
type BoardEffect = z.infer<typeof BoardEffectSchema>;
|
|
195
|
-
type BoardSequence = z.infer<typeof BoardSequenceSchema>;
|
|
196
125
|
type BoardRecord = {
|
|
197
126
|
id: string;
|
|
198
127
|
spaceId: string;
|
|
@@ -285,15 +214,14 @@ type BoardOperation = (BoardOperationBase & {
|
|
|
285
214
|
effectId: string;
|
|
286
215
|
};
|
|
287
216
|
}) | (BoardOperationBase & {
|
|
288
|
-
type: "
|
|
217
|
+
type: "composition.apply";
|
|
289
218
|
payload: {
|
|
290
|
-
|
|
291
|
-
clips: Array<Omit<BoardClip, "sequenceId">>;
|
|
219
|
+
composition: Omit<BoardComposition, "revision">;
|
|
292
220
|
};
|
|
293
221
|
}) | (BoardOperationBase & {
|
|
294
|
-
type: "
|
|
222
|
+
type: "composition.delete";
|
|
295
223
|
payload: {
|
|
296
|
-
|
|
224
|
+
compositionId: string;
|
|
297
225
|
};
|
|
298
226
|
});
|
|
299
227
|
type BoardDiagnostic = {
|
|
@@ -314,11 +242,10 @@ type BoardValidationResult = {
|
|
|
314
242
|
};
|
|
315
243
|
/** Persisted on `boards.metadata.playback`: how a Board plays when opened. */
|
|
316
244
|
declare const BoardPlaybackPolicySchema: z.ZodObject<{
|
|
317
|
-
|
|
245
|
+
compositionId: z.ZodString;
|
|
318
246
|
delayMs: z.ZodDefault<z.ZodNumber>;
|
|
319
|
-
loop: z.ZodDefault<z.ZodBoolean>;
|
|
320
247
|
}, z.core.$strip>;
|
|
321
248
|
type BoardPlaybackPolicy = z.infer<typeof BoardPlaybackPolicySchema>;
|
|
322
249
|
declare function isBoardPath(path: string): boolean;
|
|
323
250
|
//#endregion
|
|
324
|
-
export { BOARD_DELETE_REASONS, BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardAssetRef, BoardAssetRefSchema, BoardCameraFocus, BoardCameraFocusParams, BoardCameraFocusParamsSchema, BoardCameraFocusSchema, BoardCameraState, BoardCameraStateSchema,
|
|
251
|
+
export { BOARD_DELETE_REASONS, BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardAssetRef, BoardAssetRefSchema, BoardCameraFocus, BoardCameraFocusParams, BoardCameraFocusParamsSchema, BoardCameraFocusSchema, BoardCameraState, BoardCameraStateSchema, type BoardCapability, BoardDeleteReason, BoardDiagnostic, BoardEffect, BoardEffectSchema, BoardManifest, BoardManifestSchema, BoardNodeInput, BoardNodeRecord, BoardOperation, BoardPlaybackPolicy, BoardPlaybackPolicySchema, BoardRecord, type BoardRenderCost, BoardValidationResult, InvalidBoardFileError, isBoardPath, parseBoardManifest, serializeBoardManifest };
|