@neta-art/cohub 10.0.0 → 11.1.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 -7
- package/dist/board/editor/animation.d.ts +3 -0
- package/dist/board/editor/animation.js +16 -1
- package/dist/board/editor/clipboard.js +7 -0
- package/dist/board/editor/copy.js +23 -18
- package/dist/board/editor/creation.d.ts +7 -3
- package/dist/board/editor/creation.js +5 -4
- package/dist/board/editor/deletion.js +3 -3
- package/dist/board/editor/document.d.ts +8 -2
- package/dist/board/editor/document.js +54 -7
- package/dist/board/editor/editor.d.ts +22 -7
- package/dist/board/editor/editor.js +12 -2
- package/dist/board/editor/index.d.ts +2 -2
- package/dist/board/editor/interaction.d.ts +8 -2
- package/dist/board/editor/interaction.js +34 -1
- package/dist/board/editor/query.d.ts +5 -5
- package/dist/board/editor/query.js +14 -12
- package/dist/board/editor/selection.js +2 -1
- package/dist/board/editor/snapshots.d.ts +0 -2
- package/dist/board/editor/snapshots.js +4 -20
- package/dist/board/export/index.d.ts +25 -4
- package/dist/board/export/index.js +45 -12
- package/dist/board/export/node/index.d.ts +5 -4
- package/dist/board/export/node/index.js +16 -11
- package/dist/board/export/node/scripts.d.ts +16 -0
- package/dist/board/export/node/scripts.js +258 -0
- package/dist/board/export/scene.d.ts +2 -1
- package/dist/board/export/scene.js +24 -7
- package/dist/board/model/animation.d.ts +4 -1
- package/dist/board/model/animation.js +34 -7
- package/dist/board/model/authoring.d.ts +20 -0
- package/dist/board/model/authoring.js +185 -0
- package/dist/board/model/export-plan.js +1 -0
- package/dist/board/model/file-preview.js +1 -1
- package/dist/board/model/file-snapshot.js +3 -2
- package/dist/board/model/image-key.js +7 -3
- package/dist/board/model/index.d.ts +15 -7
- package/dist/board/model/index.js +16 -9
- package/dist/board/model/items/builtin.js +2 -2
- package/dist/board/model/items/create.d.ts +19 -4
- package/dist/board/model/items/create.js +130 -9
- package/dist/board/model/items/index.d.ts +2 -2
- package/dist/board/model/items/index.js +2 -2
- package/dist/board/model/media-playback.d.ts +2 -1
- package/dist/board/model/media-playback.js +15 -5
- package/dist/board/model/media.js +7 -1
- package/dist/board/model/overlay-placement.d.ts +25 -0
- package/dist/board/model/overlay-placement.js +35 -0
- package/dist/board/model/replay.d.ts +1 -1
- package/dist/board/model/replay.js +1 -0
- package/dist/board/model/sampling.d.ts +19 -0
- package/dist/board/model/sampling.js +96 -0
- package/dist/board/model/script-example.d.ts +4 -0
- package/dist/board/model/script-example.js +21 -0
- package/dist/board/model/script-hit.d.ts +27 -0
- package/dist/board/model/script-hit.js +109 -0
- package/dist/board/model/script-index.d.ts +7 -0
- package/dist/board/model/script-index.js +15 -0
- package/dist/board/model/script-observers.d.ts +18 -0
- package/dist/board/model/script-observers.js +92 -0
- package/dist/board/model/script-scene.d.ts +24 -0
- package/dist/board/model/script-scene.js +294 -0
- package/dist/board/model/script.d.ts +149 -0
- package/dist/board/model/script.js +1 -0
- package/dist/board/render/board-background.js +5 -4
- package/dist/board/render/css-color.d.ts +6 -1
- package/dist/board/render/css-color.js +34 -20
- package/dist/board/render/diagnostics.d.ts +20 -0
- package/dist/board/render/diagnostics.js +117 -0
- package/dist/board/render/index.d.ts +9 -6
- package/dist/board/render/index.js +10 -7
- package/dist/board/render/media-interaction.js +1 -1
- package/dist/board/render/palette.d.ts +2 -1
- package/dist/board/render/palette.js +6 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +3 -2
- package/dist/board/render/renderers/audio-card-renderer.js +2 -1
- package/dist/board/render/renderers/board-renderer-registry.d.ts +25 -5
- package/dist/board/render/renderers/board-renderer-registry.js +11 -4
- package/dist/board/render/renderers/custom-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/{sketch-card-renderer.js → custom-card-renderer.js} +18 -16
- package/dist/board/render/renderers/draw-card-renderer.js +3 -2
- package/dist/board/render/renderers/effect-card-renderer.js +22 -5
- package/dist/board/render/renderers/frame-card-renderer.js +30 -14
- package/dist/board/render/renderers/image-card-renderer.js +43 -4
- package/dist/board/render/renderers/shape-card-renderer.js +10 -27
- package/dist/board/render/renderers/task-card-renderer.d.ts +2 -1
- package/dist/board/render/renderers/task-card-renderer.js +220 -71
- package/dist/board/render/renderers/text-card-renderer.js +5 -3
- package/dist/board/render/renderers/unknown-card-renderer.js +1 -0
- package/dist/board/render/renderers/video-card-renderer.js +2 -1
- package/dist/board/render/sampling.d.ts +22 -0
- package/dist/board/render/sampling.js +21 -0
- package/dist/board/render/script-export.d.ts +11 -0
- package/dist/board/render/script-export.js +86 -0
- package/dist/board/render/script-host.d.ts +31 -0
- package/dist/board/render/script-host.js +446 -0
- package/dist/board/render/script-modules.d.ts +2 -0
- package/dist/board/render/script-modules.js +2 -0
- package/dist/board/render/script-runtime.d.ts +29 -0
- package/dist/board/render/script-runtime.js +223 -0
- package/dist/board/render/script-sandbox.d.ts +4 -0
- package/dist/board/render/script-sandbox.js +173 -0
- package/dist/board/render/script-texture.d.ts +11 -0
- package/dist/board/render/script-texture.js +33 -0
- package/dist/board/render/stroke.d.ts +2 -1
- package/dist/board/render/stroke.js +22 -1
- package/dist/board/render/text-measurement.js +1 -1
- package/dist/board/stage/assets.js +7 -2
- package/dist/board/stage/maintenance.d.ts +5 -0
- package/dist/board/stage/maintenance.js +11 -0
- package/dist/board/stage/scene.d.ts +2 -0
- package/dist/board/stage/scene.js +21 -2
- package/dist/board/stage/script-pointer.d.ts +20 -0
- package/dist/board/stage/script-pointer.js +41 -0
- package/dist/board/stage/stage.d.ts +21 -3
- package/dist/board/stage/stage.js +350 -47
- package/dist/board/stage/texture-pool.js +2 -3
- package/dist/chunks/environment.d.ts +305 -27
- package/dist/chunks/environment.js +12 -4
- package/dist/chunks/host-bridge.d.ts +2 -2
- package/dist/chunks/http.d.ts +90 -7
- package/dist/chunks/http.js +157 -64
- package/dist/chunks/transport.js +4 -2
- package/dist/chunks/websocket.d.ts +9 -1
- package/dist/chunks/websocket.js +16 -2
- package/dist/host-bridge.js +2 -1
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +182 -4
- package/dist/index.js +1559 -299
- package/dist/protocol/dist/board-assets.d.ts +1 -0
- package/dist/protocol/dist/board-constants.js +2 -2
- package/dist/protocol/dist/board-model.d.ts +236 -11
- package/dist/protocol/dist/board-model.js +46 -17
- package/dist/protocol/dist/board-patch.js +2 -1
- package/dist/protocol/dist/board-schema.d.ts +4 -2
- package/dist/protocol/dist/board-schema.js +18 -4
- package/dist/protocol/dist/board-script-modules.d.ts +25 -0
- package/dist/protocol/dist/board-script-modules.js +127 -0
- package/dist/protocol/dist/board-task.d.ts +22 -0
- package/dist/{board/model/task.js → protocol/dist/board-task.js} +34 -7
- package/dist/protocol/dist/display/index.d.ts +1 -0
- package/dist/protocol/dist/generation/blocks.d.ts +8 -0
- package/dist/{generation-blocks.js → protocol/dist/generation/blocks.js} +14 -15
- package/dist/protocol/dist/index.d.ts +7 -2
- package/dist/protocol/dist/realtime/types.d.ts +1 -0
- package/dist/protocol/dist/rtc/index.d.ts +1 -0
- package/dist/protocol/dist/task/index.d.ts +4 -0
- package/package.json +2 -1
- package/dist/board/export/node/sketch.d.ts +0 -19
- package/dist/board/export/node/sketch.js +0 -146
- package/dist/board/model/task.d.ts +0 -11
- package/dist/board/render/renderers/sketch-card-renderer.d.ts +0 -5
- package/dist/board/render/sketch-host.d.ts +0 -14
- package/dist/board/render/sketch-host.js +0 -216
- package/dist/types.d.ts +0 -36
|
@@ -90,6 +90,11 @@ type BoardPointerEvent = {
|
|
|
90
90
|
pressure: number;
|
|
91
91
|
samples?: readonly BoardDrawInputSample[];
|
|
92
92
|
};
|
|
93
|
+
type BoardTransformEnd = {
|
|
94
|
+
ids: string[];
|
|
95
|
+
operation: "move" | "resize" | "rotate" | "arrow";
|
|
96
|
+
cancelled: boolean;
|
|
97
|
+
};
|
|
93
98
|
declare function createInteractionModule(ctx: EditorContext): {
|
|
94
99
|
marquee: () => Rect | null;
|
|
95
100
|
hoveredControl: () => BoardTransformControl | null;
|
|
@@ -108,8 +113,9 @@ declare function createInteractionModule(ctx: EditorContext): {
|
|
|
108
113
|
pointerUp: (event: BoardPointerEvent) => void;
|
|
109
114
|
pointerLeave: () => void;
|
|
110
115
|
cancel: () => void;
|
|
111
|
-
|
|
116
|
+
subscribeTransforms(listener: (event: BoardTransformEnd) => void): () => void;
|
|
117
|
+
destroy(): void;
|
|
112
118
|
};
|
|
113
119
|
type InteractionModule = ReturnType<typeof createInteractionModule>;
|
|
114
120
|
//#endregion
|
|
115
|
-
export { BoardInteraction, BoardPointerEvent, InteractionModule, createInteractionModule };
|
|
121
|
+
export { BoardInteraction, BoardPointerEvent, BoardTransformEnd, InteractionModule, createInteractionModule };
|
|
@@ -15,6 +15,23 @@ function angleFrom(center, point) {
|
|
|
15
15
|
return Math.atan2(point.y - center.y, point.x - center.x) * 180 / Math.PI;
|
|
16
16
|
}
|
|
17
17
|
function createInteractionModule(ctx) {
|
|
18
|
+
const transformListeners = /* @__PURE__ */ new Set();
|
|
19
|
+
function transformEnd(gesture, cancelled) {
|
|
20
|
+
if (!transformListeners.size || !("moved" in gesture) || !gesture.moved) return;
|
|
21
|
+
let event;
|
|
22
|
+
if (gesture.type === "translating" || gesture.type === "resizing" || gesture.type === "rotating") event = {
|
|
23
|
+
ids: [...gesture.origin.keys()],
|
|
24
|
+
operation: gesture.type === "translating" ? "move" : gesture.type === "resizing" ? "resize" : "rotate",
|
|
25
|
+
cancelled
|
|
26
|
+
};
|
|
27
|
+
else if (gesture.type === "draggingArrowHandle") event = {
|
|
28
|
+
ids: [gesture.arrowId],
|
|
29
|
+
operation: "arrow",
|
|
30
|
+
cancelled
|
|
31
|
+
};
|
|
32
|
+
else return;
|
|
33
|
+
for (const listener of transformListeners) listener(event);
|
|
34
|
+
}
|
|
18
35
|
const { state, options, registry } = ctx;
|
|
19
36
|
const activePointers = /* @__PURE__ */ new Map();
|
|
20
37
|
let pinch = null;
|
|
@@ -493,6 +510,10 @@ function createInteractionModule(ctx) {
|
|
|
493
510
|
if (activePointers.size > 0) return;
|
|
494
511
|
const gesture = state.interaction;
|
|
495
512
|
if (gesture.type === "drawing" && gesture.pointerId !== event.pointerId) return;
|
|
513
|
+
if (event.cancelled) {
|
|
514
|
+
cancel();
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
496
517
|
state.snapGuides = [];
|
|
497
518
|
state.interaction = { type: "idle" };
|
|
498
519
|
switch (gesture.type) {
|
|
@@ -531,6 +552,7 @@ function createInteractionModule(ctx) {
|
|
|
531
552
|
case "creatingBox": ctx.creation.commitBox(gesture);
|
|
532
553
|
}
|
|
533
554
|
ctx.remote.flushPending();
|
|
555
|
+
transformEnd(gesture, false);
|
|
534
556
|
}
|
|
535
557
|
function pointerLeave() {
|
|
536
558
|
if (state.interaction.type !== "idle") return;
|
|
@@ -538,12 +560,14 @@ function createInteractionModule(ctx) {
|
|
|
538
560
|
state.hoverId = null;
|
|
539
561
|
}
|
|
540
562
|
function cancel() {
|
|
563
|
+
const gesture = state.interaction;
|
|
541
564
|
activePointers.clear();
|
|
542
565
|
pinch = null;
|
|
543
566
|
state.snapGuides = [];
|
|
544
567
|
state.interaction = { type: "idle" };
|
|
545
568
|
ctx.document.discardDraft();
|
|
546
569
|
ctx.remote.flushPending();
|
|
570
|
+
transformEnd(gesture, true);
|
|
547
571
|
}
|
|
548
572
|
const ports = memo(() => [
|
|
549
573
|
state.scene,
|
|
@@ -577,7 +601,16 @@ function createInteractionModule(ctx) {
|
|
|
577
601
|
pointerUp,
|
|
578
602
|
pointerLeave,
|
|
579
603
|
cancel,
|
|
580
|
-
|
|
604
|
+
subscribeTransforms(listener) {
|
|
605
|
+
transformListeners.add(listener);
|
|
606
|
+
return () => {
|
|
607
|
+
transformListeners.delete(listener);
|
|
608
|
+
};
|
|
609
|
+
},
|
|
610
|
+
destroy() {
|
|
611
|
+
activePointers.clear();
|
|
612
|
+
transformListeners.clear();
|
|
613
|
+
}
|
|
581
614
|
};
|
|
582
615
|
}
|
|
583
616
|
//#endregion
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Rect, WorldPoint } from "../model/geometry.js";
|
|
2
|
-
import { BoardSceneItem } from "../model/scene.js";
|
|
2
|
+
import { BoardScene, BoardSceneItem } from "../model/scene.js";
|
|
3
3
|
import "../model/index.js";
|
|
4
4
|
import { EditorContext } from "./context.js";
|
|
5
5
|
//#region src/board/editor/query.d.ts
|
|
6
6
|
declare function createQueryModule(ctx: EditorContext): {
|
|
7
7
|
invalidate: (ids?: readonly string[]) => void;
|
|
8
|
-
boundsOf: (item: BoardSceneItem) => Rect;
|
|
8
|
+
boundsOf: (item: BoardSceneItem, scene?: BoardScene) => Rect;
|
|
9
9
|
itemById: (id: string) => BoardSceneItem | null;
|
|
10
10
|
isLocked: (item: {
|
|
11
11
|
locked?: boolean;
|
|
@@ -14,10 +14,10 @@ declare function createQueryModule(ctx: EditorContext): {
|
|
|
14
14
|
rootsOf: (ids: Iterable<string>) => string[];
|
|
15
15
|
withSubtrees: (ids: Iterable<string>) => Set<string>;
|
|
16
16
|
mediaIdsForPath: (path: string) => ReadonlySet<string>;
|
|
17
|
-
contentBounds: (ids?: Iterable<string
|
|
18
|
-
idsInRect: (rect: Rect) => string[];
|
|
17
|
+
contentBounds: (ids?: Iterable<string>, scene?: BoardScene) => Rect | null;
|
|
18
|
+
idsInRect: (rect: Rect, includeTemporary?: boolean) => string[];
|
|
19
19
|
frameAt: (point: WorldPoint, exclude?: ReadonlySet<string>) => BoardSceneItem | null;
|
|
20
|
-
itemAt: (point: WorldPoint, exclude?: ReadonlySet<string
|
|
20
|
+
itemAt: (point: WorldPoint, exclude?: ReadonlySet<string>, includeTemporary?: boolean) => BoardSceneItem | null;
|
|
21
21
|
labelItemAt: (point: WorldPoint) => BoardSceneItem | null;
|
|
22
22
|
arrowHandleAt: (point: WorldPoint) => "start" | "end" | "mid" | null;
|
|
23
23
|
connectTargetAt: (point: WorldPoint, exclude?: ReadonlySet<string>) => string | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseBoardMediaSource } from "../../protocol/dist/board-model.js";
|
|
1
2
|
import { rectContainsPoint, unionRects } from "../model/geometry.js";
|
|
2
3
|
import { arrowHitRadius, arrowPathBounds, distanceToArrow, resolveSceneArrow } from "../model/arrow-geometry.js";
|
|
3
4
|
import { createSpatialIndex } from "./spatial.js";
|
|
@@ -53,8 +54,8 @@ function createQueryModule(ctx) {
|
|
|
53
54
|
}
|
|
54
55
|
spatial.upsert(upserts);
|
|
55
56
|
}
|
|
56
|
-
function boundsOf(item) {
|
|
57
|
-
if (item.type === "arrow") return arrowPathBounds(resolveSceneArrow(item,
|
|
57
|
+
function boundsOf(item, scene = state.scene) {
|
|
58
|
+
if (item.type === "arrow") return arrowPathBounds(resolveSceneArrow(item, scene), item.style.strokeWidth);
|
|
58
59
|
return registry.bounds(item);
|
|
59
60
|
}
|
|
60
61
|
function itemById(id) {
|
|
@@ -87,7 +88,7 @@ function createQueryModule(ctx) {
|
|
|
87
88
|
const result = /* @__PURE__ */ new Set();
|
|
88
89
|
for (const id of ids) {
|
|
89
90
|
result.add(id);
|
|
90
|
-
for (const child of state.scene.descendants(id)) result.add(child);
|
|
91
|
+
for (const child of state.scene.descendants(id)) if (state.base.items[child]) result.add(child);
|
|
91
92
|
}
|
|
92
93
|
return result;
|
|
93
94
|
}
|
|
@@ -97,6 +98,7 @@ function createQueryModule(ctx) {
|
|
|
97
98
|
for (const item of state.scene.items) {
|
|
98
99
|
if (item.type !== "image" && item.type !== "video" && item.type !== "audio") continue;
|
|
99
100
|
const src = item.props.src;
|
|
101
|
+
if (parseBoardMediaSource(src)?.kind !== "file") continue;
|
|
100
102
|
const ids = mediaIdsByPath.get(src) ?? /* @__PURE__ */ new Set();
|
|
101
103
|
ids.add(item.id);
|
|
102
104
|
mediaIdsByPath.set(src, ids);
|
|
@@ -104,20 +106,20 @@ function createQueryModule(ctx) {
|
|
|
104
106
|
}
|
|
105
107
|
return mediaIdsByPath.get(path) ?? NO_IDS;
|
|
106
108
|
}
|
|
107
|
-
function contentBounds(ids) {
|
|
108
|
-
const scene = state.scene;
|
|
109
|
+
function contentBounds(ids, scene = state.scene) {
|
|
109
110
|
const list = ids ? [...ids].flatMap((id) => scene.get(id) ? [scene.get(id)] : []) : scene.items;
|
|
110
|
-
return unionRects(list.map(boundsOf));
|
|
111
|
+
return unionRects((ctx.document.hasScriptItems ? list.filter((item) => Boolean(state.base.items[item.id])) : list).map((item) => boundsOf(item, scene)));
|
|
111
112
|
}
|
|
112
|
-
function idsInRect(rect) {
|
|
113
|
+
function idsInRect(rect, includeTemporary = false) {
|
|
113
114
|
ensureSpatial();
|
|
114
|
-
|
|
115
|
+
const ids = spatial.idsInRect(rect);
|
|
116
|
+
return includeTemporary || !ctx.document.hasScriptItems ? ids : ids.filter((id) => Boolean(state.base.items[id]));
|
|
115
117
|
}
|
|
116
118
|
function frameAt(point, exclude) {
|
|
117
119
|
ensureSpatial();
|
|
118
120
|
for (const id of spatial.idsAtPoint(point)) {
|
|
119
121
|
const item = state.scene.get(id);
|
|
120
|
-
if (item?.type !== "frame" || exclude?.has(id)) continue;
|
|
122
|
+
if (!state.base.items[id] || item?.type !== "frame" || exclude?.has(id)) continue;
|
|
121
123
|
if (registry.hitTest(item, point)) return item;
|
|
122
124
|
}
|
|
123
125
|
return null;
|
|
@@ -129,11 +131,11 @@ function createQueryModule(ctx) {
|
|
|
129
131
|
}
|
|
130
132
|
return registry.hitTest(item, point);
|
|
131
133
|
}
|
|
132
|
-
function itemAt(point, exclude) {
|
|
134
|
+
function itemAt(point, exclude, includeTemporary = false) {
|
|
133
135
|
ensureSpatial();
|
|
134
136
|
for (const id of spatial.idsAtPoint(point)) {
|
|
135
137
|
const item = state.scene.get(id);
|
|
136
|
-
if (item && !exclude?.has(id) && hitsItem(item, point)) return item;
|
|
138
|
+
if (item && (includeTemporary || state.base.items[id]) && !exclude?.has(id) && hitsItem(item, point)) return item;
|
|
137
139
|
}
|
|
138
140
|
return null;
|
|
139
141
|
}
|
|
@@ -144,7 +146,7 @@ function createQueryModule(ctx) {
|
|
|
144
146
|
const candidates = selection.length === 1 ? [...selection, ...nearby] : nearby;
|
|
145
147
|
for (const id of new Set(candidates)) {
|
|
146
148
|
const item = scene.get(id);
|
|
147
|
-
if (!item || isLocked(item)) continue;
|
|
149
|
+
if (!item || !state.base.items[id] || isLocked(item)) continue;
|
|
148
150
|
if (item.type === "frame" && rectContainsPoint({
|
|
149
151
|
x: item.frame.x,
|
|
150
152
|
y: item.frame.y - 22,
|
|
@@ -19,9 +19,10 @@ function createSelectionModule(ctx) {
|
|
|
19
19
|
const bounds = memo(() => [items()], (selected) => selectionBounds(selected.map((item) => item.frame)));
|
|
20
20
|
const transform = memo(() => [items(), bounds()], (selected, rect) => resolveSelectionTransform(registry, selected, rect));
|
|
21
21
|
function set(ids) {
|
|
22
|
-
state.selection = ids;
|
|
22
|
+
state.selection = ids.filter((id) => Boolean(state.base.items[id]));
|
|
23
23
|
}
|
|
24
24
|
function toggle(id) {
|
|
25
|
+
if (!state.base.items[id]) return;
|
|
25
26
|
const { selection } = state;
|
|
26
27
|
state.selection = selection.includes(id) ? selection.filter((selected) => selected !== id) : [...selection, id];
|
|
27
28
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { BoardTaskSnapshot } from "../../protocol/dist/board-model.js";
|
|
2
1
|
import { BoardFileSnapshotFacts } from "../model/file-snapshot.js";
|
|
3
2
|
import "../model/index.js";
|
|
4
3
|
import { EditorContext } from "./context.js";
|
|
@@ -20,7 +19,6 @@ declare function createSnapshotsModule(ctx: EditorContext): {
|
|
|
20
19
|
snapshot: BoardFileSnapshotFacts;
|
|
21
20
|
replace?: boolean;
|
|
22
21
|
}>) => void;
|
|
23
|
-
applyTaskSnapshots: (snapshots: ReadonlyMap<string, BoardTaskSnapshot>) => void;
|
|
24
22
|
};
|
|
25
23
|
type SnapshotsModule = ReturnType<typeof createSnapshotsModule>;
|
|
26
24
|
//#endregion
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
|
|
1
2
|
import { mergeFileSnapshot } from "../model/file-preview.js";
|
|
2
|
-
import { featuredTaskArtifact } from "../model/task.js";
|
|
3
3
|
import { sameJson } from "./document-edits.js";
|
|
4
4
|
//#region src/board/editor/snapshots.ts
|
|
5
5
|
function fitHeight(item, natural) {
|
|
6
6
|
const height = item.size.width * natural.height / natural.width;
|
|
7
7
|
if (!Number.isFinite(height) || height <= 0) return null;
|
|
8
|
+
const shift = item.type === "task" ? 0 : (item.size.height - height) / 2;
|
|
8
9
|
return {
|
|
9
10
|
...item,
|
|
10
11
|
position: {
|
|
11
12
|
x: item.position.x,
|
|
12
|
-
y: item.position.y +
|
|
13
|
+
y: item.position.y + shift
|
|
13
14
|
},
|
|
14
15
|
size: {
|
|
15
16
|
...item.size,
|
|
@@ -105,27 +106,10 @@ function createSnapshotsModule(ctx) {
|
|
|
105
106
|
}
|
|
106
107
|
commit(changes);
|
|
107
108
|
}
|
|
108
|
-
function applyTaskSnapshots(snapshots) {
|
|
109
|
-
if (snapshots.size === 0) return;
|
|
110
|
-
const changes = /* @__PURE__ */ new Map();
|
|
111
|
-
for (const [id, item] of Object.entries(state.base.items)) {
|
|
112
|
-
if (item.type !== "task") continue;
|
|
113
|
-
const snapshot = snapshots.get(item.props.taskRunId);
|
|
114
|
-
if (snapshot && !sameJson(snapshot, item.props.snapshot)) changes.set(id, {
|
|
115
|
-
...item,
|
|
116
|
-
props: {
|
|
117
|
-
...item.props,
|
|
118
|
-
snapshot
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
commit(changes);
|
|
123
|
-
}
|
|
124
109
|
return {
|
|
125
110
|
applyMediaFileChange,
|
|
126
111
|
adoptMediaNaturalSizes,
|
|
127
|
-
applyFileSnapshots
|
|
128
|
-
applyTaskSnapshots
|
|
112
|
+
applyFileSnapshots
|
|
129
113
|
};
|
|
130
114
|
}
|
|
131
115
|
//#endregion
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { BoardDocument } from "../../protocol/dist/board-model.js";
|
|
2
|
+
import { BoardFrame } from "../../protocol/dist/board-layout.js";
|
|
2
3
|
import "../../protocol/dist/index.js";
|
|
3
|
-
import { BoardSceneItem } from "../model/scene.js";
|
|
4
|
+
import { BoardScene, BoardSceneItem } from "../model/scene.js";
|
|
5
|
+
import { BoardEvaluation } from "../model/animation.js";
|
|
6
|
+
import { BoardAnimationSampler } from "../model/sampling.js";
|
|
4
7
|
import { BoardExportPlan, BoardExportPlanInput, BoardExportRegion } from "../model/export-plan.js";
|
|
5
8
|
import { BoardShapeColors } from "../model/palette.js";
|
|
6
|
-
import { BoardCardRendererResolver, BoardRenderPalette,
|
|
9
|
+
import { BoardCardRendererResolver, BoardRenderPalette, BoardScriptHost } from "../render/renderers/board-renderer-registry.js";
|
|
7
10
|
import "../render/index.js";
|
|
8
11
|
import { BoardExportScene, BoardExportSceneInput, createBoardExportScene } from "./scene.js";
|
|
9
12
|
import { ICanvas, Renderer, Texture } from "pixi.js";
|
|
@@ -11,6 +14,11 @@ import { ICanvas, Renderer, Texture } from "pixi.js";
|
|
|
11
14
|
type BoardExportBackground = "paper" | "transparent" | number;
|
|
12
15
|
type BoardExportOptions = {
|
|
13
16
|
region?: BoardExportRegion;
|
|
17
|
+
camera?: {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
};
|
|
21
|
+
sampler?: BoardAnimationSampler;
|
|
14
22
|
at?: {
|
|
15
23
|
animation?: string;
|
|
16
24
|
time: number;
|
|
@@ -22,7 +30,7 @@ type BoardExportOptions = {
|
|
|
22
30
|
palette?: Partial<BoardRenderPalette>;
|
|
23
31
|
colors?: BoardShapeColors;
|
|
24
32
|
textures?: Map<string, Texture>;
|
|
25
|
-
|
|
33
|
+
scripts?: BoardScriptHost;
|
|
26
34
|
assetKey?: (item: BoardSceneItem) => string | null;
|
|
27
35
|
renderers?: BoardCardRendererResolver;
|
|
28
36
|
backgroundImage?: {
|
|
@@ -50,7 +58,20 @@ type BoardExportResult = {
|
|
|
50
58
|
plan: BoardExportPlan;
|
|
51
59
|
warnings: BoardExportWarning[];
|
|
52
60
|
};
|
|
61
|
+
declare function prepareBoardExport(input: BoardDocument, options?: BoardExportOptions): {
|
|
62
|
+
document: BoardDocument;
|
|
63
|
+
scene: BoardScene;
|
|
64
|
+
plan: BoardExportPlan;
|
|
65
|
+
sampler: {
|
|
66
|
+
frameAt(id: string, time: number): BoardFrame | undefined;
|
|
67
|
+
at(time: number): {
|
|
68
|
+
document: BoardDocument;
|
|
69
|
+
evaluation: BoardEvaluation;
|
|
70
|
+
scene: BoardScene;
|
|
71
|
+
};
|
|
72
|
+
} | undefined;
|
|
73
|
+
} | null;
|
|
53
74
|
declare function renderBoardExport(renderer: Renderer, input: BoardDocument, options?: BoardExportOptions): BoardExportResult | null;
|
|
54
75
|
declare function describeBoardExportWarning(warning: BoardExportWarning): string;
|
|
55
76
|
//#endregion
|
|
56
|
-
export { BoardExportBackground, BoardExportOptions, type BoardExportPlan, type BoardExportPlanInput, type BoardExportRegion, BoardExportResult, type BoardExportScene, type BoardExportSceneInput, BoardExportWarning, createBoardExportScene, describeBoardExportWarning, renderBoardExport };
|
|
77
|
+
export { BoardExportBackground, BoardExportOptions, type BoardExportPlan, type BoardExportPlanInput, type BoardExportRegion, BoardExportResult, type BoardExportScene, type BoardExportSceneInput, BoardExportWarning, createBoardExportScene, describeBoardExportWarning, prepareBoardExport, renderBoardExport };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { boardDocumentAt } from "../model/animation.js";
|
|
2
|
-
import { normalizeBoardDocument, planBoardExport } from "../model/export-plan.js";
|
|
3
1
|
import { buildBoardScene } from "../model/scene.js";
|
|
2
|
+
import { resolveBoardAnimationCamera } from "../model/sampling.js";
|
|
3
|
+
import { normalizeBoardDocument, planBoardExport } from "../model/export-plan.js";
|
|
4
4
|
import { parseBoardCssColor } from "../render/css-color.js";
|
|
5
5
|
import { defaultBoardPalette } from "../render/palette.js";
|
|
6
|
+
import { createBoardRenderSampler } from "../render/sampling.js";
|
|
6
7
|
import { ensureBoardTextMeasurement } from "../render/text-measurement.js";
|
|
7
8
|
import { createBoardExportScene } from "./scene.js";
|
|
8
9
|
import { Rectangle } from "pixi.js";
|
|
@@ -14,20 +15,51 @@ function resolveBackground(background, palette, document, colorScheme) {
|
|
|
14
15
|
const css = typeof declared === "object" ? declared[colorScheme] : declared;
|
|
15
16
|
return css ? parseBoardCssColor(css) ?? palette.bg : palette.bg;
|
|
16
17
|
}
|
|
17
|
-
function
|
|
18
|
+
function prepareBoardExport(input, options = {}) {
|
|
18
19
|
ensureBoardTextMeasurement();
|
|
19
|
-
const base = normalizeBoardDocument(input);
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const base = options.sampler ? input : normalizeBoardDocument(input);
|
|
21
|
+
if (options.camera && options.region && options.region.kind !== "all") throw new Error("Camera export cannot be combined with a fixed region.");
|
|
22
|
+
if (options.camera && !options.at) throw new Error("Camera export needs an animation time.");
|
|
23
|
+
if (options.camera && ![options.camera.width, options.camera.height].every((n) => Number.isSafeInteger(n) && n > 0)) throw new Error("Camera dimensions must be positive integers.");
|
|
24
|
+
const sampler = options.at ? options.sampler ?? createBoardRenderSampler(base, options.at.animation ?? null, options) : void 0;
|
|
25
|
+
const sample = options.at ? sampler?.at(options.at.time) : void 0;
|
|
26
|
+
const sampled = sample?.document ?? base;
|
|
27
|
+
const document = options.scripts?.document?.(sampled, options.at?.time ?? 0) ?? sampled;
|
|
28
|
+
const scene = document === sampled ? sample?.scene ?? buildBoardScene(document) : buildBoardScene(document);
|
|
29
|
+
const camera = options.camera ? resolveBoardAnimationCamera(sample?.evaluation.camera ?? {}, (id) => scene.get(id)?.frame, options.camera, options.at?.time ?? 0) : void 0;
|
|
30
|
+
const region = camera && options.camera ? {
|
|
31
|
+
kind: "rect",
|
|
32
|
+
rect: {
|
|
33
|
+
x: -camera.x / camera.zoom,
|
|
34
|
+
y: -camera.y / camera.zoom,
|
|
35
|
+
width: options.camera.width / camera.zoom,
|
|
36
|
+
height: options.camera.height / camera.zoom
|
|
37
|
+
}
|
|
38
|
+
} : options.region ?? { kind: "all" };
|
|
22
39
|
const plan = planBoardExport({
|
|
23
40
|
scene,
|
|
24
|
-
region
|
|
25
|
-
scale: options.scale,
|
|
26
|
-
padding: options.padding,
|
|
41
|
+
region,
|
|
42
|
+
scale: camera?.zoom ?? options.scale,
|
|
43
|
+
padding: camera ? 0 : options.padding,
|
|
27
44
|
maxEdge: options.maxEdge,
|
|
28
45
|
maxPixels: options.maxPixels
|
|
29
46
|
});
|
|
30
|
-
if (
|
|
47
|
+
if (plan && camera && options.camera) {
|
|
48
|
+
const ratio = plan.clamped ? plan.scale / camera.zoom : 1;
|
|
49
|
+
plan.width = Math.max(1, Math.floor(options.camera.width * ratio));
|
|
50
|
+
plan.height = Math.max(1, Math.floor(options.camera.height * ratio));
|
|
51
|
+
}
|
|
52
|
+
return plan ? {
|
|
53
|
+
document,
|
|
54
|
+
scene,
|
|
55
|
+
plan,
|
|
56
|
+
sampler
|
|
57
|
+
} : null;
|
|
58
|
+
}
|
|
59
|
+
function renderBoardExport(renderer, input, options = {}) {
|
|
60
|
+
const prepared = prepareBoardExport(input, options);
|
|
61
|
+
if (!prepared) return null;
|
|
62
|
+
const { document, scene, plan, sampler } = prepared;
|
|
31
63
|
const colorScheme = options.colorScheme ?? "dark";
|
|
32
64
|
const palette = {
|
|
33
65
|
...defaultBoardPalette(colorScheme),
|
|
@@ -38,13 +70,14 @@ function renderBoardExport(renderer, input, options = {}) {
|
|
|
38
70
|
scene,
|
|
39
71
|
items: plan.items,
|
|
40
72
|
time: options.at?.time ?? 0,
|
|
73
|
+
frameAt: sampler?.frameAt,
|
|
41
74
|
world: plan.world,
|
|
42
75
|
scale: plan.scale,
|
|
43
76
|
colorScheme,
|
|
44
77
|
palette,
|
|
45
78
|
colors: options.colors,
|
|
46
79
|
textures: options.textures,
|
|
47
|
-
|
|
80
|
+
scripts: options.scripts,
|
|
48
81
|
assetKey: options.assetKey,
|
|
49
82
|
renderers: options.renderers,
|
|
50
83
|
background: resolveBackground(options.background, palette, document, colorScheme),
|
|
@@ -89,4 +122,4 @@ function describeBoardExportWarning(warning) {
|
|
|
89
122
|
}
|
|
90
123
|
}
|
|
91
124
|
//#endregion
|
|
92
|
-
export { createBoardExportScene, describeBoardExportWarning, renderBoardExport };
|
|
125
|
+
export { createBoardExportScene, describeBoardExportWarning, prepareBoardExport, renderBoardExport };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BoardDocument } from "../../../protocol/dist/board-model.js";
|
|
2
2
|
import "../../../protocol/dist/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { BoardScriptHost } from "../../render/renderers/board-renderer-registry.js";
|
|
4
4
|
import { BoardExportOptions, BoardExportResult } from "../index.js";
|
|
5
|
-
import {
|
|
5
|
+
import { createNodeBoardScriptHost } from "./scripts.js";
|
|
6
6
|
import { Renderer } from "pixi.js";
|
|
7
7
|
//#region src/board/export/node/index.d.ts
|
|
8
8
|
type NodeCanvasModule = {
|
|
@@ -24,6 +24,7 @@ type BoardNodeRendererOptions = {
|
|
|
24
24
|
};
|
|
25
25
|
type BoardNodeTexture = {
|
|
26
26
|
readonly __boardTexture: unique symbol;
|
|
27
|
+
destroy: (destroySource?: boolean) => void;
|
|
27
28
|
};
|
|
28
29
|
type BoardNodeRenderer = {
|
|
29
30
|
renderer: Renderer;
|
|
@@ -41,7 +42,7 @@ type BoardNodeExportOptions = Omit<BoardExportOptions, "textures" | "backgroundI
|
|
|
41
42
|
position: "center" | "top" | "bottom" | "left" | "right";
|
|
42
43
|
opacity: number;
|
|
43
44
|
};
|
|
44
|
-
|
|
45
|
+
scripts?: BoardScriptHost;
|
|
45
46
|
format?: BoardNodeExportFormat;
|
|
46
47
|
quality?: number;
|
|
47
48
|
};
|
|
@@ -52,4 +53,4 @@ type BoardNodeExportResult = Omit<BoardExportResult, "canvas"> & {
|
|
|
52
53
|
declare function boardImageMimeType(format: BoardNodeExportFormat): string;
|
|
53
54
|
declare function exportBoardImageBytes(renderer: BoardNodeRenderer, document: BoardDocument, options?: BoardNodeExportOptions): BoardNodeExportResult | null;
|
|
54
55
|
//#endregion
|
|
55
|
-
export { BoardNodeExportFormat, BoardNodeExportOptions, BoardNodeExportResult, BoardNodeFont, BoardNodeRenderer, BoardNodeRendererOptions, BoardNodeTexture, NodeCanvasModule, boardImageMimeType, createNodeBoardRenderer,
|
|
56
|
+
export { BoardNodeExportFormat, BoardNodeExportOptions, BoardNodeExportResult, BoardNodeFont, BoardNodeRenderer, BoardNodeRendererOptions, BoardNodeTexture, NodeCanvasModule, boardImageMimeType, createNodeBoardRenderer, createNodeBoardScriptHost, exportBoardImageBytes };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../../protocol/dist/board-constants.js";
|
|
2
2
|
import { installBoardTextMeasurement } from "../../render/text-measurement.js";
|
|
3
3
|
import { renderBoardExport } from "../index.js";
|
|
4
|
-
import {
|
|
4
|
+
import { createNodeBoardScriptHost } from "./scripts.js";
|
|
5
5
|
import { CanvasGraphicsContextSystem, CanvasGraphicsPipe, CanvasRenderer, CanvasRendererTextSystem, CanvasTextPipe, CanvasTextSystem, DOMAdapter, GraphicsContextSystem, GraphicsPipe, ImageSource, Texture, extensions } from "pixi.js";
|
|
6
6
|
//#region src/board/export/node/index.ts
|
|
7
7
|
const SYSTEM_UI_FAMILIES = [
|
|
@@ -131,10 +131,10 @@ function boardImageMimeType(format) {
|
|
|
131
131
|
return MIME[format];
|
|
132
132
|
}
|
|
133
133
|
function exportBoardImageBytes(renderer, document, options = {}) {
|
|
134
|
-
const { format = "png", quality = .92, textures,
|
|
134
|
+
const { format = "png", quality = .92, textures, scripts, backgroundImage, ...rest } = options;
|
|
135
135
|
const result = renderBoardExport(renderer.renderer, document, {
|
|
136
136
|
...rest,
|
|
137
|
-
...
|
|
137
|
+
...scripts ? { scripts } : {},
|
|
138
138
|
...textures ? { textures } : {},
|
|
139
139
|
...backgroundImage ? { backgroundImage: {
|
|
140
140
|
...backgroundImage,
|
|
@@ -143,13 +143,18 @@ function exportBoardImageBytes(renderer, document, options = {}) {
|
|
|
143
143
|
});
|
|
144
144
|
if (!result) return null;
|
|
145
145
|
const canvas = result.canvas;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
try {
|
|
147
|
+
const bytes = format === "png" ? canvas.toBuffer(MIME.png) : canvas.toBuffer(MIME[format], Math.round(quality * 100));
|
|
148
|
+
return {
|
|
149
|
+
bytes: new Uint8Array(bytes),
|
|
150
|
+
plan: result.plan,
|
|
151
|
+
warnings: result.warnings,
|
|
152
|
+
format
|
|
153
|
+
};
|
|
154
|
+
} finally {
|
|
155
|
+
canvas.width = 1;
|
|
156
|
+
canvas.height = 1;
|
|
157
|
+
}
|
|
153
158
|
}
|
|
154
159
|
//#endregion
|
|
155
|
-
export { boardImageMimeType, createNodeBoardRenderer,
|
|
160
|
+
export { boardImageMimeType, createNodeBoardRenderer, createNodeBoardScriptHost, exportBoardImageBytes };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BoardSceneItem } from "../../model/scene.js";
|
|
2
|
+
import { BoardScriptHost } from "../../render/renderers/board-renderer-registry.js";
|
|
3
|
+
import { BoardNodeRenderer } from "./index.js";
|
|
4
|
+
//#region src/board/export/node/scripts.d.ts
|
|
5
|
+
type BoardNodeScriptOptions = {
|
|
6
|
+
readModule(src: string): Promise<string>;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
readTimeoutMs?: number;
|
|
9
|
+
};
|
|
10
|
+
declare function createNodeBoardScriptHost(renderer: BoardNodeRenderer, options: BoardNodeScriptOptions): BoardScriptHost & {
|
|
11
|
+
prepare(items: readonly BoardSceneItem[], times: readonly number[], zoom: number): Promise<void>;
|
|
12
|
+
clearFrames(): void;
|
|
13
|
+
destroy(): void;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { BoardNodeScriptOptions, createNodeBoardScriptHost };
|