@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
|
@@ -1,91 +1,94 @@
|
|
|
1
|
-
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
1
|
import { getMediaResourceTitle } from "../../model/media.js";
|
|
3
|
-
import {
|
|
2
|
+
import { boardCardDetailed } from "../text-resolution.js";
|
|
3
|
+
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
4
|
+
import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
4
5
|
import { positionShell } from "./base-card-renderer.js";
|
|
5
6
|
import { drawFarPlate } from "./far-plate.js";
|
|
6
|
-
import {
|
|
7
|
+
import { drawMediaPlayKey } from "./media-key.js";
|
|
8
|
+
import { Container, Graphics, Sprite, Texture } from "pixi.js";
|
|
7
9
|
//#region src/board/render/renderers/video-card-renderer.ts
|
|
8
10
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const scale = Math.min(width / texture.width, height / texture.height);
|
|
14
|
-
sprite.width = texture.width * scale;
|
|
15
|
-
sprite.height = texture.height * scale;
|
|
16
|
-
sprite.x = (width - sprite.width) / 2;
|
|
17
|
-
sprite.y = (height - sprite.height) / 2;
|
|
11
|
+
const FILM_RAIL = 10;
|
|
12
|
+
const FILM_HOLE = 4;
|
|
13
|
+
function videoTitle(item) {
|
|
14
|
+
return item.props.snapshot?.title ?? getMediaResourceTitle(item.props.src);
|
|
18
15
|
}
|
|
19
16
|
function sync(container, item, context) {
|
|
20
17
|
const parts = partsByContainer.get(container);
|
|
21
18
|
if (!parts) return;
|
|
22
19
|
positionShell(parts.root, item);
|
|
23
20
|
const { width, height } = item.frame;
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
21
|
+
const title = videoTitle(item);
|
|
22
|
+
const durationMs = item.props.snapshot?.durationMs;
|
|
23
|
+
const duration = durationMs ? formatBoardDuration(durationMs) : "";
|
|
24
|
+
syncCardTag(parts.tag, {
|
|
25
|
+
glyph: "video",
|
|
26
|
+
text: duration ? `${title} · ${duration}` : title,
|
|
27
|
+
width
|
|
28
|
+
}, context);
|
|
28
29
|
const key = context.assetKey(item);
|
|
29
30
|
const texture = key ? context.getTexture(key) : null;
|
|
30
|
-
const
|
|
31
|
-
syncTextResolution(parts.label, parts, context.zoom);
|
|
32
|
-
if (parts.label.text !== title) parts.label.text = title;
|
|
33
|
-
syncTextWrapWidth(parts.label, parts, Math.max(1, width - 16), resizing);
|
|
34
|
-
parts.label.position.set(8, Math.max(8, height - parts.label.height - 8));
|
|
31
|
+
const elevation = cardElevation(context, item.id);
|
|
35
32
|
const sig = [
|
|
36
33
|
key ?? "",
|
|
37
34
|
texture ? `${texture.width}x${texture.height}` : "none",
|
|
38
35
|
width,
|
|
39
36
|
height,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
title,
|
|
44
|
-
item.props.time ?? 0,
|
|
45
|
-
parts.label.height,
|
|
46
|
-
context.palette.surface,
|
|
47
|
-
context.palette.brand,
|
|
48
|
-
context.palette.muted,
|
|
49
|
-
context.palette.border,
|
|
50
|
-
context.palette.hover,
|
|
51
|
-
context.palette.text
|
|
37
|
+
elevation,
|
|
38
|
+
boardCardDetailed(context.zoom),
|
|
39
|
+
context.themeKey
|
|
52
40
|
].join("|");
|
|
53
41
|
if (sig === parts.sig) return;
|
|
54
42
|
parts.sig = sig;
|
|
43
|
+
const framed = context.style.media === "framed";
|
|
44
|
+
const rect = {
|
|
45
|
+
x: 0,
|
|
46
|
+
y: 0,
|
|
47
|
+
width,
|
|
48
|
+
height
|
|
49
|
+
};
|
|
50
|
+
const rail = framed ? Math.min(FILM_RAIL, height / 6) : 0;
|
|
51
|
+
const screen = {
|
|
52
|
+
x: framed ? rail * .6 : 0,
|
|
53
|
+
y: rail,
|
|
54
|
+
width: width - (framed ? rail * 1.2 : 0),
|
|
55
|
+
height: height - rail * 2
|
|
56
|
+
};
|
|
57
|
+
drawCardSurface(parts.plate.clear(), rect, context.style, {
|
|
58
|
+
fill: framed ? context.palette.text : context.palette.surface,
|
|
59
|
+
border: framed ? null : context.palette.border,
|
|
60
|
+
borderAlpha: .85,
|
|
61
|
+
elevation
|
|
62
|
+
});
|
|
63
|
+
if (framed) drawFilmRails(parts.plate, width, height, rail, context.palette.bg);
|
|
64
|
+
traceCardOutline(parts.mask.clear(), framed ? screen : rect, framed ? {
|
|
65
|
+
corner: "round",
|
|
66
|
+
radius: 1
|
|
67
|
+
} : context.style).fill({ color: 16777215 });
|
|
55
68
|
if (texture && parts.sprite.texture !== texture) parts.sprite.texture = texture;
|
|
56
69
|
parts.sprite.visible = Boolean(texture);
|
|
57
|
-
if (texture) layoutContain(parts.sprite, width, height);
|
|
58
|
-
parts.mask.clear().roundRect(0, 0, width, height, RADIUS).fill({ color: 16777215 });
|
|
59
|
-
parts.plate.clear().roundRect(0, 0, width, height, RADIUS).fill({
|
|
60
|
-
color: context.palette.surface,
|
|
61
|
-
alpha: .96
|
|
62
|
-
});
|
|
63
|
-
parts.chrome.clear();
|
|
64
70
|
if (texture) {
|
|
65
|
-
const
|
|
66
|
-
parts.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
71
|
+
const fitted = containRect(screen.width, screen.height, texture.width, texture.height);
|
|
72
|
+
parts.sprite.position.set(screen.x + fitted.x, screen.y + fitted.y);
|
|
73
|
+
parts.sprite.width = fitted.width;
|
|
74
|
+
parts.sprite.height = fitted.height;
|
|
70
75
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
color:
|
|
85
|
-
|
|
86
|
-
alpha: selected ? .95 : .85
|
|
76
|
+
parts.chrome.clear();
|
|
77
|
+
if (boardCardDetailed(context.zoom)) drawMediaPlayKey(parts.chrome, screen.x + screen.width / 2, screen.y + screen.height / 2, Math.min(18, Math.min(screen.width, screen.height) * .16), context);
|
|
78
|
+
}
|
|
79
|
+
function drawFilmRails(graphics, width, height, rail, hole) {
|
|
80
|
+
const size = Math.min(FILM_HOLE, rail * .45);
|
|
81
|
+
const step = size * 2.5;
|
|
82
|
+
const count = Math.max(1, Math.floor((width - step) / step));
|
|
83
|
+
const start = (width - (count - 1) * step - size) / 2;
|
|
84
|
+
for (let index = 0; index < count; index += 1) {
|
|
85
|
+
const x = start + index * step;
|
|
86
|
+
graphics.rect(x, (rail - size) / 2, size, size).rect(x, height - rail + (rail - size) / 2, size, size);
|
|
87
|
+
}
|
|
88
|
+
graphics.fill({
|
|
89
|
+
color: hole,
|
|
90
|
+
alpha: .9
|
|
87
91
|
});
|
|
88
|
-
parts.label.style.fill = texture ? context.palette.text : context.palette.muted;
|
|
89
92
|
}
|
|
90
93
|
const videoCardRenderer = {
|
|
91
94
|
id: "video-card",
|
|
@@ -96,20 +99,8 @@ const videoCardRenderer = {
|
|
|
96
99
|
const sprite = new Sprite(Texture.EMPTY);
|
|
97
100
|
const mask = new Graphics();
|
|
98
101
|
const chrome = new Graphics();
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
text: "",
|
|
102
|
-
style: {
|
|
103
|
-
fill: context.palette.muted,
|
|
104
|
-
fontFamily: BOARD_FONT_STACK,
|
|
105
|
-
fontSize: 12,
|
|
106
|
-
fontWeight: "500",
|
|
107
|
-
wordWrap: true
|
|
108
|
-
},
|
|
109
|
-
resolution,
|
|
110
|
-
roundPixels: true
|
|
111
|
-
});
|
|
112
|
-
root.addChild(plate, sprite, mask, chrome, label);
|
|
102
|
+
const tag = createCardTag();
|
|
103
|
+
root.addChild(plate, sprite, mask, chrome, tag.root);
|
|
113
104
|
sprite.mask = mask;
|
|
114
105
|
partsByContainer.set(root, {
|
|
115
106
|
root,
|
|
@@ -117,10 +108,8 @@ const videoCardRenderer = {
|
|
|
117
108
|
sprite,
|
|
118
109
|
mask,
|
|
119
110
|
chrome,
|
|
120
|
-
|
|
121
|
-
sig: ""
|
|
122
|
-
wrapWidth: 0,
|
|
123
|
-
resolution
|
|
111
|
+
tag,
|
|
112
|
+
sig: ""
|
|
124
113
|
});
|
|
125
114
|
if (item.type === "video") sync(root, item, context);
|
|
126
115
|
return root;
|
|
@@ -128,6 +117,10 @@ const videoCardRenderer = {
|
|
|
128
117
|
update: (container, item, context) => {
|
|
129
118
|
if (item.type === "video") sync(container, item, context);
|
|
130
119
|
},
|
|
120
|
+
zoom: (container, zoom) => {
|
|
121
|
+
const tag = partsByContainer.get(container)?.tag;
|
|
122
|
+
if (tag) zoomCardTag(tag, zoom);
|
|
123
|
+
},
|
|
131
124
|
renderFar: (graphics, item, context) => {
|
|
132
125
|
drawFarPlate(graphics, item.frame, {
|
|
133
126
|
fill: context.palette.surface,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BoardDocument } from "../../protocol/dist/board-model.js";
|
|
2
2
|
import "../../protocol/dist/index.js";
|
|
3
|
-
import { BoardScriptEvent, BoardScriptOutput, BoardScriptSnapshot } from "../model/script.js";
|
|
4
3
|
import { BoardViewport } from "../model/geometry.js";
|
|
4
|
+
import { BoardScriptEvent, BoardScriptOutput, BoardScriptSnapshot } from "../model/script.js";
|
|
5
5
|
import { BoardScene } from "../model/scene.js";
|
|
6
6
|
import { BoardScriptHost } from "./renderers/board-renderer-registry.js";
|
|
7
7
|
//#region src/board/render/script-host.d.ts
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { boardScriptItems } from "../model/script-index.js";
|
|
2
2
|
import { boardScriptScope } from "../model/script-scene.js";
|
|
3
|
+
import { boardScriptHitVisible, resolveBoardScriptHit } from "../model/script-hit.js";
|
|
4
|
+
import { BoardScriptTexture } from "./script-texture.js";
|
|
3
5
|
import { createBoardScriptModuleReader, loadBoardScriptSources } from "../../protocol/dist/board-script-modules.js";
|
|
4
6
|
import { boardScriptFrameSource } from "./script-sandbox.js";
|
|
5
|
-
import { Texture } from "pixi.js";
|
|
6
7
|
//#region src/board/render/script-host.ts
|
|
7
8
|
function createBoardScriptHost(options) {
|
|
8
9
|
const revisions = /* @__PURE__ */ new Map();
|
|
@@ -25,11 +26,27 @@ function createBoardScriptHost(options) {
|
|
|
25
26
|
return value;
|
|
26
27
|
}
|
|
27
28
|
const focusTargets = /* @__PURE__ */ new Map();
|
|
29
|
+
const focusStyles = /* @__PURE__ */ new WeakMap();
|
|
28
30
|
const layer = document.createElement("div");
|
|
31
|
+
let interactive = false;
|
|
29
32
|
layer.style.cssText = "position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:2";
|
|
30
33
|
layer.dataset.boardScripts = "";
|
|
31
34
|
options.host.appendChild(layer);
|
|
32
35
|
let disposed = false;
|
|
36
|
+
const retiredTextures = /* @__PURE__ */ new Set();
|
|
37
|
+
let retirementFrame = 0;
|
|
38
|
+
function retireTexture(texture) {
|
|
39
|
+
if (!texture.current) return;
|
|
40
|
+
retiredTextures.add(texture);
|
|
41
|
+
if (retirementFrame) return;
|
|
42
|
+
retirementFrame = requestAnimationFrame(() => {
|
|
43
|
+
retirementFrame = requestAnimationFrame(() => {
|
|
44
|
+
retirementFrame = 0;
|
|
45
|
+
for (const retired of retiredTextures) retired.destroy();
|
|
46
|
+
retiredTextures.clear();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
33
50
|
function ensureBroker() {
|
|
34
51
|
if (broker) return;
|
|
35
52
|
broker = document.createElement("iframe");
|
|
@@ -58,7 +75,7 @@ function createBoardScriptHost(options) {
|
|
|
58
75
|
post(entry, { kind: "dispose" });
|
|
59
76
|
entry.timer = setTimeout(() => removeFrame(entry), 100);
|
|
60
77
|
} else removeFrame(entry);
|
|
61
|
-
entry.texture
|
|
78
|
+
retireTexture(entry.texture);
|
|
62
79
|
entries.delete(entry.id);
|
|
63
80
|
revisions.set(entry.id, (revisions.get(entry.id) ?? 0) + 1);
|
|
64
81
|
options.onOutput(entry.id, null);
|
|
@@ -99,7 +116,10 @@ function createBoardScriptHost(options) {
|
|
|
99
116
|
removeFrame(entry);
|
|
100
117
|
return;
|
|
101
118
|
}
|
|
102
|
-
if (entries.get(entry.id) !== entry)
|
|
119
|
+
if (entries.get(entry.id) !== entry) {
|
|
120
|
+
data.bitmap?.close?.();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
103
123
|
if (data.kind === "ready") {
|
|
104
124
|
entry.ready = true;
|
|
105
125
|
options.onFrame();
|
|
@@ -149,11 +169,7 @@ function createBoardScriptHost(options) {
|
|
|
149
169
|
clearTimeout(entry.timer);
|
|
150
170
|
entry.pending = false;
|
|
151
171
|
revisions.set(entry.id, (revisions.get(entry.id) ?? 0) + 1);
|
|
152
|
-
if (data.bitmap)
|
|
153
|
-
const previous = entry.texture;
|
|
154
|
-
entry.texture = Texture.from(data.bitmap);
|
|
155
|
-
previous?.destroy(true);
|
|
156
|
-
}
|
|
172
|
+
if (data.bitmap) entry.texture.update(data.bitmap);
|
|
157
173
|
try {
|
|
158
174
|
const output = data.output;
|
|
159
175
|
if (output) {
|
|
@@ -170,7 +186,7 @@ function createBoardScriptHost(options) {
|
|
|
170
186
|
return {
|
|
171
187
|
revision: (id) => revisions.get(id) ?? 0,
|
|
172
188
|
ready: (id) => entries.get(id)?.output !== null && entries.get(id)?.output !== void 0,
|
|
173
|
-
frame: (item) => entries.get(item.id)?.texture ?? null,
|
|
189
|
+
frame: (item) => entries.get(item.id)?.texture.current ?? null,
|
|
174
190
|
error: (id) => entries.get(id)?.error ?? null,
|
|
175
191
|
release: () => {},
|
|
176
192
|
fault(id, message) {
|
|
@@ -215,10 +231,12 @@ function createBoardScriptHost(options) {
|
|
|
215
231
|
get animated() {
|
|
216
232
|
return [...entries.values()].some((entry) => !entry.error && entry.output?.animated && (entry.visible || entry.output.updating) && !entry.pending);
|
|
217
233
|
},
|
|
218
|
-
sync(board, scene, camera, time,
|
|
234
|
+
sync(board, scene, camera, time, inputEnabled, visibleIds) {
|
|
219
235
|
if (disposed) return;
|
|
236
|
+
interactive = inputEnabled;
|
|
220
237
|
const alive = /* @__PURE__ */ new Set();
|
|
221
238
|
const liveFocusTargets = /* @__PURE__ */ new Set();
|
|
239
|
+
let focusSurface;
|
|
222
240
|
for (const [id, item] of boardScriptItems(board)) {
|
|
223
241
|
if (!item.script?.enabled) continue;
|
|
224
242
|
alive.add(id);
|
|
@@ -255,7 +273,7 @@ function createBoardScriptHost(options) {
|
|
|
255
273
|
inputKey: "",
|
|
256
274
|
inputDocument: null,
|
|
257
275
|
startedAt: (options.export ? 0 : time) - (input.snapshot?.time ?? 0),
|
|
258
|
-
texture:
|
|
276
|
+
texture: new BoardScriptTexture(),
|
|
259
277
|
error: null,
|
|
260
278
|
output: null,
|
|
261
279
|
events: [],
|
|
@@ -306,14 +324,15 @@ function createBoardScriptHost(options) {
|
|
|
306
324
|
}
|
|
307
325
|
if (entry.output && !options.export) {
|
|
308
326
|
const hits = Object.entries(entry.output.hits).filter(([, hit]) => hit.label);
|
|
309
|
-
if (!hits.length && entry.output.listens.length) hits.push([id, {
|
|
310
|
-
x: 0,
|
|
311
|
-
y: 0,
|
|
312
|
-
width: box.width,
|
|
313
|
-
height: box.height,
|
|
314
|
-
label: "text" in item.props && typeof item.props.text === "string" ? item.props.text : item.script.src
|
|
315
|
-
}]);
|
|
316
327
|
for (const [target, hit] of hits) {
|
|
328
|
+
const resolved = resolveBoardScriptHit(scene, id, hit);
|
|
329
|
+
if (!resolved) continue;
|
|
330
|
+
const { rect } = resolved;
|
|
331
|
+
if (interactive) focusSurface ??= {
|
|
332
|
+
width: options.host.clientWidth,
|
|
333
|
+
height: options.host.clientHeight
|
|
334
|
+
};
|
|
335
|
+
const focusable = Boolean(focusSurface && interactive && boardScriptHitVisible(scene, resolved, camera, focusSurface));
|
|
317
336
|
const key = `${id}/${target}`;
|
|
318
337
|
liveFocusTargets.add(key);
|
|
319
338
|
let button = focusTargets.get(key);
|
|
@@ -322,15 +341,11 @@ function createBoardScriptHost(options) {
|
|
|
322
341
|
button.type = "button";
|
|
323
342
|
const emit = (type, key) => {
|
|
324
343
|
const current = entries.get(id);
|
|
325
|
-
if (!current || current.error) return;
|
|
344
|
+
if (!interactive || !current || current.error || !current.output?.listens.includes(type)) return;
|
|
326
345
|
current.events.push({
|
|
327
346
|
type,
|
|
328
347
|
target,
|
|
329
|
-
key
|
|
330
|
-
point: {
|
|
331
|
-
x: hit.x + hit.width / 2,
|
|
332
|
-
y: hit.y + hit.height / 2
|
|
333
|
-
}
|
|
348
|
+
key
|
|
334
349
|
});
|
|
335
350
|
current.dirty = true;
|
|
336
351
|
options.onFrame();
|
|
@@ -343,10 +358,16 @@ function createBoardScriptHost(options) {
|
|
|
343
358
|
focusTargets.set(key, button);
|
|
344
359
|
layer.appendChild(button);
|
|
345
360
|
}
|
|
346
|
-
|
|
347
|
-
button.
|
|
348
|
-
const
|
|
349
|
-
|
|
361
|
+
const label = hit.label ?? target;
|
|
362
|
+
if (button.getAttribute("aria-label") !== label) button.setAttribute("aria-label", label);
|
|
363
|
+
const tabIndex = focusable ? 0 : -1;
|
|
364
|
+
if (button.tabIndex !== tabIndex) button.tabIndex = tabIndex;
|
|
365
|
+
const [a, b, c, d, x, y] = scene.layout.matrix(resolved.id);
|
|
366
|
+
const style = `position:absolute;pointer-events:none;background:transparent;border:0;padding:0;transform-origin:0 0;width:${rect.width}px;height:${rect.height}px;transform:matrix(${a * camera.zoom},${b * camera.zoom},${c * camera.zoom},${d * camera.zoom},${(x + a * rect.x + c * rect.y) * camera.zoom + camera.x},${(y + b * rect.x + d * rect.y) * camera.zoom + camera.y})`;
|
|
367
|
+
if (focusStyles.get(button) !== style) {
|
|
368
|
+
button.style.cssText = style;
|
|
369
|
+
focusStyles.set(button, style);
|
|
370
|
+
}
|
|
350
371
|
}
|
|
351
372
|
}
|
|
352
373
|
if (!entry.ready || !entry.sources || entry.pending || !entry.dirty && (!entry.output?.animated || !visible && !entry.output.updating || entry.time === time)) continue;
|
|
@@ -378,6 +399,10 @@ function createBoardScriptHost(options) {
|
|
|
378
399
|
event(id, event) {
|
|
379
400
|
const entry = entries.get(id);
|
|
380
401
|
if (!entry || entry.error || entry.output && !entry.output.listens.includes(event.type)) return;
|
|
402
|
+
if (event.type === "viewchange" || event.type === "selectionchange") {
|
|
403
|
+
const queued = entry.events.findIndex((pending) => pending.type === event.type);
|
|
404
|
+
if (queued >= 0) entry.events.splice(queued, 1);
|
|
405
|
+
}
|
|
381
406
|
if (event.type === "pointermove" && entry.events.at(-1)?.type === "pointermove") entry.events.pop();
|
|
382
407
|
if (entry.events.length >= 128) return;
|
|
383
408
|
entry.events.push(event);
|
|
@@ -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 };
|
|
@@ -5,7 +5,7 @@ import { Graphics } from "pixi.js";
|
|
|
5
5
|
//#region src/board/render/stroke.d.ts
|
|
6
6
|
declare function dashPattern(dash: BoardDash | undefined, width: number): [number, number] | null;
|
|
7
7
|
declare function trimPolyline(path: readonly WorldPoint[], trim: number | undefined): readonly WorldPoint[];
|
|
8
|
-
declare function tracePolyline(graphics: Graphics, path: readonly WorldPoint[], pattern: [number, number] | null, closed?: boolean): void;
|
|
8
|
+
declare function tracePolyline(graphics: Graphics, path: readonly WorldPoint[], pattern: [number, number] | null, closed?: boolean, offset?: number): 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
11
|
declare function roundRectPoints(width: number, height: number, radius: number): WorldPoint[];
|
|
@@ -31,7 +31,7 @@ function trimPolyline(path, trim) {
|
|
|
31
31
|
}
|
|
32
32
|
return out;
|
|
33
33
|
}
|
|
34
|
-
function tracePolyline(graphics, path, pattern, closed = false) {
|
|
34
|
+
function tracePolyline(graphics, path, pattern, closed = false, offset = 0) {
|
|
35
35
|
const points = closed && path.length > 2 ? [...path, path[0]] : path;
|
|
36
36
|
if (points.length < 2) return;
|
|
37
37
|
if (!pattern) {
|
|
@@ -45,9 +45,10 @@ function tracePolyline(graphics, path, pattern, closed = false) {
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
const [dash, gap] = pattern;
|
|
48
|
-
|
|
49
|
-
let
|
|
50
|
-
let
|
|
48
|
+
const phase = Math.max(0, offset) % (dash + gap);
|
|
49
|
+
let penDown = phase < dash;
|
|
50
|
+
let fresh = penDown;
|
|
51
|
+
let remaining = penDown ? dash - phase : dash + gap - phase;
|
|
51
52
|
for (let index = 1; index < points.length; index += 1) {
|
|
52
53
|
const a = points[index - 1];
|
|
53
54
|
const b = points[index];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/board/render/style.d.ts
|
|
2
|
+
type BoardRenderStyle = {
|
|
3
|
+
corner: "round" | "pixel";
|
|
4
|
+
radius: number;
|
|
5
|
+
shadow: BoardShadowStyle | null;
|
|
6
|
+
selection: BoardSelectionStyle;
|
|
7
|
+
media: "plain" | "framed";
|
|
8
|
+
progress: "shimmer" | "mosaic";
|
|
9
|
+
icons: "line" | "pixel";
|
|
10
|
+
motion: "smooth" | "stepped";
|
|
11
|
+
font: string;
|
|
12
|
+
};
|
|
13
|
+
type BoardShadowStyle = {
|
|
14
|
+
color: number;
|
|
15
|
+
alpha: number;
|
|
16
|
+
blur: number;
|
|
17
|
+
y: number;
|
|
18
|
+
};
|
|
19
|
+
type BoardSelectionStyle = {
|
|
20
|
+
width: number;
|
|
21
|
+
outset: number;
|
|
22
|
+
dash: number;
|
|
23
|
+
handle: "circle" | "square";
|
|
24
|
+
handleSize: number;
|
|
25
|
+
};
|
|
26
|
+
declare function defaultBoardRenderStyle(mode: "dark" | "light"): BoardRenderStyle;
|
|
27
|
+
declare function resolveBoardRenderStyle(mode: "dark" | "light", style?: Partial<BoardRenderStyle>): BoardRenderStyle;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { BoardRenderStyle, BoardSelectionStyle, BoardShadowStyle, defaultBoardRenderStyle, resolveBoardRenderStyle };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BOARD_FONT_STACK } from "../../protocol/dist/board-constants.js";
|
|
2
|
+
//#region src/board/render/style.ts
|
|
3
|
+
const BASE = {
|
|
4
|
+
corner: "round",
|
|
5
|
+
radius: 6,
|
|
6
|
+
selection: {
|
|
7
|
+
width: 1.5,
|
|
8
|
+
outset: 3,
|
|
9
|
+
dash: 0,
|
|
10
|
+
handle: "square",
|
|
11
|
+
handleSize: 8
|
|
12
|
+
},
|
|
13
|
+
media: "plain",
|
|
14
|
+
progress: "shimmer",
|
|
15
|
+
icons: "line",
|
|
16
|
+
motion: "smooth",
|
|
17
|
+
font: BOARD_FONT_STACK
|
|
18
|
+
};
|
|
19
|
+
const SHADOW = {
|
|
20
|
+
light: {
|
|
21
|
+
color: 1447704,
|
|
22
|
+
alpha: .06,
|
|
23
|
+
blur: 12,
|
|
24
|
+
y: 2
|
|
25
|
+
},
|
|
26
|
+
dark: {
|
|
27
|
+
color: 0,
|
|
28
|
+
alpha: .24,
|
|
29
|
+
blur: 12,
|
|
30
|
+
y: 2
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function defaultBoardRenderStyle(mode) {
|
|
34
|
+
return {
|
|
35
|
+
...BASE,
|
|
36
|
+
selection: { ...BASE.selection },
|
|
37
|
+
shadow: { ...SHADOW[mode] }
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function resolveBoardRenderStyle(mode, style) {
|
|
41
|
+
const base = defaultBoardRenderStyle(mode);
|
|
42
|
+
if (!style) return base;
|
|
43
|
+
return {
|
|
44
|
+
...base,
|
|
45
|
+
...style,
|
|
46
|
+
selection: {
|
|
47
|
+
...base.selection,
|
|
48
|
+
...style.selection
|
|
49
|
+
},
|
|
50
|
+
shadow: style.shadow === void 0 ? base.shadow : style.shadow
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { defaultBoardRenderStyle, resolveBoardRenderStyle };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { WorldPoint } from "../model/geometry.js";
|
|
2
|
+
import { BoardRenderStyle, BoardShadowStyle } from "./style.js";
|
|
3
|
+
import { Graphics } from "pixi.js";
|
|
4
|
+
//#region src/board/render/surface.d.ts
|
|
5
|
+
declare const PIXEL_STEP = 2;
|
|
6
|
+
type CardRect = {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
};
|
|
12
|
+
declare function traceCardOutline(graphics: Graphics, rect: CardRect, style: Pick<BoardRenderStyle, "corner" | "radius">, grow?: number): Graphics;
|
|
13
|
+
declare function tracePixelRect(graphics: Graphics, x: number, y: number, width: number, height: number, step: number): Graphics;
|
|
14
|
+
declare function cardOutlinePoints(rect: CardRect, style: Pick<BoardRenderStyle, "corner" | "radius">, grow?: number): WorldPoint[];
|
|
15
|
+
declare function drawCardShadow(graphics: Graphics, rect: CardRect, style: Pick<BoardRenderStyle, "corner" | "radius">, shadow: BoardShadowStyle | null): void;
|
|
16
|
+
type CardSurface = {
|
|
17
|
+
fill: number;
|
|
18
|
+
fillAlpha?: number;
|
|
19
|
+
border?: number | null;
|
|
20
|
+
borderAlpha?: number;
|
|
21
|
+
elevation?: CardElevation;
|
|
22
|
+
};
|
|
23
|
+
type CardElevation = 0 | 1 | 2;
|
|
24
|
+
declare function cardShadow(style: BoardRenderStyle, elevation: CardElevation): BoardShadowStyle | null;
|
|
25
|
+
declare function drawCardSurface(graphics: Graphics, rect: CardRect, style: BoardRenderStyle, surface: CardSurface): Graphics;
|
|
26
|
+
declare function containRect(width: number, height: number, imageWidth: number, imageHeight: number): CardRect;
|
|
27
|
+
declare function cardElevation(context: {
|
|
28
|
+
liftedIds: ReadonlySet<string>;
|
|
29
|
+
}, id: string): CardElevation;
|
|
30
|
+
declare function isBoardCard(item: {
|
|
31
|
+
type: string;
|
|
32
|
+
}): boolean;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { CardElevation, CardRect, CardSurface, PIXEL_STEP, cardElevation, cardOutlinePoints, cardShadow, containRect, drawCardShadow, drawCardSurface, isBoardCard, traceCardOutline, tracePixelRect };
|