@neta-art/cohub 10.0.0 → 11.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/README.md +42 -7
- package/dist/board/editor/animation.d.ts +3 -0
- package/dist/board/editor/animation.js +16 -1
- package/dist/board/editor/clipboard.js +7 -0
- package/dist/board/editor/copy.js +23 -18
- package/dist/board/editor/creation.d.ts +7 -3
- package/dist/board/editor/creation.js +5 -4
- package/dist/board/editor/deletion.js +3 -3
- package/dist/board/editor/document.d.ts +8 -2
- package/dist/board/editor/document.js +54 -7
- package/dist/board/editor/editor.d.ts +22 -7
- package/dist/board/editor/editor.js +12 -2
- package/dist/board/editor/index.d.ts +2 -2
- package/dist/board/editor/interaction.d.ts +8 -2
- package/dist/board/editor/interaction.js +34 -1
- package/dist/board/editor/query.d.ts +5 -5
- package/dist/board/editor/query.js +14 -12
- package/dist/board/editor/selection.js +2 -1
- package/dist/board/editor/snapshots.d.ts +0 -2
- package/dist/board/editor/snapshots.js +4 -20
- package/dist/board/export/index.d.ts +25 -4
- package/dist/board/export/index.js +45 -12
- package/dist/board/export/node/index.d.ts +5 -4
- package/dist/board/export/node/index.js +16 -11
- package/dist/board/export/node/scripts.d.ts +16 -0
- package/dist/board/export/node/scripts.js +258 -0
- package/dist/board/export/scene.d.ts +2 -1
- package/dist/board/export/scene.js +24 -7
- package/dist/board/model/animation.d.ts +4 -1
- package/dist/board/model/animation.js +34 -7
- package/dist/board/model/authoring.d.ts +20 -0
- package/dist/board/model/authoring.js +185 -0
- package/dist/board/model/export-plan.js +1 -0
- package/dist/board/model/file-preview.js +1 -1
- package/dist/board/model/file-snapshot.js +3 -2
- package/dist/board/model/image-key.js +7 -3
- package/dist/board/model/index.d.ts +15 -7
- package/dist/board/model/index.js +16 -9
- package/dist/board/model/items/builtin.js +2 -2
- package/dist/board/model/items/create.d.ts +19 -4
- package/dist/board/model/items/create.js +130 -9
- package/dist/board/model/items/index.d.ts +2 -2
- package/dist/board/model/items/index.js +2 -2
- package/dist/board/model/media-playback.d.ts +2 -1
- package/dist/board/model/media-playback.js +15 -5
- package/dist/board/model/media.js +7 -1
- package/dist/board/model/overlay-placement.d.ts +25 -0
- package/dist/board/model/overlay-placement.js +35 -0
- package/dist/board/model/replay.d.ts +1 -1
- package/dist/board/model/replay.js +1 -0
- package/dist/board/model/sampling.d.ts +19 -0
- package/dist/board/model/sampling.js +96 -0
- package/dist/board/model/script-example.d.ts +4 -0
- package/dist/board/model/script-example.js +21 -0
- package/dist/board/model/script-hit.d.ts +27 -0
- package/dist/board/model/script-hit.js +109 -0
- package/dist/board/model/script-index.d.ts +7 -0
- package/dist/board/model/script-index.js +15 -0
- package/dist/board/model/script-observers.d.ts +18 -0
- package/dist/board/model/script-observers.js +92 -0
- package/dist/board/model/script-scene.d.ts +24 -0
- package/dist/board/model/script-scene.js +294 -0
- package/dist/board/model/script.d.ts +149 -0
- package/dist/board/model/script.js +1 -0
- package/dist/board/render/board-background.js +5 -4
- package/dist/board/render/css-color.d.ts +6 -1
- package/dist/board/render/css-color.js +34 -20
- package/dist/board/render/diagnostics.d.ts +20 -0
- package/dist/board/render/diagnostics.js +117 -0
- package/dist/board/render/index.d.ts +9 -6
- package/dist/board/render/index.js +10 -7
- package/dist/board/render/media-interaction.js +1 -1
- package/dist/board/render/palette.d.ts +2 -1
- package/dist/board/render/palette.js +6 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +3 -2
- package/dist/board/render/renderers/audio-card-renderer.js +2 -1
- package/dist/board/render/renderers/board-renderer-registry.d.ts +25 -5
- package/dist/board/render/renderers/board-renderer-registry.js +11 -4
- package/dist/board/render/renderers/custom-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/{sketch-card-renderer.js → custom-card-renderer.js} +18 -16
- package/dist/board/render/renderers/draw-card-renderer.js +3 -2
- package/dist/board/render/renderers/effect-card-renderer.js +22 -5
- package/dist/board/render/renderers/frame-card-renderer.js +30 -14
- package/dist/board/render/renderers/image-card-renderer.js +43 -4
- package/dist/board/render/renderers/shape-card-renderer.js +10 -27
- package/dist/board/render/renderers/task-card-renderer.d.ts +2 -1
- package/dist/board/render/renderers/task-card-renderer.js +220 -71
- package/dist/board/render/renderers/text-card-renderer.js +5 -3
- package/dist/board/render/renderers/unknown-card-renderer.js +1 -0
- package/dist/board/render/renderers/video-card-renderer.js +2 -1
- package/dist/board/render/sampling.d.ts +22 -0
- package/dist/board/render/sampling.js +21 -0
- package/dist/board/render/script-export.d.ts +11 -0
- package/dist/board/render/script-export.js +86 -0
- package/dist/board/render/script-host.d.ts +31 -0
- package/dist/board/render/script-host.js +446 -0
- package/dist/board/render/script-modules.d.ts +2 -0
- package/dist/board/render/script-modules.js +2 -0
- package/dist/board/render/script-runtime.d.ts +29 -0
- package/dist/board/render/script-runtime.js +223 -0
- package/dist/board/render/script-sandbox.d.ts +4 -0
- package/dist/board/render/script-sandbox.js +173 -0
- package/dist/board/render/script-texture.d.ts +11 -0
- package/dist/board/render/script-texture.js +33 -0
- package/dist/board/render/stroke.d.ts +2 -1
- package/dist/board/render/stroke.js +22 -1
- package/dist/board/render/text-measurement.js +1 -1
- package/dist/board/stage/assets.js +7 -2
- package/dist/board/stage/maintenance.d.ts +5 -0
- package/dist/board/stage/maintenance.js +11 -0
- package/dist/board/stage/scene.d.ts +2 -0
- package/dist/board/stage/scene.js +21 -2
- package/dist/board/stage/script-pointer.d.ts +20 -0
- package/dist/board/stage/script-pointer.js +41 -0
- package/dist/board/stage/stage.d.ts +21 -3
- package/dist/board/stage/stage.js +350 -47
- package/dist/board/stage/texture-pool.js +2 -3
- package/dist/chunks/environment.d.ts +305 -27
- package/dist/chunks/environment.js +12 -4
- package/dist/chunks/host-bridge.d.ts +2 -2
- package/dist/chunks/http.d.ts +90 -7
- package/dist/chunks/http.js +157 -64
- package/dist/chunks/transport.js +4 -2
- package/dist/chunks/websocket.d.ts +9 -1
- package/dist/chunks/websocket.js +16 -2
- package/dist/host-bridge.js +2 -1
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +182 -4
- package/dist/index.js +1559 -299
- package/dist/protocol/dist/board-assets.d.ts +1 -0
- package/dist/protocol/dist/board-constants.js +2 -2
- package/dist/protocol/dist/board-model.d.ts +236 -11
- package/dist/protocol/dist/board-model.js +46 -17
- package/dist/protocol/dist/board-patch.js +2 -1
- package/dist/protocol/dist/board-schema.d.ts +4 -2
- package/dist/protocol/dist/board-schema.js +18 -4
- package/dist/protocol/dist/board-script-modules.d.ts +25 -0
- package/dist/protocol/dist/board-script-modules.js +127 -0
- package/dist/protocol/dist/board-task.d.ts +22 -0
- package/dist/{board/model/task.js → protocol/dist/board-task.js} +34 -7
- package/dist/protocol/dist/display/index.d.ts +1 -0
- package/dist/protocol/dist/generation/blocks.d.ts +8 -0
- package/dist/{generation-blocks.js → protocol/dist/generation/blocks.js} +14 -15
- package/dist/protocol/dist/index.d.ts +7 -2
- package/dist/protocol/dist/realtime/types.d.ts +1 -0
- package/dist/protocol/dist/rtc/index.d.ts +1 -0
- package/dist/protocol/dist/task/index.d.ts +4 -0
- package/package.json +2 -1
- package/dist/board/export/node/sketch.d.ts +0 -19
- package/dist/board/export/node/sketch.js +0 -146
- package/dist/board/model/task.d.ts +0 -11
- package/dist/board/render/renderers/sketch-card-renderer.d.ts +0 -5
- package/dist/board/render/sketch-host.d.ts +0 -14
- package/dist/board/render/sketch-host.js +0 -216
- package/dist/types.d.ts +0 -36
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { layoutBoardText } from "../../protocol/dist/board-layout.js";
|
|
2
|
+
import { itemBounds, rectsIntersect } from "../model/geometry.js";
|
|
3
|
+
import { boardFontFamily } from "../model/text-metrics.js";
|
|
4
|
+
import { BOARD_FONT_STACKS, ensureBoardTextMeasurement } from "./text-measurement.js";
|
|
5
|
+
import { DOMAdapter } from "pixi.js";
|
|
6
|
+
//#region src/board/render/diagnostics.ts
|
|
7
|
+
const glyphCache = /* @__PURE__ */ new Map();
|
|
8
|
+
let glyphContext;
|
|
9
|
+
function missingGlyph(character, font) {
|
|
10
|
+
if (/\s/u.test(character)) return false;
|
|
11
|
+
const key = `${font}:${character}`;
|
|
12
|
+
const cached = glyphCache.get(key);
|
|
13
|
+
if (cached !== void 0) return cached;
|
|
14
|
+
try {
|
|
15
|
+
glyphContext ??= DOMAdapter.get().createCanvas(64, 64).getContext("2d");
|
|
16
|
+
const ctx = glyphContext;
|
|
17
|
+
ctx.font = `32px ${font}`;
|
|
18
|
+
const absent = "";
|
|
19
|
+
if (ctx.measureText(character).width !== ctx.measureText(absent).width) {
|
|
20
|
+
if (glyphCache.size >= 2048) glyphCache.clear();
|
|
21
|
+
glyphCache.set(key, false);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const pixels = (text) => {
|
|
25
|
+
ctx.clearRect(0, 0, 64, 64);
|
|
26
|
+
ctx.fillStyle = "#000000";
|
|
27
|
+
ctx.fillText(text, 0, 40);
|
|
28
|
+
return ctx.getImageData(0, 0, 64, 64).data;
|
|
29
|
+
};
|
|
30
|
+
const a = pixels(character);
|
|
31
|
+
const b = pixels(absent);
|
|
32
|
+
const missing = a.some((n) => n !== 0) && a.every((n, i) => n === b[i]);
|
|
33
|
+
if (glyphCache.size >= 2048) glyphCache.clear();
|
|
34
|
+
glyphCache.set(key, missing);
|
|
35
|
+
return missing;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function measureBoardText(props) {
|
|
41
|
+
ensureBoardTextMeasurement();
|
|
42
|
+
const font = boardFontFamily(props.font, BOARD_FONT_STACKS);
|
|
43
|
+
const characters = [...new Set(props.text)].slice(0, 512).filter((char) => missingGlyph(char, font)).join("");
|
|
44
|
+
return {
|
|
45
|
+
...layoutBoardText(props),
|
|
46
|
+
missingCharacters: characters
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function inspectBoardScene(scene, limit = 100) {
|
|
50
|
+
ensureBoardTextMeasurement();
|
|
51
|
+
const diagnostics = [];
|
|
52
|
+
const texts = scene.items.filter((item) => item.type === "text" && scene.opacity(item.id) > .01);
|
|
53
|
+
const push = (entry) => {
|
|
54
|
+
if (diagnostics.length < limit) diagnostics.push(entry);
|
|
55
|
+
};
|
|
56
|
+
for (const item of scene.items) {
|
|
57
|
+
if (diagnostics.length >= limit) break;
|
|
58
|
+
if (item.type === "effect" && item.props.follow && item.props.kind !== "trail") push({
|
|
59
|
+
code: "effect-follow-unused",
|
|
60
|
+
item: item.id
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
let glyphBudget = 256;
|
|
64
|
+
for (const item of texts) {
|
|
65
|
+
if (diagnostics.length >= limit || item.type !== "text") break;
|
|
66
|
+
if (glyphBudget-- > 0) {
|
|
67
|
+
const measured = measureBoardText(item.props);
|
|
68
|
+
if (measured.missingCharacters) push({
|
|
69
|
+
code: "glyph-unavailable",
|
|
70
|
+
item: item.id,
|
|
71
|
+
characters: measured.missingCharacters
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const bounds = itemBounds(item.frame);
|
|
75
|
+
let parentId = item.parent;
|
|
76
|
+
while (parentId) {
|
|
77
|
+
const parent = scene.get(parentId);
|
|
78
|
+
if (!parent) break;
|
|
79
|
+
if (parent.type === "frame" && parent.props.clip) {
|
|
80
|
+
const clip = itemBounds(parent.frame);
|
|
81
|
+
if (bounds.x < clip.x - 1 || bounds.y < clip.y - 1 || bounds.x + bounds.width > clip.x + clip.width + 1 || bounds.y + bounds.height > clip.y + clip.height + 1) {
|
|
82
|
+
push({
|
|
83
|
+
code: "text-clipped",
|
|
84
|
+
item: item.id,
|
|
85
|
+
related: parentId
|
|
86
|
+
});
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
parentId = parent.parent;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const sorted = texts.map((item) => ({
|
|
94
|
+
item,
|
|
95
|
+
rect: itemBounds(item.frame)
|
|
96
|
+
})).sort((a, b) => a.rect.x - b.rect.x);
|
|
97
|
+
let comparisons = 0;
|
|
98
|
+
for (let i = 0; i < sorted.length && diagnostics.length < limit; i++) {
|
|
99
|
+
const a = sorted[i];
|
|
100
|
+
if (!a) continue;
|
|
101
|
+
for (let j = i + 1; j < sorted.length; j++) {
|
|
102
|
+
const b = sorted[j];
|
|
103
|
+
if (!b) continue;
|
|
104
|
+
if (b.rect.x >= a.rect.x + a.rect.width) break;
|
|
105
|
+
if (++comparisons > 1e4) return diagnostics;
|
|
106
|
+
if (a.item.parent === b.item.parent && rectsIntersect(a.rect, b.rect)) push({
|
|
107
|
+
code: "text-overlap",
|
|
108
|
+
item: a.item.id,
|
|
109
|
+
related: b.item.id
|
|
110
|
+
});
|
|
111
|
+
if (diagnostics.length >= limit) break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return diagnostics;
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
export { inspectBoardScene, measureBoardText };
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { BoardCardRenderer, BoardCardRendererResolver, BoardRenderContext, BoardRenderPalette,
|
|
1
|
+
import { BoardCardRenderer, BoardCardRendererResolver, BoardRenderContext, BoardRenderLabels, BoardRenderPalette, BoardScriptHost, DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
2
|
+
import { createBoardRenderSampler } from "./sampling.js";
|
|
3
|
+
import { BoardRenderDiagnostic, inspectBoardScene, measureBoardText } from "./diagnostics.js";
|
|
2
4
|
import { BoardBackgroundContext, createBoardBackground, updateBoardBackground } from "./board-background.js";
|
|
3
5
|
import { ClipGroup, clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline } from "./clip.js";
|
|
4
|
-
import { parseBoardCssColor } from "./css-color.js";
|
|
6
|
+
import { BoardCssPaint, parseBoardCssColor, parseBoardCssPaint } from "./css-color.js";
|
|
5
7
|
import { BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible } from "./media-interaction.js";
|
|
6
|
-
import { defaultBoardPalette, itemColor } from "./palette.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
8
|
+
import { defaultBoardPalette, itemAlpha, itemColor } from "./palette.js";
|
|
9
|
+
import { BoardScriptHostOptions, BrowserBoardScriptHost, createBoardScriptHost } from "./script-host.js";
|
|
10
|
+
import { prepareBrowserBoardScripts } from "./script-export.js";
|
|
11
|
+
import { dashPattern, endAngle, roundRectPoints, traceArrowhead, tracePolyline, trimPolyline } from "./stroke.js";
|
|
9
12
|
import { BOARD_EFFECT_MAX_PARTICLES } from "./renderers/effect-card-renderer.js";
|
|
10
13
|
import { TASK_CARD_FULL_DETAIL_ZOOM } from "./renderers/task-card-renderer.js";
|
|
11
14
|
import { BOARD_FONT_STACKS, ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
12
15
|
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
13
16
|
import { VIDEO_THUMBNAIL_MAX_EDGE, VideoNaturalSize, loadVideoThumbnailTexture, videoTextureNaturalSize, videoThumbnailSize } from "./video-thumbnail.js";
|
|
14
|
-
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, BoardBackgroundContext, BoardCardRenderer, BoardCardRendererResolver, BoardMediaAction, BoardRenderContext, BoardRenderPalette,
|
|
17
|
+
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, BoardBackgroundContext, BoardCardRenderer, BoardCardRendererResolver, BoardCssPaint, BoardMediaAction, BoardRenderContext, BoardRenderDiagnostic, BoardRenderLabels, BoardRenderPalette, BoardScriptHost, BoardScriptHostOptions, BrowserBoardScriptHost, ClipGroup, DEFAULT_BOARD_RENDER_LABELS, TASK_CARD_FULL_DETAIL_ZOOM, VIDEO_THUMBNAIL_MAX_EDGE, VideoNaturalSize, boardMediaActionAt, clippingAncestor, createBoardBackground, createBoardCardRendererResolver, createBoardRenderSampler, createBoardScriptHost, dashPattern, defaultBoardPalette, endAngle, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, inspectBoardScene, installBoardTextMeasurement, isClippingFrame, itemAlpha, itemColor, loadVideoThumbnailTexture, measureBoardText, mediaPlayBadgeHit, mediaPlayBadgeVisible, parseBoardCssColor, parseBoardCssPaint, prepareBrowserBoardScripts, roundRectPoints, syncClipGroup, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, traceArrowhead, traceFrameOutline, tracePolyline, trimPolyline, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize };
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { parseBoardCssColor } from "./css-color.js";
|
|
1
|
+
import { parseBoardCssColor, parseBoardCssPaint } from "./css-color.js";
|
|
2
|
+
import { defaultBoardPalette, itemAlpha, itemColor } from "./palette.js";
|
|
3
|
+
import { createBoardRenderSampler } from "./sampling.js";
|
|
4
|
+
import { BOARD_FONT_STACKS, ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
5
|
+
import { inspectBoardScene, measureBoardText } from "./diagnostics.js";
|
|
2
6
|
import { createBoardBackground, updateBoardBackground } from "./board-background.js";
|
|
3
7
|
import { clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline } from "./clip.js";
|
|
4
8
|
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
5
9
|
import { TASK_CARD_FULL_DETAIL_ZOOM } from "./renderers/task-card-renderer.js";
|
|
6
10
|
import { boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible } from "./media-interaction.js";
|
|
7
|
-
import {
|
|
8
|
-
import { BOARD_FONT_STACKS, ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
9
|
-
import { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline } from "./stroke.js";
|
|
11
|
+
import { dashPattern, endAngle, roundRectPoints, traceArrowhead, tracePolyline, trimPolyline } from "./stroke.js";
|
|
10
12
|
import { BOARD_EFFECT_MAX_PARTICLES } from "./renderers/effect-card-renderer.js";
|
|
11
|
-
import { createBoardCardRendererResolver, getBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
12
|
-
import {
|
|
13
|
+
import { DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
14
|
+
import { createBoardScriptHost } from "./script-host.js";
|
|
15
|
+
import { prepareBrowserBoardScripts } from "./script-export.js";
|
|
13
16
|
import { VIDEO_THUMBNAIL_MAX_EDGE, loadVideoThumbnailTexture, videoTextureNaturalSize, videoThumbnailSize } from "./video-thumbnail.js";
|
|
14
|
-
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, TASK_CARD_FULL_DETAIL_ZOOM, VIDEO_THUMBNAIL_MAX_EDGE, boardMediaActionAt, clippingAncestor, createBoardBackground, createBoardCardRendererResolver,
|
|
17
|
+
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, DEFAULT_BOARD_RENDER_LABELS, TASK_CARD_FULL_DETAIL_ZOOM, VIDEO_THUMBNAIL_MAX_EDGE, boardMediaActionAt, clippingAncestor, createBoardBackground, createBoardCardRendererResolver, createBoardRenderSampler, createBoardScriptHost, dashPattern, defaultBoardPalette, endAngle, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, inspectBoardScene, installBoardTextMeasurement, isClippingFrame, itemAlpha, itemColor, loadVideoThumbnailTexture, measureBoardText, mediaPlayBadgeHit, mediaPlayBadgeVisible, parseBoardCssColor, parseBoardCssPaint, prepareBrowserBoardScripts, roundRectPoints, syncClipGroup, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, traceArrowhead, traceFrameOutline, tracePolyline, trimPolyline, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { featuredTaskArtifact } from "
|
|
1
|
+
import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
|
|
2
2
|
import "./renderers/task-card-renderer.js";
|
|
3
3
|
//#region src/board/render/media-interaction.ts
|
|
4
4
|
function mediaPlayBadgeVisible(item, zoom, options) {
|
|
@@ -4,6 +4,7 @@ import { BoardColorId } from "../model/palette.js";
|
|
|
4
4
|
import { BoardRenderContext, BoardRenderPalette } from "./renderers/board-renderer-registry.js";
|
|
5
5
|
//#region src/board/render/palette.d.ts
|
|
6
6
|
declare function defaultBoardPalette(mode: "dark" | "light"): BoardRenderPalette;
|
|
7
|
+
declare function itemAlpha(context: Pick<BoardRenderContext, "colorScheme">, color: BoardColor | undefined): number;
|
|
7
8
|
declare function itemColor(context: Pick<BoardRenderContext, "colors" | "colorScheme" | "palette">, color: BoardColor | undefined, fallback: BoardColorId, part?: "stroke" | "fill" | "label"): number;
|
|
8
9
|
//#endregion
|
|
9
|
-
export { defaultBoardPalette, itemColor };
|
|
10
|
+
export { defaultBoardPalette, itemAlpha, itemColor };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveItemColor } from "../model/palette.js";
|
|
2
|
-
import { parseBoardCssColor } from "./css-color.js";
|
|
2
|
+
import { parseBoardCssColor, parseBoardCssPaint } from "./css-color.js";
|
|
3
3
|
//#region src/board/render/palette.ts
|
|
4
4
|
const DARK = {
|
|
5
5
|
bg: 1315860,
|
|
@@ -28,9 +28,13 @@ const LIGHT = {
|
|
|
28
28
|
function defaultBoardPalette(mode) {
|
|
29
29
|
return { ...mode === "light" ? LIGHT : DARK };
|
|
30
30
|
}
|
|
31
|
+
function itemAlpha(context, color) {
|
|
32
|
+
const value = typeof color === "object" && color ? color[context.colorScheme] : color;
|
|
33
|
+
return value ? parseBoardCssPaint(value)?.alpha ?? 1 : 1;
|
|
34
|
+
}
|
|
31
35
|
function itemColor(context, color, fallback, part = "stroke") {
|
|
32
36
|
if (((typeof color === "object" && color ? color[context.colorScheme] : color) ?? fallback) === "neutral" && part !== "fill") return context.palette.text;
|
|
33
37
|
return resolveItemColor(color, fallback, context.colors, context.colorScheme, parseBoardCssColor, part);
|
|
34
38
|
}
|
|
35
39
|
//#endregion
|
|
36
|
-
export { defaultBoardPalette, itemColor };
|
|
40
|
+
export { defaultBoardPalette, itemAlpha, itemColor };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
2
|
import { pathPointAt, resolveSceneArrow } from "../../model/arrow-geometry.js";
|
|
3
|
+
import { itemAlpha, itemColor } from "../palette.js";
|
|
3
4
|
import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
4
5
|
import { drawFarStroke } from "./far-plate.js";
|
|
5
|
-
import { itemColor } from "../palette.js";
|
|
6
6
|
import { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline } from "../stroke.js";
|
|
7
7
|
import { Container, Graphics, Text } from "pixi.js";
|
|
8
8
|
//#region src/board/render/renderers/arrow-card-renderer.ts
|
|
@@ -16,6 +16,7 @@ function sync(container, item, context) {
|
|
|
16
16
|
const { props, style } = item;
|
|
17
17
|
const selected = context.selectedIds.has(item.id);
|
|
18
18
|
const hovered = context.hoveredId === item.id;
|
|
19
|
+
parts.line.alpha = itemAlpha(context, style.stroke);
|
|
19
20
|
const color = itemColor(context, style.stroke, "brand");
|
|
20
21
|
const size = style.strokeWidth ?? 2.5;
|
|
21
22
|
syncTextResolution(parts.label, parts, context.zoom);
|
|
@@ -130,7 +131,7 @@ const arrowCardRenderer = {
|
|
|
130
131
|
drawFarStroke(graphics, trimPolyline(resolved.path, arrow.style.trim), {
|
|
131
132
|
color: itemColor(context, arrow.style.stroke, "brand"),
|
|
132
133
|
width: arrow.style.strokeWidth ?? 2.5,
|
|
133
|
-
alpha: .85
|
|
134
|
+
alpha: .85 * itemAlpha(context, arrow.style.stroke)
|
|
134
135
|
});
|
|
135
136
|
},
|
|
136
137
|
destroy: (container) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
|
+
import { getMediaResourceTitle } from "../../model/media.js";
|
|
2
3
|
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
3
4
|
import { syncTextResolution, syncTextWrapWidth, textResolutionForZoom } from "../text-resolution.js";
|
|
4
5
|
import { positionShell } from "./base-card-renderer.js";
|
|
@@ -15,7 +16,7 @@ function sync(container, item, context) {
|
|
|
15
16
|
const { width, height } = item.frame;
|
|
16
17
|
const selected = context.selectedIds.has(item.id);
|
|
17
18
|
const hovered = context.hoveredId === item.id;
|
|
18
|
-
const title = item.props.snapshot?.title ?? item.props.src
|
|
19
|
+
const title = item.props.snapshot?.title ?? getMediaResourceTitle(item.props.src);
|
|
19
20
|
syncTextResolution(parts.label, parts, context.zoom);
|
|
20
21
|
if (parts.label.text !== title) parts.label.text = title;
|
|
21
22
|
syncTextWrapWidth(parts.label, parts, Math.max(1, width - 24), false);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { BoardSettings,
|
|
1
|
+
import { BoardCustomItem, BoardDocument, BoardSettings, BoardTaskItem } from "../../../protocol/dist/board-model.js";
|
|
2
|
+
import { BoardFrame } from "../../../protocol/dist/board-layout.js";
|
|
2
3
|
import "../../../protocol/dist/index.js";
|
|
3
4
|
import { BoardScene, BoardSceneItem, SceneItem } from "../../model/scene.js";
|
|
4
5
|
import { BoardShapeColors } from "../../model/palette.js";
|
|
@@ -16,11 +17,22 @@ type BoardRenderPalette = {
|
|
|
16
17
|
epic: number;
|
|
17
18
|
legendary: number;
|
|
18
19
|
};
|
|
19
|
-
type
|
|
20
|
-
|
|
20
|
+
type BoardScriptHost = {
|
|
21
|
+
document?: (document: BoardDocument, time: number) => BoardDocument;
|
|
22
|
+
ready?: (id: string) => boolean;
|
|
23
|
+
revision?: (id: string) => number;
|
|
24
|
+
frame: (item: SceneItem<BoardCustomItem>, time: number, resolution: number) => Texture | null;
|
|
21
25
|
error: (id: string) => string | null;
|
|
22
26
|
release: (id: string) => void;
|
|
23
27
|
};
|
|
28
|
+
type BoardRenderLabels = {
|
|
29
|
+
queued: string;
|
|
30
|
+
generating: string;
|
|
31
|
+
failed: string;
|
|
32
|
+
previewUnavailable: string;
|
|
33
|
+
noPreview: string;
|
|
34
|
+
};
|
|
35
|
+
declare const DEFAULT_BOARD_RENDER_LABELS: BoardRenderLabels;
|
|
24
36
|
type BoardRenderContext = {
|
|
25
37
|
settings: BoardSettings;
|
|
26
38
|
scene: BoardScene;
|
|
@@ -33,7 +45,14 @@ type BoardRenderContext = {
|
|
|
33
45
|
rendererType: "gpu" | "canvas";
|
|
34
46
|
zoom: number;
|
|
35
47
|
time: number;
|
|
36
|
-
|
|
48
|
+
reducedMotion: boolean;
|
|
49
|
+
labels: BoardRenderLabels;
|
|
50
|
+
taskRun: (taskRunId: string) => {
|
|
51
|
+
status: BoardTaskItem["props"]["snapshot"]["status"];
|
|
52
|
+
startedAt?: string;
|
|
53
|
+
} | null;
|
|
54
|
+
frameAt?: (id: string, time: number) => BoardFrame | undefined;
|
|
55
|
+
scripts?: BoardScriptHost;
|
|
37
56
|
assetKey: (item: BoardSceneItem) => string | null;
|
|
38
57
|
getTexture: (key: string) => Texture | null;
|
|
39
58
|
hasError: (key: string) => boolean;
|
|
@@ -45,6 +64,7 @@ type BoardCardRenderer = {
|
|
|
45
64
|
id: string;
|
|
46
65
|
canRender: (item: BoardSceneItem, context: BoardRenderContext) => boolean;
|
|
47
66
|
animated?: boolean;
|
|
67
|
+
tick?: (container: Container, clock: number) => number | null;
|
|
48
68
|
create: (item: BoardSceneItem, context: BoardRenderContext) => Container;
|
|
49
69
|
update: (container: Container, item: BoardSceneItem, context: BoardRenderContext) => void;
|
|
50
70
|
renderFar?: (graphics: Graphics, item: BoardSceneItem, context: BoardRenderContext) => void;
|
|
@@ -59,4 +79,4 @@ declare function createBoardCardRendererResolver(renderers?: Iterable<BoardCardR
|
|
|
59
79
|
/** The built-in renderers alone. */
|
|
60
80
|
declare const getBoardCardRenderer: BoardCardRendererResolver;
|
|
61
81
|
//#endregion
|
|
62
|
-
export { BoardCardRenderer, BoardCardRendererResolver, BoardRenderContext, BoardRenderPalette,
|
|
82
|
+
export { BoardCardRenderer, BoardCardRendererResolver, BoardRenderContext, BoardRenderLabels, BoardRenderPalette, BoardScriptHost, DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer };
|
|
@@ -1,18 +1,25 @@
|
|
|
1
|
+
import { ensureBoardTextMeasurement } from "../text-measurement.js";
|
|
1
2
|
import { fileCardRenderer } from "./file-card-renderer.js";
|
|
2
3
|
import { taskCardRenderer } from "./task-card-renderer.js";
|
|
3
|
-
import { ensureBoardTextMeasurement } from "../text-measurement.js";
|
|
4
4
|
import { arrowCardRenderer } from "./arrow-card-renderer.js";
|
|
5
5
|
import { audioCardRenderer } from "./audio-card-renderer.js";
|
|
6
6
|
import { drawCardRenderer } from "./draw-card-renderer.js";
|
|
7
7
|
import { effectCardRenderer } from "./effect-card-renderer.js";
|
|
8
8
|
import { frameCardRenderer } from "./frame-card-renderer.js";
|
|
9
9
|
import { shapeCardRenderer } from "./shape-card-renderer.js";
|
|
10
|
-
import {
|
|
10
|
+
import { customCardRenderer } from "./custom-card-renderer.js";
|
|
11
11
|
import { imageCardRenderer } from "./image-card-renderer.js";
|
|
12
12
|
import { textCardRenderer } from "./text-card-renderer.js";
|
|
13
13
|
import { unknownCardRenderer } from "./unknown-card-renderer.js";
|
|
14
14
|
import { videoCardRenderer } from "./video-card-renderer.js";
|
|
15
15
|
//#region src/board/render/renderers/board-renderer-registry.ts
|
|
16
|
+
const DEFAULT_BOARD_RENDER_LABELS = {
|
|
17
|
+
queued: "Queued",
|
|
18
|
+
generating: "Generating",
|
|
19
|
+
failed: "Failed",
|
|
20
|
+
previewUnavailable: "Preview unavailable",
|
|
21
|
+
noPreview: "No preview"
|
|
22
|
+
};
|
|
16
23
|
const builtinCardRenderers = [
|
|
17
24
|
textCardRenderer,
|
|
18
25
|
imageCardRenderer,
|
|
@@ -25,7 +32,7 @@ const builtinCardRenderers = [
|
|
|
25
32
|
arrowCardRenderer,
|
|
26
33
|
frameCardRenderer,
|
|
27
34
|
effectCardRenderer,
|
|
28
|
-
|
|
35
|
+
customCardRenderer
|
|
29
36
|
];
|
|
30
37
|
/**
|
|
31
38
|
* Pick a renderer per item: `renderers` first, then the built-ins. Items no
|
|
@@ -41,4 +48,4 @@ function createBoardCardRendererResolver(renderers = []) {
|
|
|
41
48
|
/** The built-in renderers alone. */
|
|
42
49
|
const getBoardCardRenderer = createBoardCardRendererResolver();
|
|
43
50
|
//#endregion
|
|
44
|
-
export { createBoardCardRendererResolver, getBoardCardRenderer };
|
|
51
|
+
export { DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer };
|
|
@@ -3,26 +3,28 @@ import { getBoardResolution } from "../text-resolution.js";
|
|
|
3
3
|
import { positionShell } from "./base-card-renderer.js";
|
|
4
4
|
import { drawFarPlate } from "./far-plate.js";
|
|
5
5
|
import { Container, Graphics, Sprite, Text, Texture } from "pixi.js";
|
|
6
|
-
//#region src/board/render/renderers/
|
|
6
|
+
//#region src/board/render/renderers/custom-card-renderer.ts
|
|
7
7
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
8
8
|
function sync(container, item, context) {
|
|
9
9
|
const parts = partsByContainer.get(container);
|
|
10
10
|
if (!parts) return;
|
|
11
11
|
if (parts.id !== item.id) {
|
|
12
|
-
context.
|
|
12
|
+
context.scripts?.release(parts.id);
|
|
13
13
|
parts.id = item.id;
|
|
14
14
|
}
|
|
15
15
|
positionShell(parts.root, item);
|
|
16
16
|
const { width, height } = item.frame;
|
|
17
17
|
const resolution = Math.min(4, Math.max(.25, context.zoom * getBoardResolution()));
|
|
18
|
-
const texture = context.
|
|
19
|
-
const error = context.
|
|
18
|
+
const texture = context.scripts?.frame(item, context.time, resolution) ?? null;
|
|
19
|
+
const error = context.scripts?.error(item.id) ?? null;
|
|
20
20
|
parts.sprite.visible = Boolean(texture);
|
|
21
|
-
|
|
21
|
+
const display = texture ?? Texture.EMPTY;
|
|
22
|
+
if (parts.sprite.texture !== display) parts.sprite.texture = display;
|
|
22
23
|
parts.sprite.width = width;
|
|
23
24
|
parts.sprite.height = height;
|
|
24
25
|
const selected = context.selectedIds.has(item.id);
|
|
25
|
-
const
|
|
26
|
+
const ready = Boolean(texture) || context.scripts?.ready?.(item.id) === true;
|
|
27
|
+
const message = error ? `${item.script.src}\n${error}` : ready ? "" : item.script.src;
|
|
26
28
|
const sig = [
|
|
27
29
|
width,
|
|
28
30
|
height,
|
|
@@ -35,21 +37,21 @@ function sync(container, item, context) {
|
|
|
35
37
|
if (sig === parts.sig) return;
|
|
36
38
|
parts.sig = sig;
|
|
37
39
|
parts.placeholder.clear();
|
|
38
|
-
if (!
|
|
40
|
+
if (!ready || selected || error) parts.placeholder.rect(0, 0, width, height).stroke({
|
|
39
41
|
color: selected ? context.palette.brand : context.palette.border,
|
|
40
42
|
width: selected ? 2 : 1,
|
|
41
43
|
alpha: .8
|
|
42
44
|
});
|
|
43
|
-
parts.label.visible = !
|
|
45
|
+
parts.label.visible = !ready || Boolean(error);
|
|
44
46
|
parts.label.text = message;
|
|
45
47
|
parts.label.style.fill = error ? context.colors.rose.stroke : context.palette.muted;
|
|
46
48
|
parts.label.style.wordWrapWidth = Math.max(40, width - 16);
|
|
47
49
|
parts.label.position.set(width / 2, height / 2);
|
|
48
50
|
}
|
|
49
|
-
const
|
|
50
|
-
id: "
|
|
51
|
-
canRender: (item) => item.type === "
|
|
52
|
-
animated:
|
|
51
|
+
const customCardRenderer = {
|
|
52
|
+
id: "custom-card",
|
|
53
|
+
canRender: (item) => item.type === "custom",
|
|
54
|
+
animated: false,
|
|
53
55
|
create: (item, context) => {
|
|
54
56
|
const root = new Container();
|
|
55
57
|
const sprite = new Sprite(Texture.EMPTY);
|
|
@@ -75,11 +77,11 @@ const sketchCardRenderer = {
|
|
|
75
77
|
label,
|
|
76
78
|
sig: ""
|
|
77
79
|
});
|
|
78
|
-
if (item.type === "
|
|
80
|
+
if (item.type === "custom") sync(root, item, context);
|
|
79
81
|
return root;
|
|
80
82
|
},
|
|
81
83
|
update: (container, item, context) => {
|
|
82
|
-
if (item.type === "
|
|
84
|
+
if (item.type === "custom") sync(container, item, context);
|
|
83
85
|
},
|
|
84
86
|
renderFar: (graphics, item, context) => {
|
|
85
87
|
drawFarPlate(graphics, item.frame, {
|
|
@@ -89,10 +91,10 @@ const sketchCardRenderer = {
|
|
|
89
91
|
},
|
|
90
92
|
destroy: (container, context) => {
|
|
91
93
|
const parts = partsByContainer.get(container);
|
|
92
|
-
if (parts) context.
|
|
94
|
+
if (parts) context.scripts?.release(parts.id);
|
|
93
95
|
parts?.root.destroy({ children: true });
|
|
94
96
|
partsByContainer.delete(container);
|
|
95
97
|
}
|
|
96
98
|
};
|
|
97
99
|
//#endregion
|
|
98
|
-
export {
|
|
100
|
+
export { customCardRenderer };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { applyMatrix } from "../../../protocol/dist/board-layout.js";
|
|
2
2
|
import { computeDrawBounds, createStrokeRibbonBuilder, trimDrawPoints } from "../../model/draw-geometry.js";
|
|
3
|
+
import { itemAlpha, itemColor } from "../palette.js";
|
|
3
4
|
import { positionShell } from "./base-card-renderer.js";
|
|
4
5
|
import { drawFarStroke, farStrokeSamples } from "./far-plate.js";
|
|
5
|
-
import { itemColor } from "../palette.js";
|
|
6
6
|
import { Container, Graphics, Mesh, MeshGeometry, Texture } from "pixi.js";
|
|
7
7
|
//#region src/board/render/renderers/draw-card-renderer.ts
|
|
8
8
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
@@ -77,6 +77,7 @@ function sync(container, item, context) {
|
|
|
77
77
|
}
|
|
78
78
|
const stroke = parts.stroke;
|
|
79
79
|
if (!stroke) return;
|
|
80
|
+
stroke.alpha = itemAlpha(context, item.style.stroke);
|
|
80
81
|
if (stroke instanceof Mesh) stroke.tint = color;
|
|
81
82
|
const { box } = parts;
|
|
82
83
|
const sx = item.frame.width / box.width;
|
|
@@ -120,7 +121,7 @@ const drawCardRenderer = {
|
|
|
120
121
|
drawFarStroke(graphics, samples.map((point) => applyMatrix(matrix, point)), {
|
|
121
122
|
color: itemColor(context, draw.style.stroke, "brand"),
|
|
122
123
|
width: draw.style.strokeWidth ?? 4,
|
|
123
|
-
alpha:
|
|
124
|
+
alpha: itemAlpha(context, draw.style.stroke)
|
|
124
125
|
});
|
|
125
126
|
},
|
|
126
127
|
destroy: (container) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { itemAlpha, itemColor } from "../palette.js";
|
|
1
2
|
import { positionShell } from "./base-card-renderer.js";
|
|
2
3
|
import { drawFarPlate } from "./far-plate.js";
|
|
3
|
-
import { itemColor } from "../palette.js";
|
|
4
4
|
import { Container, Graphics } from "pixi.js";
|
|
5
5
|
//#region src/board/render/renderers/effect-card-renderer.ts
|
|
6
6
|
const BOARD_EFFECT_MAX_PARTICLES = 4e3;
|
|
@@ -109,11 +109,27 @@ function drawTrail(graphics, parts, item, context, color) {
|
|
|
109
109
|
parts.trail.length = 0;
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
const angle = item.frame.rotation * Math.PI / 180;
|
|
113
|
+
const localPoint = (frame, t) => {
|
|
114
|
+
const dx = frame.x + frame.width / 2 - item.frame.x - item.frame.width / 2;
|
|
115
|
+
const dy = frame.y + frame.height / 2 - item.frame.y - item.frame.height / 2;
|
|
116
|
+
return {
|
|
117
|
+
x: dx * Math.cos(angle) + dy * Math.sin(angle) + item.frame.width / 2,
|
|
118
|
+
y: -dx * Math.sin(angle) + dy * Math.cos(angle) + item.frame.height / 2,
|
|
119
|
+
t
|
|
120
|
+
};
|
|
116
121
|
};
|
|
122
|
+
const head = localPoint(target.frame, time);
|
|
123
|
+
if (context.frameAt) {
|
|
124
|
+
parts.trail.length = 0;
|
|
125
|
+
const start = Math.max(0, time - item.props.life);
|
|
126
|
+
const step = Math.max(1e3 / 30, item.props.life / 63);
|
|
127
|
+
for (let t = Math.ceil(start / step) * step; t < time; t += step) {
|
|
128
|
+
const past = context.frameAt(target.id, t);
|
|
129
|
+
if (past) parts.trail.push(localPoint(past, t));
|
|
130
|
+
}
|
|
131
|
+
parts.trail.push(head);
|
|
132
|
+
}
|
|
117
133
|
const last = parts.trail.at(-1);
|
|
118
134
|
if (last && (time < last.t || time - last.t > item.props.life)) parts.trail.length = 0;
|
|
119
135
|
if (!last || Math.hypot(head.x - last.x, head.y - last.y) > .5) parts.trail.push(head);
|
|
@@ -140,6 +156,7 @@ function sync(container, item, context) {
|
|
|
140
156
|
const seed = hashString(props.seed ?? item.id);
|
|
141
157
|
const time = Math.max(0, context.time);
|
|
142
158
|
const graphics = parts.graphics;
|
|
159
|
+
graphics.alpha = itemAlpha(context, item.style.fill ?? item.style.stroke);
|
|
143
160
|
graphics.clear();
|
|
144
161
|
switch (props.kind) {
|
|
145
162
|
case "particles":
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
|
+
import { itemAlpha, itemColor } from "../palette.js";
|
|
2
3
|
import { syncTextResolution } from "../text-resolution.js";
|
|
3
4
|
import { createLabel, positionShell } from "./base-card-renderer.js";
|
|
4
5
|
import { drawFarPlate } from "./far-plate.js";
|
|
5
|
-
import {
|
|
6
|
+
import { dashPattern, roundRectPoints, tracePolyline, trimPolyline } from "../stroke.js";
|
|
6
7
|
import { Container, Graphics } from "pixi.js";
|
|
7
8
|
//#region src/board/render/renderers/frame-card-renderer.ts
|
|
8
9
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
@@ -16,13 +17,15 @@ function sync(container, item, context) {
|
|
|
16
17
|
const selected = context.selectedIds.has(item.id);
|
|
17
18
|
const hovered = context.hoveredId === item.id;
|
|
18
19
|
const fill = itemColor(context, style.fill ?? style.stroke, "neutral", "fill");
|
|
19
|
-
const fillAlpha = style.fillOpacity ?? (style.fill ? 1 : DEFAULT_WASH);
|
|
20
|
+
const fillAlpha = (style.fillOpacity ?? (style.fill ? 1 : DEFAULT_WASH)) * itemAlpha(context, style.fill ?? style.stroke);
|
|
20
21
|
const baseStroke = itemColor(context, style.stroke, "neutral");
|
|
21
|
-
const stroke = selected ? context.palette.brand : baseStroke;
|
|
22
|
-
const alpha = selected ? 1 : hovered ? .85 : .55;
|
|
22
|
+
const stroke = selected ? context.palette.brand : hovered && style.stroke ? context.palette.muted : baseStroke;
|
|
23
|
+
const alpha = (selected || style.stroke ? 1 : hovered ? .85 : .55) * itemAlpha(context, style.stroke);
|
|
23
24
|
const radius = style.radius ?? 4;
|
|
24
25
|
const strokeWidth = style.strokeWidth ?? 1.5;
|
|
26
|
+
const decorated = props.decoration !== "none";
|
|
25
27
|
const visualSig = [
|
|
28
|
+
props.decoration,
|
|
26
29
|
frame.width,
|
|
27
30
|
frame.height,
|
|
28
31
|
selected,
|
|
@@ -30,23 +33,36 @@ function sync(container, item, context) {
|
|
|
30
33
|
fill,
|
|
31
34
|
fillAlpha,
|
|
32
35
|
stroke,
|
|
36
|
+
alpha,
|
|
33
37
|
radius,
|
|
34
|
-
strokeWidth
|
|
38
|
+
strokeWidth,
|
|
39
|
+
style.dash,
|
|
40
|
+
style.trim
|
|
35
41
|
].join("|");
|
|
36
42
|
if (visualSig !== parts.visualSig) {
|
|
37
43
|
parts.visualSig = visualSig;
|
|
38
44
|
parts.box.clear();
|
|
39
|
-
parts.box.roundRect(0, 0, frame.width, frame.height, radius).fill({
|
|
45
|
+
if (decorated) parts.box.roundRect(0, 0, frame.width, frame.height, radius).fill({
|
|
40
46
|
color: fill,
|
|
41
47
|
alpha: fillAlpha
|
|
42
48
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
const width = selected ? Math.max(2, strokeWidth) : strokeWidth;
|
|
50
|
+
const pattern = decorated ? dashPattern(style.dash, width) : null;
|
|
51
|
+
const trim = decorated ? style.trim ?? 1 : 1;
|
|
52
|
+
if ((decorated && strokeWidth > 0 || selected || hovered) && trim > 0) {
|
|
53
|
+
if (pattern || trim < 1) tracePolyline(parts.box, trimPolyline(roundRectPoints(frame.width, frame.height, radius), trim), pattern);
|
|
54
|
+
else parts.box.roundRect(0, 0, frame.width, frame.height, radius);
|
|
55
|
+
parts.box.stroke({
|
|
56
|
+
color: stroke,
|
|
57
|
+
width,
|
|
58
|
+
alpha,
|
|
59
|
+
cap: pattern || trim < 1 ? "round" : "butt",
|
|
60
|
+
join: "round"
|
|
61
|
+
});
|
|
62
|
+
}
|
|
48
63
|
}
|
|
49
|
-
|
|
64
|
+
parts.label.visible = decorated;
|
|
65
|
+
const title = locked ? `🔒 ${props.label}`.trim() : props.label;
|
|
50
66
|
const labelColor = style.stroke ? baseStroke : context.palette.muted;
|
|
51
67
|
const textSig = [title, labelColor].join("|");
|
|
52
68
|
if (textSig !== parts.textSig) {
|
|
@@ -84,10 +100,10 @@ const frameCardRenderer = {
|
|
|
84
100
|
if (item.type === "frame") sync(container, item, context);
|
|
85
101
|
},
|
|
86
102
|
renderFar: (graphics, item, context) => {
|
|
87
|
-
if (item.type !== "frame") return;
|
|
103
|
+
if (item.type !== "frame" || item.props.decoration === "none") return;
|
|
88
104
|
drawFarPlate(graphics, item.frame, {
|
|
89
105
|
fill: itemColor(context, item.style.fill ?? item.style.stroke, "neutral", "fill"),
|
|
90
|
-
fillAlpha: Math.max(.07, item.style.fillOpacity ?? (item.style.fill ? 1 : 0))
|
|
106
|
+
fillAlpha: Math.max(.07, item.style.fillOpacity ?? (item.style.fill ? 1 : 0)) * itemAlpha(context, item.style.fill ?? item.style.stroke)
|
|
91
107
|
});
|
|
92
108
|
},
|
|
93
109
|
destroy: (container) => {
|