@neta-art/cohub 11.0.0 → 11.2.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/context.d.ts +1 -0
- package/dist/board/editor/context.js +1 -0
- package/dist/board/editor/creation.d.ts +2 -2
- package/dist/board/editor/creation.js +3 -3
- package/dist/board/editor/editor.d.ts +5 -4
- package/dist/board/editor/editor.js +8 -1
- package/dist/board/editor/index.d.ts +2 -2
- package/dist/board/editor/interaction.d.ts +12 -2
- package/dist/board/editor/interaction.js +50 -8
- package/dist/board/editor/selection-transform.d.ts +1 -1
- package/dist/board/editor/selection-transform.js +13 -2
- package/dist/board/editor/snapshots.d.ts +0 -2
- package/dist/board/editor/snapshots.js +4 -20
- package/dist/board/export/index.d.ts +2 -0
- package/dist/board/export/index.js +1 -0
- package/dist/board/export/scene.d.ts +2 -0
- package/dist/board/export/scene.js +8 -1
- package/dist/board/model/file-preview.d.ts +0 -1
- package/dist/board/model/file-preview.js +10 -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/audio-waveform.d.ts +1 -1
- package/dist/board/render/audio-waveform.js +8 -5
- package/dist/board/render/board-background.js +5 -4
- package/dist/board/render/card-tag.d.ts +24 -0
- package/dist/board/render/card-tag.js +205 -0
- package/dist/board/render/index.d.ts +8 -5
- package/dist/board/render/index.js +8 -5
- package/dist/board/render/media-interaction.d.ts +2 -1
- package/dist/board/render/media-interaction.js +15 -7
- package/dist/board/render/palette.js +2 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +20 -16
- package/dist/board/render/renderers/audio-card-renderer.d.ts +8 -1
- package/dist/board/render/renderers/audio-card-renderer.js +64 -60
- package/dist/board/render/renderers/base-card-renderer.d.ts +1 -26
- package/dist/board/render/renderers/base-card-renderer.js +6 -92
- package/dist/board/render/renderers/board-renderer-registry.d.ts +25 -2
- package/dist/board/render/renderers/board-renderer-registry.js +11 -4
- package/dist/board/render/renderers/custom-card-renderer.js +6 -8
- package/dist/board/render/renderers/effect-card-renderer.js +0 -5
- package/dist/board/render/renderers/file-card-renderer.d.ts +1 -11
- package/dist/board/render/renderers/file-card-renderer.js +43 -105
- package/dist/board/render/renderers/frame-card-renderer.js +14 -15
- package/dist/board/render/renderers/image-card-renderer.js +62 -67
- package/dist/board/render/renderers/media-key.d.ts +6 -0
- package/dist/board/render/renderers/media-key.js +39 -0
- package/dist/board/render/renderers/shape-card-renderer.js +6 -12
- package/dist/board/render/renderers/task-card-renderer.d.ts +1 -8
- package/dist/board/render/renderers/task-card-renderer.js +286 -111
- package/dist/board/render/renderers/unknown-card-renderer.js +17 -16
- package/dist/board/render/renderers/video-card-renderer.js +73 -80
- 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/render/stroke.d.ts +1 -1
- package/dist/board/render/stroke.js +5 -4
- package/dist/board/render/style.d.ts +29 -0
- package/dist/board/render/style.js +54 -0
- package/dist/board/render/surface.d.ts +34 -0
- package/dist/board/render/surface.js +132 -0
- package/dist/board/render/text-fit.d.ts +8 -0
- package/dist/board/render/text-fit.js +60 -0
- package/dist/board/render/text-resolution.d.ts +2 -1
- package/dist/board/render/text-resolution.js +4 -1
- package/dist/board/stage/assets.js +1 -1
- package/dist/board/stage/index.d.ts +3 -2
- package/dist/board/stage/index.js +2 -1
- package/dist/board/stage/overlay.d.ts +41 -0
- package/dist/board/stage/overlay.js +182 -0
- package/dist/board/stage/scene.d.ts +4 -43
- package/dist/board/stage/scene.js +38 -130
- 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 +13 -3
- package/dist/board/stage/stage.js +217 -53
- package/dist/chunks/environment.d.ts +1037 -8
- package/dist/chunks/environment.js +12 -4
- package/dist/chunks/http.d.ts +51 -2
- package/dist/chunks/http.js +10 -1
- package/dist/chunks/transport.js +1 -1
- package/dist/chunks/websocket.d.ts +1 -1
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +3 -3
- 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 +2 -1
- package/dist/board/model/task.d.ts +0 -11
- package/dist/types.d.ts +0 -36
|
@@ -2,11 +2,75 @@ import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
|
|
|
2
2
|
import { frameContainsPoint } from "./geometry.js";
|
|
3
3
|
import { scriptTemporaryPrefix } from "./script-scene.js";
|
|
4
4
|
//#region src/board/model/script-hit.ts
|
|
5
|
+
function resolveBoardScriptHit(scene, owner, hit) {
|
|
6
|
+
const id = "item" in hit ? `${scriptTemporaryPrefix(owner)}${hit.item}` : owner;
|
|
7
|
+
const item = scene.get(id);
|
|
8
|
+
if (!item || scene.opacity(id) <= 0) return null;
|
|
9
|
+
const box = scene.layout.box(id);
|
|
10
|
+
return {
|
|
11
|
+
id,
|
|
12
|
+
item,
|
|
13
|
+
rect: "x" in hit ? hit : {
|
|
14
|
+
x: 0,
|
|
15
|
+
y: 0,
|
|
16
|
+
width: box.width,
|
|
17
|
+
height: box.height
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function boardScriptHitVisible(scene, hit, camera, surface) {
|
|
22
|
+
const { x, y, width, height } = hit.rect;
|
|
23
|
+
if (width <= 0 || height <= 0) return false;
|
|
24
|
+
const matrix = scene.layout.matrix(hit.id);
|
|
25
|
+
const corners = [
|
|
26
|
+
applyMatrix(matrix, {
|
|
27
|
+
x,
|
|
28
|
+
y
|
|
29
|
+
}),
|
|
30
|
+
applyMatrix(matrix, {
|
|
31
|
+
x: x + width,
|
|
32
|
+
y
|
|
33
|
+
}),
|
|
34
|
+
applyMatrix(matrix, {
|
|
35
|
+
x,
|
|
36
|
+
y: y + height
|
|
37
|
+
}),
|
|
38
|
+
applyMatrix(matrix, {
|
|
39
|
+
x: x + width,
|
|
40
|
+
y: y + height
|
|
41
|
+
})
|
|
42
|
+
];
|
|
43
|
+
const xs = corners.map((point) => point.x * camera.zoom + camera.x);
|
|
44
|
+
const ys = corners.map((point) => point.y * camera.zoom + camera.y);
|
|
45
|
+
return Math.max(...xs) > 0 && Math.min(...xs) < surface.width && Math.max(...ys) > 0 && Math.min(...ys) < surface.height;
|
|
46
|
+
}
|
|
47
|
+
const bindings = /* @__PURE__ */ new WeakMap();
|
|
48
|
+
function bindingsFor(owner, output) {
|
|
49
|
+
const cached = bindings.get(output);
|
|
50
|
+
if (cached?.owner === owner) return cached.byItem;
|
|
51
|
+
const byItem = /* @__PURE__ */ new Map();
|
|
52
|
+
for (const [target, hit] of Object.entries(output.hits)) {
|
|
53
|
+
const id = "item" in hit ? `${scriptTemporaryPrefix(owner)}${hit.item}` : owner;
|
|
54
|
+
const list = byItem.get(id) ?? [];
|
|
55
|
+
list.push({
|
|
56
|
+
owner,
|
|
57
|
+
target,
|
|
58
|
+
hit
|
|
59
|
+
});
|
|
60
|
+
byItem.set(id, list);
|
|
61
|
+
}
|
|
62
|
+
bindings.set(output, {
|
|
63
|
+
owner,
|
|
64
|
+
byItem
|
|
65
|
+
});
|
|
66
|
+
return byItem;
|
|
67
|
+
}
|
|
5
68
|
function boardScriptTarget(scene, candidates, point, outputs, hitTest) {
|
|
6
|
-
const
|
|
69
|
+
const declared = [...outputs].map(([owner, output]) => bindingsFor(owner, output));
|
|
70
|
+
const prefixes = [...outputs.keys()].map(scriptTemporaryPrefix);
|
|
7
71
|
for (const id of [...candidates].sort((a, b) => scene.indexOf(b) - scene.indexOf(a))) {
|
|
8
72
|
const item = scene.get(id);
|
|
9
|
-
if (!item || scene.opacity(id) <= 0
|
|
73
|
+
if (!item || scene.opacity(id) <= 0) continue;
|
|
10
74
|
let parent = item.parent;
|
|
11
75
|
let clipped = false;
|
|
12
76
|
for (let depth = 0; parent && depth < 64; depth++) {
|
|
@@ -19,34 +83,27 @@ function boardScriptTarget(scene, candidates, point, outputs, hitTest) {
|
|
|
19
83
|
parent = ancestor.parent;
|
|
20
84
|
}
|
|
21
85
|
if (clipped) continue;
|
|
22
|
-
const
|
|
23
|
-
|
|
86
|
+
for (const byItem of declared) {
|
|
87
|
+
const hits = byItem.get(id);
|
|
88
|
+
if (!hits) continue;
|
|
24
89
|
const local = applyMatrix(invertMatrix(scene.layout.matrix(id)), point);
|
|
25
|
-
for (
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
owner: current.id,
|
|
35
|
-
target: id
|
|
36
|
-
};
|
|
37
|
-
for (const [prefix, owner] of owners) {
|
|
38
|
-
if (current.id === `${prefix}root`) break;
|
|
39
|
-
if (current.id.startsWith(prefix)) return {
|
|
40
|
-
owner,
|
|
41
|
-
target: current.id.slice(prefix.length)
|
|
90
|
+
for (let i = hits.length - 1; i >= 0; i--) {
|
|
91
|
+
const binding = hits[i];
|
|
92
|
+
if (!binding) continue;
|
|
93
|
+
const resolved = resolveBoardScriptHit(scene, binding.owner, binding.hit);
|
|
94
|
+
if (!resolved) continue;
|
|
95
|
+
const r = resolved.rect;
|
|
96
|
+
if (local.x >= r.x && local.y >= r.y && local.x <= r.x + r.width && local.y <= r.y + r.height && ("x" in binding.hit || hitTest(item, point))) return {
|
|
97
|
+
owner: binding.owner,
|
|
98
|
+
target: binding.target
|
|
42
99
|
};
|
|
43
100
|
}
|
|
44
|
-
current = current.parent ? scene.get(current.parent) : void 0;
|
|
45
101
|
}
|
|
102
|
+
if (prefixes.some((prefix) => id.startsWith(prefix))) continue;
|
|
46
103
|
if (item.type === "frame" && item.props.decoration === "none") continue;
|
|
47
|
-
return null;
|
|
104
|
+
if (hitTest(item, point)) return null;
|
|
48
105
|
}
|
|
49
106
|
return null;
|
|
50
107
|
}
|
|
51
108
|
//#endregion
|
|
52
|
-
export { boardScriptTarget };
|
|
109
|
+
export { boardScriptHitVisible, boardScriptTarget, resolveBoardScriptHit };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BoardDocument } from "../../protocol/dist/board-model.js";
|
|
2
|
+
import "../../protocol/dist/index.js";
|
|
3
|
+
import { BoardScriptEvent, BoardScriptOutput, BoardScriptView } from "./script.js";
|
|
4
|
+
//#region src/board/model/script-observers.d.ts
|
|
5
|
+
declare function createBoardScriptObservers(send: (owner: string, event: BoardScriptEvent) => void): {
|
|
6
|
+
readonly size: number;
|
|
7
|
+
readonly transforms: boolean;
|
|
8
|
+
update(owner: string, output: BoardScriptOutput | null): void;
|
|
9
|
+
sync(document: BoardDocument, selection: readonly string[], readView: () => BoardScriptView): void;
|
|
10
|
+
transform(document: BoardDocument, event: {
|
|
11
|
+
ids: readonly string[];
|
|
12
|
+
operation: string;
|
|
13
|
+
cancelled: boolean;
|
|
14
|
+
}): void;
|
|
15
|
+
clear(): void;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { createBoardScriptObservers };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { boardScriptScope } from "./script-scene.js";
|
|
2
|
+
//#region src/board/model/script-observers.ts
|
|
3
|
+
const EVENTS = [
|
|
4
|
+
"viewchange",
|
|
5
|
+
"selectionchange",
|
|
6
|
+
"transformend"
|
|
7
|
+
];
|
|
8
|
+
function createBoardScriptObservers(send) {
|
|
9
|
+
const subscribers = /* @__PURE__ */ new Map();
|
|
10
|
+
function scope(owner, entry, document) {
|
|
11
|
+
if (entry.document !== document) {
|
|
12
|
+
entry.scope = boardScriptScope(document, owner);
|
|
13
|
+
entry.document = document;
|
|
14
|
+
entry.selection = void 0;
|
|
15
|
+
}
|
|
16
|
+
return entry.scope;
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
get size() {
|
|
20
|
+
return subscribers.size;
|
|
21
|
+
},
|
|
22
|
+
get transforms() {
|
|
23
|
+
return [...subscribers.values()].some((entry) => entry.listens.has("transformend"));
|
|
24
|
+
},
|
|
25
|
+
update(owner, output) {
|
|
26
|
+
const listens = new Set(EVENTS.filter((type) => output?.listens.includes(type)));
|
|
27
|
+
if (!listens.size) {
|
|
28
|
+
subscribers.delete(owner);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const entry = subscribers.get(owner) ?? {
|
|
32
|
+
listens,
|
|
33
|
+
scope: /* @__PURE__ */ new Set()
|
|
34
|
+
};
|
|
35
|
+
if (!listens.has("viewchange")) entry.view = void 0;
|
|
36
|
+
if (!listens.has("selectionchange")) {
|
|
37
|
+
entry.selection = void 0;
|
|
38
|
+
entry.selected = void 0;
|
|
39
|
+
}
|
|
40
|
+
entry.listens = listens;
|
|
41
|
+
subscribers.set(owner, entry);
|
|
42
|
+
},
|
|
43
|
+
sync(document, selection, readView) {
|
|
44
|
+
let view;
|
|
45
|
+
let key;
|
|
46
|
+
for (const [owner, entry] of subscribers) {
|
|
47
|
+
if (entry.listens.has("viewchange")) {
|
|
48
|
+
view ??= readView();
|
|
49
|
+
key ??= JSON.stringify(view);
|
|
50
|
+
if (entry.view !== key) {
|
|
51
|
+
entry.view = key;
|
|
52
|
+
send(owner, {
|
|
53
|
+
type: "viewchange",
|
|
54
|
+
data: view
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (entry.listens.has("selectionchange")) {
|
|
59
|
+
const allowed = scope(owner, entry, document);
|
|
60
|
+
if (entry.selection === selection) continue;
|
|
61
|
+
entry.selection = selection;
|
|
62
|
+
const ids = selection.filter((id) => allowed.has(id));
|
|
63
|
+
if (entry.selected && ids.length === entry.selected.length && ids.every((id, i) => id === entry.selected?.[i])) continue;
|
|
64
|
+
entry.selected = ids;
|
|
65
|
+
send(owner, {
|
|
66
|
+
type: "selectionchange",
|
|
67
|
+
data: { ids }
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
transform(document, event) {
|
|
73
|
+
for (const [owner, entry] of subscribers) {
|
|
74
|
+
if (!entry.listens.has("transformend")) continue;
|
|
75
|
+
const allowed = scope(owner, entry, document);
|
|
76
|
+
const ids = event.ids.filter((id) => allowed.has(id));
|
|
77
|
+
if (ids.length) send(owner, {
|
|
78
|
+
type: "transformend",
|
|
79
|
+
data: {
|
|
80
|
+
...event,
|
|
81
|
+
ids
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
clear() {
|
|
87
|
+
subscribers.clear();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { createBoardScriptObservers };
|
|
@@ -19,6 +19,6 @@ type PreparedOutput = {
|
|
|
19
19
|
declare function prepareBoardScriptOutput(document: BoardDocument, owner: string, output: BoardScriptOutput): PreparedOutput;
|
|
20
20
|
declare function composeBoardScriptItems(document: BoardDocument, scene: BoardScene, outputs: ReadonlyMap<string, BoardScriptOutput>, incoming?: ReadonlyMap<string, BoardItem>, screen?: {
|
|
21
21
|
zoom: number;
|
|
22
|
-
}, onError?: (owner: string, error: unknown) => void): Map<string, BoardItem>;
|
|
22
|
+
}, onError?: (owner: string, error: unknown) => void, gestureLayout?: BoardScene["layout"]): Map<string, BoardItem>;
|
|
23
23
|
//#endregion
|
|
24
24
|
export { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, scriptTemporaryPrefix, validateBoardScriptCommit, validateBoardScriptOutput };
|
|
@@ -35,6 +35,10 @@ function validateBoardScriptOutput(output, scope) {
|
|
|
35
35
|
if (!output || typeof output !== "object" || !output.patches || !output.items || !output.hits || !Array.isArray(output.listens)) throw new Error("Invalid script output.");
|
|
36
36
|
if (JSON.stringify(output).length > 1e6) throw new Error("Script output exceeds the 1 MB limit.");
|
|
37
37
|
if (output.space !== void 0 && output.space !== "world" && output.space !== "screen") throw new Error("Invalid script scene space.");
|
|
38
|
+
if (output.anchor) {
|
|
39
|
+
const { item, point } = output.anchor;
|
|
40
|
+
if (output.space !== "screen" || typeof item !== "string" || !item || point && ![point.x, point.y].every((n) => Number.isFinite(n) && n >= 0 && n <= 1)) throw new Error("Invalid screen scene anchor.");
|
|
41
|
+
}
|
|
38
42
|
if (output.parameters) {
|
|
39
43
|
if (Object.keys(output.parameters).length > 64) throw new Error("A script may declare at most 64 parameters.");
|
|
40
44
|
for (const spec of Object.values(output.parameters)) {
|
|
@@ -58,6 +62,7 @@ function validateBoardScriptOutput(output, scope) {
|
|
|
58
62
|
if (!patch || typeof patch !== "object" || Object.keys(patch).some((key) => !DISPLAY_FIELDS.has(key))) throw new Error("Scripts may only present display properties.");
|
|
59
63
|
}
|
|
60
64
|
for (const hit of Object.values(output.hits)) {
|
|
65
|
+
if (!hit || typeof hit !== "object") throw new Error("Invalid script hit region.");
|
|
61
66
|
if (hit.cursor && ![
|
|
62
67
|
"default",
|
|
63
68
|
"pointer",
|
|
@@ -70,7 +75,11 @@ function validateBoardScriptOutput(output, scope) {
|
|
|
70
75
|
"ns-resize",
|
|
71
76
|
"not-allowed"
|
|
72
77
|
].includes(hit.cursor)) throw new Error("Invalid script cursor.");
|
|
73
|
-
if (
|
|
78
|
+
if ("target" in hit) {
|
|
79
|
+
if (hit.target !== "self" || "item" in hit || "x" in hit) throw new Error("Invalid script hit target.");
|
|
80
|
+
} else if ("item" in hit) {
|
|
81
|
+
if (typeof hit.item !== "string" || !Object.hasOwn(output.items, hit.item) || "x" in hit) throw new Error("Hit items must belong to the temporary scene.");
|
|
82
|
+
} else if (![
|
|
74
83
|
hit.x,
|
|
75
84
|
hit.y,
|
|
76
85
|
hit.width,
|
|
@@ -100,6 +109,15 @@ function scriptTemporaryPrefix(owner) {
|
|
|
100
109
|
}
|
|
101
110
|
const preparedOutputs = /* @__PURE__ */ new WeakMap();
|
|
102
111
|
const preparedScopes = /* @__PURE__ */ new WeakMap();
|
|
112
|
+
const itemOrders = /* @__PURE__ */ new WeakMap();
|
|
113
|
+
function orderedScriptOwners(document, outputs) {
|
|
114
|
+
let order = itemOrders.get(document.items);
|
|
115
|
+
if (!order) {
|
|
116
|
+
order = new Map(Object.keys(document.items).map((id, index) => [id, index]));
|
|
117
|
+
itemOrders.set(document.items, order);
|
|
118
|
+
}
|
|
119
|
+
return [...outputs.keys()].filter((id) => order.has(id)).sort((a, b) => (order.get(a) ?? 0) - (order.get(b) ?? 0));
|
|
120
|
+
}
|
|
103
121
|
function prepareBoardScriptOutput(document, owner, output) {
|
|
104
122
|
const previous = preparedOutputs.get(output);
|
|
105
123
|
if (previous?.document === document && previous.owner === owner) return previous;
|
|
@@ -113,6 +131,7 @@ function prepareBoardScriptOutput(document, owner, output) {
|
|
|
113
131
|
scope = boardScriptScope(document, owner);
|
|
114
132
|
scopes.set(owner, scope);
|
|
115
133
|
}
|
|
134
|
+
if (output.anchor && document.items[output.anchor.item] && !scope.has(output.anchor.item)) throw new Error("Scene anchor is outside the script scope.");
|
|
116
135
|
validateBoardScriptOutput(output, scope);
|
|
117
136
|
const presented = /* @__PURE__ */ new Map();
|
|
118
137
|
for (const [id, patch] of Object.entries(output.patches)) {
|
|
@@ -177,11 +196,11 @@ function prepareBoardScriptOutput(document, owner, output) {
|
|
|
177
196
|
preparedOutputs.set(output, prepared);
|
|
178
197
|
return prepared;
|
|
179
198
|
}
|
|
180
|
-
function composeBoardScriptItems(document, scene, outputs, incoming = /* @__PURE__ */ new Map(), screen, onError) {
|
|
199
|
+
function composeBoardScriptItems(document, scene, outputs, incoming = /* @__PURE__ */ new Map(), screen, onError, gestureLayout) {
|
|
181
200
|
const result = new Map(incoming);
|
|
182
201
|
const screenAnchors = /* @__PURE__ */ new Map();
|
|
183
202
|
if (outputs.size === 0) return result;
|
|
184
|
-
for (const owner of
|
|
203
|
+
for (const owner of orderedScriptOwners(document, outputs)) {
|
|
185
204
|
const output = outputs.get(owner);
|
|
186
205
|
if (!output) continue;
|
|
187
206
|
try {
|
|
@@ -249,15 +268,23 @@ function composeBoardScriptItems(document, scene, outputs, incoming = /* @__PURE
|
|
|
249
268
|
}
|
|
250
269
|
}
|
|
251
270
|
if (screenAnchors.size) {
|
|
252
|
-
const layout = createBoardLayout((id) => result.get(id) ?? document.items[id]);
|
|
271
|
+
const layout = gestureLayout ?? createBoardLayout((id) => result.get(id) ?? document.items[id]);
|
|
253
272
|
for (const [owner, rootId] of screenAnchors) {
|
|
254
273
|
const root = result.get(rootId);
|
|
274
|
+
const anchor = outputs.get(owner)?.anchor;
|
|
275
|
+
const target = anchor?.item ?? owner;
|
|
276
|
+
const exists = Boolean(document.items[target]);
|
|
277
|
+
const box = exists ? layout.box(target) : {
|
|
278
|
+
width: 0,
|
|
279
|
+
height: 0
|
|
280
|
+
};
|
|
255
281
|
if (root) result.set(rootId, {
|
|
256
282
|
...root,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
283
|
+
opacity: exists ? root.opacity : 0,
|
|
284
|
+
position: exists ? applyMatrix(layout.matrix(target), {
|
|
285
|
+
x: (anchor?.point?.x ?? 0) * box.width,
|
|
286
|
+
y: (anchor?.point?.y ?? 0) * box.height
|
|
287
|
+
}) : root.position
|
|
261
288
|
});
|
|
262
289
|
}
|
|
263
290
|
}
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import { BoardItem, BoardPatch, BoardScript, BoardVec2 } from "../../protocol/dist/board-model.js";
|
|
2
2
|
import "../../protocol/dist/index.js";
|
|
3
3
|
//#region src/board/model/script.d.ts
|
|
4
|
+
type BoardScriptView = {
|
|
5
|
+
camera: {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
zoom: number;
|
|
9
|
+
};
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
safeRect: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
type BoardScriptAnchor = {
|
|
20
|
+
item: string;
|
|
21
|
+
point?: BoardVec2;
|
|
22
|
+
};
|
|
23
|
+
type BoardScriptSceneOptions = {
|
|
24
|
+
space?: "world" | "screen";
|
|
25
|
+
anchor?: BoardScriptAnchor;
|
|
26
|
+
};
|
|
4
27
|
type BoardScriptEvent = {
|
|
5
28
|
type: string;
|
|
6
29
|
target?: string;
|
|
@@ -17,6 +40,22 @@ type BoardScriptEvent = {
|
|
|
17
40
|
metaKey?: boolean;
|
|
18
41
|
data?: unknown;
|
|
19
42
|
};
|
|
43
|
+
type BoardScriptHostEvents = {
|
|
44
|
+
viewchange: BoardScriptView;
|
|
45
|
+
selectionchange: {
|
|
46
|
+
ids: string[];
|
|
47
|
+
};
|
|
48
|
+
transformend: {
|
|
49
|
+
ids: string[];
|
|
50
|
+
operation: "move" | "resize" | "rotate" | "arrow";
|
|
51
|
+
cancelled: boolean;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
type BoardScriptEventOf<Type extends string> = BoardScriptEvent & {
|
|
55
|
+
type: Type;
|
|
56
|
+
} & (Type extends keyof BoardScriptHostEvents ? {
|
|
57
|
+
data: BoardScriptHostEvents[Type];
|
|
58
|
+
} : unknown);
|
|
20
59
|
type BoardScriptFrame = {
|
|
21
60
|
t: number;
|
|
22
61
|
dt: number;
|
|
@@ -33,11 +72,16 @@ type BoardScriptItemPatch = Partial<Pick<BoardItem, "position" | "scale" | "rota
|
|
|
33
72
|
};
|
|
34
73
|
props?: Record<string, unknown>;
|
|
35
74
|
};
|
|
36
|
-
type BoardScriptHit = {
|
|
75
|
+
type BoardScriptHit = ({
|
|
37
76
|
x: number;
|
|
38
77
|
y: number;
|
|
39
78
|
width: number;
|
|
40
79
|
height: number;
|
|
80
|
+
} | {
|
|
81
|
+
target: "self";
|
|
82
|
+
} | {
|
|
83
|
+
item: string;
|
|
84
|
+
}) & {
|
|
41
85
|
label?: string;
|
|
42
86
|
cursor?: string;
|
|
43
87
|
};
|
|
@@ -46,7 +90,7 @@ type BoardScriptSnapshot = {
|
|
|
46
90
|
time: number;
|
|
47
91
|
random: number;
|
|
48
92
|
configuration?: string;
|
|
49
|
-
effects?: Pick<BoardScriptOutput, "patches" | "items" | "hits" | "space">;
|
|
93
|
+
effects?: Pick<BoardScriptOutput, "patches" | "items" | "hits" | "space" | "anchor">;
|
|
50
94
|
};
|
|
51
95
|
type BoardScriptParameter = {
|
|
52
96
|
type: "number" | "boolean" | "string" | "color";
|
|
@@ -59,6 +103,7 @@ type BoardScriptParameter = {
|
|
|
59
103
|
type BoardScriptOutput = {
|
|
60
104
|
parameters?: Record<string, BoardScriptParameter>;
|
|
61
105
|
space?: "world" | "screen";
|
|
106
|
+
anchor?: BoardScriptAnchor;
|
|
62
107
|
patches: Record<string, Record<string, unknown>>;
|
|
63
108
|
items: Record<string, unknown>;
|
|
64
109
|
hits: Record<string, BoardScriptHit>;
|
|
@@ -78,16 +123,15 @@ type BoardScriptContext = {
|
|
|
78
123
|
emit(target: string, type: string, data?: unknown): Promise<void>;
|
|
79
124
|
readonly state: Record<string, unknown>;
|
|
80
125
|
readonly frame: BoardScriptFrame;
|
|
126
|
+
readonly view: BoardScriptView | null;
|
|
81
127
|
random(): number;
|
|
82
|
-
on(type:
|
|
128
|
+
on<Type extends string>(type: Type, handler: (event: BoardScriptEventOf<Type>) => void): () => void;
|
|
83
129
|
onFrame(handler: (frame: BoardScriptFrame) => void): () => void;
|
|
84
130
|
onDispose(handler: () => void): void;
|
|
85
131
|
invalidate(): void;
|
|
86
132
|
get(id: string): BoardItem | undefined;
|
|
87
133
|
present(id: string, patch: BoardScriptItemPatch | null): void;
|
|
88
|
-
scene(items: Record<string, unknown>, options?:
|
|
89
|
-
space?: "world" | "screen";
|
|
90
|
-
}): void;
|
|
134
|
+
scene(items: Record<string, unknown>, options?: BoardScriptSceneOptions): void;
|
|
91
135
|
hitRegions(hits: Record<string, BoardScriptHit>): void;
|
|
92
136
|
commit(patch: BoardPatch): Promise<void>;
|
|
93
137
|
capabilities: {
|
|
@@ -102,4 +146,4 @@ type BoardScriptModule = {
|
|
|
102
146
|
animated?: boolean;
|
|
103
147
|
};
|
|
104
148
|
//#endregion
|
|
105
|
-
export { BoardScriptContext, BoardScriptEvent, BoardScriptFrame, BoardScriptHit, BoardScriptItemPatch, BoardScriptModule, BoardScriptOutput, BoardScriptParameter, BoardScriptSnapshot };
|
|
149
|
+
export { BoardScriptAnchor, BoardScriptContext, BoardScriptEvent, BoardScriptEventOf, BoardScriptFrame, BoardScriptHit, BoardScriptHostEvents, BoardScriptItemPatch, BoardScriptModule, BoardScriptOutput, BoardScriptParameter, BoardScriptSceneOptions, BoardScriptSnapshot, BoardScriptView };
|
|
@@ -7,6 +7,6 @@ declare function drawAudioWaveform(graphics: Graphics, seed: string, rect: {
|
|
|
7
7
|
y: number;
|
|
8
8
|
width: number;
|
|
9
9
|
height: number;
|
|
10
|
-
}, color: number, alpha?: number): void;
|
|
10
|
+
}, color: number, alpha?: number, square?: boolean): void;
|
|
11
11
|
//#endregion
|
|
12
12
|
export { audioWaveformBars, drawAudioWaveform };
|
|
@@ -17,7 +17,7 @@ function audioWaveformBars(seed, count) {
|
|
|
17
17
|
}
|
|
18
18
|
return bars;
|
|
19
19
|
}
|
|
20
|
-
function drawAudioWaveform(graphics, seed, rect, color, alpha = .72) {
|
|
20
|
+
function drawAudioWaveform(graphics, seed, rect, color, alpha = .72, square = false) {
|
|
21
21
|
const count = Math.max(8, Math.min(DEFAULT_BARS, Math.floor(rect.width / 4)));
|
|
22
22
|
const step = rect.width / count;
|
|
23
23
|
const barWidth = Math.max(1.5, step - BAR_GAP);
|
|
@@ -26,11 +26,14 @@ function drawAudioWaveform(graphics, seed, rect, color, alpha = .72) {
|
|
|
26
26
|
const bars = audioWaveformBars(seed, count);
|
|
27
27
|
for (let index = 0; index < count; index += 1) {
|
|
28
28
|
const height = Math.max(2, (bars[index] ?? .4) * maxHeight);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
29
|
+
const x = rect.x + index * step;
|
|
30
|
+
if (square) graphics.rect(x, centerY - height / 2, barWidth, height);
|
|
31
|
+
else graphics.roundRect(x, centerY - height / 2, barWidth, height, barWidth / 2);
|
|
33
32
|
}
|
|
33
|
+
graphics.fill({
|
|
34
|
+
color,
|
|
35
|
+
alpha
|
|
36
|
+
});
|
|
34
37
|
}
|
|
35
38
|
//#endregion
|
|
36
39
|
export { audioWaveformBars, drawAudioWaveform };
|
|
@@ -12,7 +12,7 @@ function buildGridTexture(context, size, color, opacity, kind) {
|
|
|
12
12
|
width: 1,
|
|
13
13
|
alpha: opacity
|
|
14
14
|
});
|
|
15
|
-
else graphics.circle(
|
|
15
|
+
else graphics.circle(size / 2, size / 2, 1.1).fill({
|
|
16
16
|
color,
|
|
17
17
|
alpha: opacity
|
|
18
18
|
});
|
|
@@ -49,8 +49,9 @@ function sync(parts, context) {
|
|
|
49
49
|
const kind = settings.background.kind === "grid" ? "grid" : "dots";
|
|
50
50
|
const visible = settings.grid?.visible === true;
|
|
51
51
|
const size = Math.max(4, settings.grid?.size ?? 24);
|
|
52
|
-
const
|
|
53
|
-
const
|
|
52
|
+
const color = kind === "grid" ? palette.border : palette.muted;
|
|
53
|
+
const opacity = kind === "grid" ? .9 : .4;
|
|
54
|
+
const key = `${kind}|${size}|${color}|${opacity}`;
|
|
54
55
|
if (!visible) {
|
|
55
56
|
if (parts.sprite) parts.sprite.visible = false;
|
|
56
57
|
return;
|
|
@@ -61,7 +62,7 @@ function sync(parts, context) {
|
|
|
61
62
|
parts.sprite.destroy();
|
|
62
63
|
previousTexture.destroy(true);
|
|
63
64
|
}
|
|
64
|
-
const texture = buildGridTexture(context, size,
|
|
65
|
+
const texture = buildGridTexture(context, size, color, opacity, kind);
|
|
65
66
|
parts.sprite = new TilingSprite({
|
|
66
67
|
texture,
|
|
67
68
|
width,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BoardRenderContext } from "./renderers/board-renderer-registry.js";
|
|
2
|
+
import { Container, Graphics, Text } from "pixi.js";
|
|
3
|
+
//#region src/board/render/card-tag.d.ts
|
|
4
|
+
type CardGlyph = "image" | "video" | "audio" | "file" | "task";
|
|
5
|
+
declare const CARD_TAG_SIZE = 11;
|
|
6
|
+
declare function formatBoardDuration(ms: number): string;
|
|
7
|
+
declare function drawCardGlyph(graphics: Graphics, glyph: CardGlyph, color: number, pixel: boolean): void;
|
|
8
|
+
type CardTag = {
|
|
9
|
+
root: Container;
|
|
10
|
+
icon: Graphics;
|
|
11
|
+
text: Text | null;
|
|
12
|
+
sig: string;
|
|
13
|
+
resolution: number;
|
|
14
|
+
width: number;
|
|
15
|
+
};
|
|
16
|
+
declare function createCardTag(): CardTag;
|
|
17
|
+
declare function zoomCardTag(tag: CardTag, zoom: number): void;
|
|
18
|
+
declare function syncCardTag(tag: CardTag, input: {
|
|
19
|
+
glyph: CardGlyph;
|
|
20
|
+
text: string;
|
|
21
|
+
width: number;
|
|
22
|
+
}, context: BoardRenderContext): void;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { CARD_TAG_SIZE, CardGlyph, CardTag, createCardTag, drawCardGlyph, formatBoardDuration, syncCardTag, zoomCardTag };
|