@neta-art/cohub 11.0.0 → 11.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -5
- package/dist/board/editor/context.d.ts +1 -0
- package/dist/board/editor/context.js +1 -0
- package/dist/board/editor/creation.d.ts +2 -2
- package/dist/board/editor/creation.js +3 -3
- package/dist/board/editor/editor.d.ts +5 -4
- package/dist/board/editor/editor.js +8 -1
- package/dist/board/editor/index.d.ts +2 -2
- package/dist/board/editor/interaction.d.ts +12 -2
- package/dist/board/editor/interaction.js +50 -8
- package/dist/board/editor/selection-transform.d.ts +1 -1
- package/dist/board/editor/selection-transform.js +13 -2
- package/dist/board/editor/snapshots.d.ts +0 -2
- package/dist/board/editor/snapshots.js +4 -20
- package/dist/board/export/index.d.ts +2 -0
- package/dist/board/export/index.js +1 -0
- package/dist/board/export/scene.d.ts +2 -0
- package/dist/board/export/scene.js +8 -1
- package/dist/board/model/file-preview.d.ts +0 -1
- package/dist/board/model/file-preview.js +10 -1
- package/dist/board/model/image-key.js +1 -1
- package/dist/board/model/index.d.ts +8 -7
- package/dist/board/model/index.js +6 -5
- package/dist/board/model/items/create.d.ts +16 -3
- package/dist/board/model/items/create.js +125 -5
- package/dist/board/model/items/index.d.ts +2 -2
- package/dist/board/model/items/index.js +2 -2
- package/dist/board/model/media-playback.js +1 -1
- package/dist/board/model/overlay-placement.d.ts +25 -0
- package/dist/board/model/overlay-placement.js +35 -0
- package/dist/board/model/replay.d.ts +1 -1
- package/dist/board/model/replay.js +1 -0
- package/dist/board/model/script-hit.d.ts +20 -3
- package/dist/board/model/script-hit.js +81 -24
- package/dist/board/model/script-observers.d.ts +18 -0
- package/dist/board/model/script-observers.js +92 -0
- package/dist/board/model/script-scene.d.ts +1 -1
- package/dist/board/model/script-scene.js +35 -8
- package/dist/board/model/script.d.ts +51 -7
- package/dist/board/render/audio-waveform.d.ts +1 -1
- package/dist/board/render/audio-waveform.js +8 -5
- package/dist/board/render/board-background.js +5 -4
- package/dist/board/render/card-tag.d.ts +24 -0
- package/dist/board/render/card-tag.js +205 -0
- package/dist/board/render/index.d.ts +8 -5
- package/dist/board/render/index.js +8 -5
- package/dist/board/render/media-interaction.d.ts +2 -1
- package/dist/board/render/media-interaction.js +15 -7
- package/dist/board/render/palette.js +2 -2
- package/dist/board/render/renderers/arrow-card-renderer.js +20 -16
- package/dist/board/render/renderers/audio-card-renderer.d.ts +8 -1
- package/dist/board/render/renderers/audio-card-renderer.js +64 -60
- package/dist/board/render/renderers/base-card-renderer.d.ts +1 -26
- package/dist/board/render/renderers/base-card-renderer.js +6 -92
- package/dist/board/render/renderers/board-renderer-registry.d.ts +25 -2
- package/dist/board/render/renderers/board-renderer-registry.js +11 -4
- package/dist/board/render/renderers/custom-card-renderer.js +6 -8
- package/dist/board/render/renderers/effect-card-renderer.js +0 -5
- package/dist/board/render/renderers/file-card-renderer.d.ts +1 -11
- package/dist/board/render/renderers/file-card-renderer.js +43 -105
- package/dist/board/render/renderers/frame-card-renderer.js +14 -15
- package/dist/board/render/renderers/image-card-renderer.js +62 -67
- package/dist/board/render/renderers/media-key.d.ts +6 -0
- package/dist/board/render/renderers/media-key.js +39 -0
- package/dist/board/render/renderers/shape-card-renderer.js +6 -12
- package/dist/board/render/renderers/task-card-renderer.d.ts +1 -8
- package/dist/board/render/renderers/task-card-renderer.js +286 -111
- package/dist/board/render/renderers/unknown-card-renderer.js +17 -16
- package/dist/board/render/renderers/video-card-renderer.js +73 -80
- package/dist/board/render/script-host.d.ts +1 -1
- package/dist/board/render/script-host.js +53 -28
- package/dist/board/render/script-runtime.js +13 -3
- package/dist/board/render/script-texture.d.ts +11 -0
- package/dist/board/render/script-texture.js +33 -0
- package/dist/board/render/stroke.d.ts +1 -1
- package/dist/board/render/stroke.js +5 -4
- package/dist/board/render/style.d.ts +29 -0
- package/dist/board/render/style.js +54 -0
- package/dist/board/render/surface.d.ts +34 -0
- package/dist/board/render/surface.js +132 -0
- package/dist/board/render/text-fit.d.ts +8 -0
- package/dist/board/render/text-fit.js +60 -0
- package/dist/board/render/text-resolution.d.ts +2 -1
- package/dist/board/render/text-resolution.js +4 -1
- package/dist/board/stage/assets.js +1 -1
- package/dist/board/stage/index.d.ts +3 -2
- package/dist/board/stage/index.js +2 -1
- package/dist/board/stage/overlay.d.ts +41 -0
- package/dist/board/stage/overlay.js +182 -0
- package/dist/board/stage/scene.d.ts +4 -43
- package/dist/board/stage/scene.js +38 -130
- package/dist/board/stage/script-pointer.d.ts +1 -0
- package/dist/board/stage/script-pointer.js +8 -2
- package/dist/board/stage/stage.d.ts +13 -3
- package/dist/board/stage/stage.js +217 -53
- package/dist/chunks/environment.d.ts +1037 -8
- package/dist/chunks/environment.js +12 -4
- package/dist/chunks/http.d.ts +51 -2
- package/dist/chunks/http.js +10 -1
- package/dist/chunks/transport.js +1 -1
- package/dist/chunks/websocket.d.ts +1 -1
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +151 -139
- package/dist/protocol/dist/board-model.d.ts +36 -1
- package/dist/protocol/dist/board-model.js +14 -4
- package/dist/protocol/dist/board-task.d.ts +22 -0
- package/dist/{board/model/task.js → protocol/dist/board-task.js} +34 -7
- package/dist/protocol/dist/generation/blocks.d.ts +8 -0
- package/dist/{generation-blocks.js → protocol/dist/generation/blocks.js} +14 -15
- package/dist/protocol/dist/index.d.ts +5 -2
- package/dist/protocol/dist/task/index.d.ts +4 -0
- package/package.json +2 -1
- package/dist/board/model/task.d.ts +0 -11
- package/dist/types.d.ts +0 -36
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { fitTextToWidth } from "./text-fit.js";
|
|
2
|
+
import { syncTextResolution, textResolutionForZoom } from "./text-resolution.js";
|
|
3
|
+
import { Container, Graphics, Text } from "pixi.js";
|
|
4
|
+
//#region src/board/render/card-tag.ts
|
|
5
|
+
const CARD_TAG_SIZE = 11;
|
|
6
|
+
const ICON = 12;
|
|
7
|
+
const GAP = 5;
|
|
8
|
+
const MAX_GROWTH = 1.25;
|
|
9
|
+
const MIN_READABLE = 7;
|
|
10
|
+
const SECOND = 1e3;
|
|
11
|
+
function formatBoardDuration(ms) {
|
|
12
|
+
const total = Math.max(0, Math.floor(ms / SECOND));
|
|
13
|
+
const hours = Math.floor(total / 3600);
|
|
14
|
+
const minutes = Math.floor(total % 3600 / 60);
|
|
15
|
+
const seconds = String(total % 60).padStart(2, "0");
|
|
16
|
+
return hours > 0 ? `${hours}:${String(minutes).padStart(2, "0")}:${seconds}` : `${minutes}:${seconds}`;
|
|
17
|
+
}
|
|
18
|
+
const PIXEL_GLYPHS = {
|
|
19
|
+
image: [
|
|
20
|
+
"######",
|
|
21
|
+
"#....#",
|
|
22
|
+
"#.#..#",
|
|
23
|
+
"#.##.#",
|
|
24
|
+
"######",
|
|
25
|
+
"......"
|
|
26
|
+
],
|
|
27
|
+
video: [
|
|
28
|
+
"######",
|
|
29
|
+
"#.#..#",
|
|
30
|
+
"#.##.#",
|
|
31
|
+
"#.#..#",
|
|
32
|
+
"######",
|
|
33
|
+
"......"
|
|
34
|
+
],
|
|
35
|
+
audio: [
|
|
36
|
+
"...#..",
|
|
37
|
+
"...##.",
|
|
38
|
+
"...#.#",
|
|
39
|
+
"...#..",
|
|
40
|
+
".###..",
|
|
41
|
+
".###.."
|
|
42
|
+
],
|
|
43
|
+
file: [
|
|
44
|
+
"####..",
|
|
45
|
+
"#..##.",
|
|
46
|
+
"#...##",
|
|
47
|
+
"#....#",
|
|
48
|
+
"#....#",
|
|
49
|
+
"######"
|
|
50
|
+
],
|
|
51
|
+
task: [
|
|
52
|
+
"..#...",
|
|
53
|
+
".###..",
|
|
54
|
+
"#####.",
|
|
55
|
+
".###..",
|
|
56
|
+
"..#...",
|
|
57
|
+
"......"
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
function drawLineGlyph(graphics, glyph, color) {
|
|
61
|
+
const line = {
|
|
62
|
+
color,
|
|
63
|
+
width: 1.25,
|
|
64
|
+
alpha: 1,
|
|
65
|
+
cap: "round",
|
|
66
|
+
join: "round"
|
|
67
|
+
};
|
|
68
|
+
switch (glyph) {
|
|
69
|
+
case "image":
|
|
70
|
+
graphics.roundRect(1, 2, 10, 8, 1.5).stroke(line);
|
|
71
|
+
graphics.moveTo(2.5, 9).lineTo(5, 6).lineTo(7, 8).lineTo(8.5, 6.5).lineTo(10, 8).stroke(line);
|
|
72
|
+
return;
|
|
73
|
+
case "video":
|
|
74
|
+
graphics.roundRect(1, 2.5, 10, 7, 1.5).stroke(line);
|
|
75
|
+
graphics.poly([
|
|
76
|
+
5,
|
|
77
|
+
4.5,
|
|
78
|
+
5,
|
|
79
|
+
7.5,
|
|
80
|
+
7.5,
|
|
81
|
+
6
|
|
82
|
+
]).fill({ color });
|
|
83
|
+
return;
|
|
84
|
+
case "audio":
|
|
85
|
+
for (const [x, height] of [
|
|
86
|
+
[2.5, 3],
|
|
87
|
+
[5, 7],
|
|
88
|
+
[7.5, 9],
|
|
89
|
+
[10, 5]
|
|
90
|
+
]) graphics.moveTo(x, 6 - height / 2).lineTo(x, 6 + height / 2);
|
|
91
|
+
graphics.stroke(line);
|
|
92
|
+
return;
|
|
93
|
+
case "file":
|
|
94
|
+
graphics.poly([
|
|
95
|
+
2.5,
|
|
96
|
+
1,
|
|
97
|
+
7.5,
|
|
98
|
+
1,
|
|
99
|
+
9.5,
|
|
100
|
+
3,
|
|
101
|
+
9.5,
|
|
102
|
+
11,
|
|
103
|
+
2.5,
|
|
104
|
+
11
|
|
105
|
+
]).stroke(line);
|
|
106
|
+
graphics.moveTo(7.5, 1).lineTo(7.5, 3).lineTo(9.5, 3).stroke(line);
|
|
107
|
+
return;
|
|
108
|
+
case "task":
|
|
109
|
+
graphics.poly([
|
|
110
|
+
6,
|
|
111
|
+
1,
|
|
112
|
+
7.3,
|
|
113
|
+
4.7,
|
|
114
|
+
11,
|
|
115
|
+
6,
|
|
116
|
+
7.3,
|
|
117
|
+
7.3,
|
|
118
|
+
6,
|
|
119
|
+
11,
|
|
120
|
+
4.7,
|
|
121
|
+
7.3,
|
|
122
|
+
1,
|
|
123
|
+
6,
|
|
124
|
+
4.7,
|
|
125
|
+
4.7
|
|
126
|
+
]).fill({ color });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function drawCardGlyph(graphics, glyph, color, pixel) {
|
|
131
|
+
if (!pixel) {
|
|
132
|
+
drawLineGlyph(graphics, glyph, color);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
PIXEL_GLYPHS[glyph].forEach((row, y) => {
|
|
136
|
+
for (let x = 0; x < row.length; x += 1) if (row[x] === "#") graphics.rect(x * 2, y * 2, 2, 2);
|
|
137
|
+
});
|
|
138
|
+
graphics.fill({ color });
|
|
139
|
+
}
|
|
140
|
+
function createCardTag() {
|
|
141
|
+
const root = new Container({ label: "card-tag" });
|
|
142
|
+
const icon = new Graphics();
|
|
143
|
+
root.addChild(icon);
|
|
144
|
+
root.visible = false;
|
|
145
|
+
return {
|
|
146
|
+
root,
|
|
147
|
+
icon,
|
|
148
|
+
text: null,
|
|
149
|
+
sig: "",
|
|
150
|
+
resolution: 0,
|
|
151
|
+
width: 0
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function zoomCardTag(tag, zoom) {
|
|
155
|
+
if (!tag.text || !tag.sig) return;
|
|
156
|
+
const scale = Math.min(MAX_GROWTH, Math.max(1, 1 / Math.max(zoom, .01)));
|
|
157
|
+
const span = 17 + tag.text.width;
|
|
158
|
+
tag.root.scale.set(scale);
|
|
159
|
+
tag.root.position.set(0, -18 * scale);
|
|
160
|
+
tag.root.visible = 11 * scale * zoom >= MIN_READABLE && span * scale <= tag.width + .5;
|
|
161
|
+
}
|
|
162
|
+
function syncCardTag(tag, input, context) {
|
|
163
|
+
tag.width = input.width;
|
|
164
|
+
if (!input.text || input.width <= 24) {
|
|
165
|
+
tag.sig = "";
|
|
166
|
+
tag.root.visible = false;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (!tag.text) {
|
|
170
|
+
tag.resolution = textResolutionForZoom(context.zoom);
|
|
171
|
+
tag.text = new Text({
|
|
172
|
+
text: "",
|
|
173
|
+
style: {
|
|
174
|
+
fontFamily: context.style.font,
|
|
175
|
+
fontSize: 11,
|
|
176
|
+
fontWeight: "500"
|
|
177
|
+
},
|
|
178
|
+
resolution: tag.resolution,
|
|
179
|
+
roundPixels: true
|
|
180
|
+
});
|
|
181
|
+
tag.root.addChild(tag.text);
|
|
182
|
+
}
|
|
183
|
+
syncTextResolution(tag.text, tag, context.zoom);
|
|
184
|
+
const sig = [
|
|
185
|
+
input.glyph,
|
|
186
|
+
input.text,
|
|
187
|
+
input.width,
|
|
188
|
+
context.themeKey
|
|
189
|
+
].join("|");
|
|
190
|
+
if (sig === tag.sig) {
|
|
191
|
+
zoomCardTag(tag, context.zoom);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
tag.sig = sig;
|
|
195
|
+
const color = context.palette.muted;
|
|
196
|
+
const pixel = context.style.icons === "pixel";
|
|
197
|
+
drawCardGlyph(tag.icon.clear(), input.glyph, color, pixel);
|
|
198
|
+
tag.text.style.fill = color;
|
|
199
|
+
tag.text.style.fontFamily = context.style.font;
|
|
200
|
+
fitTextToWidth(tag.text, input.text, Math.max(1, input.width - ICON - GAP));
|
|
201
|
+
tag.text.position.set(17, (ICON - tag.text.height) / 2);
|
|
202
|
+
zoomCardTag(tag, context.zoom);
|
|
203
|
+
}
|
|
204
|
+
//#endregion
|
|
205
|
+
export { CARD_TAG_SIZE, createCardTag, drawCardGlyph, formatBoardDuration, syncCardTag, zoomCardTag };
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BoardRenderStyle, BoardSelectionStyle, BoardShadowStyle, defaultBoardRenderStyle, resolveBoardRenderStyle } from "./style.js";
|
|
2
|
+
import { BoardCardRenderer, BoardCardRendererResolver, BoardRenderContext, BoardRenderLabels, BoardRenderPalette, BoardScriptHost, DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
2
3
|
import { createBoardRenderSampler } from "./sampling.js";
|
|
3
4
|
import { BoardRenderDiagnostic, inspectBoardScene, measureBoardText } from "./diagnostics.js";
|
|
4
5
|
import { BoardBackgroundContext, createBoardBackground, updateBoardBackground } from "./board-background.js";
|
|
6
|
+
import { CARD_TAG_SIZE, CardGlyph, CardTag, createCardTag, drawCardGlyph, formatBoardDuration, syncCardTag, zoomCardTag } from "./card-tag.js";
|
|
5
7
|
import { ClipGroup, clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline } from "./clip.js";
|
|
6
8
|
import { BoardCssPaint, parseBoardCssColor, parseBoardCssPaint } from "./css-color.js";
|
|
7
|
-
import { BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible } from "./media-interaction.js";
|
|
9
|
+
import { BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter } from "./media-interaction.js";
|
|
8
10
|
import { defaultBoardPalette, itemAlpha, itemColor } from "./palette.js";
|
|
9
11
|
import { BoardScriptHostOptions, BrowserBoardScriptHost, createBoardScriptHost } from "./script-host.js";
|
|
10
12
|
import { prepareBrowserBoardScripts } from "./script-export.js";
|
|
11
13
|
import { dashPattern, endAngle, roundRectPoints, traceArrowhead, tracePolyline, trimPolyline } from "./stroke.js";
|
|
14
|
+
import { CardElevation, CardRect, CardSurface, PIXEL_STEP, cardElevation, cardOutlinePoints, cardShadow, containRect, drawCardShadow, drawCardSurface, isBoardCard, traceCardOutline, tracePixelRect } from "./surface.js";
|
|
12
15
|
import { BOARD_EFFECT_MAX_PARTICLES } from "./renderers/effect-card-renderer.js";
|
|
13
|
-
import {
|
|
16
|
+
import { ellipsizeWrappedLines, fitLineWithEllipsis, fitTextToLines, fitTextToWidth } from "./text-fit.js";
|
|
14
17
|
import { BOARD_FONT_STACKS, ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
15
|
-
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
18
|
+
import { boardCardDetailed, getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
16
19
|
import { VIDEO_THUMBNAIL_MAX_EDGE, VideoNaturalSize, loadVideoThumbnailTexture, videoTextureNaturalSize, videoThumbnailSize } from "./video-thumbnail.js";
|
|
17
|
-
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, BoardBackgroundContext, BoardCardRenderer, BoardCardRendererResolver, BoardCssPaint, BoardMediaAction, BoardRenderContext, BoardRenderDiagnostic, BoardRenderPalette, BoardScriptHost, BoardScriptHostOptions, BrowserBoardScriptHost, ClipGroup,
|
|
20
|
+
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, BoardBackgroundContext, BoardCardRenderer, BoardCardRendererResolver, BoardCssPaint, BoardMediaAction, BoardRenderContext, BoardRenderDiagnostic, BoardRenderLabels, BoardRenderPalette, BoardRenderStyle, BoardScriptHost, BoardScriptHostOptions, BoardSelectionStyle, BoardShadowStyle, BrowserBoardScriptHost, CARD_TAG_SIZE, CardElevation, CardGlyph, CardRect, CardSurface, CardTag, ClipGroup, DEFAULT_BOARD_RENDER_LABELS, PIXEL_STEP, VIDEO_THUMBNAIL_MAX_EDGE, VideoNaturalSize, boardCardDetailed, boardMediaActionAt, cardElevation, cardOutlinePoints, cardShadow, clippingAncestor, containRect, createBoardBackground, createBoardCardRendererResolver, createBoardRenderSampler, createBoardScriptHost, createCardTag, dashPattern, defaultBoardPalette, defaultBoardRenderStyle, drawCardGlyph, drawCardShadow, drawCardSurface, ellipsizeWrappedLines, endAngle, ensureBoardTextMeasurement, fitLineWithEllipsis, fitTextToLines, fitTextToWidth, formatBoardDuration, getBoardCardRenderer, getBoardResolution, inspectBoardScene, installBoardTextMeasurement, isBoardCard, isClippingFrame, itemAlpha, itemColor, loadVideoThumbnailTexture, measureBoardText, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter, parseBoardCssColor, parseBoardCssPaint, prepareBrowserBoardScripts, resolveBoardRenderStyle, roundRectPoints, syncCardTag, syncClipGroup, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, traceArrowhead, traceCardOutline, traceFrameOutline, tracePixelRect, tracePolyline, trimPolyline, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize, zoomCardTag };
|
|
@@ -4,14 +4,17 @@ import { createBoardRenderSampler } from "./sampling.js";
|
|
|
4
4
|
import { BOARD_FONT_STACKS, ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
5
5
|
import { inspectBoardScene, measureBoardText } from "./diagnostics.js";
|
|
6
6
|
import { createBoardBackground, updateBoardBackground } from "./board-background.js";
|
|
7
|
+
import { ellipsizeWrappedLines, fitLineWithEllipsis, fitTextToLines, fitTextToWidth } from "./text-fit.js";
|
|
8
|
+
import { boardCardDetailed, getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
9
|
+
import { CARD_TAG_SIZE, createCardTag, drawCardGlyph, formatBoardDuration, syncCardTag, zoomCardTag } from "./card-tag.js";
|
|
7
10
|
import { clippingAncestor, isClippingFrame, syncClipGroup, traceFrameOutline } from "./clip.js";
|
|
8
|
-
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
9
|
-
import { TASK_CARD_FULL_DETAIL_ZOOM } from "./renderers/task-card-renderer.js";
|
|
10
|
-
import { boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible } from "./media-interaction.js";
|
|
11
11
|
import { dashPattern, endAngle, roundRectPoints, traceArrowhead, tracePolyline, trimPolyline } from "./stroke.js";
|
|
12
|
+
import { PIXEL_STEP, cardElevation, cardOutlinePoints, cardShadow, containRect, drawCardShadow, drawCardSurface, isBoardCard, traceCardOutline, tracePixelRect } from "./surface.js";
|
|
13
|
+
import { boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter } from "./media-interaction.js";
|
|
12
14
|
import { BOARD_EFFECT_MAX_PARTICLES } from "./renderers/effect-card-renderer.js";
|
|
13
|
-
import { createBoardCardRendererResolver, getBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
15
|
+
import { DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
14
16
|
import { createBoardScriptHost } from "./script-host.js";
|
|
15
17
|
import { prepareBrowserBoardScripts } from "./script-export.js";
|
|
18
|
+
import { defaultBoardRenderStyle, resolveBoardRenderStyle } from "./style.js";
|
|
16
19
|
import { VIDEO_THUMBNAIL_MAX_EDGE, loadVideoThumbnailTexture, videoTextureNaturalSize, videoThumbnailSize } from "./video-thumbnail.js";
|
|
17
|
-
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS,
|
|
20
|
+
export { BOARD_EFFECT_MAX_PARTICLES, BOARD_FONT_STACKS, CARD_TAG_SIZE, DEFAULT_BOARD_RENDER_LABELS, PIXEL_STEP, VIDEO_THUMBNAIL_MAX_EDGE, boardCardDetailed, boardMediaActionAt, cardElevation, cardOutlinePoints, cardShadow, clippingAncestor, containRect, createBoardBackground, createBoardCardRendererResolver, createBoardRenderSampler, createBoardScriptHost, createCardTag, dashPattern, defaultBoardPalette, defaultBoardRenderStyle, drawCardGlyph, drawCardShadow, drawCardSurface, ellipsizeWrappedLines, endAngle, ensureBoardTextMeasurement, fitLineWithEllipsis, fitTextToLines, fitTextToWidth, formatBoardDuration, getBoardCardRenderer, getBoardResolution, inspectBoardScene, installBoardTextMeasurement, isBoardCard, isClippingFrame, itemAlpha, itemColor, loadVideoThumbnailTexture, measureBoardText, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter, parseBoardCssColor, parseBoardCssPaint, prepareBrowserBoardScripts, resolveBoardRenderStyle, roundRectPoints, syncCardTag, syncClipGroup, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket, traceArrowhead, traceCardOutline, traceFrameOutline, tracePixelRect, tracePolyline, trimPolyline, updateBoardBackground, videoTextureNaturalSize, videoThumbnailSize, zoomCardTag };
|
|
@@ -9,10 +9,11 @@ declare function mediaPlayBadgeVisible(item: BoardSceneItem, zoom: number, optio
|
|
|
9
9
|
materialized: boolean;
|
|
10
10
|
hasVideoPreview: boolean;
|
|
11
11
|
}): boolean;
|
|
12
|
+
declare function mediaPlayKeyCenter(item: BoardSceneItem): WorldPoint;
|
|
12
13
|
declare function mediaPlayBadgeHit(item: BoardSceneItem, point: WorldPoint, zoom: number): boolean;
|
|
13
14
|
declare function boardMediaActionAt(item: BoardSceneItem, point: WorldPoint, zoom: number, options: {
|
|
14
15
|
materialized: boolean;
|
|
15
16
|
hasVideoPreview: boolean;
|
|
16
17
|
}): BoardMediaAction | null;
|
|
17
18
|
//#endregion
|
|
18
|
-
export { BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible };
|
|
19
|
+
export { BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter };
|
|
@@ -1,19 +1,27 @@
|
|
|
1
|
-
import { featuredTaskArtifact } from "
|
|
2
|
-
import "
|
|
1
|
+
import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
|
|
2
|
+
import { degToRad, rotatePointAround, worldPoint } from "../model/geometry.js";
|
|
3
|
+
import { boardCardDetailed } from "./text-resolution.js";
|
|
4
|
+
import { audioKeyCenter } from "./renderers/audio-card-renderer.js";
|
|
3
5
|
//#region src/board/render/media-interaction.ts
|
|
4
6
|
function mediaPlayBadgeVisible(item, zoom, options) {
|
|
5
7
|
if (!options.materialized) return false;
|
|
6
8
|
if (item.type === "video" || item.type === "audio") return true;
|
|
7
|
-
if (item.type !== "task" || zoom
|
|
9
|
+
if (item.type !== "task" || !boardCardDetailed(zoom)) return false;
|
|
8
10
|
const artifact = featuredTaskArtifact(item.props.snapshot.artifacts);
|
|
9
11
|
if (artifact?.type === "audio") return true;
|
|
10
12
|
return artifact?.type === "video" && (Boolean(artifact.previewUrl) || options.hasVideoPreview);
|
|
11
13
|
}
|
|
14
|
+
function mediaPlayKeyCenter(item) {
|
|
15
|
+
const { x, y, width, height, rotation } = item.frame;
|
|
16
|
+
const center = worldPoint(x + width / 2, y + height / 2);
|
|
17
|
+
if (item.type !== "audio") return center;
|
|
18
|
+
const key = audioKeyCenter(width, height);
|
|
19
|
+
return rotatePointAround(worldPoint(x + key.x, y + key.y), center, degToRad(rotation || 0));
|
|
20
|
+
}
|
|
12
21
|
function mediaPlayBadgeHit(item, point, zoom) {
|
|
13
22
|
const radius = 28 / Math.max(zoom, .05);
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
return Math.hypot(point.x - centerX, point.y - centerY) <= radius;
|
|
23
|
+
const center = mediaPlayKeyCenter(item);
|
|
24
|
+
return Math.hypot(point.x - center.x, point.y - center.y) <= radius;
|
|
17
25
|
}
|
|
18
26
|
function boardMediaActionAt(item, point, zoom, options) {
|
|
19
27
|
return mediaPlayBadgeVisible(item, zoom, options) && mediaPlayBadgeHit(item, point, zoom) ? {
|
|
@@ -22,4 +30,4 @@ function boardMediaActionAt(item, point, zoom, options) {
|
|
|
22
30
|
} : null;
|
|
23
31
|
}
|
|
24
32
|
//#endregion
|
|
25
|
-
export { boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible };
|
|
33
|
+
export { boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter };
|
|
@@ -2,8 +2,9 @@ import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
|
2
2
|
import { pathPointAt, resolveSceneArrow } from "../../model/arrow-geometry.js";
|
|
3
3
|
import { itemAlpha, itemColor } from "../palette.js";
|
|
4
4
|
import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
5
|
-
import { drawFarStroke } from "./far-plate.js";
|
|
6
5
|
import { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline } from "../stroke.js";
|
|
6
|
+
import { drawCardSurface } from "../surface.js";
|
|
7
|
+
import { drawFarStroke } from "./far-plate.js";
|
|
7
8
|
import { Container, Graphics, Text } from "pixi.js";
|
|
8
9
|
//#region src/board/render/renderers/arrow-card-renderer.ts
|
|
9
10
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
@@ -14,8 +15,6 @@ function sync(container, item, context) {
|
|
|
14
15
|
parts.root.rotation = 0;
|
|
15
16
|
parts.root.scale.set(1);
|
|
16
17
|
const { props, style } = item;
|
|
17
|
-
const selected = context.selectedIds.has(item.id);
|
|
18
|
-
const hovered = context.hoveredId === item.id;
|
|
19
18
|
parts.line.alpha = itemAlpha(context, style.stroke);
|
|
20
19
|
const color = itemColor(context, style.stroke, "brand");
|
|
21
20
|
const size = style.strokeWidth ?? 2.5;
|
|
@@ -24,8 +23,6 @@ function sync(container, item, context) {
|
|
|
24
23
|
const path = trimPolyline(resolved.path, style.trim);
|
|
25
24
|
const lineSig = [
|
|
26
25
|
path.map((point) => `${point.x},${point.y}`).join(";"),
|
|
27
|
-
selected,
|
|
28
|
-
hovered,
|
|
29
26
|
color,
|
|
30
27
|
size,
|
|
31
28
|
style.dash,
|
|
@@ -35,11 +32,11 @@ function sync(container, item, context) {
|
|
|
35
32
|
if (lineSig !== parts.lineSig) {
|
|
36
33
|
parts.lineSig = lineSig;
|
|
37
34
|
parts.line.clear();
|
|
38
|
-
const width =
|
|
35
|
+
const width = size;
|
|
39
36
|
const stroke = {
|
|
40
37
|
color,
|
|
41
38
|
width,
|
|
42
|
-
alpha:
|
|
39
|
+
alpha: .92,
|
|
43
40
|
cap: "round",
|
|
44
41
|
join: "round"
|
|
45
42
|
};
|
|
@@ -63,22 +60,29 @@ function sync(container, item, context) {
|
|
|
63
60
|
}
|
|
64
61
|
const labelSig = [
|
|
65
62
|
props.label,
|
|
66
|
-
|
|
67
|
-
context.
|
|
68
|
-
props.fontSize
|
|
63
|
+
props.fontSize,
|
|
64
|
+
context.themeKey
|
|
69
65
|
].join("|");
|
|
70
66
|
if (labelSig !== parts.labelSig) {
|
|
71
67
|
parts.labelSig = labelSig;
|
|
72
68
|
parts.label.text = props.label;
|
|
73
69
|
parts.label.style.fill = context.palette.text;
|
|
74
70
|
parts.label.style.fontSize = props.fontSize;
|
|
75
|
-
const padX = props.fontSize * .
|
|
76
|
-
const padY = props.fontSize * .
|
|
71
|
+
const padX = props.fontSize * .5;
|
|
72
|
+
const padY = props.fontSize * .25;
|
|
77
73
|
const { width, height } = parts.label;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
const plate = {
|
|
75
|
+
x: -width / 2 - padX,
|
|
76
|
+
y: -height / 2 - padY,
|
|
77
|
+
width: width + padX * 2,
|
|
78
|
+
height: height + padY * 2
|
|
79
|
+
};
|
|
80
|
+
drawCardSurface(parts.backdrop.clear(), plate, {
|
|
81
|
+
...context.style,
|
|
82
|
+
radius: Math.min(context.style.radius, plate.height / 2)
|
|
83
|
+
}, {
|
|
84
|
+
fill: context.palette.surface,
|
|
85
|
+
border: context.palette.border
|
|
82
86
|
});
|
|
83
87
|
}
|
|
84
88
|
const visible = props.label.length > 0 && (style.trim === void 0 || style.trim >= .5);
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { BoardCardRenderer } from "./board-renderer-registry.js";
|
|
2
2
|
//#region src/board/render/renderers/audio-card-renderer.d.ts
|
|
3
|
+
declare const AUDIO_PADDING = 14;
|
|
4
|
+
declare const AUDIO_KEY_RADIUS = 16;
|
|
5
|
+
declare function audioKeyCenter(width: number, height: number): {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
radius: number;
|
|
9
|
+
};
|
|
3
10
|
declare const audioCardRenderer: BoardCardRenderer;
|
|
4
11
|
//#endregion
|
|
5
|
-
export { audioCardRenderer };
|
|
12
|
+
export { AUDIO_KEY_RADIUS, AUDIO_PADDING, audioCardRenderer, audioKeyCenter };
|
|
@@ -1,70 +1,80 @@
|
|
|
1
|
-
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
1
|
import { getMediaResourceTitle } from "../../model/media.js";
|
|
2
|
+
import { fitTextToWidth } from "../text-fit.js";
|
|
3
|
+
import { boardCardDetailed, syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
4
|
+
import { formatBoardDuration } from "../card-tag.js";
|
|
3
5
|
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
4
|
-
import {
|
|
6
|
+
import { cardElevation, drawCardSurface } from "../surface.js";
|
|
5
7
|
import { positionShell } from "./base-card-renderer.js";
|
|
6
8
|
import { drawFarPlate } from "./far-plate.js";
|
|
9
|
+
import { drawMediaPlayKey } from "./media-key.js";
|
|
7
10
|
import { Container, Graphics, Text } from "pixi.js";
|
|
8
11
|
//#region src/board/render/renderers/audio-card-renderer.ts
|
|
9
|
-
const
|
|
10
|
-
const
|
|
12
|
+
const AUDIO_PADDING = 14;
|
|
13
|
+
const AUDIO_KEY_RADIUS = 16;
|
|
14
|
+
const GAP = 12;
|
|
15
|
+
const WAVE_HEIGHT = 16;
|
|
11
16
|
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
17
|
+
function audioKeyCenter(width, height) {
|
|
18
|
+
const radius = Math.min(16, Math.max(8, height / 2 - 8), width / 4);
|
|
19
|
+
return {
|
|
20
|
+
x: 14 + radius,
|
|
21
|
+
y: height / 2,
|
|
22
|
+
radius
|
|
23
|
+
};
|
|
24
|
+
}
|
|
12
25
|
function sync(container, item, context) {
|
|
13
26
|
const parts = partsByContainer.get(container);
|
|
14
27
|
if (!parts) return;
|
|
15
28
|
positionShell(parts.root, item);
|
|
16
29
|
const { width, height } = item.frame;
|
|
17
|
-
const selected = context.selectedIds.has(item.id);
|
|
18
|
-
const hovered = context.hoveredId === item.id;
|
|
19
30
|
const title = item.props.snapshot?.title ?? getMediaResourceTitle(item.props.src);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
const durationMs = item.props.snapshot?.durationMs;
|
|
32
|
+
const detailed = boardCardDetailed(context.zoom);
|
|
33
|
+
syncTextResolution(parts.title, parts, context.zoom);
|
|
34
|
+
const elevation = cardElevation(context, item.id);
|
|
24
35
|
const sig = [
|
|
25
36
|
width,
|
|
26
37
|
height,
|
|
27
|
-
selected,
|
|
28
|
-
hovered,
|
|
29
38
|
title,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
context.
|
|
39
|
+
durationMs ?? "",
|
|
40
|
+
detailed,
|
|
41
|
+
elevation,
|
|
42
|
+
item.props.src,
|
|
43
|
+
item.props.snapshot?.mtimeMs ?? "",
|
|
44
|
+
context.themeKey
|
|
36
45
|
].join("|");
|
|
37
46
|
if (sig === parts.sig) return;
|
|
38
47
|
parts.sig = sig;
|
|
39
|
-
parts.plate.clear()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
parts.waveform.clear();
|
|
50
|
-
drawAudioWaveform(parts.waveform, `${item.props.src}:${item.props.snapshot?.mtimeMs ?? "unknown"}`, {
|
|
51
|
-
x: waveformInset,
|
|
52
|
-
y: 10,
|
|
53
|
-
width: Math.max(1, width - waveformInset * 2),
|
|
54
|
-
height: Math.max(8, height - labelBand - 16)
|
|
55
|
-
}, context.palette.brand);
|
|
56
|
-
const cx = width / 2;
|
|
57
|
-
const cy = Math.max(24, (height - labelBand) / 2);
|
|
58
|
-
parts.chrome.clear().circle(cx, cy, PLAY_RADIUS).fill({
|
|
59
|
-
color: selected ? context.palette.brand : context.palette.surface,
|
|
60
|
-
alpha: .92
|
|
61
|
-
});
|
|
62
|
-
const triangle = PLAY_RADIUS * .58;
|
|
63
|
-
parts.chrome.moveTo(cx - triangle * .35, cy - triangle * .62).lineTo(cx - triangle * .35, cy + triangle * .62).lineTo(cx + triangle * .72, cy).closePath().fill({
|
|
64
|
-
color: context.palette.text,
|
|
65
|
-
alpha: .96
|
|
48
|
+
drawCardSurface(parts.plate.clear(), {
|
|
49
|
+
x: 0,
|
|
50
|
+
y: 0,
|
|
51
|
+
width,
|
|
52
|
+
height
|
|
53
|
+
}, context.style, {
|
|
54
|
+
fill: context.palette.surface,
|
|
55
|
+
border: context.palette.border,
|
|
56
|
+
borderAlpha: .85,
|
|
57
|
+
elevation
|
|
66
58
|
});
|
|
67
|
-
|
|
59
|
+
const key = audioKeyCenter(width, height);
|
|
60
|
+
drawMediaPlayKey(parts.plate, key.x, key.y, key.radius, context, true);
|
|
61
|
+
const left = key.x + key.radius + GAP;
|
|
62
|
+
const room = width - 14 - left;
|
|
63
|
+
parts.title.visible = detailed && room > 24;
|
|
64
|
+
parts.wave.clear();
|
|
65
|
+
if (!parts.title.visible) return;
|
|
66
|
+
parts.title.style.fontFamily = context.style.font;
|
|
67
|
+
parts.title.style.fill = context.palette.text;
|
|
68
|
+
fitTextToWidth(parts.title, durationMs ? `${title} · ${formatBoardDuration(durationMs)}` : title, room);
|
|
69
|
+
const withWave = height >= 56;
|
|
70
|
+
const top = (height - (parts.title.height + (withWave ? 22 : 0))) / 2;
|
|
71
|
+
parts.title.position.set(left, top);
|
|
72
|
+
if (withWave) drawAudioWaveform(parts.wave, `${item.props.src}:${item.props.snapshot?.mtimeMs ?? "unknown"}`, {
|
|
73
|
+
x: left,
|
|
74
|
+
y: top + parts.title.height + 6,
|
|
75
|
+
width: room,
|
|
76
|
+
height: WAVE_HEIGHT
|
|
77
|
+
}, context.palette.muted, .45, context.style.corner === "pixel");
|
|
68
78
|
}
|
|
69
79
|
const audioCardRenderer = {
|
|
70
80
|
id: "audio-card",
|
|
@@ -72,30 +82,24 @@ const audioCardRenderer = {
|
|
|
72
82
|
create: (item, context) => {
|
|
73
83
|
const root = new Container();
|
|
74
84
|
const plate = new Graphics();
|
|
75
|
-
const
|
|
76
|
-
const chrome = new Graphics();
|
|
85
|
+
const wave = new Graphics();
|
|
77
86
|
const resolution = textResolutionForZoom(context.zoom);
|
|
78
|
-
const
|
|
87
|
+
const title = new Text({
|
|
79
88
|
text: "",
|
|
80
89
|
style: {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
fontSize: 12,
|
|
84
|
-
fontWeight: "500",
|
|
85
|
-
wordWrap: true
|
|
90
|
+
fontSize: 13,
|
|
91
|
+
fontWeight: "600"
|
|
86
92
|
},
|
|
87
93
|
resolution,
|
|
88
94
|
roundPixels: true
|
|
89
95
|
});
|
|
90
|
-
root.addChild(plate,
|
|
96
|
+
root.addChild(plate, wave, title);
|
|
91
97
|
partsByContainer.set(root, {
|
|
92
98
|
root,
|
|
93
99
|
plate,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
label,
|
|
100
|
+
wave,
|
|
101
|
+
title,
|
|
97
102
|
sig: "",
|
|
98
|
-
wrapWidth: 0,
|
|
99
103
|
resolution
|
|
100
104
|
});
|
|
101
105
|
if (item.type === "audio") sync(root, item, context);
|
|
@@ -118,4 +122,4 @@ const audioCardRenderer = {
|
|
|
118
122
|
}
|
|
119
123
|
};
|
|
120
124
|
//#endregion
|
|
121
|
-
export { audioCardRenderer };
|
|
125
|
+
export { AUDIO_KEY_RADIUS, AUDIO_PADDING, audioCardRenderer, audioKeyCenter };
|
|
@@ -1,35 +1,10 @@
|
|
|
1
1
|
import { BoardFrame } from "../../../protocol/dist/board-layout.js";
|
|
2
2
|
import "../../../protocol/dist/index.js";
|
|
3
|
-
import { BoardRenderPalette } from "./board-renderer-registry.js";
|
|
4
3
|
import { Container, Text } from "pixi.js";
|
|
5
4
|
//#region src/board/render/renderers/base-card-renderer.d.ts
|
|
6
|
-
declare const CARD_RADIUS = 10;
|
|
7
|
-
declare const CARD_PADDING = 12;
|
|
8
|
-
declare const FOOTER_HEIGHT = 34;
|
|
9
5
|
declare function createLabel(text: string, style: Record<string, unknown>): Text;
|
|
10
|
-
type CardShellState = {
|
|
11
|
-
width: number;
|
|
12
|
-
height: number;
|
|
13
|
-
selected: boolean;
|
|
14
|
-
hovered: boolean;
|
|
15
|
-
accent: number;
|
|
16
|
-
title: string;
|
|
17
|
-
};
|
|
18
|
-
type CardShell = {
|
|
19
|
-
root: Container;
|
|
20
|
-
content: Container;
|
|
21
|
-
contentRect: () => {
|
|
22
|
-
x: number;
|
|
23
|
-
y: number;
|
|
24
|
-
width: number;
|
|
25
|
-
height: number;
|
|
26
|
-
};
|
|
27
|
-
update: (state: CardShellState, palette: BoardRenderPalette, footer: boolean) => void;
|
|
28
|
-
destroy: () => void;
|
|
29
|
-
};
|
|
30
|
-
declare function createCardShell(): CardShell;
|
|
31
6
|
declare function positionShell(root: Container, item: {
|
|
32
7
|
frame: BoardFrame;
|
|
33
8
|
}): void;
|
|
34
9
|
//#endregion
|
|
35
|
-
export {
|
|
10
|
+
export { createLabel, positionShell };
|