@neta-art/cohub 11.5.1 → 12.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/dist/board/editor/animation.js +2 -1
- package/dist/board/editor/creation.js +1 -1
- package/dist/board/editor/document-edits.d.ts +1 -1
- package/dist/board/editor/document-edits.js +1 -19
- package/dist/board/editor/document.js +2 -1
- package/dist/board/editor/index.d.ts +2 -1
- package/dist/board/editor/index.js +2 -1
- package/dist/board/editor/snapshots.js +11 -13
- package/dist/board/export/index.js +1 -1
- package/dist/board/export/scene.js +1 -1
- package/dist/board/model/client-geometry.d.ts +22 -0
- package/dist/board/model/client-geometry.js +94 -0
- package/dist/board/model/document-share.d.ts +5 -0
- package/dist/board/model/document-share.js +27 -0
- package/dist/board/model/index.d.ts +5 -4
- package/dist/board/model/index.js +4 -3
- package/dist/board/model/items/create.d.ts +5 -1
- package/dist/board/model/items/create.js +29 -58
- package/dist/board/model/items/index.d.ts +2 -2
- package/dist/board/model/items/index.js +2 -2
- package/dist/board/model/items/registry.js +2 -5
- package/dist/board/model/json.d.ts +4 -0
- package/dist/board/model/json.js +22 -0
- package/dist/board/model/media-playback.d.ts +6 -3
- package/dist/board/player/index.d.ts +6 -2
- package/dist/board/player/index.js +33 -15
- package/dist/board/render/index.d.ts +2 -2
- package/dist/board/render/index.js +6 -6
- package/dist/board/render/renderers/arrow-card-renderer.js +5 -1
- package/dist/board/render/renderers/audio-card-renderer.js +4 -1
- package/dist/board/render/renderers/board-renderer-registry.d.ts +4 -2
- package/dist/board/render/renderers/custom-card-renderer.js +5 -2
- package/dist/board/render/renderers/file-card-renderer.js +4 -1
- package/dist/board/render/renderers/frame-card-renderer.js +5 -1
- package/dist/board/render/renderers/image-card-renderer.js +13 -49
- package/dist/board/render/renderers/model-card-renderer.js +4 -1
- package/dist/board/render/renderers/shape-card-renderer.js +5 -1
- package/dist/board/render/renderers/task-card-renderer.js +6 -3
- package/dist/board/render/renderers/text-card-renderer.js +6 -2
- package/dist/board/render/renderers/unknown-card-renderer.js +4 -0
- package/dist/board/render/renderers/video-card-renderer.js +19 -18
- package/dist/board/render/script-host.d.ts +2 -0
- package/dist/board/render/script-host.js +44 -9
- package/dist/board/render/script-resolution.d.ts +4 -0
- package/dist/board/render/script-resolution.js +18 -0
- package/dist/board/render/surface.d.ts +9 -2
- package/dist/board/render/surface.js +15 -1
- package/dist/board/replica/index.js +4 -1
- package/dist/board/stage/assets.d.ts +12 -8
- package/dist/board/stage/assets.js +173 -88
- package/dist/board/stage/index.d.ts +3 -3
- package/dist/board/stage/index.js +3 -3
- package/dist/board/stage/lru.d.ts +3 -2
- package/dist/board/stage/lru.js +8 -4
- package/dist/board/stage/pointer.d.ts +1 -1
- package/dist/board/stage/pointer.js +4 -5
- package/dist/board/stage/scene.d.ts +3 -0
- package/dist/board/stage/scene.js +44 -8
- package/dist/board/stage/stage.d.ts +1 -0
- package/dist/board/stage/stage.js +123 -56
- package/dist/board/stage/views.d.ts +7 -2
- package/dist/board/stage/views.js +50 -21
- package/dist/chunks/environment.d.ts +16 -2
- package/dist/index.js +65 -22
- package/dist/protocol/dist/board-constants.js +56 -1
- package/dist/protocol/dist/board-layout.d.ts +8 -1
- package/dist/protocol/dist/board-layout.js +16 -4
- package/dist/protocol/dist/board-model.js +13 -19
- package/dist/protocol/dist/board-schema.d.ts +52 -0
- package/dist/protocol/dist/board-schema.js +8 -0
- package/dist/protocol/dist/core/media.js +1 -0
- package/dist/protocol/dist/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { cardElevation, containRect, drawCardSurface,
|
|
1
|
+
import { cardElevation, containRect, drawCardSurface, fillCardPicture } from "../surface.js";
|
|
2
2
|
import { positionShell } from "./base-card-renderer.js";
|
|
3
3
|
import { drawFarPlate } from "./far-plate.js";
|
|
4
|
-
import { Container, Graphics
|
|
4
|
+
import { Container, Graphics } from "pixi.js";
|
|
5
5
|
//#region src/board/render/renderers/image-card-renderer.ts
|
|
6
6
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
7
7
|
function cropRect(crop) {
|
|
@@ -15,28 +15,6 @@ function cropRect(crop) {
|
|
|
15
15
|
h
|
|
16
16
|
} : null;
|
|
17
17
|
}
|
|
18
|
-
function showTexture(parts, texture, crop) {
|
|
19
|
-
const rect = texture ? cropRect(crop) : null;
|
|
20
|
-
const key = rect ? `${rect.x}|${rect.y}|${rect.w}|${rect.h}` : "";
|
|
21
|
-
const previous = parts.cropped;
|
|
22
|
-
const reusable = previous && parts.cropSource === texture && parts.cropKey === key;
|
|
23
|
-
if (texture && rect && !reusable) {
|
|
24
|
-
const { frame } = texture;
|
|
25
|
-
const width = Math.max(1, frame.width * rect.w);
|
|
26
|
-
const height = Math.max(1, frame.height * rect.h);
|
|
27
|
-
const x = frame.x + Math.min(frame.width * rect.x, frame.width - width);
|
|
28
|
-
const y = frame.y + Math.min(frame.height * rect.y, frame.height - height);
|
|
29
|
-
parts.cropped = new Texture({
|
|
30
|
-
source: texture.source,
|
|
31
|
-
frame: new Rectangle(x, y, width, height)
|
|
32
|
-
});
|
|
33
|
-
} else if (!rect) parts.cropped = null;
|
|
34
|
-
parts.cropSource = rect ? texture : null;
|
|
35
|
-
parts.cropKey = key;
|
|
36
|
-
const display = parts.cropped ?? texture ?? Texture.EMPTY;
|
|
37
|
-
if (parts.sprite.texture !== display) parts.sprite.texture = display;
|
|
38
|
-
if (previous && previous !== parts.cropped) previous.destroy(false);
|
|
39
|
-
}
|
|
40
18
|
const PRINT_MARGIN = 6;
|
|
41
19
|
function sync(container, item, context) {
|
|
42
20
|
const parts = partsByContainer.get(container);
|
|
@@ -51,7 +29,7 @@ function sync(container, item, context) {
|
|
|
51
29
|
key ?? "",
|
|
52
30
|
width,
|
|
53
31
|
height,
|
|
54
|
-
texture
|
|
32
|
+
texture?.uid ?? "none",
|
|
55
33
|
JSON.stringify(item.props.crop ?? null),
|
|
56
34
|
failed,
|
|
57
35
|
elevation,
|
|
@@ -59,8 +37,7 @@ function sync(container, item, context) {
|
|
|
59
37
|
].join("|");
|
|
60
38
|
if (sig === parts.sig) return;
|
|
61
39
|
parts.sig = sig;
|
|
62
|
-
|
|
63
|
-
const display = parts.sprite.texture;
|
|
40
|
+
const crop = cropRect(item.props.crop);
|
|
64
41
|
const framed = context.style.media === "framed";
|
|
65
42
|
const margin = framed ? Math.min(PRINT_MARGIN, width / 8, height / 8) : 0;
|
|
66
43
|
const area = {
|
|
@@ -69,7 +46,7 @@ function sync(container, item, context) {
|
|
|
69
46
|
width: width - margin * 2,
|
|
70
47
|
height: height - margin * 2
|
|
71
48
|
};
|
|
72
|
-
const fitted = texture ? containRect(area.width, area.height,
|
|
49
|
+
const fitted = texture ? containRect(area.width, area.height, texture.width * (crop?.w ?? 1), texture.height * (crop?.h ?? 1)) : {
|
|
73
50
|
...area,
|
|
74
51
|
x: 0,
|
|
75
52
|
y: 0
|
|
@@ -86,16 +63,11 @@ function sync(container, item, context) {
|
|
|
86
63
|
width: picture.width + margin * 2,
|
|
87
64
|
height: picture.height + margin * 2
|
|
88
65
|
} : picture;
|
|
89
|
-
parts.
|
|
90
|
-
if (texture) {
|
|
91
|
-
parts.sprite.position.set(picture.x, picture.y);
|
|
92
|
-
parts.sprite.width = picture.width;
|
|
93
|
-
parts.sprite.height = picture.height;
|
|
94
|
-
}
|
|
95
|
-
traceCardOutline(parts.mask.clear(), picture, framed ? {
|
|
66
|
+
parts.picture.clear();
|
|
67
|
+
if (texture) fillCardPicture(parts.picture, texture, picture, framed ? {
|
|
96
68
|
corner: "round",
|
|
97
69
|
radius: 0
|
|
98
|
-
} : context.style
|
|
70
|
+
} : context.style, crop);
|
|
99
71
|
parts.placeholder.clear();
|
|
100
72
|
if (texture && !framed) return;
|
|
101
73
|
drawCardSurface(parts.placeholder, card, context.style, {
|
|
@@ -122,20 +94,14 @@ const imageCardRenderer = {
|
|
|
122
94
|
canRender: (item) => item.type === "image",
|
|
123
95
|
create: (item, context) => {
|
|
124
96
|
const root = new Container();
|
|
125
|
-
const sprite = new Sprite(Texture.EMPTY);
|
|
126
97
|
const placeholder = new Graphics();
|
|
127
|
-
const
|
|
128
|
-
root.addChild(placeholder,
|
|
129
|
-
sprite.mask = mask;
|
|
98
|
+
const picture = new Graphics();
|
|
99
|
+
root.addChild(placeholder, picture);
|
|
130
100
|
partsByContainer.set(root, {
|
|
131
101
|
root,
|
|
132
|
-
sprite,
|
|
133
102
|
placeholder,
|
|
134
|
-
|
|
135
|
-
sig: ""
|
|
136
|
-
cropped: null,
|
|
137
|
-
cropSource: null,
|
|
138
|
-
cropKey: ""
|
|
103
|
+
picture,
|
|
104
|
+
sig: ""
|
|
139
105
|
});
|
|
140
106
|
if (item.type === "image") sync(root, item, context);
|
|
141
107
|
return root;
|
|
@@ -150,9 +116,7 @@ const imageCardRenderer = {
|
|
|
150
116
|
});
|
|
151
117
|
},
|
|
152
118
|
destroy: (container) => {
|
|
153
|
-
|
|
154
|
-
parts?.root.destroy({ children: true });
|
|
155
|
-
parts?.cropped?.destroy(false);
|
|
119
|
+
partsByContainer.get(container)?.root.destroy({ children: true });
|
|
156
120
|
partsByContainer.delete(container);
|
|
157
121
|
}
|
|
158
122
|
};
|
|
@@ -42,7 +42,7 @@ function sync(container, item, context) {
|
|
|
42
42
|
const elevation = cardElevation(context, item.id);
|
|
43
43
|
const sig = [
|
|
44
44
|
key ?? "",
|
|
45
|
-
texture
|
|
45
|
+
texture?.uid ?? "none",
|
|
46
46
|
failed,
|
|
47
47
|
width,
|
|
48
48
|
height,
|
|
@@ -111,6 +111,9 @@ const modelCardRenderer = {
|
|
|
111
111
|
update: (container, item, context) => {
|
|
112
112
|
if (item.type === "file") sync(container, item, context);
|
|
113
113
|
},
|
|
114
|
+
resolution: (container, item, context) => {
|
|
115
|
+
if (item.type === "file") sync(container, item, context);
|
|
116
|
+
},
|
|
114
117
|
zoom: (container, zoom) => {
|
|
115
118
|
const tag = partsByContainer.get(container)?.tag;
|
|
116
119
|
if (tag) zoomCardTag(tag, zoom);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
2
|
import { worldPoint } from "../../model/geometry.js";
|
|
3
|
-
import { itemAlpha, itemColor } from "../palette.js";
|
|
4
3
|
import { syncTextResolution, syncTextWrapWidth, textResolutionForZoom } from "../text-resolution.js";
|
|
4
|
+
import { itemAlpha, itemColor } from "../palette.js";
|
|
5
5
|
import { dashPattern, roundRectPoints, tracePolyline, trimPolyline } from "../stroke.js";
|
|
6
6
|
import { positionShell } from "./base-card-renderer.js";
|
|
7
7
|
import { drawFarPlate } from "./far-plate.js";
|
|
@@ -199,6 +199,10 @@ const shapeCardRenderer = {
|
|
|
199
199
|
update: (container, item, context) => {
|
|
200
200
|
if (item.type === "shape") sync(container, item, context);
|
|
201
201
|
},
|
|
202
|
+
resolution: (container, _item, context) => {
|
|
203
|
+
const parts = partsByContainer.get(container);
|
|
204
|
+
if (parts) syncTextResolution(parts.label, parts, context.zoom);
|
|
205
|
+
},
|
|
202
206
|
renderFar: (graphics, item, context) => {
|
|
203
207
|
if (item.type !== "shape") return;
|
|
204
208
|
drawFarPlate(graphics, item.frame, {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK, BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
2
|
import { featuredTaskArtifact } from "../../../protocol/dist/board-task.js";
|
|
3
|
+
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
3
4
|
import { fitTextToLines } from "../text-fit.js";
|
|
4
5
|
import { boardCardDetailed, syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
5
6
|
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
6
|
-
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
7
7
|
import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
8
8
|
import { positionShell } from "./base-card-renderer.js";
|
|
9
9
|
import { drawFarPlate } from "./far-plate.js";
|
|
@@ -259,7 +259,7 @@ function sync(container, item, context) {
|
|
|
259
259
|
if (key !== parts.assetKey) {
|
|
260
260
|
if (parts.assetKey) context.releaseTexture(parts.assetKey);
|
|
261
261
|
parts.assetKey = key;
|
|
262
|
-
if (key) context.acquireTexture(key);
|
|
262
|
+
if (key) context.acquireTexture(key, item);
|
|
263
263
|
}
|
|
264
264
|
const texture = key ? context.getTexture(key) : null;
|
|
265
265
|
const previewFailed = Boolean(key && !texture && context.hasError(key));
|
|
@@ -332,7 +332,7 @@ function sync(container, item, context) {
|
|
|
332
332
|
artifact?.type ?? "none",
|
|
333
333
|
artifact?.id ?? "none",
|
|
334
334
|
item.props.taskRunId,
|
|
335
|
-
texture
|
|
335
|
+
texture?.uid ?? "none",
|
|
336
336
|
context.themeKey
|
|
337
337
|
].join("|");
|
|
338
338
|
if (visualSig !== parts.visualSig) {
|
|
@@ -501,6 +501,9 @@ const taskCardRenderer = {
|
|
|
501
501
|
const parts = partsByContainer.get(container);
|
|
502
502
|
return parts ? advance(parts, clock) : null;
|
|
503
503
|
},
|
|
504
|
+
resolution: (container, item, context) => {
|
|
505
|
+
if (item.type === "task") sync(container, item, context);
|
|
506
|
+
},
|
|
504
507
|
zoom: (container, zoom) => {
|
|
505
508
|
const tag = partsByContainer.get(container)?.tag;
|
|
506
509
|
if (tag) zoomCardTag(tag, zoom);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { layoutBoardText } from "../../../protocol/dist/board-layout.js";
|
|
2
2
|
import { boardFontFamily } from "../../model/text-metrics.js";
|
|
3
|
-
import { itemAlpha, itemColor } from "../palette.js";
|
|
4
|
-
import { BOARD_FONT_STACKS } from "../text-measurement.js";
|
|
5
3
|
import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
4
|
+
import { BOARD_FONT_STACKS } from "../text-measurement.js";
|
|
5
|
+
import { itemAlpha, itemColor } from "../palette.js";
|
|
6
6
|
import { positionShell } from "./base-card-renderer.js";
|
|
7
7
|
import { drawFarPlate } from "./far-plate.js";
|
|
8
8
|
import { Container, Graphics, Text } from "pixi.js";
|
|
@@ -91,6 +91,10 @@ const textCardRenderer = {
|
|
|
91
91
|
update: (container, item, context) => {
|
|
92
92
|
if (item.type === "text") sync(container, item, context);
|
|
93
93
|
},
|
|
94
|
+
resolution: (container, _item, context) => {
|
|
95
|
+
const parts = partsByContainer.get(container);
|
|
96
|
+
if (parts) syncTextResolution(parts.body, parts, context.zoom * Math.max(1, parts.body.scale.x));
|
|
97
|
+
},
|
|
94
98
|
renderFar: (graphics, item, context) => {
|
|
95
99
|
if (item.type !== "text") return;
|
|
96
100
|
drawFarPlate(graphics, item.frame, {
|
|
@@ -83,6 +83,10 @@ const unknownCardRenderer = {
|
|
|
83
83
|
update: (container, item, context) => {
|
|
84
84
|
sync(container, item, context);
|
|
85
85
|
},
|
|
86
|
+
resolution: (container, _item, context) => {
|
|
87
|
+
const parts = partsByContainer.get(container);
|
|
88
|
+
if (parts) syncTextResolution(parts.label, parts, context.zoom);
|
|
89
|
+
},
|
|
86
90
|
renderFar: (graphics, item, context) => {
|
|
87
91
|
drawFarPlate(graphics, item.frame, {
|
|
88
92
|
fill: context.palette.muted,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getMediaResourceTitle } from "../../model/media.js";
|
|
2
2
|
import { boardCardDetailed } from "../text-resolution.js";
|
|
3
3
|
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
4
|
-
import { cardElevation, containRect, drawCardSurface,
|
|
4
|
+
import { cardElevation, containRect, drawCardSurface, fillCardPicture } from "../surface.js";
|
|
5
5
|
import { positionShell } from "./base-card-renderer.js";
|
|
6
6
|
import { drawFarPlate } from "./far-plate.js";
|
|
7
7
|
import { drawMediaPlayKey } from "./media-key.js";
|
|
8
|
-
import { Container, Graphics
|
|
8
|
+
import { Container, Graphics } from "pixi.js";
|
|
9
9
|
//#region src/board/render/renderers/video-card-renderer.ts
|
|
10
10
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
11
11
|
const FILM_RAIL = 10;
|
|
@@ -31,7 +31,7 @@ function sync(container, item, context) {
|
|
|
31
31
|
const elevation = cardElevation(context, item.id);
|
|
32
32
|
const sig = [
|
|
33
33
|
key ?? "",
|
|
34
|
-
texture
|
|
34
|
+
texture?.uid ?? "none",
|
|
35
35
|
width,
|
|
36
36
|
height,
|
|
37
37
|
elevation,
|
|
@@ -61,17 +61,18 @@ function sync(container, item, context) {
|
|
|
61
61
|
elevation
|
|
62
62
|
});
|
|
63
63
|
if (framed) drawFilmRails(parts.plate, width, height, rail, context.palette.bg);
|
|
64
|
-
|
|
65
|
-
corner: "round",
|
|
66
|
-
radius: 1
|
|
67
|
-
} : context.style).fill({ color: 16777215 });
|
|
68
|
-
if (texture && parts.sprite.texture !== texture) parts.sprite.texture = texture;
|
|
69
|
-
parts.sprite.visible = Boolean(texture);
|
|
64
|
+
parts.picture.clear();
|
|
70
65
|
if (texture) {
|
|
71
66
|
const fitted = containRect(screen.width, screen.height, texture.width, texture.height);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
const picture = {
|
|
68
|
+
...fitted,
|
|
69
|
+
x: screen.x + fitted.x,
|
|
70
|
+
y: screen.y + fitted.y
|
|
71
|
+
};
|
|
72
|
+
fillCardPicture(parts.picture, texture, picture, framed ? {
|
|
73
|
+
corner: "round",
|
|
74
|
+
radius: 1
|
|
75
|
+
} : context.style);
|
|
75
76
|
}
|
|
76
77
|
parts.chrome.clear();
|
|
77
78
|
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);
|
|
@@ -96,17 +97,14 @@ const videoCardRenderer = {
|
|
|
96
97
|
create: (item, context) => {
|
|
97
98
|
const root = new Container();
|
|
98
99
|
const plate = new Graphics();
|
|
99
|
-
const
|
|
100
|
-
const mask = new Graphics();
|
|
100
|
+
const picture = new Graphics();
|
|
101
101
|
const chrome = new Graphics();
|
|
102
102
|
const tag = createCardTag();
|
|
103
|
-
root.addChild(plate,
|
|
104
|
-
sprite.mask = mask;
|
|
103
|
+
root.addChild(plate, picture, chrome, tag.root);
|
|
105
104
|
partsByContainer.set(root, {
|
|
106
105
|
root,
|
|
107
106
|
plate,
|
|
108
|
-
|
|
109
|
-
mask,
|
|
107
|
+
picture,
|
|
110
108
|
chrome,
|
|
111
109
|
tag,
|
|
112
110
|
sig: ""
|
|
@@ -117,6 +115,9 @@ const videoCardRenderer = {
|
|
|
117
115
|
update: (container, item, context) => {
|
|
118
116
|
if (item.type === "video") sync(container, item, context);
|
|
119
117
|
},
|
|
118
|
+
resolution: (container, item, context) => {
|
|
119
|
+
if (item.type === "video") sync(container, item, context);
|
|
120
|
+
},
|
|
120
121
|
zoom: (container, zoom) => {
|
|
121
122
|
const tag = partsByContainer.get(container)?.tag;
|
|
122
123
|
if (tag) zoomCardTag(tag, zoom);
|
|
@@ -9,6 +9,8 @@ type BoardScriptHostOptions = {
|
|
|
9
9
|
readModule(path: string): Promise<string>;
|
|
10
10
|
host: HTMLElement;
|
|
11
11
|
onFrame(): void;
|
|
12
|
+
onSchedule?(): void;
|
|
13
|
+
isMaterialized?(id: string): boolean;
|
|
12
14
|
onOutput(id: string, output: BoardScriptOutput | null): void;
|
|
13
15
|
capabilities?: Record<string, (id: string, input: unknown) => Promise<unknown>>;
|
|
14
16
|
timeoutMs?: number;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { boardScriptItems } from "../model/script-index.js";
|
|
2
2
|
import { boardScriptScope } from "../model/script-scene.js";
|
|
3
3
|
import { boardScriptHitVisible, resolveBoardScriptHit } from "../model/script-hit.js";
|
|
4
|
+
import { getBoardResolution } from "./text-resolution.js";
|
|
4
5
|
import { BoardScriptTexture } from "./script-texture.js";
|
|
6
|
+
import { scriptResolution } from "./script-resolution.js";
|
|
5
7
|
import { createBoardScriptModuleReader, loadBoardScriptSources } from "../../protocol/dist/board-script-modules.js";
|
|
6
8
|
import { boardScriptFrameSource } from "./script-sandbox.js";
|
|
7
9
|
//#region src/board/render/script-host.ts
|
|
@@ -33,6 +35,11 @@ function createBoardScriptHost(options) {
|
|
|
33
35
|
layer.dataset.boardScripts = "";
|
|
34
36
|
options.host.appendChild(layer);
|
|
35
37
|
let disposed = false;
|
|
38
|
+
const schedule = () => (options.onSchedule ?? options.onFrame)();
|
|
39
|
+
let lastZoom = NaN;
|
|
40
|
+
let settledAt = 0;
|
|
41
|
+
let resolutionTimer;
|
|
42
|
+
const needsTick = (entry) => !entry.error && entry.ready && entry.sources !== null && !entry.pending && (entry.dirty || Boolean(entry.output?.updating || entry.output?.animated && entry.draw));
|
|
36
43
|
const retiredTextures = /* @__PURE__ */ new Set();
|
|
37
44
|
let retirementFrame = 0;
|
|
38
45
|
function retireTexture(texture) {
|
|
@@ -127,7 +134,7 @@ function createBoardScriptHost(options) {
|
|
|
127
134
|
}
|
|
128
135
|
if (data.kind === "dirty") {
|
|
129
136
|
entry.dirty = true;
|
|
130
|
-
|
|
137
|
+
schedule();
|
|
131
138
|
return;
|
|
132
139
|
}
|
|
133
140
|
if (data.kind === "call") {
|
|
@@ -168,8 +175,11 @@ function createBoardScriptHost(options) {
|
|
|
168
175
|
}
|
|
169
176
|
clearTimeout(entry.timer);
|
|
170
177
|
entry.pending = false;
|
|
171
|
-
|
|
172
|
-
if (
|
|
178
|
+
const acceptsBitmap = Boolean(data.bitmap) && (options.export || !options.isMaterialized || options.isMaterialized(entry.id)) && entry.draw;
|
|
179
|
+
if (acceptsBitmap) entry.texture.update(data.bitmap);
|
|
180
|
+
else data.bitmap?.close?.();
|
|
181
|
+
const changed = acceptsBitmap || Boolean(data.output);
|
|
182
|
+
if (changed) revisions.set(entry.id, (revisions.get(entry.id) ?? 0) + 1);
|
|
173
183
|
try {
|
|
174
184
|
const output = data.output;
|
|
175
185
|
if (output) {
|
|
@@ -180,7 +190,8 @@ function createBoardScriptHost(options) {
|
|
|
180
190
|
fail(entry, error instanceof Error ? error.message : String(error));
|
|
181
191
|
return;
|
|
182
192
|
}
|
|
183
|
-
options.onFrame();
|
|
193
|
+
if (changed) options.onFrame();
|
|
194
|
+
else if (needsTick(entry)) schedule();
|
|
184
195
|
};
|
|
185
196
|
window.addEventListener("message", onMessage);
|
|
186
197
|
return {
|
|
@@ -229,11 +240,20 @@ function createBoardScriptHost(options) {
|
|
|
229
240
|
},
|
|
230
241
|
output: (id) => entries.get(id)?.output ?? null,
|
|
231
242
|
get animated() {
|
|
232
|
-
|
|
243
|
+
for (const entry of entries.values()) if (needsTick(entry)) return true;
|
|
244
|
+
return false;
|
|
233
245
|
},
|
|
234
246
|
sync(board, scene, camera, time, inputEnabled, visibleIds) {
|
|
235
247
|
if (disposed) return;
|
|
236
248
|
interactive = inputEnabled;
|
|
249
|
+
const now = performance.now();
|
|
250
|
+
if (!options.export && camera.zoom !== lastZoom) {
|
|
251
|
+
const first = Number.isNaN(lastZoom);
|
|
252
|
+
lastZoom = camera.zoom;
|
|
253
|
+
settledAt = first ? now : now + 120;
|
|
254
|
+
clearTimeout(resolutionTimer);
|
|
255
|
+
if (!first) resolutionTimer = setTimeout(schedule, 120);
|
|
256
|
+
}
|
|
237
257
|
const alive = /* @__PURE__ */ new Set();
|
|
238
258
|
const liveFocusTargets = /* @__PURE__ */ new Set();
|
|
239
259
|
let focusSurface;
|
|
@@ -282,7 +302,9 @@ function createBoardScriptHost(options) {
|
|
|
282
302
|
pending: false,
|
|
283
303
|
time: -1,
|
|
284
304
|
sentSources: false,
|
|
285
|
-
visible: true
|
|
305
|
+
visible: true,
|
|
306
|
+
draw: false,
|
|
307
|
+
scale: 0
|
|
286
308
|
};
|
|
287
309
|
entries.set(id, entry);
|
|
288
310
|
restored.delete(id);
|
|
@@ -313,6 +335,18 @@ function createBoardScriptHost(options) {
|
|
|
313
335
|
entry.visible = visible;
|
|
314
336
|
if (visible) entry.dirty = true;
|
|
315
337
|
}
|
|
338
|
+
const draw = Boolean(options.export || visible && (options.isMaterialized?.(id) ?? true));
|
|
339
|
+
if (entry.draw !== draw) {
|
|
340
|
+
entry.draw = draw;
|
|
341
|
+
if (draw) entry.dirty = true;
|
|
342
|
+
}
|
|
343
|
+
const frame = scene.get(id)?.frame;
|
|
344
|
+
const itemScale = Math.max((frame?.width ?? box.width) / Math.max(1, box.width), (frame?.height ?? box.height) / Math.max(1, box.height));
|
|
345
|
+
const scale = options.export ? Math.min(2, 2048 / Math.max(1, box.width, box.height)) : scriptResolution(box.width, box.height, now < settledAt && entry.scale > 0 ? entry.scale : camera.zoom * getBoardResolution() * itemScale, entry.scale);
|
|
346
|
+
if (scale !== entry.scale) {
|
|
347
|
+
entry.scale = scale;
|
|
348
|
+
if (draw) entry.dirty = true;
|
|
349
|
+
}
|
|
316
350
|
if (entry.input !== input || entry.inputDocument !== board) {
|
|
317
351
|
const inputKey = JSON.stringify(input);
|
|
318
352
|
if (entry.inputKey !== inputKey) {
|
|
@@ -370,7 +404,7 @@ function createBoardScriptHost(options) {
|
|
|
370
404
|
}
|
|
371
405
|
}
|
|
372
406
|
}
|
|
373
|
-
if (!entry.ready || !entry.sources || entry.pending || !entry.dirty && (!entry.output?.animated || !
|
|
407
|
+
if (!entry.ready || !entry.sources || entry.pending || !entry.dirty && (!entry.output?.animated || !entry.draw && !entry.output.updating || entry.time === time)) continue;
|
|
374
408
|
entry.pending = true;
|
|
375
409
|
entry.dirty = false;
|
|
376
410
|
entry.time = time;
|
|
@@ -382,9 +416,9 @@ function createBoardScriptHost(options) {
|
|
|
382
416
|
request: entry.request,
|
|
383
417
|
input: entry.sentInput === entry.input ? void 0 : entry.input,
|
|
384
418
|
sources: entry.sentSources ? void 0 : entry.sources,
|
|
385
|
-
draw:
|
|
419
|
+
draw: entry.draw,
|
|
386
420
|
t: time - entry.startedAt,
|
|
387
|
-
scale:
|
|
421
|
+
scale: entry.scale,
|
|
388
422
|
events: entry.events.splice(0)
|
|
389
423
|
});
|
|
390
424
|
entry.sentInput = entry.input;
|
|
@@ -428,6 +462,7 @@ function createBoardScriptHost(options) {
|
|
|
428
462
|
},
|
|
429
463
|
destroy() {
|
|
430
464
|
disposed = true;
|
|
465
|
+
clearTimeout(resolutionTimer);
|
|
431
466
|
window.removeEventListener("message", onMessage);
|
|
432
467
|
for (const entry of entries.values()) release(entry);
|
|
433
468
|
layer.remove();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/board/render/script-resolution.ts
|
|
2
|
+
const RESOLUTIONS = [
|
|
3
|
+
.125,
|
|
4
|
+
.25,
|
|
5
|
+
.5,
|
|
6
|
+
1,
|
|
7
|
+
2,
|
|
8
|
+
4
|
|
9
|
+
];
|
|
10
|
+
const MAX_EDGE = 2048;
|
|
11
|
+
const MAX_PIXELS = 2097152;
|
|
12
|
+
function scriptResolution(width, height, demand, current = 0) {
|
|
13
|
+
const target = Number.isFinite(demand) && demand > 0 ? demand : 1;
|
|
14
|
+
const tier = current > 0 && target <= current * 1.15 && target >= current * .4 ? current : RESOLUTIONS.find((value) => value >= target) ?? 4;
|
|
15
|
+
return Math.min(tier, MAX_EDGE / Math.max(1, width, height), Math.sqrt(MAX_PIXELS / Math.max(1, width * height)));
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { scriptResolution };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WorldPoint } from "../model/geometry.js";
|
|
2
2
|
import { BoardRenderStyle, BoardShadowStyle } from "./style.js";
|
|
3
|
-
import { Graphics } from "pixi.js";
|
|
3
|
+
import { Graphics, Texture } from "pixi.js";
|
|
4
4
|
//#region src/board/render/surface.d.ts
|
|
5
5
|
declare const PIXEL_STEP = 2;
|
|
6
6
|
type CardRect = {
|
|
@@ -10,6 +10,13 @@ type CardRect = {
|
|
|
10
10
|
height: number;
|
|
11
11
|
};
|
|
12
12
|
declare function traceCardOutline(graphics: Graphics, rect: CardRect, style: Pick<BoardRenderStyle, "corner" | "radius">, grow?: number): Graphics;
|
|
13
|
+
type CardCrop = {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
w: number;
|
|
17
|
+
h: number;
|
|
18
|
+
};
|
|
19
|
+
declare function fillCardPicture(graphics: Graphics, texture: Texture, picture: CardRect, style: Pick<BoardRenderStyle, "corner" | "radius">, crop?: CardCrop | null): Graphics;
|
|
13
20
|
declare function tracePixelRect(graphics: Graphics, x: number, y: number, width: number, height: number, step: number): Graphics;
|
|
14
21
|
declare function cardOutlinePoints(rect: CardRect, style: Pick<BoardRenderStyle, "corner" | "radius">, grow?: number): WorldPoint[];
|
|
15
22
|
declare function drawCardShadow(graphics: Graphics, rect: CardRect, style: Pick<BoardRenderStyle, "corner" | "radius">, shadow: BoardShadowStyle | null): void;
|
|
@@ -31,4 +38,4 @@ declare function isBoardCard(item: {
|
|
|
31
38
|
type: string;
|
|
32
39
|
}): boolean;
|
|
33
40
|
//#endregion
|
|
34
|
-
export { CardElevation, CardRect, CardSurface, PIXEL_STEP, cardElevation, cardOutlinePoints, cardShadow, containRect, drawCardShadow, drawCardSurface, isBoardCard, traceCardOutline, tracePixelRect };
|
|
41
|
+
export { CardCrop, CardElevation, CardRect, CardSurface, PIXEL_STEP, cardElevation, cardOutlinePoints, cardShadow, containRect, drawCardShadow, drawCardSurface, fillCardPicture, isBoardCard, traceCardOutline, tracePixelRect };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { worldPoint } from "../model/geometry.js";
|
|
2
2
|
import { roundRectPoints } from "./stroke.js";
|
|
3
|
+
import { Matrix } from "pixi.js";
|
|
3
4
|
//#region src/board/render/surface.ts
|
|
4
5
|
const PIXEL_STEP = 2;
|
|
5
6
|
const SHADOW_LAYERS = 5;
|
|
@@ -12,6 +13,19 @@ function traceCardOutline(graphics, rect, style, grow = 0) {
|
|
|
12
13
|
const radius = Math.min(Math.max(0, style.radius + grow), width / 2, height / 2);
|
|
13
14
|
return radius > 0 ? graphics.roundRect(x, y, width, height, radius) : graphics.rect(x, y, width, height);
|
|
14
15
|
}
|
|
16
|
+
function fillCardPicture(graphics, texture, picture, style, crop) {
|
|
17
|
+
const sampling = texture.source.style;
|
|
18
|
+
if (sampling.addressMode !== "mirror-repeat") {
|
|
19
|
+
sampling.addressMode = "mirror-repeat";
|
|
20
|
+
sampling.update();
|
|
21
|
+
}
|
|
22
|
+
const matrix = crop ? new Matrix(1 / crop.w, 0, 0, 1 / crop.h, -crop.x / crop.w, -crop.y / crop.h) : void 0;
|
|
23
|
+
return traceCardOutline(graphics, picture, style).fill({
|
|
24
|
+
texture,
|
|
25
|
+
textureSpace: "local",
|
|
26
|
+
...matrix ? { matrix } : {}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
15
29
|
function tracePixelRect(graphics, x, y, width, height, step) {
|
|
16
30
|
const s = Math.min(step, width / 4, height / 4);
|
|
17
31
|
if (s <= 0) return graphics.rect(x, y, width, height);
|
|
@@ -129,4 +143,4 @@ function isBoardCard(item) {
|
|
|
129
143
|
return !FREE_FORM_TYPES.has(item.type);
|
|
130
144
|
}
|
|
131
145
|
//#endregion
|
|
132
|
-
export { PIXEL_STEP, cardElevation, cardOutlinePoints, cardShadow, containRect, drawCardShadow, drawCardSurface, isBoardCard, traceCardOutline, tracePixelRect };
|
|
146
|
+
export { PIXEL_STEP, cardElevation, cardOutlinePoints, cardShadow, containRect, drawCardShadow, drawCardSurface, fillCardPicture, isBoardCard, traceCardOutline, tracePixelRect };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { applyBoardDelta, applyBoardPatchToDocument, parseBoardDocument } from "../../protocol/dist/board-patch.js";
|
|
2
2
|
import { createBoardEntityId } from "../model/items/id.js";
|
|
3
|
+
import { shareBoardDocument } from "../model/document-share.js";
|
|
3
4
|
//#region src/board/replica/index.ts
|
|
4
5
|
function memoryStorage() {
|
|
5
6
|
return {
|
|
@@ -118,7 +119,9 @@ function createBoardReplica(options) {
|
|
|
118
119
|
title = result.title;
|
|
119
120
|
if (readPlaybackRevision === playbackRevision) playback = result.playback;
|
|
120
121
|
loaded = true;
|
|
121
|
-
|
|
122
|
+
const next = shareBoardDocument(server, parsed.document);
|
|
123
|
+
if (next === server && result.version === version) return;
|
|
124
|
+
adoptServer(next, result.version, true);
|
|
122
125
|
}
|
|
123
126
|
function refresh() {
|
|
124
127
|
if (refreshing) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ModelFormat } from "../../protocol/dist/fs/mime.js";
|
|
2
2
|
import { BoardSceneItem } from "../model/scene.js";
|
|
3
|
+
import { BoardAssetUrlOptions } from "../model/media-playback.js";
|
|
3
4
|
import "../model/index.js";
|
|
4
5
|
import { LruBudget } from "./lru.js";
|
|
5
6
|
import { BoardImageTexturePool } from "./texture-pool.js";
|
|
@@ -7,7 +8,12 @@ import { Texture } from "pixi.js";
|
|
|
7
8
|
//#region src/board/stage/assets.d.ts
|
|
8
9
|
type BoardUrlMedia = "image" | "video";
|
|
9
10
|
type BoardAssetMedia = BoardUrlMedia | "model";
|
|
11
|
+
declare function boardTextureEdge(item: BoardSceneItem, scale: number): number;
|
|
10
12
|
declare function boardAssetKey(item: BoardSceneItem): string | null;
|
|
13
|
+
type Size = {
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
};
|
|
11
17
|
type BoardModelPreviewRequest = {
|
|
12
18
|
key: string;
|
|
13
19
|
src: string;
|
|
@@ -21,24 +27,22 @@ type BoardModelPreviews = {
|
|
|
21
27
|
type BoardAssetManager = {
|
|
22
28
|
assetKey: (item: BoardSceneItem) => string | null;
|
|
23
29
|
invalidatePath: (path: string) => void;
|
|
24
|
-
requestItem: (item: BoardSceneItem) => void;
|
|
30
|
+
requestItem: (item: BoardSceneItem, edge?: number) => void;
|
|
25
31
|
getTexture: (key: string) => Texture | null;
|
|
26
|
-
getNaturalSize: (key: string) =>
|
|
27
|
-
width: number;
|
|
28
|
-
height: number;
|
|
29
|
-
} | null;
|
|
32
|
+
getNaturalSize: (key: string) => Size | null;
|
|
30
33
|
hasError: (key: string) => boolean;
|
|
31
34
|
acquire: (key: string) => void;
|
|
32
35
|
release: (key: string) => void;
|
|
33
36
|
withTextures: <T>(items: BoardSceneItem[], use: (textures: Map<string, Texture>) => T | Promise<T>, options?: {
|
|
34
37
|
timeoutMs?: number;
|
|
38
|
+
edge?: (item: BoardSceneItem) => number;
|
|
35
39
|
}) => Promise<T>;
|
|
36
|
-
subscribe: (listener: () => void) => () => void;
|
|
40
|
+
subscribe: (listener: (key: string) => void) => () => void;
|
|
37
41
|
destroy: () => void;
|
|
38
42
|
};
|
|
39
43
|
type BoardAssetManagerOptions = {
|
|
40
44
|
/** Resolve a Space file path to a URL a texture can load from; null when unavailable. */
|
|
41
|
-
resolveFileUrl: (path: string) => Promise<string | null>;
|
|
45
|
+
resolveFileUrl: (path: string, options?: BoardAssetUrlOptions) => Promise<string | null>;
|
|
42
46
|
concurrency?: number;
|
|
43
47
|
videoConcurrency?: number;
|
|
44
48
|
loadVideoPreviews?: boolean;
|
|
@@ -51,4 +55,4 @@ type BoardAssetManagerOptions = {
|
|
|
51
55
|
};
|
|
52
56
|
declare function createBoardAssetManager(options: BoardAssetManagerOptions): BoardAssetManager;
|
|
53
57
|
//#endregion
|
|
54
|
-
export { BoardAssetManager, BoardAssetManagerOptions, BoardModelPreviewRequest, BoardModelPreviews, boardAssetKey, createBoardAssetManager };
|
|
58
|
+
export { BoardAssetManager, BoardAssetManagerOptions, BoardModelPreviewRequest, BoardModelPreviews, boardAssetKey, boardTextureEdge, createBoardAssetManager };
|