@neta-art/cohub 10.0.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- 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 +5 -1
- package/dist/board/editor/creation.js +2 -1
- 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 +18 -3
- package/dist/board/editor/editor.js +11 -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/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 +20 -6
- 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 +6 -2
- package/dist/board/model/index.d.ts +13 -6
- package/dist/board/model/index.js +14 -8
- package/dist/board/model/items/builtin.js +2 -2
- package/dist/board/model/items/create.d.ts +4 -2
- package/dist/board/model/items/create.js +6 -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.d.ts +2 -1
- package/dist/board/model/media-playback.js +14 -4
- package/dist/board/model/media.js +7 -1
- 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 +10 -0
- package/dist/board/model/script-hit.js +52 -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-scene.d.ts +24 -0
- package/dist/board/model/script-scene.js +267 -0
- package/dist/board/model/script.d.ts +105 -0
- package/dist/board/model/script.js +1 -0
- 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 +9 -6
- 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 +10 -5
- package/dist/board/render/renderers/board-renderer-registry.js +3 -3
- 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} +16 -15
- 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/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 +421 -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 +213 -0
- package/dist/board/render/script-sandbox.d.ts +4 -0
- package/dist/board/render/script-sandbox.js +173 -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 +6 -1
- package/dist/board/stage/maintenance.d.ts +5 -0
- package/dist/board/stage/maintenance.js +11 -0
- package/dist/board/stage/scene.js +5 -2
- package/dist/board/stage/script-pointer.d.ts +19 -0
- package/dist/board/stage/script-pointer.js +35 -0
- package/dist/board/stage/stage.d.ts +10 -0
- package/dist/board/stage/stage.js +249 -43
- package/dist/board/stage/texture-pool.js +2 -3
- package/dist/chunks/environment.d.ts +266 -23
- package/dist/chunks/host-bridge.d.ts +2 -2
- package/dist/chunks/http.d.ts +88 -7
- package/dist/chunks/http.js +155 -63
- package/dist/chunks/transport.js +3 -1
- 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 +2 -2
- package/dist/index.d.ts +182 -4
- package/dist/index.js +1374 -126
- 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 +201 -11
- package/dist/protocol/dist/board-model.js +33 -14
- 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/display/index.d.ts +1 -0
- package/dist/protocol/dist/index.d.ts +4 -2
- package/dist/protocol/dist/realtime/types.d.ts +1 -0
- package/dist/protocol/dist/rtc/index.d.ts +1 -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/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
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { scriptModuleUrls } from "../../protocol/dist/board-script-modules.js";
|
|
2
|
+
import { createScriptRuntime } from "./script-runtime.js";
|
|
3
|
+
//#region src/board/render/script-sandbox.ts
|
|
4
|
+
function scriptAgent(runtimeFactory, moduleUrls, load) {
|
|
5
|
+
let runtime = null;
|
|
6
|
+
let input = null;
|
|
7
|
+
let module = null;
|
|
8
|
+
let urls = null;
|
|
9
|
+
let outputVersion = -1;
|
|
10
|
+
let canvas = null;
|
|
11
|
+
let callId = 0;
|
|
12
|
+
const calls = /* @__PURE__ */ new Map();
|
|
13
|
+
const send = (data, transfer = []) => {
|
|
14
|
+
self.postMessage(data, transfer);
|
|
15
|
+
};
|
|
16
|
+
const call = (name, input) => new Promise((resolve, reject) => {
|
|
17
|
+
const id = ++callId;
|
|
18
|
+
calls.set(id, {
|
|
19
|
+
resolve,
|
|
20
|
+
reject
|
|
21
|
+
});
|
|
22
|
+
send({
|
|
23
|
+
kind: "call",
|
|
24
|
+
call: id,
|
|
25
|
+
name,
|
|
26
|
+
input
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
let processing = false;
|
|
30
|
+
const queue = [];
|
|
31
|
+
async function process(data) {
|
|
32
|
+
try {
|
|
33
|
+
if (data.input) input = data.input;
|
|
34
|
+
if (!input) throw new Error("Missing script input.");
|
|
35
|
+
if (!runtime) {
|
|
36
|
+
if (!data.sources) throw new Error("Missing script modules.");
|
|
37
|
+
urls = moduleUrls(data.sources);
|
|
38
|
+
const src = input.item.script?.src;
|
|
39
|
+
const url = src ? urls.urls[src] : void 0;
|
|
40
|
+
if (!url) throw new Error("Missing entry module.");
|
|
41
|
+
module = await load(url);
|
|
42
|
+
runtime = runtimeFactory(module, input, {
|
|
43
|
+
call,
|
|
44
|
+
invalidate: () => {
|
|
45
|
+
if (!processing) send({ kind: "dirty" });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (data.input) runtime.update(input);
|
|
50
|
+
for (const event of data.events ?? []) runtime.event(event);
|
|
51
|
+
runtime.step(data.t);
|
|
52
|
+
let bitmap;
|
|
53
|
+
if (module?.draw && data.draw !== false) {
|
|
54
|
+
const width = Math.max(1, Math.round(input.width * data.scale));
|
|
55
|
+
const height = Math.max(1, Math.round(input.height * data.scale));
|
|
56
|
+
canvas ??= new OffscreenCanvas(width, height);
|
|
57
|
+
if (canvas.width !== width) canvas.width = width;
|
|
58
|
+
if (canvas.height !== height) canvas.height = height;
|
|
59
|
+
const context = canvas.getContext("2d");
|
|
60
|
+
if (!context) throw new Error("Canvas 2D is unavailable.");
|
|
61
|
+
context.reset();
|
|
62
|
+
context.scale(data.scale, data.scale);
|
|
63
|
+
runtime.draw(context);
|
|
64
|
+
bitmap = canvas.transferToImageBitmap();
|
|
65
|
+
}
|
|
66
|
+
const output = runtime.output();
|
|
67
|
+
const changed = output.version !== outputVersion;
|
|
68
|
+
outputVersion = output.version;
|
|
69
|
+
send({
|
|
70
|
+
kind: "frame",
|
|
71
|
+
request: data.request,
|
|
72
|
+
output: changed ? output : void 0,
|
|
73
|
+
bitmap
|
|
74
|
+
}, bitmap ? [bitmap] : []);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
send({
|
|
77
|
+
kind: "error",
|
|
78
|
+
request: data.request,
|
|
79
|
+
error: error instanceof Error ? error.stack ?? error.message : String(error)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function drain() {
|
|
84
|
+
if (processing) return;
|
|
85
|
+
processing = true;
|
|
86
|
+
while (queue.length) {
|
|
87
|
+
const request = queue.shift();
|
|
88
|
+
if (request) await process(request);
|
|
89
|
+
}
|
|
90
|
+
processing = false;
|
|
91
|
+
}
|
|
92
|
+
self.addEventListener("message", (event) => {
|
|
93
|
+
const data = event.data;
|
|
94
|
+
if (data.kind === "snapshot") {
|
|
95
|
+
try {
|
|
96
|
+
for (const event of data.events ?? []) runtime?.event(event);
|
|
97
|
+
send({
|
|
98
|
+
kind: "snapshot",
|
|
99
|
+
snapshot: runtime?.snapshot(true, false) ?? null
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
send({
|
|
103
|
+
kind: "snapshot",
|
|
104
|
+
error: String(error)
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (data.kind === "dispose") {
|
|
110
|
+
try {
|
|
111
|
+
runtime?.destroy();
|
|
112
|
+
urls?.dispose();
|
|
113
|
+
} finally {
|
|
114
|
+
send({ kind: "disposed" });
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (data.kind === "result" && data.call !== void 0) {
|
|
119
|
+
const pending = calls.get(data.call);
|
|
120
|
+
calls.delete(data.call);
|
|
121
|
+
if (data.error) pending?.reject(new Error(data.error));
|
|
122
|
+
else pending?.resolve(data.value);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
queue.push(data);
|
|
126
|
+
drain();
|
|
127
|
+
});
|
|
128
|
+
self.addEventListener("unhandledrejection", (event) => {
|
|
129
|
+
send({
|
|
130
|
+
kind: "error",
|
|
131
|
+
error: String(event.reason)
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function boardScriptFrameSource() {
|
|
136
|
+
const runtime = createScriptRuntime.toString();
|
|
137
|
+
const urls = scriptModuleUrls.toString();
|
|
138
|
+
const agent = scriptAgent.toString();
|
|
139
|
+
const prelude = "const __name = (value, name) => Object.defineProperty(value, 'name', { value: name, configurable: true });";
|
|
140
|
+
const worker = `${prelude} (${agent})(${runtime}, ${urls}, url => import(url));`;
|
|
141
|
+
return `<!doctype html><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' blob:; worker-src blob:; connect-src 'none'; form-action 'none'; base-uri 'none'"><script>
|
|
142
|
+
${prelude}
|
|
143
|
+
const workerUrl = URL.createObjectURL(new Blob([${JSON.stringify(worker)}], {type:'text/javascript'}));
|
|
144
|
+
const workers = new Map();
|
|
145
|
+
addEventListener('message', event => {
|
|
146
|
+
if(event.source !== parent) return;
|
|
147
|
+
const {token, data} = event.data;
|
|
148
|
+
if(typeof token !== 'number' || !data) return;
|
|
149
|
+
let entry = workers.get(token);
|
|
150
|
+
if(data.kind === 'terminate') {
|
|
151
|
+
if(entry) { clearTimeout(entry.timer); entry.worker.terminate(); workers.delete(token); }
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if(!entry) {
|
|
155
|
+
if(!data.sources) return;
|
|
156
|
+
const worker = new Worker(workerUrl);
|
|
157
|
+
entry = {worker}; workers.set(token, entry);
|
|
158
|
+
worker.onmessage = event => {
|
|
159
|
+
parent.postMessage({...event.data, token}, '*', event.data.bitmap ? [event.data.bitmap] : []);
|
|
160
|
+
if(event.data.kind === 'disposed') {
|
|
161
|
+
clearTimeout(entry.timer); worker.terminate(); workers.delete(token);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
worker.onerror = event => parent.postMessage({token,kind:'error',error:event.message || 'Script worker failed to start.'}, '*');
|
|
165
|
+
}
|
|
166
|
+
entry.worker.postMessage(data);
|
|
167
|
+
if(data.kind === 'dispose') entry.timer = setTimeout(() => {entry.worker.terminate(); workers.delete(token);},100);
|
|
168
|
+
});
|
|
169
|
+
parent.postMessage({kind:'ready'}, '*');
|
|
170
|
+
<\/script>`;
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
export { boardScriptFrameSource };
|
|
@@ -8,5 +8,6 @@ declare function trimPolyline(path: readonly WorldPoint[], trim: number | undefi
|
|
|
8
8
|
declare function tracePolyline(graphics: Graphics, path: readonly WorldPoint[], pattern: [number, number] | null, closed?: boolean): void;
|
|
9
9
|
declare function traceArrowhead(graphics: Graphics, tip: WorldPoint, angle: number, size: number): void;
|
|
10
10
|
declare function endAngle(path: readonly WorldPoint[], atStart: boolean): number | null;
|
|
11
|
+
declare function roundRectPoints(width: number, height: number, radius: number): WorldPoint[];
|
|
11
12
|
//#endregion
|
|
12
|
-
export { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline };
|
|
13
|
+
export { dashPattern, endAngle, roundRectPoints, traceArrowhead, tracePolyline, trimPolyline };
|
|
@@ -86,5 +86,26 @@ function endAngle(path, atStart) {
|
|
|
86
86
|
}
|
|
87
87
|
return null;
|
|
88
88
|
}
|
|
89
|
+
function roundRectPoints(width, height, radius) {
|
|
90
|
+
const r = Math.min(radius, width / 2, height / 2);
|
|
91
|
+
if (r <= 0) return [
|
|
92
|
+
worldPoint(0, 0),
|
|
93
|
+
worldPoint(width, 0),
|
|
94
|
+
worldPoint(width, height),
|
|
95
|
+
worldPoint(0, height),
|
|
96
|
+
worldPoint(0, 0)
|
|
97
|
+
];
|
|
98
|
+
const corner = (cx, cy, from) => Array.from({ length: 9 }, (_, index) => {
|
|
99
|
+
const angle = from + index / 8 * (Math.PI / 2);
|
|
100
|
+
return worldPoint(cx + Math.cos(angle) * r, cy + Math.sin(angle) * r);
|
|
101
|
+
});
|
|
102
|
+
return [
|
|
103
|
+
...corner(width - r, r, -Math.PI / 2),
|
|
104
|
+
...corner(width - r, height - r, 0),
|
|
105
|
+
...corner(r, height - r, Math.PI / 2),
|
|
106
|
+
...corner(r, r, Math.PI),
|
|
107
|
+
worldPoint(width - r, 0)
|
|
108
|
+
];
|
|
109
|
+
}
|
|
89
110
|
//#endregion
|
|
90
|
-
export { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline };
|
|
111
|
+
export { dashPattern, endAngle, roundRectPoints, traceArrowhead, tracePolyline, trimPolyline };
|
|
@@ -5,7 +5,7 @@ import { DOMAdapter } from "pixi.js";
|
|
|
5
5
|
//#region src/board/render/text-measurement.ts
|
|
6
6
|
const BOARD_FONT_STACKS = {
|
|
7
7
|
sans: BOARD_FONT_STACK,
|
|
8
|
-
serif: "ui-serif, Georgia, \"Noto Serif CJK SC\", \"Songti SC\", serif",
|
|
8
|
+
serif: "ui-serif, Georgia, \"Noto Serif CJK SC\", \"Songti SC\", \"Noto Sans Math\", \"DejaVu Sans\", \"Noto Sans CJK SC\", \"FreeSans\", \"FreeSerif\", sans-serif",
|
|
9
9
|
mono: BOARD_MONO_FONT_STACK
|
|
10
10
|
};
|
|
11
11
|
let measureContext;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mediaPreviewCandidates } from "../../media.js";
|
|
2
|
+
import { parseBoardMediaSource } from "../../protocol/dist/board-model.js";
|
|
2
3
|
import { featuredTaskArtifact } from "../model/task.js";
|
|
3
4
|
import { boardImageKeySource, imageAssetKey } from "../model/image-key.js";
|
|
4
5
|
import { loadVideoThumbnailTexture, videoTextureNaturalSize } from "../render/video-thumbnail.js";
|
|
@@ -14,7 +15,11 @@ function taskPreviewKey(artifact) {
|
|
|
14
15
|
}
|
|
15
16
|
function boardAssetKey(item) {
|
|
16
17
|
if (item.type === "task") return taskPreviewKey(featuredTaskArtifact(item.props.snapshot.artifacts));
|
|
17
|
-
if (item.type === "video")
|
|
18
|
+
if (item.type === "video") {
|
|
19
|
+
const source = parseBoardMediaSource(item.props.src);
|
|
20
|
+
if (!source) return null;
|
|
21
|
+
return source.kind === "url" ? `video-url:${encodeURIComponent(source.value)}` : `video:${encodeURIComponent(source.value)}:${item.props.snapshot?.mtimeMs ?? "unknown"}`;
|
|
22
|
+
}
|
|
18
23
|
return imageAssetKey(item);
|
|
19
24
|
}
|
|
20
25
|
function keySource(key) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Ticker } from "pixi.js";
|
|
2
|
+
//#region src/board/stage/maintenance.ts
|
|
3
|
+
function scheduleBoardMaintenance(renderer) {
|
|
4
|
+
renderer.events.setTargetElement(null);
|
|
5
|
+
const scheduler = renderer.scheduler;
|
|
6
|
+
Ticker.system.remove(scheduler._update, scheduler);
|
|
7
|
+
const timer = setInterval(() => scheduler._update(), 1e3);
|
|
8
|
+
return () => clearInterval(timer);
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { scheduleBoardMaintenance };
|
|
@@ -130,7 +130,8 @@ function createBoardScene(options) {
|
|
|
130
130
|
selected: context.selectedIds.has(item.id),
|
|
131
131
|
hovered: context.hoveredId === item.id,
|
|
132
132
|
resizing: context.resizingIds.has(item.id),
|
|
133
|
-
globalSig
|
|
133
|
+
globalSig,
|
|
134
|
+
scriptRevision: context.scripts?.revision?.(item.id) ?? 0
|
|
134
135
|
};
|
|
135
136
|
cards.set(item.id, entry);
|
|
136
137
|
setHeldKey(context, item.id, context.assetKey(item));
|
|
@@ -350,7 +351,9 @@ function createBoardScene(options) {
|
|
|
350
351
|
const selected = context.selectedIds.has(id);
|
|
351
352
|
const hovered = context.hoveredId === id;
|
|
352
353
|
const resizing = context.resizingIds.has(id);
|
|
353
|
-
const
|
|
354
|
+
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;
|
|
356
|
+
entry.scriptRevision = scriptRevision;
|
|
354
357
|
entry.item = item;
|
|
355
358
|
entry.selected = selected;
|
|
356
359
|
entry.hovered = hovered;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/board/stage/script-pointer.d.ts
|
|
2
|
+
type BoardScriptPointerTarget = {
|
|
3
|
+
owner: string;
|
|
4
|
+
target: string;
|
|
5
|
+
};
|
|
6
|
+
declare function createBoardScriptPointerRouter(): {
|
|
7
|
+
needsRouting(pointerId: number, scriptsEnabled: boolean): boolean;
|
|
8
|
+
owner(pointerId: number): "editor" | "script" | null;
|
|
9
|
+
route(phase: "down" | "move" | "up" | "leave", pointerId: number, target: BoardScriptPointerTarget | null, point: {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
}, cancelled?: boolean): {
|
|
13
|
+
recipient: BoardScriptPointerTarget | null;
|
|
14
|
+
click: BoardScriptPointerTarget | null;
|
|
15
|
+
};
|
|
16
|
+
clear(): void;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { BoardScriptPointerTarget, createBoardScriptPointerRouter };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/board/stage/script-pointer.ts
|
|
2
|
+
function createBoardScriptPointerRouter() {
|
|
3
|
+
const gestures = /* @__PURE__ */ new Map();
|
|
4
|
+
return {
|
|
5
|
+
needsRouting(pointerId, scriptsEnabled) {
|
|
6
|
+
return scriptsEnabled || gestures.has(pointerId);
|
|
7
|
+
},
|
|
8
|
+
owner(pointerId) {
|
|
9
|
+
const gesture = gestures.get(pointerId);
|
|
10
|
+
return gesture ? gesture.target ? "script" : "editor" : null;
|
|
11
|
+
},
|
|
12
|
+
route(phase, pointerId, target, point, cancelled = false) {
|
|
13
|
+
if (phase === "down") gestures.set(pointerId, {
|
|
14
|
+
target,
|
|
15
|
+
...point
|
|
16
|
+
});
|
|
17
|
+
const gesture = gestures.get(pointerId);
|
|
18
|
+
const recipient = gesture ? gesture.target : phase === "move" ? target : null;
|
|
19
|
+
let click = null;
|
|
20
|
+
if (phase === "up") {
|
|
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;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
recipient,
|
|
26
|
+
click
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
clear() {
|
|
30
|
+
gestures.clear();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { createBoardScriptPointerRouter };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BoardItem } from "../../protocol/dist/board-model.js";
|
|
2
2
|
import { BoardPlaybackSnapshot } from "../../protocol/dist/board.js";
|
|
3
3
|
import "../../protocol/dist/index.js";
|
|
4
|
+
import { BoardScriptOutput, BoardScriptSnapshot } from "../model/script.js";
|
|
4
5
|
import { BoardViewport, WorldPoint } from "../model/geometry.js";
|
|
5
6
|
import { BoardScene, BoardSceneItem } from "../model/scene.js";
|
|
6
7
|
import { BoardShapeColors } from "../model/palette.js";
|
|
@@ -47,6 +48,7 @@ type BoardStageOptions = {
|
|
|
47
48
|
height: number;
|
|
48
49
|
}) => void;
|
|
49
50
|
onVisibleChange?: (ids: ReadonlySet<string> | null) => void;
|
|
51
|
+
scriptCapabilities?: Record<string, (id: string, input: unknown) => Promise<unknown>>;
|
|
50
52
|
};
|
|
51
53
|
type BoardStage = {
|
|
52
54
|
readonly ready: Promise<boolean>;
|
|
@@ -54,6 +56,14 @@ type BoardStage = {
|
|
|
54
56
|
readonly camera: BoardViewport;
|
|
55
57
|
readonly theme: BoardStageTheme;
|
|
56
58
|
setActive(active: boolean): void;
|
|
59
|
+
setScriptMode(mode: "edit" | "interact" | "paused"): void;
|
|
60
|
+
resetScripts(): void;
|
|
61
|
+
invalidateScript(path: string): void;
|
|
62
|
+
scriptError(id: string): string | null;
|
|
63
|
+
scriptOutput(id: string): BoardScriptOutput | null;
|
|
64
|
+
snapshotScripts(): Promise<Record<string, BoardScriptSnapshot>>;
|
|
65
|
+
restoreScript(id: string, snapshot: BoardScriptSnapshot): void;
|
|
66
|
+
subscribeScripts(listener: () => void): () => void;
|
|
57
67
|
invalidate(options?: {
|
|
58
68
|
cards?: boolean;
|
|
59
69
|
}): void;
|