@neta-art/cohub 11.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 +31 -5
- package/dist/board/editor/creation.d.ts +2 -2
- package/dist/board/editor/creation.js +3 -3
- package/dist/board/editor/editor.d.ts +4 -4
- package/dist/board/editor/editor.js +1 -1
- 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/snapshots.d.ts +0 -2
- package/dist/board/editor/snapshots.js +4 -20
- package/dist/board/export/scene.js +4 -1
- package/dist/board/model/image-key.js +1 -1
- package/dist/board/model/index.d.ts +8 -7
- package/dist/board/model/index.js +6 -5
- package/dist/board/model/items/create.d.ts +16 -3
- package/dist/board/model/items/create.js +125 -5
- 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.js +1 -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/script-hit.d.ts +20 -3
- package/dist/board/model/script-hit.js +81 -24
- 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 +1 -1
- package/dist/board/model/script-scene.js +35 -8
- package/dist/board/model/script.d.ts +51 -7
- package/dist/board/render/board-background.js +5 -4
- package/dist/board/render/index.d.ts +2 -2
- package/dist/board/render/index.js +2 -2
- package/dist/board/render/media-interaction.js +1 -1
- package/dist/board/render/renderers/board-renderer-registry.d.ts +17 -2
- package/dist/board/render/renderers/board-renderer-registry.js +8 -1
- package/dist/board/render/renderers/custom-card-renderer.js +2 -1
- 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/script-host.d.ts +1 -1
- package/dist/board/render/script-host.js +53 -28
- package/dist/board/render/script-runtime.js +13 -3
- package/dist/board/render/script-texture.d.ts +11 -0
- package/dist/board/render/script-texture.js +33 -0
- package/dist/board/stage/assets.js +1 -1
- package/dist/board/stage/scene.d.ts +2 -0
- package/dist/board/stage/scene.js +17 -1
- package/dist/board/stage/script-pointer.d.ts +1 -0
- package/dist/board/stage/script-pointer.js +8 -2
- package/dist/board/stage/stage.d.ts +11 -3
- package/dist/board/stage/stage.js +118 -21
- package/dist/chunks/environment.d.ts +40 -5
- package/dist/chunks/environment.js +12 -4
- package/dist/chunks/http.d.ts +3 -1
- package/dist/chunks/http.js +2 -1
- package/dist/chunks/transport.js +1 -1
- package/dist/chunks/websocket.d.ts +1 -1
- package/dist/http.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +151 -139
- package/dist/protocol/dist/board-model.d.ts +36 -1
- package/dist/protocol/dist/board-model.js +14 -4
- 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/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 +5 -2
- package/dist/protocol/dist/task/index.d.ts +4 -0
- package/package.json +1 -1
- package/dist/board/model/task.d.ts +0 -11
- package/dist/types.d.ts +0 -36
|
@@ -33,6 +33,8 @@ function createScriptRuntime(module, initial, host) {
|
|
|
33
33
|
let patches = effects?.patches ?? {};
|
|
34
34
|
let items = effects?.items ?? {};
|
|
35
35
|
let space = effects?.space ?? "world";
|
|
36
|
+
let anchor = effects?.anchor;
|
|
37
|
+
let view = null;
|
|
36
38
|
let hits = effects?.hits ?? {};
|
|
37
39
|
const invalidate = () => {
|
|
38
40
|
if (disposed) return;
|
|
@@ -69,6 +71,9 @@ function createScriptRuntime(module, initial, host) {
|
|
|
69
71
|
get frame() {
|
|
70
72
|
return frame;
|
|
71
73
|
},
|
|
74
|
+
get view() {
|
|
75
|
+
return view;
|
|
76
|
+
},
|
|
72
77
|
random() {
|
|
73
78
|
randomState = Math.imul(randomState, 1664525) + 1013904223 >>> 0;
|
|
74
79
|
return randomState / 4294967296;
|
|
@@ -79,10 +84,11 @@ function createScriptRuntime(module, initial, host) {
|
|
|
79
84
|
listeners = /* @__PURE__ */ new Set();
|
|
80
85
|
handlers.set(type, listeners);
|
|
81
86
|
}
|
|
82
|
-
|
|
87
|
+
const listener = (event) => handler(event);
|
|
88
|
+
listeners.add(listener);
|
|
83
89
|
invalidate();
|
|
84
90
|
return () => {
|
|
85
|
-
listeners.delete(
|
|
91
|
+
listeners.delete(listener);
|
|
86
92
|
invalidate();
|
|
87
93
|
};
|
|
88
94
|
},
|
|
@@ -101,6 +107,7 @@ function createScriptRuntime(module, initial, host) {
|
|
|
101
107
|
scene(next, options) {
|
|
102
108
|
items = structuredClone(next);
|
|
103
109
|
space = options?.space ?? "world";
|
|
110
|
+
anchor = options?.anchor ? structuredClone(options.anchor) : void 0;
|
|
104
111
|
invalidate();
|
|
105
112
|
},
|
|
106
113
|
hitRegions(next) {
|
|
@@ -162,6 +169,7 @@ function createScriptRuntime(module, initial, host) {
|
|
|
162
169
|
},
|
|
163
170
|
event(event) {
|
|
164
171
|
if (disposed) return;
|
|
172
|
+
if (event.type === "viewchange") view = event.data;
|
|
165
173
|
const listeners = handlers.get(event.type);
|
|
166
174
|
if (!listeners?.size) return;
|
|
167
175
|
for (const handler of listeners) handler(event);
|
|
@@ -175,6 +183,7 @@ function createScriptRuntime(module, initial, host) {
|
|
|
175
183
|
return {
|
|
176
184
|
parameters: module.parameters,
|
|
177
185
|
space,
|
|
186
|
+
anchor,
|
|
178
187
|
patches,
|
|
179
188
|
items,
|
|
180
189
|
hits,
|
|
@@ -193,7 +202,8 @@ function createScriptRuntime(module, initial, host) {
|
|
|
193
202
|
patches,
|
|
194
203
|
items,
|
|
195
204
|
hits,
|
|
196
|
-
space
|
|
205
|
+
space,
|
|
206
|
+
anchor
|
|
197
207
|
} : void 0
|
|
198
208
|
};
|
|
199
209
|
return clone ? structuredClone(snapshot) : snapshot;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Texture } from "pixi.js";
|
|
2
|
+
//#region src/board/render/script-texture.d.ts
|
|
3
|
+
declare class BoardScriptTexture {
|
|
4
|
+
private texture;
|
|
5
|
+
private bitmap;
|
|
6
|
+
get current(): Texture | null;
|
|
7
|
+
update(bitmap: ImageBitmap): void;
|
|
8
|
+
destroy(): void;
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { BoardScriptTexture };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ImageSource, Texture } from "pixi.js";
|
|
2
|
+
//#region src/board/render/script-texture.ts
|
|
3
|
+
var BoardScriptTexture = class {
|
|
4
|
+
texture = null;
|
|
5
|
+
bitmap = null;
|
|
6
|
+
get current() {
|
|
7
|
+
return this.texture;
|
|
8
|
+
}
|
|
9
|
+
update(bitmap) {
|
|
10
|
+
const previous = this.bitmap;
|
|
11
|
+
this.bitmap = bitmap;
|
|
12
|
+
if (!this.texture) {
|
|
13
|
+
this.texture = new Texture({
|
|
14
|
+
source: new ImageSource({ resource: bitmap }),
|
|
15
|
+
dynamic: true
|
|
16
|
+
});
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const source = this.texture.source;
|
|
20
|
+
source.resource = bitmap;
|
|
21
|
+
source.update();
|
|
22
|
+
if (previous !== bitmap) previous?.close();
|
|
23
|
+
}
|
|
24
|
+
destroy() {
|
|
25
|
+
if (!this.texture) return;
|
|
26
|
+
this.texture.destroy(true);
|
|
27
|
+
this.bitmap?.close();
|
|
28
|
+
this.bitmap = null;
|
|
29
|
+
this.texture = null;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { BoardScriptTexture };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mediaPreviewCandidates } from "../../media.js";
|
|
2
2
|
import { parseBoardMediaSource } from "../../protocol/dist/board-model.js";
|
|
3
|
-
import { featuredTaskArtifact } from "
|
|
3
|
+
import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
|
|
4
4
|
import { boardImageKeySource, imageAssetKey } from "../model/image-key.js";
|
|
5
5
|
import { loadVideoThumbnailTexture, videoTextureNaturalSize } from "../render/video-thumbnail.js";
|
|
6
6
|
import { DEFAULT_LRU_BUDGET, selectLruEvictions } from "./lru.js";
|
|
@@ -24,6 +24,7 @@ type SceneSyncInput = {
|
|
|
24
24
|
visibleIds: Set<string> | null;
|
|
25
25
|
pinnedIds: Set<string>;
|
|
26
26
|
globalSig: string;
|
|
27
|
+
staleIds?: ReadonlySet<string>;
|
|
27
28
|
structureVersion: number;
|
|
28
29
|
geometryVersion: number;
|
|
29
30
|
gestureActive: boolean;
|
|
@@ -72,6 +73,7 @@ type BoardScene = {
|
|
|
72
73
|
sync: (input: SceneSyncInput) => void;
|
|
73
74
|
getNode: (itemId: string) => BoardSceneNode | null;
|
|
74
75
|
readonly animated: boolean;
|
|
76
|
+
tick: (clock: number) => number | null;
|
|
75
77
|
drawOverlay: (input: SceneOverlayInput, palette: BoardRenderPalette) => void;
|
|
76
78
|
destroy: (context: BoardRenderContext) => void;
|
|
77
79
|
};
|
|
@@ -48,6 +48,7 @@ function createBoardScene(options) {
|
|
|
48
48
|
const cards = /* @__PURE__ */ new Map();
|
|
49
49
|
const clips = /* @__PURE__ */ new Map();
|
|
50
50
|
const animatedIds = /* @__PURE__ */ new Set();
|
|
51
|
+
const tickingIds = /* @__PURE__ */ new Set();
|
|
51
52
|
const pools = /* @__PURE__ */ new Map();
|
|
52
53
|
const heldKeys = /* @__PURE__ */ new Map();
|
|
53
54
|
let orderById = /* @__PURE__ */ new Map();
|
|
@@ -72,6 +73,7 @@ function createBoardScene(options) {
|
|
|
72
73
|
setHeldKey(context, id, null);
|
|
73
74
|
cards.delete(id);
|
|
74
75
|
animatedIds.delete(id);
|
|
76
|
+
tickingIds.delete(id);
|
|
75
77
|
if (destroyed) return;
|
|
76
78
|
entry.container.parent?.removeChild(entry.container);
|
|
77
79
|
entry.container.visible = false;
|
|
@@ -123,6 +125,7 @@ function createBoardScene(options) {
|
|
|
123
125
|
container.alpha = scene.opacity(item.id);
|
|
124
126
|
hostFor(item, scene).addChild(container);
|
|
125
127
|
if (renderer.animated) animatedIds.add(item.id);
|
|
128
|
+
if (renderer.tick) tickingIds.add(item.id);
|
|
126
129
|
const entry = {
|
|
127
130
|
item,
|
|
128
131
|
container,
|
|
@@ -352,7 +355,7 @@ function createBoardScene(options) {
|
|
|
352
355
|
const hovered = context.hoveredId === id;
|
|
353
356
|
const resizing = context.resizingIds.has(id);
|
|
354
357
|
const scriptRevision = context.scripts?.revision?.(id) ?? 0;
|
|
355
|
-
const changed = scriptRevision !== entry.scriptRevision || item !== entry.item || entry.renderer.animated || selected !== entry.selected || hovered !== entry.hovered || resizing !== entry.resizing || globalSig !== entry.globalSig;
|
|
358
|
+
const changed = input.staleIds?.has(id) || scriptRevision !== entry.scriptRevision || item !== entry.item || entry.renderer.animated || selected !== entry.selected || hovered !== entry.hovered || resizing !== entry.resizing || globalSig !== entry.globalSig;
|
|
356
359
|
entry.scriptRevision = scriptRevision;
|
|
357
360
|
entry.item = item;
|
|
358
361
|
entry.selected = selected;
|
|
@@ -363,12 +366,23 @@ function createBoardScene(options) {
|
|
|
363
366
|
if (changed) {
|
|
364
367
|
entry.renderer.update(entry.container, item, context);
|
|
365
368
|
entry.container.alpha = scene.opacity(id);
|
|
369
|
+
if (entry.renderer.tick) tickingIds.add(id);
|
|
366
370
|
}
|
|
367
371
|
}
|
|
368
372
|
if (structureChanged || liveSetChanged) syncClips(scene);
|
|
369
373
|
if (structureChanged || farModeChanged || liveSetChanged) applyChildOrder();
|
|
370
374
|
syncLiveStrokes(input);
|
|
371
375
|
}
|
|
376
|
+
function tick(clock) {
|
|
377
|
+
let next = null;
|
|
378
|
+
for (const id of tickingIds) {
|
|
379
|
+
const entry = cards.get(id);
|
|
380
|
+
const wait = entry?.container.visible ? entry.renderer.tick?.(entry.container, clock) ?? null : null;
|
|
381
|
+
if (wait === null) tickingIds.delete(id);
|
|
382
|
+
else next = next === null ? wait : Math.min(next, wait);
|
|
383
|
+
}
|
|
384
|
+
return next;
|
|
385
|
+
}
|
|
372
386
|
function applyChildOrder() {
|
|
373
387
|
for (const [id, entry] of cards) entry.container.zIndex = orderById.get(id) ?? 0;
|
|
374
388
|
world.sortableChildren = true;
|
|
@@ -489,6 +503,7 @@ function createBoardScene(options) {
|
|
|
489
503
|
for (const entry of clips.values()) entry.group.destroy({ children: true });
|
|
490
504
|
clips.clear();
|
|
491
505
|
animatedIds.clear();
|
|
506
|
+
tickingIds.clear();
|
|
492
507
|
for (const id of [...liveStrokes.keys()]) removeLiveStroke(id, context);
|
|
493
508
|
resetFarLayer();
|
|
494
509
|
farActive = false;
|
|
@@ -507,6 +522,7 @@ function createBoardScene(options) {
|
|
|
507
522
|
get animated() {
|
|
508
523
|
return animatedIds.size > 0;
|
|
509
524
|
},
|
|
525
|
+
tick,
|
|
510
526
|
drawOverlay,
|
|
511
527
|
destroy
|
|
512
528
|
};
|
|
@@ -13,6 +13,7 @@ declare function createBoardScriptPointerRouter(): {
|
|
|
13
13
|
recipient: BoardScriptPointerTarget | null;
|
|
14
14
|
click: BoardScriptPointerTarget | null;
|
|
15
15
|
};
|
|
16
|
+
cancelScripts(cancel: (pointerId: number, target: BoardScriptPointerTarget) => void, owner?: string, retained?: Readonly<Record<string, unknown>>): void;
|
|
16
17
|
clear(): void;
|
|
17
18
|
};
|
|
18
19
|
//#endregion
|
|
@@ -15,17 +15,23 @@ function createBoardScriptPointerRouter() {
|
|
|
15
15
|
...point
|
|
16
16
|
});
|
|
17
17
|
const gesture = gestures.get(pointerId);
|
|
18
|
-
const recipient = gesture ? gesture.target : phase === "move" ? target : null;
|
|
18
|
+
const recipient = gesture ? gesture.cancelled ? null : gesture.target : phase === "move" ? target : null;
|
|
19
19
|
let click = null;
|
|
20
20
|
if (phase === "up") {
|
|
21
21
|
gestures.delete(pointerId);
|
|
22
|
-
if (!cancelled && gesture?.target && target?.owner === gesture.target.owner && target.target === gesture.target.target && Math.hypot(point.x - gesture.x, point.y - gesture.y) < 5) click = gesture.target;
|
|
22
|
+
if (!cancelled && !gesture?.cancelled && gesture?.target && target?.owner === gesture.target.owner && target.target === gesture.target.target && Math.hypot(point.x - gesture.x, point.y - gesture.y) < 5) click = gesture.target;
|
|
23
23
|
}
|
|
24
24
|
return {
|
|
25
25
|
recipient,
|
|
26
26
|
click
|
|
27
27
|
};
|
|
28
28
|
},
|
|
29
|
+
cancelScripts(cancel, owner, retained) {
|
|
30
|
+
for (const [pointerId, gesture] of gestures) if (!gesture.cancelled && gesture.target && (!owner || gesture.target.owner === owner) && (!retained || !Object.hasOwn(retained, gesture.target.target))) {
|
|
31
|
+
gesture.cancelled = true;
|
|
32
|
+
cancel(pointerId, gesture.target);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
29
35
|
clear() {
|
|
30
36
|
gestures.clear();
|
|
31
37
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { BoardItem } from "../../protocol/dist/board-model.js";
|
|
1
|
+
import { BoardItem, BoardTaskItem } from "../../protocol/dist/board-model.js";
|
|
2
2
|
import { BoardPlaybackSnapshot } from "../../protocol/dist/board.js";
|
|
3
3
|
import "../../protocol/dist/index.js";
|
|
4
|
+
import { BoardViewport, Rect, WorldPoint } from "../model/geometry.js";
|
|
4
5
|
import { BoardScriptOutput, BoardScriptSnapshot } from "../model/script.js";
|
|
5
|
-
import { BoardViewport, WorldPoint } from "../model/geometry.js";
|
|
6
6
|
import { BoardScene, BoardSceneItem } from "../model/scene.js";
|
|
7
7
|
import { BoardShapeColors } from "../model/palette.js";
|
|
8
8
|
import { BoardAssetSource } from "../model/media-playback.js";
|
|
@@ -10,7 +10,7 @@ import "../model/index.js";
|
|
|
10
10
|
import { BoardPointerEvent } from "../editor/interaction.js";
|
|
11
11
|
import { BoardEditor } from "../editor/editor.js";
|
|
12
12
|
import "../editor/index.js";
|
|
13
|
-
import { BoardCardRendererResolver, BoardRenderPalette } from "../render/renderers/board-renderer-registry.js";
|
|
13
|
+
import { BoardCardRendererResolver, BoardRenderLabels, BoardRenderPalette } from "../render/renderers/board-renderer-registry.js";
|
|
14
14
|
import "../render/index.js";
|
|
15
15
|
import { BoardAssetManager } from "./assets.js";
|
|
16
16
|
import { BoardLiveStroke } from "./scene.js";
|
|
@@ -32,6 +32,12 @@ type BoardStageOptions = {
|
|
|
32
32
|
renderers?: BoardCardRendererResolver;
|
|
33
33
|
views?: readonly BoardItemView[];
|
|
34
34
|
theme?: () => BoardStageTheme;
|
|
35
|
+
labels?: () => BoardRenderLabels;
|
|
36
|
+
taskRun?: (taskRunId: string) => {
|
|
37
|
+
status: BoardTaskItem["props"]["snapshot"]["status"];
|
|
38
|
+
startedAt?: string;
|
|
39
|
+
} | null;
|
|
40
|
+
reducedMotion?: () => boolean;
|
|
35
41
|
playback?: () => BoardPlaybackSnapshot | null;
|
|
36
42
|
fileState?: (path: string) => "ok" | "missing" | "unavailable";
|
|
37
43
|
previews?: () => ReadonlyMap<string, BoardItem>;
|
|
@@ -48,6 +54,7 @@ type BoardStageOptions = {
|
|
|
48
54
|
height: number;
|
|
49
55
|
}) => void;
|
|
50
56
|
onVisibleChange?: (ids: ReadonlySet<string> | null) => void;
|
|
57
|
+
safeRect?: () => Rect;
|
|
51
58
|
scriptCapabilities?: Record<string, (id: string, input: unknown) => Promise<unknown>>;
|
|
52
59
|
};
|
|
53
60
|
type BoardStage = {
|
|
@@ -66,6 +73,7 @@ type BoardStage = {
|
|
|
66
73
|
subscribeScripts(listener: () => void): () => void;
|
|
67
74
|
invalidate(options?: {
|
|
68
75
|
cards?: boolean;
|
|
76
|
+
items?: Iterable<string>;
|
|
69
77
|
}): void;
|
|
70
78
|
isMaterialized(id: string): boolean;
|
|
71
79
|
toWorld(clientX: number, clientY: number): WorldPoint;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
|
|
2
|
+
import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
|
|
2
3
|
import { screenPoint, screenToWorld, stableCullRect, visibleWorldRect, worldPoint } from "../model/geometry.js";
|
|
3
4
|
import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
|
|
4
5
|
import { boardScriptTarget } from "../model/script-hit.js";
|
|
5
6
|
import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "../model/sampling.js";
|
|
6
7
|
import { resolveSceneArrow } from "../model/arrow-geometry.js";
|
|
7
8
|
import { buildFallbackShapeColors, pickBoardColor, resolveItemColor } from "../model/palette.js";
|
|
8
|
-
import { featuredTaskArtifact } from "../model/task.js";
|
|
9
9
|
import { isCreationBoardTool } from "../editor/tool.js";
|
|
10
10
|
import { resizeCursorForHandle } from "../editor/selection-transform.js";
|
|
11
11
|
import { parseBoardCssColor } from "../render/css-color.js";
|
|
12
12
|
import { defaultBoardPalette, itemAlpha } from "../render/palette.js";
|
|
13
13
|
import { createBoardBackground, updateBoardBackground } from "../render/board-background.js";
|
|
14
14
|
import { getBoardResolution, textZoomBucket } from "../render/text-resolution.js";
|
|
15
|
-
import { getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
|
|
15
|
+
import { DEFAULT_BOARD_RENDER_LABELS, getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
|
|
16
16
|
import { createBoardScriptHost } from "../render/script-host.js";
|
|
17
17
|
import { createBoardPlayer } from "../player/index.js";
|
|
18
|
+
import { createBoardScriptObservers } from "../model/script-observers.js";
|
|
18
19
|
import { toBoardPointerEvent } from "./pointer.js";
|
|
19
20
|
import { createBoardScene } from "./scene.js";
|
|
20
21
|
import { scheduleBoardMaintenance } from "./maintenance.js";
|
|
@@ -56,12 +57,26 @@ function mountBoardStage(host, options) {
|
|
|
56
57
|
let scriptTime = 0;
|
|
57
58
|
let scriptLastTick = performance.now();
|
|
58
59
|
const scriptOutputs = /* @__PURE__ */ new Map();
|
|
60
|
+
const interactiveScripts = /* @__PURE__ */ new Set();
|
|
61
|
+
const screenScripts = /* @__PURE__ */ new Set();
|
|
62
|
+
const scriptObservers = createBoardScriptObservers((owner, event) => scripts?.event(owner, event));
|
|
63
|
+
let stopTransforms = null;
|
|
64
|
+
function syncTransformSubscription() {
|
|
65
|
+
if (scriptObservers.transforms && !stopTransforms) stopTransforms = editor.subscribeTransforms((event) => {
|
|
66
|
+
if (active && scriptMode !== "paused") scriptObservers.transform(editor.document, event);
|
|
67
|
+
});
|
|
68
|
+
else if (!scriptObservers.transforms && stopTransforms) {
|
|
69
|
+
stopTransforms();
|
|
70
|
+
stopTransforms = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
59
73
|
const scriptListeners = /* @__PURE__ */ new Set();
|
|
60
74
|
let scriptVersion = 0;
|
|
61
75
|
let composedVersion = -1;
|
|
62
76
|
let composedZoom = 0;
|
|
63
77
|
let composedPlayhead = "";
|
|
64
78
|
let composedMoving = false;
|
|
79
|
+
let composedGesture = false;
|
|
65
80
|
let composedDocument = null;
|
|
66
81
|
let scriptHover = null;
|
|
67
82
|
const scriptPointers = createBoardScriptPointerRouter();
|
|
@@ -70,6 +85,10 @@ function mountBoardStage(host, options) {
|
|
|
70
85
|
let disposed = false;
|
|
71
86
|
let renderFrame = 0;
|
|
72
87
|
let tickFrame = 0;
|
|
88
|
+
let cardTickFrame = 0;
|
|
89
|
+
let cardTickTimer = null;
|
|
90
|
+
let cardTickDue = 0;
|
|
91
|
+
const staleIds = /* @__PURE__ */ new Set();
|
|
73
92
|
let resizeFrame = 0;
|
|
74
93
|
let cardEpoch = 0;
|
|
75
94
|
let assetVersion = 0;
|
|
@@ -144,6 +163,9 @@ function mountBoardStage(host, options) {
|
|
|
144
163
|
colorScheme: current.colorScheme,
|
|
145
164
|
rendererType: app?.renderer.type === RendererType.CANVAS ? "canvas" : "gpu",
|
|
146
165
|
zoom: renderCamera().zoom,
|
|
166
|
+
reducedMotion: options.reducedMotion?.() ?? false,
|
|
167
|
+
labels: options.labels?.() ?? DEFAULT_BOARD_RENDER_LABELS,
|
|
168
|
+
taskRun: options.taskRun ?? (() => null),
|
|
147
169
|
assetKey: assets.assetKey,
|
|
148
170
|
getTexture: (key) => assets.getTexture(key),
|
|
149
171
|
hasError: (key) => assets.hasError(key),
|
|
@@ -282,6 +304,28 @@ function mountBoardStage(host, options) {
|
|
|
282
304
|
app?.render();
|
|
283
305
|
});
|
|
284
306
|
}
|
|
307
|
+
function scheduleCardTick(wait) {
|
|
308
|
+
if (!active || disposed) return;
|
|
309
|
+
const due = performance.now() + wait;
|
|
310
|
+
if (cardTickFrame || cardTickTimer !== null && cardTickDue <= due) return;
|
|
311
|
+
if (cardTickTimer !== null) clearTimeout(cardTickTimer);
|
|
312
|
+
cardTickTimer = null;
|
|
313
|
+
if (wait > 0) {
|
|
314
|
+
cardTickDue = due;
|
|
315
|
+
cardTickTimer = setTimeout(() => {
|
|
316
|
+
cardTickTimer = null;
|
|
317
|
+
scheduleCardTick(0);
|
|
318
|
+
}, wait);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
cardTickFrame = requestAnimationFrame(() => {
|
|
322
|
+
cardTickFrame = 0;
|
|
323
|
+
if (!scene) return;
|
|
324
|
+
const next = scene.tick(performance.now());
|
|
325
|
+
scheduleRender();
|
|
326
|
+
if (next !== null) scheduleCardTick(next);
|
|
327
|
+
});
|
|
328
|
+
}
|
|
285
329
|
function scheduleTick() {
|
|
286
330
|
if (tickFrame || !active || disposed) return;
|
|
287
331
|
tickFrame = requestAnimationFrame(() => {
|
|
@@ -289,6 +333,16 @@ function mountBoardStage(host, options) {
|
|
|
289
333
|
sync();
|
|
290
334
|
});
|
|
291
335
|
}
|
|
336
|
+
function cancelScriptPointers(owner, retained) {
|
|
337
|
+
scriptPointers.cancelScripts((pointerId, target) => {
|
|
338
|
+
scripts?.event(target.owner, {
|
|
339
|
+
type: "pointercancel",
|
|
340
|
+
target: target.target,
|
|
341
|
+
pointerId
|
|
342
|
+
});
|
|
343
|
+
}, owner, retained);
|
|
344
|
+
if (!retained || scriptHover && scriptHover.owner === owner && !Object.hasOwn(retained, scriptHover.target)) scriptHover = null;
|
|
345
|
+
}
|
|
292
346
|
function createScripts() {
|
|
293
347
|
return createBoardScriptHost({
|
|
294
348
|
host,
|
|
@@ -310,8 +364,20 @@ function mountBoardStage(host, options) {
|
|
|
310
364
|
onOutput: (id, output) => {
|
|
311
365
|
if (output) {
|
|
312
366
|
prepareBoardScriptOutput(editor.document, id, output);
|
|
367
|
+
cancelScriptPointers(id, output.hits);
|
|
313
368
|
scriptOutputs.set(id, output);
|
|
314
|
-
|
|
369
|
+
if (Object.keys(output.hits).length) interactiveScripts.add(id);
|
|
370
|
+
else interactiveScripts.delete(id);
|
|
371
|
+
if (output.space === "screen" && Object.keys(output.items).length) screenScripts.add(id);
|
|
372
|
+
else screenScripts.delete(id);
|
|
373
|
+
} else {
|
|
374
|
+
cancelScriptPointers(id);
|
|
375
|
+
scriptOutputs.delete(id);
|
|
376
|
+
interactiveScripts.delete(id);
|
|
377
|
+
screenScripts.delete(id);
|
|
378
|
+
}
|
|
379
|
+
scriptObservers.update(id, output);
|
|
380
|
+
syncTransformSubscription();
|
|
315
381
|
scriptVersion++;
|
|
316
382
|
scheduleTick();
|
|
317
383
|
},
|
|
@@ -340,6 +406,10 @@ function mountBoardStage(host, options) {
|
|
|
340
406
|
const previous = scripts;
|
|
341
407
|
scripts = null;
|
|
342
408
|
previous.destroy();
|
|
409
|
+
scriptObservers.clear();
|
|
410
|
+
syncTransformSubscription();
|
|
411
|
+
interactiveScripts.clear();
|
|
412
|
+
screenScripts.clear();
|
|
343
413
|
scriptOutputs.clear();
|
|
344
414
|
editor.setScriptItems(/* @__PURE__ */ new Map());
|
|
345
415
|
scriptHover = null;
|
|
@@ -354,38 +424,48 @@ function mountBoardStage(host, options) {
|
|
|
354
424
|
const moving = new Map(previews);
|
|
355
425
|
for (const [id, item] of frame.items) moving.set(id, item);
|
|
356
426
|
editor.setPlayedItems(moving);
|
|
427
|
+
const animationId = editor.playhead?.animationId ?? (frame.playbackTime !== null ? playback?.animationId : null) ?? null;
|
|
428
|
+
if (animationId && (effectDocument !== editor.document || effectAnimation !== animationId)) {
|
|
429
|
+
effectDocument = editor.document;
|
|
430
|
+
effectAnimation = animationId;
|
|
431
|
+
effectSampler = createBoardAnimationSampler(editor.document, animationId);
|
|
432
|
+
}
|
|
433
|
+
if (editor.playhead && effectSampler) {
|
|
434
|
+
frame.camera = effectSampler.at(editor.playhead.time).evaluation.camera;
|
|
435
|
+
frame.time = editor.playhead.time;
|
|
436
|
+
}
|
|
437
|
+
playbackCamera = editor.cameraPolicy === "follow" && Object.keys(frame.camera).length > 0 ? followCamera(frame, editor.scene) : null;
|
|
438
|
+
const camera = renderCamera();
|
|
357
439
|
if (scripts && (scriptOutputs.size || composedVersion !== scriptVersion)) {
|
|
358
440
|
const playheadKey = `${editor.playhead?.animationId ?? ""}:${editor.playhead?.time ?? ""}`;
|
|
359
|
-
if (scriptVersion !== composedVersion || composedDocument !== editor.document || moving.size || composedMoving || composedZoom !==
|
|
441
|
+
if (scriptVersion !== composedVersion || composedDocument !== editor.document || screenScripts.size > 0 && editor.gestureActive || composedGesture || moving.size || composedMoving || composedZoom !== camera.zoom || composedPlayhead !== playheadKey) {
|
|
360
442
|
const animationItems = editor.animationItems();
|
|
361
|
-
const composed = composeBoardScriptItems(editor.document, editor.scene, scriptOutputs, animationItems,
|
|
443
|
+
const composed = composeBoardScriptItems(editor.document, editor.scene, scriptOutputs, animationItems, camera, (owner, error) => scripts?.fault(owner, error instanceof Error ? error.message : String(error)), editor.gestureActive ? editor.scene.layout : void 0);
|
|
362
444
|
const scriptedIds = new Set([...scriptOutputs.values()].flatMap((output) => Object.keys(output.patches)));
|
|
363
445
|
for (const id of animationItems.keys()) if (!scriptedIds.has(id)) composed.delete(id);
|
|
364
446
|
editor.setScriptItems(composed);
|
|
365
447
|
composedMoving = moving.size > 0;
|
|
366
448
|
composedPlayhead = playheadKey;
|
|
367
|
-
composedZoom =
|
|
449
|
+
composedZoom = camera.zoom;
|
|
450
|
+
composedGesture = screenScripts.size > 0 && editor.gestureActive;
|
|
368
451
|
composedVersion = scriptVersion;
|
|
369
452
|
composedDocument = editor.document;
|
|
370
453
|
}
|
|
371
454
|
}
|
|
372
455
|
const renderScene = editor.scene;
|
|
373
|
-
const animationId = editor.playhead?.animationId ?? (frame.playbackTime !== null ? playback?.animationId : null) ?? null;
|
|
374
|
-
if (animationId && (effectDocument !== editor.document || effectAnimation !== animationId)) {
|
|
375
|
-
effectDocument = editor.document;
|
|
376
|
-
effectAnimation = animationId;
|
|
377
|
-
effectSampler = createBoardAnimationSampler(editor.document, animationId);
|
|
378
|
-
}
|
|
379
|
-
if (editor.playhead && effectSampler) {
|
|
380
|
-
frame.camera = effectSampler.at(editor.playhead.time).evaluation.camera;
|
|
381
|
-
frame.time = editor.playhead.time;
|
|
382
|
-
}
|
|
383
|
-
playbackCamera = editor.cameraPolicy === "follow" && Object.keys(frame.camera).length > 0 ? followCamera(frame, renderScene) : null;
|
|
384
|
-
const camera = renderCamera();
|
|
385
456
|
if (scripts) {
|
|
386
457
|
const now = performance.now();
|
|
387
458
|
if (scriptMode !== "paused") scriptTime += Math.min(250, Math.max(0, now - scriptLastTick));
|
|
388
459
|
scriptLastTick = now;
|
|
460
|
+
if (scriptMode !== "paused" && scriptObservers.size) scriptObservers.sync(editor.document, editor.selection, () => ({
|
|
461
|
+
camera: { ...camera },
|
|
462
|
+
...surface,
|
|
463
|
+
safeRect: options.safeRect?.() ?? {
|
|
464
|
+
x: 0,
|
|
465
|
+
y: 0,
|
|
466
|
+
...surface
|
|
467
|
+
}
|
|
468
|
+
}));
|
|
389
469
|
scripts.sync(editor.document, renderScene, camera, scriptTime, scriptMode === "interact", visibleIds());
|
|
390
470
|
}
|
|
391
471
|
world.position.set(camera.x, camera.y);
|
|
@@ -420,10 +500,12 @@ function mountBoardStage(host, options) {
|
|
|
420
500
|
current.key,
|
|
421
501
|
textZoomBucket(camera.zoom)
|
|
422
502
|
].join("|"),
|
|
503
|
+
staleIds,
|
|
423
504
|
structureVersion: editor.structureVersion,
|
|
424
505
|
geometryVersion: editor.geometryVersion,
|
|
425
506
|
gestureActive: editor.gestureActive && editor.interaction.type !== "panning"
|
|
426
507
|
});
|
|
508
|
+
staleIds.clear();
|
|
427
509
|
const single = editor.selection.length === 1 ? renderScene.get(editor.selection[0]) : null;
|
|
428
510
|
let arrowEndpoints;
|
|
429
511
|
if (single?.type === "arrow" && !single.locked) {
|
|
@@ -467,6 +549,8 @@ function mountBoardStage(host, options) {
|
|
|
467
549
|
if (nextCursor !== cursor) host.style.cursor = cursor = nextCursor;
|
|
468
550
|
scheduleRender();
|
|
469
551
|
if (frame.running || scene.animated || scriptMode !== "paused" && scripts?.animated) scheduleTick();
|
|
552
|
+
const cardWait = scene.tick(performance.now());
|
|
553
|
+
if (cardWait !== null) scheduleCardTick(cardWait);
|
|
470
554
|
}
|
|
471
555
|
function resize() {
|
|
472
556
|
cancelAnimationFrame(resizeFrame);
|
|
@@ -517,7 +601,7 @@ function mountBoardStage(host, options) {
|
|
|
517
601
|
});
|
|
518
602
|
}
|
|
519
603
|
function scriptPointer(type, event, input) {
|
|
520
|
-
if (!scriptPointers.needsRouting(event.pointerId,
|
|
604
|
+
if (!scriptPointers.needsRouting(event.pointerId, interactiveScripts.size > 0)) return false;
|
|
521
605
|
const enabled = scriptMode === "interact" && !editor.gestureActive && !editor.spaceHeld && event.button !== 1;
|
|
522
606
|
const target = type === "leave" || !enabled || scriptPointers.owner(event.pointerId) === "editor" ? null : scriptTarget(input);
|
|
523
607
|
if (target?.owner !== scriptHover?.owner || target?.target !== scriptHover?.target) {
|
|
@@ -525,6 +609,7 @@ function mountBoardStage(host, options) {
|
|
|
525
609
|
if (target) sendScriptEvent(target, "pointerenter", event, input, scriptHover);
|
|
526
610
|
scriptHover = target;
|
|
527
611
|
}
|
|
612
|
+
const consumed = scriptPointers.owner(event.pointerId) === "script";
|
|
528
613
|
const { recipient, click } = scriptPointers.route(type, event.pointerId, target, {
|
|
529
614
|
x: event.clientX,
|
|
530
615
|
y: event.clientY
|
|
@@ -535,10 +620,10 @@ function mountBoardStage(host, options) {
|
|
|
535
620
|
}
|
|
536
621
|
if (recipient && type !== "leave") sendScriptEvent(recipient, input.cancelled ? "pointercancel" : `pointer${type}`, event, input);
|
|
537
622
|
if (click) sendScriptEvent(click, "click", event, input);
|
|
538
|
-
return recipient !== null;
|
|
623
|
+
return consumed || recipient !== null;
|
|
539
624
|
}
|
|
540
625
|
function handleScriptKey(event) {
|
|
541
|
-
if (scriptMode !== "interact" || !scriptHover || event.target !== host) return;
|
|
626
|
+
if (scriptMode !== "interact" || !scriptHover || event.target !== host || !scriptOutputs.get(scriptHover.owner)?.listens.includes(event.type)) return;
|
|
542
627
|
const input = {
|
|
543
628
|
type: event.type,
|
|
544
629
|
target: scriptHover.target,
|
|
@@ -689,6 +774,7 @@ function mountBoardStage(host, options) {
|
|
|
689
774
|
},
|
|
690
775
|
setScriptMode(mode) {
|
|
691
776
|
if (mode === scriptMode) return;
|
|
777
|
+
if (mode !== "interact") cancelScriptPointers();
|
|
692
778
|
scriptMode = mode;
|
|
693
779
|
scriptLastTick = performance.now();
|
|
694
780
|
scheduleTick();
|
|
@@ -723,10 +809,15 @@ function mountBoardStage(host, options) {
|
|
|
723
809
|
if (active === next) return;
|
|
724
810
|
active = next;
|
|
725
811
|
if (!active) {
|
|
812
|
+
cancelScriptPointers();
|
|
726
813
|
cancelAnimationFrame(renderFrame);
|
|
727
814
|
cancelAnimationFrame(tickFrame);
|
|
815
|
+
cancelAnimationFrame(cardTickFrame);
|
|
816
|
+
if (cardTickTimer !== null) clearTimeout(cardTickTimer);
|
|
728
817
|
renderFrame = 0;
|
|
729
818
|
tickFrame = 0;
|
|
819
|
+
cardTickFrame = 0;
|
|
820
|
+
cardTickTimer = null;
|
|
730
821
|
return;
|
|
731
822
|
}
|
|
732
823
|
player.reset();
|
|
@@ -738,6 +829,7 @@ function mountBoardStage(host, options) {
|
|
|
738
829
|
cardEpoch += 1;
|
|
739
830
|
requestAssets = true;
|
|
740
831
|
}
|
|
832
|
+
for (const id of invalidation?.items ?? []) staleIds.add(id);
|
|
741
833
|
scheduleTick();
|
|
742
834
|
},
|
|
743
835
|
isMaterialized: (id) => Boolean(scene?.getNode(id)),
|
|
@@ -745,6 +837,8 @@ function mountBoardStage(host, options) {
|
|
|
745
837
|
destroy() {
|
|
746
838
|
disposed = true;
|
|
747
839
|
scriptPointers.clear();
|
|
840
|
+
stopTransforms?.();
|
|
841
|
+
scriptObservers.clear();
|
|
748
842
|
scriptListeners.clear();
|
|
749
843
|
stopMaintenance?.();
|
|
750
844
|
stopEditor();
|
|
@@ -753,6 +847,9 @@ function mountBoardStage(host, options) {
|
|
|
753
847
|
cancelAnimationFrame(resizeFrame);
|
|
754
848
|
cancelAnimationFrame(renderFrame);
|
|
755
849
|
cancelAnimationFrame(tickFrame);
|
|
850
|
+
cancelAnimationFrame(cardTickFrame);
|
|
851
|
+
if (cardTickTimer !== null) clearTimeout(cardTickTimer);
|
|
852
|
+
cardTickTimer = null;
|
|
756
853
|
for (const [type, listener] of listeners) host.removeEventListener(type, listener);
|
|
757
854
|
editor.setPlayedItems(/* @__PURE__ */ new Map());
|
|
758
855
|
editor.setScriptItems(/* @__PURE__ */ new Map());
|