@neta-art/cohub 11.1.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/dist/board/editor/context.d.ts +1 -0
- package/dist/board/editor/context.js +1 -0
- package/dist/board/editor/editor.d.ts +1 -0
- package/dist/board/editor/editor.js +7 -0
- package/dist/board/editor/interaction.d.ts +4 -0
- package/dist/board/editor/interaction.js +16 -7
- package/dist/board/editor/selection-transform.d.ts +1 -1
- package/dist/board/editor/selection-transform.js +13 -2
- 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 +4 -0
- package/dist/board/model/file-preview.d.ts +0 -1
- package/dist/board/model/file-preview.js +10 -1
- package/dist/board/render/audio-waveform.d.ts +1 -1
- package/dist/board/render/audio-waveform.js +8 -5
- 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 +7 -4
- package/dist/board/render/index.js +7 -4
- package/dist/board/render/media-interaction.d.ts +2 -1
- package/dist/board/render/media-interaction.js +14 -6
- 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 +8 -0
- package/dist/board/render/renderers/board-renderer-registry.js +3 -3
- package/dist/board/render/renderers/custom-card-renderer.js +4 -7
- 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 -9
- package/dist/board/render/renderers/task-card-renderer.js +82 -56
- 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/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/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 +2 -43
- package/dist/board/stage/scene.js +23 -131
- package/dist/board/stage/stage.d.ts +2 -0
- package/dist/board/stage/stage.js +100 -33
- package/dist/chunks/environment.d.ts +997 -3
- package/dist/chunks/http.d.ts +48 -1
- package/dist/chunks/http.js +8 -0
- package/dist/http.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/package.json +2 -1
|
@@ -1,16 +1,16 @@
|
|
|
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 { fitTextToLines } from "../text-fit.js";
|
|
4
|
+
import { boardCardDetailed, syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
5
|
+
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
3
6
|
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
4
|
-
import {
|
|
7
|
+
import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
5
8
|
import { positionShell } from "./base-card-renderer.js";
|
|
6
9
|
import { drawFarPlate } from "./far-plate.js";
|
|
7
|
-
import { fitTextToLines } from "./file-card-renderer.js";
|
|
8
10
|
import { Container, FillGradient, Graphics, Sprite, Text } from "pixi.js";
|
|
9
11
|
//#region src/board/render/renderers/task-card-renderer.ts
|
|
10
|
-
const RADIUS = 4;
|
|
11
12
|
const PADDING = 12;
|
|
12
13
|
const META_HEIGHT = 28;
|
|
13
|
-
const TASK_CARD_FULL_DETAIL_ZOOM = .55;
|
|
14
14
|
const PLAY_BADGE_RADIUS = 15;
|
|
15
15
|
const SHIMMER_PERIOD_MS = 1600;
|
|
16
16
|
const SHIMMER_FRAME_MS = 33;
|
|
@@ -62,30 +62,6 @@ function statusColor(status, context) {
|
|
|
62
62
|
if (status === "running") return context.colors.brand.stroke;
|
|
63
63
|
return context.colors.neutral.stroke;
|
|
64
64
|
}
|
|
65
|
-
function formatTaskElapsed(ms) {
|
|
66
|
-
const total = Math.max(0, Math.floor(ms / SECOND));
|
|
67
|
-
const hours = Math.floor(total / 3600);
|
|
68
|
-
const minutes = Math.floor(total % 3600 / 60);
|
|
69
|
-
const seconds = String(total % 60).padStart(2, "0");
|
|
70
|
-
return hours > 0 ? `${hours}:${String(minutes).padStart(2, "0")}:${seconds}` : `${minutes}:${seconds}`;
|
|
71
|
-
}
|
|
72
|
-
function containTaskPreviewRect(width, height, imageWidth, imageHeight) {
|
|
73
|
-
if (width <= 0 || height <= 0 || imageWidth <= 0 || imageHeight <= 0) return {
|
|
74
|
-
x: 0,
|
|
75
|
-
y: 0,
|
|
76
|
-
width: 0,
|
|
77
|
-
height: 0
|
|
78
|
-
};
|
|
79
|
-
const scale = Math.min(width / imageWidth, height / imageHeight);
|
|
80
|
-
const renderedWidth = imageWidth * scale;
|
|
81
|
-
const renderedHeight = imageHeight * scale;
|
|
82
|
-
return {
|
|
83
|
-
x: (width - renderedWidth) / 2,
|
|
84
|
-
y: (height - renderedHeight) / 2,
|
|
85
|
-
width: renderedWidth,
|
|
86
|
-
height: renderedHeight
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
65
|
function drawPlayBadge(graphics, rect, context) {
|
|
90
66
|
const radius = Math.min(PLAY_BADGE_RADIUS, Math.max(8, Math.min(rect.width, rect.height) * .16));
|
|
91
67
|
const cx = rect.x + rect.width / 2;
|
|
@@ -208,17 +184,46 @@ function drawShimmerBand(graphics, width, height, color) {
|
|
|
208
184
|
const band = Math.max(48, width * .45);
|
|
209
185
|
graphics.clear().rect(-band, 0, band, height).fill(shimmerGradient(color));
|
|
210
186
|
}
|
|
187
|
+
const MOSAIC_FRAME_MS = 160;
|
|
188
|
+
const MOSAIC_CELL = 8;
|
|
189
|
+
function drawMosaic(graphics, width, height, color, frame) {
|
|
190
|
+
const columns = Math.max(1, Math.floor(width / MOSAIC_CELL));
|
|
191
|
+
const rows = Math.max(1, Math.floor(height / MOSAIC_CELL));
|
|
192
|
+
const left = (width - columns * MOSAIC_CELL) / 2;
|
|
193
|
+
const top = (height - rows * MOSAIC_CELL) / 2;
|
|
194
|
+
graphics.clear();
|
|
195
|
+
for (const [threshold, alpha] of [[.08, .16], [.02, .3]]) {
|
|
196
|
+
for (let row = 0; row < rows; row += 1) for (let column = 0; column < columns; column += 1) {
|
|
197
|
+
let hash = Math.imul(column + 1, 2654435761) ^ Math.imul(row + 1, 2246822507) ^ Math.imul(frame + 1, 3266489909);
|
|
198
|
+
hash ^= hash >>> 15;
|
|
199
|
+
hash = Math.imul(hash, 739982445);
|
|
200
|
+
hash ^= hash >>> 12;
|
|
201
|
+
if ((hash >>> 0) / 4294967295 < threshold) graphics.rect(left + column * MOSAIC_CELL + 1, top + row * MOSAIC_CELL + 1, 6, 6);
|
|
202
|
+
}
|
|
203
|
+
graphics.fill({
|
|
204
|
+
color,
|
|
205
|
+
alpha
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
211
209
|
function advance(parts, clock) {
|
|
212
210
|
const { motion } = parts;
|
|
213
211
|
let next = null;
|
|
214
|
-
if (motion.
|
|
212
|
+
if (motion.mosaic) {
|
|
213
|
+
const frame = Math.floor(clock / MOSAIC_FRAME_MS);
|
|
214
|
+
if (frame !== motion.mosaic.step) {
|
|
215
|
+
motion.mosaic.step = frame;
|
|
216
|
+
drawMosaic(parts.shimmer, motion.width, motion.mosaic.height, motion.mosaic.color, frame);
|
|
217
|
+
}
|
|
218
|
+
next = MOSAIC_FRAME_MS - clock % MOSAIC_FRAME_MS;
|
|
219
|
+
} else if (motion.shimmer) {
|
|
215
220
|
const travel = motion.width + parts.shimmer.width;
|
|
216
221
|
parts.shimmer.x = clock % SHIMMER_PERIOD_MS / SHIMMER_PERIOD_MS * travel;
|
|
217
222
|
next = SHIMMER_FRAME_MS;
|
|
218
223
|
}
|
|
219
224
|
if (motion.startedAt !== null) {
|
|
220
225
|
const elapsedMs = Date.now() - motion.startedAt;
|
|
221
|
-
const elapsed =
|
|
226
|
+
const elapsed = formatBoardDuration(elapsedMs);
|
|
222
227
|
if (elapsed !== motion.elapsed) {
|
|
223
228
|
motion.elapsed = elapsed;
|
|
224
229
|
parts.body.text = `${motion.label} · ${elapsed}`;
|
|
@@ -241,9 +246,13 @@ function sync(container, item, context) {
|
|
|
241
246
|
const { width, height } = item.frame;
|
|
242
247
|
const { snapshot } = item.props;
|
|
243
248
|
const { status, startedAt } = liveStatus(item, context);
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
|
|
249
|
+
const full = boardCardDetailed(context.zoom);
|
|
250
|
+
const elevation = cardElevation(context, item.id);
|
|
251
|
+
syncCardTag(parts.tag, {
|
|
252
|
+
glyph: "task",
|
|
253
|
+
text: snapshot.title,
|
|
254
|
+
width
|
|
255
|
+
}, context);
|
|
247
256
|
const working = status === "pending" || status === "running";
|
|
248
257
|
const color = statusColor(status, context);
|
|
249
258
|
const key = context.assetKey(item);
|
|
@@ -270,7 +279,7 @@ function sync(container, item, context) {
|
|
|
270
279
|
const showBadge = full && Boolean(count);
|
|
271
280
|
const label = stateLabel(surface, context);
|
|
272
281
|
const counting = full && working && startedAt !== null && surface !== null;
|
|
273
|
-
const elapsed = counting ?
|
|
282
|
+
const elapsed = counting ? formatBoardDuration(Date.now() - startedAt) : "";
|
|
274
283
|
const detailText = !full || !surface ? "" : status === "failed" ? snapshot.errorExcerpt ?? "" : working ? snapshot.promptExcerpt ?? "" : "";
|
|
275
284
|
const textArtifact = kind === "text" && artifact?.type === "text";
|
|
276
285
|
const bodyText = textArtifact ? artifact.textExcerpt : counting ? `${label} · ${elapsed}` : label;
|
|
@@ -290,10 +299,13 @@ function sync(container, item, context) {
|
|
|
290
299
|
height,
|
|
291
300
|
color,
|
|
292
301
|
context.palette.text,
|
|
293
|
-
context.palette.muted
|
|
302
|
+
context.palette.muted,
|
|
303
|
+
context.style.font
|
|
294
304
|
].join("|");
|
|
295
305
|
if (textSig !== parts.textSig) {
|
|
296
306
|
parts.textSig = textSig;
|
|
307
|
+
parts.body.style.fontFamily = context.style.font;
|
|
308
|
+
parts.detail.style.fontFamily = context.style.font;
|
|
297
309
|
const wrap = Math.max(24, width - 24);
|
|
298
310
|
parts.body.style.fill = surface === "failed" ? color : context.palette.text;
|
|
299
311
|
parts.body.anchor.set(textArtifact ? 0 : .5, 0);
|
|
@@ -309,9 +321,8 @@ function sync(container, item, context) {
|
|
|
309
321
|
const visualSig = [
|
|
310
322
|
width,
|
|
311
323
|
height,
|
|
312
|
-
selected,
|
|
313
|
-
hovered,
|
|
314
324
|
full,
|
|
325
|
+
elevation,
|
|
315
326
|
color,
|
|
316
327
|
kind,
|
|
317
328
|
surface,
|
|
@@ -322,30 +333,30 @@ function sync(container, item, context) {
|
|
|
322
333
|
artifact?.id ?? "none",
|
|
323
334
|
item.props.taskRunId,
|
|
324
335
|
texture ? `${texture.width}x${texture.height}` : "none",
|
|
325
|
-
context.
|
|
326
|
-
context.palette.hover,
|
|
327
|
-
context.palette.border,
|
|
328
|
-
context.palette.bg,
|
|
329
|
-
context.palette.text
|
|
336
|
+
context.themeKey
|
|
330
337
|
].join("|");
|
|
331
338
|
if (visualSig !== parts.visualSig) {
|
|
332
339
|
parts.visualSig = visualSig;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
+
const rect = {
|
|
341
|
+
x: 0,
|
|
342
|
+
y: 0,
|
|
343
|
+
width,
|
|
344
|
+
height
|
|
345
|
+
};
|
|
346
|
+
drawCardSurface(parts.plate.clear(), rect, context.style, {
|
|
347
|
+
fill: context.palette.surface,
|
|
348
|
+
border: context.palette.border,
|
|
349
|
+
borderAlpha: .82,
|
|
350
|
+
elevation
|
|
340
351
|
});
|
|
341
|
-
parts.clip.clear()
|
|
352
|
+
traceCardOutline(parts.clip.clear(), rect, context.style, -1).fill({ color: 16777215 });
|
|
342
353
|
parts.previewBg.clear().rect(frame.x, frame.y, frame.width, frame.height).fill({
|
|
343
354
|
color: context.palette.hover,
|
|
344
355
|
alpha: .5
|
|
345
356
|
});
|
|
346
357
|
parts.previewMask.clear().rect(frame.x, frame.y, frame.width, frame.height).fill({ color: 16777215 });
|
|
347
|
-
drawShimmerBand(parts.shimmer, frame.width, frame.height, context.palette.text);
|
|
348
|
-
parts.shimmer.
|
|
358
|
+
if (context.style.progress === "shimmer") drawShimmerBand(parts.shimmer, frame.width, frame.height, context.palette.text);
|
|
359
|
+
parts.shimmer.position.set(context.style.progress === "shimmer" ? 0 : frame.x, frame.y);
|
|
349
360
|
parts.previewArt.clear();
|
|
350
361
|
if (kind === "waveform") {
|
|
351
362
|
const bottomInset = showMeta ? META_HEIGHT : 0;
|
|
@@ -384,7 +395,7 @@ function sync(container, item, context) {
|
|
|
384
395
|
parts.preview.visible = showPreview;
|
|
385
396
|
if (showPreview && texture) {
|
|
386
397
|
if (parts.preview.texture !== texture) parts.preview.texture = texture;
|
|
387
|
-
const fitted =
|
|
398
|
+
const fitted = containRect(frame.width, frame.height, texture.width, texture.height);
|
|
388
399
|
parts.preview.position.set(frame.x + fitted.x, frame.y + fitted.y);
|
|
389
400
|
parts.preview.width = fitted.width;
|
|
390
401
|
parts.preview.height = fitted.height;
|
|
@@ -400,6 +411,12 @@ function sync(container, item, context) {
|
|
|
400
411
|
parts.badge.position.set(width - 8 - badgeWidth / 2, 18);
|
|
401
412
|
parts.motion.width = frame.width;
|
|
402
413
|
parts.motion.shimmer = full && working && kind !== "texture" && !context.reducedMotion;
|
|
414
|
+
const mosaic = parts.motion.shimmer && context.style.progress === "mosaic";
|
|
415
|
+
parts.motion.mosaic = mosaic ? {
|
|
416
|
+
color: context.palette.brand,
|
|
417
|
+
height: frame.height,
|
|
418
|
+
step: -1
|
|
419
|
+
} : null;
|
|
403
420
|
parts.shimmer.visible = parts.motion.shimmer;
|
|
404
421
|
parts.motion.startedAt = counting ? startedAt : null;
|
|
405
422
|
parts.motion.label = label;
|
|
@@ -439,10 +456,14 @@ const taskCardRenderer = {
|
|
|
439
456
|
detail.anchor.set(.5, 0);
|
|
440
457
|
detail.style.align = "center";
|
|
441
458
|
preview.mask = previewMask;
|
|
442
|
-
|
|
443
|
-
|
|
459
|
+
const content = new Container();
|
|
460
|
+
content.mask = clip;
|
|
461
|
+
content.addChild(previewBg, shimmer, preview, previewMask, previewArt, body, detail, meta, badge);
|
|
462
|
+
const tag = createCardTag();
|
|
463
|
+
root.addChild(plate, content, clip, tag.root);
|
|
444
464
|
partsByContainer.set(root, {
|
|
445
465
|
root,
|
|
466
|
+
tag,
|
|
446
467
|
plate,
|
|
447
468
|
clip,
|
|
448
469
|
previewBg,
|
|
@@ -462,6 +483,7 @@ const taskCardRenderer = {
|
|
|
462
483
|
itemId: "",
|
|
463
484
|
width: 0,
|
|
464
485
|
shimmer: false,
|
|
486
|
+
mosaic: null,
|
|
465
487
|
startedAt: null,
|
|
466
488
|
label: "",
|
|
467
489
|
elapsed: "",
|
|
@@ -479,6 +501,10 @@ const taskCardRenderer = {
|
|
|
479
501
|
const parts = partsByContainer.get(container);
|
|
480
502
|
return parts ? advance(parts, clock) : null;
|
|
481
503
|
},
|
|
504
|
+
zoom: (container, zoom) => {
|
|
505
|
+
const tag = partsByContainer.get(container)?.tag;
|
|
506
|
+
if (tag) zoomCardTag(tag, zoom);
|
|
507
|
+
},
|
|
482
508
|
renderFar: (graphics, item, context) => {
|
|
483
509
|
if (item.type !== "task") return;
|
|
484
510
|
const { status } = liveStatus(item, context);
|
|
@@ -500,4 +526,4 @@ const taskCardRenderer = {
|
|
|
500
526
|
}
|
|
501
527
|
};
|
|
502
528
|
//#endregion
|
|
503
|
-
export {
|
|
529
|
+
export { taskCardRenderer };
|
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
import { BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
2
|
import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
3
|
+
import { cardElevation, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
3
4
|
import { positionShell } from "./base-card-renderer.js";
|
|
4
5
|
import { drawFarPlate } from "./far-plate.js";
|
|
5
6
|
import { Container, Graphics, Text } from "pixi.js";
|
|
6
7
|
//#region src/board/render/renderers/unknown-card-renderer.ts
|
|
7
|
-
const RADIUS = 10;
|
|
8
8
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
9
9
|
function sync(container, item, context) {
|
|
10
10
|
const parts = partsByContainer.get(container);
|
|
11
11
|
if (!parts) return;
|
|
12
12
|
positionShell(parts.root, item);
|
|
13
13
|
const { width, height } = item.frame;
|
|
14
|
-
const selected = context.selectedIds.has(item.id);
|
|
15
14
|
const realType = item.type;
|
|
16
15
|
syncTextResolution(parts.label, parts, context.zoom);
|
|
16
|
+
const elevation = cardElevation(context, item.id);
|
|
17
17
|
const visualSig = [
|
|
18
18
|
width,
|
|
19
19
|
height,
|
|
20
|
-
|
|
21
|
-
context.
|
|
22
|
-
context.palette.brand,
|
|
23
|
-
context.palette.border,
|
|
24
|
-
context.palette.muted
|
|
20
|
+
elevation,
|
|
21
|
+
context.themeKey
|
|
25
22
|
].join("|");
|
|
26
23
|
if (visualSig !== parts.visualSig) {
|
|
27
24
|
parts.visualSig = visualSig;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
const rect = {
|
|
26
|
+
x: 0,
|
|
27
|
+
y: 0,
|
|
28
|
+
width,
|
|
29
|
+
height
|
|
30
|
+
};
|
|
31
|
+
drawCardSurface(parts.box.clear(), rect, context.style, {
|
|
32
|
+
fill: context.palette.surface,
|
|
33
|
+
fillAlpha: .7,
|
|
34
|
+
border: context.palette.border,
|
|
35
|
+
borderAlpha: .8,
|
|
36
|
+
elevation
|
|
36
37
|
});
|
|
37
|
-
parts.box
|
|
38
|
+
traceCardOutline(parts.box, rect, context.style, -6).stroke({
|
|
38
39
|
color: context.palette.muted,
|
|
39
40
|
width: 1,
|
|
40
41
|
alpha: .4
|
|
@@ -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,
|
|
@@ -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 };
|