@neta-art/cohub 11.5.1 → 12.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/scene.js +1 -0
- 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/card-tag.d.ts +0 -1
- package/dist/board/render/card-tag.js +15 -17
- package/dist/board/render/index.d.ts +3 -3
- package/dist/board/render/index.js +3 -3
- package/dist/board/render/renderers/arrow-card-renderer.js +8 -6
- package/dist/board/render/renderers/audio-card-renderer.js +10 -6
- package/dist/board/render/renderers/base-card-renderer.d.ts +1 -1
- package/dist/board/render/renderers/base-card-renderer.js +2 -3
- package/dist/board/render/renderers/board-renderer-registry.d.ts +6 -2
- package/dist/board/render/renderers/custom-card-renderer.js +23 -18
- package/dist/board/render/renderers/file-card-renderer.js +14 -9
- package/dist/board/render/renderers/frame-card-renderer.js +7 -4
- 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 +8 -6
- package/dist/board/render/renderers/task-card-renderer.js +13 -10
- package/dist/board/render/renderers/text-card-renderer.js +7 -5
- package/dist/board/render/renderers/unknown-card-renderer.js +8 -6
- 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/render/text-resolution.d.ts +4 -7
- package/dist/board/render/text-resolution.js +20 -22
- 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/canvas-size.d.ts +18 -0
- package/dist/board/stage/canvas-size.js +31 -0
- 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 +8 -1
- package/dist/board/stage/scene.js +72 -10
- package/dist/board/stage/stage.d.ts +1 -0
- package/dist/board/stage/stage.js +151 -63
- package/dist/board/stage/text-resolution-tracker.d.ts +8 -0
- package/dist/board/stage/text-resolution-tracker.js +33 -0
- 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
|
@@ -13,7 +13,6 @@ function sync(container, item, context) {
|
|
|
13
13
|
if (!parts) return;
|
|
14
14
|
const { frame, style, props, locked } = item;
|
|
15
15
|
positionShell(parts.root, item);
|
|
16
|
-
syncTextResolution(parts.label, parts, context.zoom);
|
|
17
16
|
const fill = itemColor(context, style.fill ?? style.stroke, "neutral", "fill");
|
|
18
17
|
const fillAlpha = (style.fillOpacity ?? (style.fill ? 1 : DEFAULT_WASH)) * itemAlpha(context, style.fill ?? style.stroke);
|
|
19
18
|
const baseStroke = itemColor(context, style.stroke, "neutral");
|
|
@@ -69,6 +68,7 @@ function sync(container, item, context) {
|
|
|
69
68
|
parts.label.style.fill = labelColor;
|
|
70
69
|
parts.label.style.fontFamily = context.style.font;
|
|
71
70
|
}
|
|
71
|
+
syncTextResolution(parts.label, context.textResolution);
|
|
72
72
|
parts.label.position.set(4, -18);
|
|
73
73
|
}
|
|
74
74
|
const frameCardRenderer = {
|
|
@@ -82,15 +82,14 @@ const frameCardRenderer = {
|
|
|
82
82
|
fontFamily: BOARD_FONT_STACK,
|
|
83
83
|
fontSize: 12,
|
|
84
84
|
fontWeight: "600"
|
|
85
|
-
});
|
|
85
|
+
}, context.textResolution);
|
|
86
86
|
root.addChild(box, label);
|
|
87
87
|
partsByContainer.set(root, {
|
|
88
88
|
root,
|
|
89
89
|
box,
|
|
90
90
|
label,
|
|
91
91
|
visualSig: "",
|
|
92
|
-
textSig: ""
|
|
93
|
-
resolution: label.resolution
|
|
92
|
+
textSig: ""
|
|
94
93
|
});
|
|
95
94
|
if (item.type === "frame") sync(root, item, context);
|
|
96
95
|
return root;
|
|
@@ -98,6 +97,10 @@ const frameCardRenderer = {
|
|
|
98
97
|
update: (container, item, context) => {
|
|
99
98
|
if (item.type === "frame") sync(container, item, context);
|
|
100
99
|
},
|
|
100
|
+
resolution: (container, _item, context) => {
|
|
101
|
+
const parts = partsByContainer.get(container);
|
|
102
|
+
if (parts) syncTextResolution(parts.label, context.textResolution);
|
|
103
|
+
},
|
|
101
104
|
renderFar: (graphics, item, context) => {
|
|
102
105
|
if (item.type !== "frame" || item.props.decoration === "none") return;
|
|
103
106
|
drawFarPlate(graphics, item.frame, {
|
|
@@ -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
3
|
import { itemAlpha, itemColor } from "../palette.js";
|
|
4
|
-
import { syncTextResolution, syncTextWrapWidth
|
|
4
|
+
import { syncTextResolution, syncTextWrapWidth } from "../text-resolution.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";
|
|
@@ -100,7 +100,6 @@ function sync(container, item, context) {
|
|
|
100
100
|
const fillOpacity = (style.fillOpacity ?? (style.fill ? 1 : 0)) * itemAlpha(context, style.fill ?? style.stroke);
|
|
101
101
|
const strokeAlpha = itemAlpha(context, style.stroke ?? style.fill);
|
|
102
102
|
const strokeWidth = style.strokeWidth ?? 1.75;
|
|
103
|
-
syncTextResolution(parts.label, parts, context.zoom);
|
|
104
103
|
const visualSig = [
|
|
105
104
|
width,
|
|
106
105
|
height,
|
|
@@ -159,6 +158,7 @@ function sync(container, item, context) {
|
|
|
159
158
|
parts.label.style.align = props.align;
|
|
160
159
|
}
|
|
161
160
|
syncTextWrapWidth(parts.label, parts, Math.max(1, width - 16), context.resizingIds.has(item.id));
|
|
161
|
+
syncTextResolution(parts.label, context.textResolution);
|
|
162
162
|
parts.label.position.set(width / 2, height / 2);
|
|
163
163
|
}
|
|
164
164
|
const shapeCardRenderer = {
|
|
@@ -167,7 +167,6 @@ const shapeCardRenderer = {
|
|
|
167
167
|
create: (item, context) => {
|
|
168
168
|
const root = new Container();
|
|
169
169
|
const shape = new Graphics();
|
|
170
|
-
const resolution = textResolutionForZoom(context.zoom);
|
|
171
170
|
const label = new Text({
|
|
172
171
|
text: "",
|
|
173
172
|
style: {
|
|
@@ -179,7 +178,7 @@ const shapeCardRenderer = {
|
|
|
179
178
|
wordWrap: true,
|
|
180
179
|
lineHeight: 28
|
|
181
180
|
},
|
|
182
|
-
resolution,
|
|
181
|
+
resolution: context.textResolution,
|
|
183
182
|
roundPixels: true
|
|
184
183
|
});
|
|
185
184
|
label.anchor.set(.5);
|
|
@@ -190,8 +189,7 @@ const shapeCardRenderer = {
|
|
|
190
189
|
label,
|
|
191
190
|
visualSig: "",
|
|
192
191
|
textSig: "",
|
|
193
|
-
wrapWidth: 0
|
|
194
|
-
resolution
|
|
192
|
+
wrapWidth: 0
|
|
195
193
|
});
|
|
196
194
|
if (item.type === "shape") sync(root, item, context);
|
|
197
195
|
return root;
|
|
@@ -199,6 +197,10 @@ const shapeCardRenderer = {
|
|
|
199
197
|
update: (container, item, context) => {
|
|
200
198
|
if (item.type === "shape") sync(container, item, context);
|
|
201
199
|
},
|
|
200
|
+
resolution: (container, _item, context) => {
|
|
201
|
+
const parts = partsByContainer.get(container);
|
|
202
|
+
if (parts) syncTextResolution(parts.label, context.textResolution);
|
|
203
|
+
},
|
|
202
204
|
renderFar: (graphics, item, context) => {
|
|
203
205
|
if (item.type !== "shape") return;
|
|
204
206
|
drawFarPlate(graphics, item.frame, {
|
|
@@ -1,7 +1,7 @@
|
|
|
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
3
|
import { fitTextToLines } from "../text-fit.js";
|
|
4
|
-
import { boardCardDetailed, syncTextResolution
|
|
4
|
+
import { boardCardDetailed, syncTextResolution } from "../text-resolution.js";
|
|
5
5
|
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
6
6
|
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
7
7
|
import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.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));
|
|
@@ -283,10 +283,6 @@ function sync(container, item, context) {
|
|
|
283
283
|
const detailText = !full || !surface ? "" : status === "failed" ? snapshot.errorExcerpt ?? "" : working ? snapshot.promptExcerpt ?? "" : "";
|
|
284
284
|
const textArtifact = kind === "text" && artifact?.type === "text";
|
|
285
285
|
const bodyText = textArtifact ? artifact.textExcerpt : counting ? `${label} · ${elapsed}` : label;
|
|
286
|
-
syncTextResolution(parts.body, parts, context.zoom);
|
|
287
|
-
syncTextResolution(parts.detail, parts, context.zoom);
|
|
288
|
-
syncTextResolution(parts.meta, parts, context.zoom);
|
|
289
|
-
syncTextResolution(parts.badge, parts, context.zoom);
|
|
290
286
|
const textSig = [
|
|
291
287
|
counting ? label : bodyText,
|
|
292
288
|
detailText,
|
|
@@ -317,6 +313,12 @@ function sync(container, item, context) {
|
|
|
317
313
|
parts.badge.style.fill = context.palette.text;
|
|
318
314
|
if (parts.badge.text !== count) parts.badge.text = count;
|
|
319
315
|
}
|
|
316
|
+
for (const text of [
|
|
317
|
+
parts.body,
|
|
318
|
+
parts.detail,
|
|
319
|
+
parts.meta,
|
|
320
|
+
parts.badge
|
|
321
|
+
]) syncTextResolution(text, context.textResolution);
|
|
320
322
|
const badgeWidth = Math.max(22, parts.badge.width + 12);
|
|
321
323
|
const visualSig = [
|
|
322
324
|
width,
|
|
@@ -332,7 +334,7 @@ function sync(container, item, context) {
|
|
|
332
334
|
artifact?.type ?? "none",
|
|
333
335
|
artifact?.id ?? "none",
|
|
334
336
|
item.props.taskRunId,
|
|
335
|
-
texture
|
|
337
|
+
texture?.uid ?? "none",
|
|
336
338
|
context.themeKey
|
|
337
339
|
].join("|");
|
|
338
340
|
if (visualSig !== parts.visualSig) {
|
|
@@ -434,7 +436,6 @@ const taskCardRenderer = {
|
|
|
434
436
|
const previewMask = new Graphics();
|
|
435
437
|
const shimmer = new Graphics();
|
|
436
438
|
const previewArt = new Graphics();
|
|
437
|
-
const resolution = textResolutionForZoom(context.zoom);
|
|
438
439
|
const text = (fontFamily, fontSize, fontWeight) => new Text({
|
|
439
440
|
text: "",
|
|
440
441
|
style: {
|
|
@@ -444,7 +445,7 @@ const taskCardRenderer = {
|
|
|
444
445
|
wordWrap: true,
|
|
445
446
|
breakWords: true
|
|
446
447
|
},
|
|
447
|
-
resolution,
|
|
448
|
+
resolution: context.textResolution,
|
|
448
449
|
roundPixels: true
|
|
449
450
|
});
|
|
450
451
|
const body = text(BOARD_FONT_STACK, 11.5, "500");
|
|
@@ -478,7 +479,6 @@ const taskCardRenderer = {
|
|
|
478
479
|
assetKey: null,
|
|
479
480
|
visualSig: "",
|
|
480
481
|
textSig: "",
|
|
481
|
-
resolution,
|
|
482
482
|
motion: {
|
|
483
483
|
itemId: "",
|
|
484
484
|
width: 0,
|
|
@@ -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);
|
|
@@ -2,7 +2,7 @@ import { layoutBoardText } from "../../../protocol/dist/board-layout.js";
|
|
|
2
2
|
import { boardFontFamily } from "../../model/text-metrics.js";
|
|
3
3
|
import { itemAlpha, itemColor } from "../palette.js";
|
|
4
4
|
import { BOARD_FONT_STACKS } from "../text-measurement.js";
|
|
5
|
-
import { syncTextResolution
|
|
5
|
+
import { syncTextResolution } from "../text-resolution.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";
|
|
@@ -32,7 +32,6 @@ function sync(container, item, context) {
|
|
|
32
32
|
const anchorX = props.align === "center" ? .5 : props.align === "right" ? 1 : 0;
|
|
33
33
|
parts.body.anchor.set(anchorX, 0);
|
|
34
34
|
parts.body.position.set(item.frame.width * anchorX, 0);
|
|
35
|
-
syncTextResolution(parts.body, parts, context.zoom * Math.max(1, previewScale));
|
|
36
35
|
parts.body.alpha = itemAlpha(context, item.style.fill);
|
|
37
36
|
parts.caret.alpha = parts.body.alpha;
|
|
38
37
|
const ink = itemColor(context, item.style.fill, "neutral");
|
|
@@ -62,6 +61,7 @@ function sync(container, item, context) {
|
|
|
62
61
|
breakWords: true
|
|
63
62
|
});
|
|
64
63
|
}
|
|
64
|
+
syncTextResolution(parts.body, context.textResolution * previewScale);
|
|
65
65
|
syncCaret(parts, item, context);
|
|
66
66
|
}
|
|
67
67
|
const textCardRenderer = {
|
|
@@ -69,11 +69,10 @@ const textCardRenderer = {
|
|
|
69
69
|
canRender: (item) => item.type === "text",
|
|
70
70
|
create: (item, context) => {
|
|
71
71
|
const root = new Container();
|
|
72
|
-
const resolution = textResolutionForZoom(context.zoom);
|
|
73
72
|
const body = new Text({
|
|
74
73
|
text: "",
|
|
75
74
|
style: { fontFamily: BOARD_FONT_STACKS.sans },
|
|
76
|
-
resolution,
|
|
75
|
+
resolution: context.textResolution,
|
|
77
76
|
roundPixels: true
|
|
78
77
|
});
|
|
79
78
|
const caret = new Graphics();
|
|
@@ -82,7 +81,6 @@ const textCardRenderer = {
|
|
|
82
81
|
root,
|
|
83
82
|
body,
|
|
84
83
|
caret,
|
|
85
|
-
resolution,
|
|
86
84
|
contentSig: ""
|
|
87
85
|
});
|
|
88
86
|
if (item.type === "text") sync(root, item, context);
|
|
@@ -91,6 +89,10 @@ const textCardRenderer = {
|
|
|
91
89
|
update: (container, item, context) => {
|
|
92
90
|
if (item.type === "text") sync(container, item, context);
|
|
93
91
|
},
|
|
92
|
+
resolution: (container, _item, context) => {
|
|
93
|
+
const parts = partsByContainer.get(container);
|
|
94
|
+
if (parts) syncTextResolution(parts.body, context.textResolution * parts.body.scale.x);
|
|
95
|
+
},
|
|
94
96
|
renderFar: (graphics, item, context) => {
|
|
95
97
|
if (item.type !== "text") return;
|
|
96
98
|
drawFarPlate(graphics, item.frame, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
|
-
import { syncTextResolution
|
|
2
|
+
import { syncTextResolution } from "../text-resolution.js";
|
|
3
3
|
import { cardElevation, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
4
4
|
import { positionShell } from "./base-card-renderer.js";
|
|
5
5
|
import { drawFarPlate } from "./far-plate.js";
|
|
@@ -12,7 +12,6 @@ function sync(container, item, context) {
|
|
|
12
12
|
positionShell(parts.root, item);
|
|
13
13
|
const { width, height } = item.frame;
|
|
14
14
|
const realType = item.type;
|
|
15
|
-
syncTextResolution(parts.label, parts, context.zoom);
|
|
16
15
|
const elevation = cardElevation(context, item.id);
|
|
17
16
|
const visualSig = [
|
|
18
17
|
width,
|
|
@@ -47,6 +46,7 @@ function sync(container, item, context) {
|
|
|
47
46
|
parts.label.text = realType;
|
|
48
47
|
parts.label.style.fill = context.palette.muted;
|
|
49
48
|
}
|
|
49
|
+
syncTextResolution(parts.label, context.textResolution);
|
|
50
50
|
parts.label.position.set(width / 2, height / 2);
|
|
51
51
|
}
|
|
52
52
|
const unknownCardRenderer = {
|
|
@@ -56,7 +56,6 @@ const unknownCardRenderer = {
|
|
|
56
56
|
const root = new Container();
|
|
57
57
|
const box = new Graphics();
|
|
58
58
|
box.context.batchMode = "batch";
|
|
59
|
-
const resolution = textResolutionForZoom(context.zoom);
|
|
60
59
|
const label = new Text({
|
|
61
60
|
text: "",
|
|
62
61
|
style: {
|
|
@@ -64,7 +63,7 @@ const unknownCardRenderer = {
|
|
|
64
63
|
fontSize: 11,
|
|
65
64
|
fontWeight: "600"
|
|
66
65
|
},
|
|
67
|
-
resolution,
|
|
66
|
+
resolution: context.textResolution,
|
|
68
67
|
roundPixels: true
|
|
69
68
|
});
|
|
70
69
|
label.anchor.set(.5);
|
|
@@ -74,8 +73,7 @@ const unknownCardRenderer = {
|
|
|
74
73
|
box,
|
|
75
74
|
label,
|
|
76
75
|
visualSig: "",
|
|
77
|
-
textSig: ""
|
|
78
|
-
resolution
|
|
76
|
+
textSig: ""
|
|
79
77
|
});
|
|
80
78
|
sync(root, item, context);
|
|
81
79
|
return root;
|
|
@@ -83,6 +81,10 @@ const unknownCardRenderer = {
|
|
|
83
81
|
update: (container, item, context) => {
|
|
84
82
|
sync(container, item, context);
|
|
85
83
|
},
|
|
84
|
+
resolution: (container, _item, context) => {
|
|
85
|
+
const parts = partsByContainer.get(container);
|
|
86
|
+
if (parts) syncTextResolution(parts.label, context.textResolution);
|
|
87
|
+
},
|
|
86
88
|
renderFar: (graphics, item, context) => {
|
|
87
89
|
drawFarPlate(graphics, item.frame, {
|
|
88
90
|
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();
|