@neta-art/cohub 12.1.1 → 12.3.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.
Files changed (134) hide show
  1. package/README.md +85 -8
  2. package/dist/board/editor/clipboard.js +1 -1
  3. package/dist/board/editor/creation.js +1 -1
  4. package/dist/board/editor/document.d.ts +3 -1
  5. package/dist/board/editor/document.js +8 -6
  6. package/dist/board/editor/editor.d.ts +8 -3
  7. package/dist/board/editor/editor.js +8 -2
  8. package/dist/board/editor/index.d.ts +3 -3
  9. package/dist/board/editor/index.js +2 -2
  10. package/dist/board/editor/interaction.d.ts +23 -2
  11. package/dist/board/editor/interaction.js +93 -4
  12. package/dist/board/editor/query.d.ts +1 -1
  13. package/dist/board/editor/query.js +3 -7
  14. package/dist/board/editor/selection.js +1 -1
  15. package/dist/board/editor/snapshots.js +5 -57
  16. package/dist/board/editor/tool.d.ts +4 -1
  17. package/dist/board/editor/tool.js +6 -1
  18. package/dist/board/export/index.d.ts +2 -2
  19. package/dist/board/export/index.js +1 -1
  20. package/dist/board/export/node/fonts.js +4 -0
  21. package/dist/board/export/node/index.d.ts +2 -0
  22. package/dist/board/export/node/index.js +8 -1
  23. package/dist/board/export/node/scripts.js +1 -1
  24. package/dist/board/export/scene.d.ts +2 -2
  25. package/dist/board/export/scene.js +2 -2
  26. package/dist/board/model/asset-key.d.ts +24 -0
  27. package/dist/board/model/asset-key.js +104 -0
  28. package/dist/board/model/export-assets.d.ts +7 -3
  29. package/dist/board/model/export-assets.js +34 -13
  30. package/dist/board/model/index.d.ts +9 -7
  31. package/dist/board/model/index.js +22 -20
  32. package/dist/board/model/items/create.js +3 -3
  33. package/dist/board/model/items/definition.d.ts +9 -1
  34. package/dist/board/model/items/index.d.ts +2 -2
  35. package/dist/board/model/items/registry.d.ts +2 -1
  36. package/dist/board/model/items/registry.js +1 -0
  37. package/dist/board/model/media-sizes.d.ts +28 -0
  38. package/dist/board/model/media-sizes.js +64 -0
  39. package/dist/board/model/palette.d.ts +1 -0
  40. package/dist/board/model/palette.js +20 -130
  41. package/dist/board/model/sampling.js +1 -1
  42. package/dist/board/model/text-metrics.d.ts +28 -3
  43. package/dist/board/model/text-metrics.js +36 -2
  44. package/dist/board/model/themes.d.ts +495 -0
  45. package/dist/board/model/themes.js +500 -0
  46. package/dist/board/render/card-tag.js +2 -2
  47. package/dist/board/render/index.d.ts +11 -7
  48. package/dist/board/render/index.js +9 -5
  49. package/dist/board/render/labels.d.ts +15 -0
  50. package/dist/board/render/labels.js +14 -0
  51. package/dist/board/render/lod.d.ts +30 -0
  52. package/dist/board/render/lod.js +33 -0
  53. package/dist/board/render/media-interaction.d.ts +5 -2
  54. package/dist/board/render/media-interaction.js +15 -3
  55. package/dist/board/render/palette.js +2 -25
  56. package/dist/board/render/renderers/arrow-card-renderer.js +7 -5
  57. package/dist/board/render/renderers/audio-card-renderer.js +3 -2
  58. package/dist/board/render/renderers/board-renderer-registry.d.ts +22 -1
  59. package/dist/board/render/renderers/board-renderer-registry.js +9 -4
  60. package/dist/board/render/renderers/custom-card-renderer.js +5 -5
  61. package/dist/board/render/renderers/draw-card-renderer.js +1 -1
  62. package/dist/board/render/renderers/far-plate.d.ts +14 -1
  63. package/dist/board/render/renderers/far-plate.js +31 -8
  64. package/dist/board/render/renderers/file-card-renderer.js +49 -31
  65. package/dist/board/render/renderers/frame-card-renderer.js +9 -3
  66. package/dist/board/render/renderers/image-card-renderer.js +34 -8
  67. package/dist/board/render/renderers/model-card-renderer.js +6 -6
  68. package/dist/board/render/renderers/shape-card-renderer.js +25 -24
  69. package/dist/board/render/renderers/task-card-renderer.js +9 -10
  70. package/dist/board/render/renderers/text-card-renderer.js +86 -41
  71. package/dist/board/render/renderers/video-card-renderer.js +5 -4
  72. package/dist/board/render/script-export.js +1 -1
  73. package/dist/board/render/script-host.js +3 -3
  74. package/dist/board/render/style.d.ts +8 -2
  75. package/dist/board/render/style.js +8 -2
  76. package/dist/board/render/surface.d.ts +5 -0
  77. package/dist/board/render/surface.js +13 -3
  78. package/dist/board/render/text-edit.d.ts +32 -0
  79. package/dist/board/render/text-edit.js +134 -0
  80. package/dist/board/render/text-fit.d.ts +1 -3
  81. package/dist/board/render/text-fit.js +6 -49
  82. package/dist/board/render/text-measurement.d.ts +25 -1
  83. package/dist/board/render/text-measurement.js +157 -19
  84. package/dist/board/render/text-resolution.d.ts +1 -6
  85. package/dist/board/render/text-resolution.js +1 -10
  86. package/dist/board/render/theme.d.ts +15 -0
  87. package/dist/board/render/theme.js +15 -0
  88. package/dist/board/replica/index.d.ts +4 -2
  89. package/dist/board/replica/index.js +28 -17
  90. package/dist/board/replica/indexeddb.d.ts +16 -0
  91. package/dist/board/replica/indexeddb.js +155 -0
  92. package/dist/board/stage/assets.d.ts +28 -5
  93. package/dist/board/stage/assets.js +293 -102
  94. package/dist/board/stage/bench.d.ts +35 -0
  95. package/dist/board/stage/bench.js +153 -0
  96. package/dist/board/stage/device.d.ts +41 -0
  97. package/dist/board/stage/device.js +62 -0
  98. package/dist/board/stage/frame-budget.d.ts +19 -0
  99. package/dist/board/stage/frame-budget.js +69 -0
  100. package/dist/board/stage/idle.d.ts +4 -0
  101. package/dist/board/stage/idle.js +26 -0
  102. package/dist/board/stage/index.d.ts +11 -7
  103. package/dist/board/stage/index.js +7 -4
  104. package/dist/board/stage/lru.d.ts +13 -9
  105. package/dist/board/stage/lru.js +38 -20
  106. package/dist/board/stage/presses.d.ts +21 -0
  107. package/dist/board/stage/presses.js +66 -0
  108. package/dist/board/stage/scene.d.ts +15 -1
  109. package/dist/board/stage/scene.js +248 -141
  110. package/dist/board/stage/stage.d.ts +28 -2
  111. package/dist/board/stage/stage.js +404 -112
  112. package/dist/board/stage/texture-pool.d.ts +10 -1
  113. package/dist/board/stage/texture-pool.js +72 -2
  114. package/dist/chunks/environment.d.ts +6 -0
  115. package/dist/chunks/http.d.ts +9 -1
  116. package/dist/chunks/http.js +791 -4
  117. package/dist/index.d.ts +52 -1
  118. package/dist/index.js +202 -862
  119. package/dist/media.d.ts +3 -27
  120. package/dist/media.js +3 -82
  121. package/dist/protocol/dist/board-constants.js +3 -3
  122. package/dist/protocol/dist/board-layout.d.ts +17 -3
  123. package/dist/protocol/dist/board-layout.js +68 -11
  124. package/dist/protocol/dist/board-model.d.ts +15 -1
  125. package/dist/protocol/dist/board-model.js +12 -2
  126. package/dist/protocol/dist/board-patch.js +1 -1
  127. package/dist/protocol/dist/board-schema.d.ts +2 -1
  128. package/dist/protocol/dist/board-schema.js +4 -1
  129. package/dist/protocol/dist/core/media.d.ts +35 -1
  130. package/dist/protocol/dist/core/media.js +127 -1
  131. package/dist/protocol/dist/index.d.ts +3 -3
  132. package/package.json +4 -2
  133. package/dist/board/model/image-key.d.ts +0 -9
  134. package/dist/board/model/image-key.js +0 -33
@@ -1,8 +1,10 @@
1
1
  import { WorldPoint } from "../model/geometry.js";
2
2
  import { BoardSceneItem } from "../model/scene.js";
3
+ import { BoardCardHit, BoardRenderContext } from "./renderers/board-renderer-registry.js";
3
4
  //#region src/board/render/media-interaction.d.ts
5
+ declare const BOARD_PLAY_MEDIA = "play-media";
4
6
  type BoardMediaAction = {
5
- action: "play-media";
7
+ action: typeof BOARD_PLAY_MEDIA;
6
8
  itemId: string;
7
9
  };
8
10
  declare function mediaPlayBadgeVisible(item: BoardSceneItem, zoom: number, options: {
@@ -15,5 +17,6 @@ declare function boardMediaActionAt(item: BoardSceneItem, point: WorldPoint, zoo
15
17
  materialized: boolean;
16
18
  hasVideoPreview: boolean;
17
19
  }): BoardMediaAction | null;
20
+ declare function mediaPlayHit(item: BoardSceneItem, point: WorldPoint, context: BoardRenderContext): BoardCardHit | null;
18
21
  //#endregion
19
- export { BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter };
22
+ export { BOARD_PLAY_MEDIA, BoardMediaAction, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayHit, mediaPlayKeyCenter };
@@ -1,10 +1,11 @@
1
1
  import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
2
2
  import { degToRad, rotatePointAround, worldPoint } from "../model/geometry.js";
3
+ import { boardCardDetailed } from "./lod.js";
3
4
  import { isBoardModelItem } from "../model/media.js";
4
- import { boardCardDetailed } from "./text-resolution.js";
5
5
  import { audioKeyCenter } from "./renderers/audio-card-renderer.js";
6
6
  import { modelKeyCenter } from "./renderers/model-card-renderer.js";
7
7
  //#region src/board/render/media-interaction.ts
8
+ const BOARD_PLAY_MEDIA = "play-media";
8
9
  function mediaPlayBadgeVisible(item, zoom, options) {
9
10
  if (!options.materialized) return false;
10
11
  if (item.type === "video" || item.type === "audio") return true;
@@ -34,9 +35,20 @@ function mediaPlayBadgeHit(item, point, zoom) {
34
35
  }
35
36
  function boardMediaActionAt(item, point, zoom, options) {
36
37
  return mediaPlayBadgeVisible(item, zoom, options) && mediaPlayBadgeHit(item, point, zoom) ? {
37
- action: "play-media",
38
+ action: BOARD_PLAY_MEDIA,
38
39
  itemId: item.id
39
40
  } : null;
40
41
  }
42
+ const PLAY_HIT = {
43
+ action: BOARD_PLAY_MEDIA,
44
+ cursor: "pointer"
45
+ };
46
+ function mediaPlayHit(item, point, context) {
47
+ const key = context.assetKey(item);
48
+ return boardMediaActionAt(item, point, context.zoom, {
49
+ materialized: true,
50
+ hasVideoPreview: Boolean(key && context.getTexture(key))
51
+ }) ? PLAY_HIT : null;
52
+ }
41
53
  //#endregion
42
- export { boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayKeyCenter };
54
+ export { BOARD_PLAY_MEDIA, boardMediaActionAt, mediaPlayBadgeHit, mediaPlayBadgeVisible, mediaPlayHit, mediaPlayKeyCenter };
@@ -1,32 +1,9 @@
1
+ import { BOARD_THEME_DATA } from "../model/themes.js";
1
2
  import { resolveItemColor } from "../model/palette.js";
2
3
  import { parseBoardCssColor, parseBoardCssPaint } from "./css-color.js";
3
4
  //#region src/board/render/palette.ts
4
- const DARK = {
5
- bg: 1315860,
6
- surface: 2105376,
7
- hover: 2763306,
8
- border: 3815994,
9
- brand: 16734751,
10
- text: 16053492,
11
- muted: 9211020,
12
- rare: 3718648,
13
- epic: 10980346,
14
- legendary: 16096779
15
- };
16
- const LIGHT = {
17
- bg: 16251129,
18
- surface: 16777215,
19
- hover: 15329772,
20
- border: 14079706,
21
- brand: 15222030,
22
- text: 1579035,
23
- muted: 7041664,
24
- rare: 2450411,
25
- epic: 8141549,
26
- legendary: 11817737
27
- };
28
5
  function defaultBoardPalette(mode) {
29
- return { ...mode === "light" ? LIGHT : DARK };
6
+ return { ...BOARD_THEME_DATA[mode].palette };
30
7
  }
31
8
  function itemAlpha(context, color) {
32
9
  const value = typeof color === "object" && color ? color[context.colorScheme] : color;
@@ -1,10 +1,11 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { pathPointAt, resolveSceneArrow } from "../../model/arrow-geometry.js";
3
2
  import { itemAlpha, itemColor } from "../palette.js";
3
+ import { resolveSceneArrow } from "../../model/arrow-geometry.js";
4
4
  import { syncTextResolution } from "../text-resolution.js";
5
5
  import { dashPattern, endAngle, traceArrowhead, tracePolyline, trimPolyline } from "../stroke.js";
6
6
  import { drawCardSurface } from "../surface.js";
7
7
  import { drawFarStroke } from "./far-plate.js";
8
+ import { ARROW_LABEL, arrowLabelAnchor } from "../labels.js";
8
9
  import { Container, Graphics, Text } from "pixi.js";
9
10
  //#region src/board/render/renderers/arrow-card-renderer.ts
10
11
  const partsByContainer = /* @__PURE__ */ new WeakMap();
@@ -67,8 +68,9 @@ function sync(container, item, context) {
67
68
  parts.label.text = props.label;
68
69
  parts.label.style.fill = context.palette.text;
69
70
  parts.label.style.fontSize = props.fontSize;
70
- const padX = props.fontSize * .5;
71
- const padY = props.fontSize * .25;
71
+ parts.label.style.lineHeight = props.fontSize * ARROW_LABEL.lineHeight;
72
+ const padX = props.fontSize * ARROW_LABEL.padX;
73
+ const padY = props.fontSize * ARROW_LABEL.padY;
72
74
  const { width, height } = parts.label;
73
75
  const plate = {
74
76
  x: -width / 2 - padX,
@@ -88,7 +90,7 @@ function sync(container, item, context) {
88
90
  const visible = props.label.length > 0 && (style.trim === void 0 || style.trim >= .5);
89
91
  parts.label.visible = visible;
90
92
  parts.backdrop.visible = visible;
91
- const mid = style.trim === void 0 ? resolved.mid : pathPointAt(resolved.path, .5);
93
+ const mid = arrowLabelAnchor(resolved, style);
92
94
  parts.label.position.set(mid.x, mid.y);
93
95
  parts.backdrop.position.set(mid.x, mid.y);
94
96
  }
@@ -104,7 +106,7 @@ const arrowCardRenderer = {
104
106
  fill: 16777215,
105
107
  fontFamily: BOARD_FONT_STACK,
106
108
  fontSize: 14,
107
- fontWeight: "500"
109
+ fontWeight: ARROW_LABEL.fontWeight
108
110
  },
109
111
  resolution: context.textResolution,
110
112
  roundPixels: true
@@ -1,7 +1,8 @@
1
- import { getMediaResourceTitle } from "../../model/media.js";
1
+ import { boardCardDetailed } from "../lod.js";
2
2
  import { fitTextToWidth } from "../text-fit.js";
3
- import { boardCardDetailed, syncTextResolution } from "../text-resolution.js";
3
+ import { syncTextResolution } from "../text-resolution.js";
4
4
  import { formatBoardDuration } from "../card-tag.js";
5
+ import { getMediaResourceTitle } from "../../model/media.js";
5
6
  import { drawAudioWaveform } from "../audio-waveform.js";
6
7
  import { cardElevation, drawCardSurface } from "../surface.js";
7
8
  import { positionShell } from "./base-card-renderer.js";
@@ -1,9 +1,11 @@
1
1
  import { BoardCustomItem, BoardDocument, BoardSettings, BoardTaskItem } from "../../../protocol/dist/board-model.js";
2
2
  import { BoardFrame } from "../../../protocol/dist/board-layout.js";
3
3
  import "../../../protocol/dist/index.js";
4
+ import { WorldPoint } from "../../model/geometry.js";
4
5
  import { BoardScene, BoardSceneItem, SceneItem } from "../../model/scene.js";
5
6
  import { BoardShapeColors } from "../../model/palette.js";
6
7
  import { BoardRenderStyle } from "../style.js";
8
+ import { BoardLodKind } from "../lod.js";
7
9
  import { Container, Graphics, Texture } from "pixi.js";
8
10
  //#region src/board/render/renderers/board-renderer-registry.d.ts
9
11
  type BoardRenderPalette = {
@@ -41,6 +43,7 @@ type BoardRenderContext = {
41
43
  hoveredId: string | null;
42
44
  resizingIds: Set<string>;
43
45
  liftedIds: ReadonlySet<string>;
46
+ editingId?: string | null;
44
47
  palette: BoardRenderPalette;
45
48
  colors: BoardShapeColors;
46
49
  colorScheme: "dark" | "light";
@@ -62,9 +65,18 @@ type BoardRenderContext = {
62
65
  assetKey: (item: BoardSceneItem) => string | null;
63
66
  getTexture: (key: string) => Texture | null;
64
67
  hasError: (key: string) => boolean;
68
+ assetTone?: (key: string) => number | null;
65
69
  fileState: (path: string) => "ok" | "missing" | "unavailable";
66
70
  acquireTexture: (key: string, item: BoardSceneItem) => void;
67
71
  releaseTexture: (key: string) => void;
72
+ hoveredHit?: {
73
+ itemId: string;
74
+ action: string;
75
+ } | null;
76
+ };
77
+ type BoardCardHit = {
78
+ action: string;
79
+ cursor?: string;
68
80
  };
69
81
  type BoardCardRenderer = {
70
82
  id: string;
@@ -79,6 +91,15 @@ type BoardCardRenderer = {
79
91
  resolution?: (container: Container, item: BoardSceneItem, context: BoardRenderContext) => void;
80
92
  /** Runs on every zoom step; only update transforms and visibility. */
81
93
  zoom?: (container: Container, zoom: number) => void;
94
+ /**
95
+ * Level of detail for `renderFar`: `size` is the world-unit measure kept
96
+ * legible (default: the long edge), held against the `BoardLod[kind]` threshold.
97
+ */
98
+ lod?: {
99
+ kind: BoardLodKind;
100
+ size?: (item: BoardSceneItem) => number;
101
+ };
102
+ hitAt?: (item: BoardSceneItem, point: WorldPoint, context: BoardRenderContext) => BoardCardHit | null;
82
103
  renderFar?: (graphics: Graphics, item: BoardSceneItem, context: BoardRenderContext) => void;
83
104
  destroy?: (container: Container, context: BoardRenderContext) => void;
84
105
  };
@@ -91,4 +112,4 @@ declare function createBoardCardRendererResolver(renderers?: Iterable<BoardCardR
91
112
  /** The built-in renderers alone. */
92
113
  declare const getBoardCardRenderer: BoardCardRendererResolver;
93
114
  //#endregion
94
- export { BoardCardRenderer, BoardCardRendererResolver, BoardRenderContext, BoardRenderLabels, BoardRenderPalette, BoardScriptHost, DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer };
115
+ export { BoardCardHit, BoardCardRenderer, BoardCardRendererResolver, BoardRenderContext, BoardRenderLabels, BoardRenderPalette, BoardScriptHost, DEFAULT_BOARD_RENDER_LABELS, createBoardCardRendererResolver, getBoardCardRenderer };
@@ -1,6 +1,7 @@
1
1
  import { ensureBoardTextMeasurement } from "../text-measurement.js";
2
2
  import { audioCardRenderer } from "./audio-card-renderer.js";
3
3
  import { modelCardRenderer } from "./model-card-renderer.js";
4
+ import { mediaPlayHit } from "../media-interaction.js";
4
5
  import { arrowCardRenderer } from "./arrow-card-renderer.js";
5
6
  import { drawCardRenderer } from "./draw-card-renderer.js";
6
7
  import { effectCardRenderer } from "./effect-card-renderer.js";
@@ -21,14 +22,18 @@ const DEFAULT_BOARD_RENDER_LABELS = {
21
22
  previewUnavailable: "Preview unavailable",
22
23
  noPreview: "No preview"
23
24
  };
25
+ const playable = (renderer) => ({
26
+ ...renderer,
27
+ hitAt: mediaPlayHit
28
+ });
24
29
  const builtinCardRenderers = [
25
30
  textCardRenderer,
26
31
  imageCardRenderer,
27
- videoCardRenderer,
28
- audioCardRenderer,
29
- modelCardRenderer,
32
+ playable(videoCardRenderer),
33
+ playable(audioCardRenderer),
34
+ playable(modelCardRenderer),
30
35
  fileCardRenderer,
31
- taskCardRenderer,
36
+ playable(taskCardRenderer),
32
37
  shapeCardRenderer,
33
38
  drawCardRenderer,
34
39
  arrowCardRenderer,
@@ -1,10 +1,12 @@
1
1
  import { BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
+ import { fitTextToLines } from "../text-fit.js";
2
3
  import { syncTextResolution } from "../text-resolution.js";
3
4
  import { positionShell } from "./base-card-renderer.js";
4
5
  import { drawFarPlate } from "./far-plate.js";
5
6
  import { Container, Graphics, Sprite, Text, Texture } from "pixi.js";
6
7
  //#region src/board/render/renderers/custom-card-renderer.ts
7
8
  const partsByContainer = /* @__PURE__ */ new WeakMap();
9
+ const LABEL_LINE = 16;
8
10
  function sync(container, item, context) {
9
11
  const parts = partsByContainer.get(container);
10
12
  if (!parts) return;
@@ -39,9 +41,8 @@ function sync(container, item, context) {
39
41
  alpha: .8
40
42
  });
41
43
  parts.label.visible = !ready || Boolean(error);
42
- parts.label.text = message;
43
44
  parts.label.style.fill = error ? context.colors.rose.stroke : context.palette.muted;
44
- parts.label.style.wordWrapWidth = Math.max(40, width - 16);
45
+ fitTextToLines(parts.label, message, Math.max(1, Math.floor((height - 16) / LABEL_LINE)), Math.max(40, width - 16));
45
46
  parts.label.position.set(width / 2, height / 2);
46
47
  }
47
48
  syncTextResolution(parts.label, context.textResolution);
@@ -59,9 +60,8 @@ const customCardRenderer = {
59
60
  style: {
60
61
  fontFamily: BOARD_MONO_FONT_STACK,
61
62
  fontSize: 12,
62
- align: "center",
63
- wordWrap: true,
64
- breakWords: true
63
+ lineHeight: LABEL_LINE,
64
+ align: "center"
65
65
  },
66
66
  resolution: context.textResolution,
67
67
  roundPixels: true
@@ -1,8 +1,8 @@
1
1
  import { applyMatrix } from "../../../protocol/dist/board-layout.js";
2
- import { computeDrawBounds, createStrokeRibbonBuilder, trimDrawPoints } from "../../model/draw-geometry.js";
3
2
  import { itemAlpha, itemColor } from "../palette.js";
4
3
  import { positionShell } from "./base-card-renderer.js";
5
4
  import { drawFarStroke, farStrokeSamples } from "./far-plate.js";
5
+ import { computeDrawBounds, createStrokeRibbonBuilder, trimDrawPoints } from "../../model/draw-geometry.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();
@@ -1,14 +1,27 @@
1
1
  import { BoardFrame } from "../../../protocol/dist/board-layout.js";
2
2
  import "../../../protocol/dist/index.js";
3
+ import { BoardSceneItem } from "../../model/scene.js";
4
+ import { BoardRenderContext } from "./board-renderer-registry.js";
3
5
  import { Graphics } from "pixi.js";
4
6
  //#region src/board/render/renderers/far-plate.d.ts
7
+ type LocalRect = {
8
+ x: number;
9
+ y: number;
10
+ width: number;
11
+ height: number;
12
+ };
5
13
  type FarPlateStyle = {
6
14
  fill: number;
7
15
  fillAlpha?: number;
8
16
  accent?: number;
9
17
  accentAlpha?: number;
10
18
  };
19
+ declare function farPictureTone(item: BoardSceneItem, context: BoardRenderContext): number | undefined;
11
20
  declare function drawFarPlate(graphics: Graphics, frame: BoardFrame, style: FarPlateStyle): void;
21
+ declare function drawFarBars(graphics: Graphics, frame: BoardFrame, bars: readonly LocalRect[], style: {
22
+ color: number;
23
+ alpha: number;
24
+ }): void;
12
25
  declare function farStrokeSamples<T>(points: readonly T[]): readonly T[];
13
26
  declare function drawFarStroke(graphics: Graphics, points: ReadonlyArray<{
14
27
  x: number;
@@ -19,4 +32,4 @@ declare function drawFarStroke(graphics: Graphics, points: ReadonlyArray<{
19
32
  alpha?: number;
20
33
  }): void;
21
34
  //#endregion
22
- export { FarPlateStyle, drawFarPlate, drawFarStroke, farStrokeSamples };
35
+ export { FarPlateStyle, drawFarBars, drawFarPlate, drawFarStroke, farPictureTone, farStrokeSamples };
@@ -4,11 +4,11 @@ const FAR_STROKE_MAX_POINTS = 24;
4
4
  const ACCENT_RATIO = .14;
5
5
  const ACCENT_MIN = 2;
6
6
  const ACCENT_MAX = 10;
7
- function traceFrame(graphics, frame, inset = 0, heightOverride) {
8
- const x = frame.x + inset;
9
- const y = frame.y + inset;
10
- const width = Math.max(0, frame.width - inset * 2);
11
- const height = Math.max(0, (heightOverride ?? frame.height) - inset * 2);
7
+ function traceLocal(graphics, frame, rect) {
8
+ const x = frame.x + rect.x;
9
+ const y = frame.y + rect.y;
10
+ const width = Math.max(0, rect.width);
11
+ const height = Math.max(0, rect.height);
12
12
  if (!frame.rotation) {
13
13
  graphics.rect(x, y, width, height);
14
14
  return;
@@ -32,20 +32,43 @@ function traceFrame(graphics, frame, inset = 0, heightOverride) {
32
32
  const d = corner(x, y + height);
33
33
  graphics.moveTo(a.x, a.y).lineTo(b.x, b.y).lineTo(c.x, c.y).lineTo(d.x, d.y).closePath();
34
34
  }
35
+ function farPictureTone(item, context) {
36
+ const key = context.assetKey(item);
37
+ return (key ? context.assetTone?.(key) : null) ?? void 0;
38
+ }
35
39
  function drawFarPlate(graphics, frame, style) {
36
40
  if (frame.width <= 0 || frame.height <= 0) return;
37
- traceFrame(graphics, frame);
41
+ traceLocal(graphics, frame, {
42
+ x: 0,
43
+ y: 0,
44
+ width: frame.width,
45
+ height: frame.height
46
+ });
38
47
  graphics.fill({
39
48
  color: style.fill,
40
49
  alpha: style.fillAlpha ?? 1
41
50
  });
42
51
  if (style.accent === void 0) return;
43
- traceFrame(graphics, frame, 0, Math.min(ACCENT_MAX, Math.max(ACCENT_MIN, frame.height * ACCENT_RATIO)));
52
+ const band = Math.min(ACCENT_MAX, Math.max(ACCENT_MIN, frame.height * ACCENT_RATIO));
53
+ traceLocal(graphics, frame, {
54
+ x: 0,
55
+ y: 0,
56
+ width: frame.width,
57
+ height: band
58
+ });
44
59
  graphics.fill({
45
60
  color: style.accent,
46
61
  alpha: style.accentAlpha ?? .9
47
62
  });
48
63
  }
64
+ function drawFarBars(graphics, frame, bars, style) {
65
+ if (bars.length === 0) return;
66
+ for (const bar of bars) traceLocal(graphics, frame, bar);
67
+ graphics.fill({
68
+ color: style.color,
69
+ alpha: style.alpha
70
+ });
71
+ }
49
72
  function farStrokeSamples(points) {
50
73
  if (points.length <= FAR_STROKE_MAX_POINTS) return points;
51
74
  const step = Math.ceil(points.length / FAR_STROKE_MAX_POINTS);
@@ -70,4 +93,4 @@ function drawFarStroke(graphics, points, style) {
70
93
  });
71
94
  }
72
95
  //#endregion
73
- export { drawFarPlate, drawFarStroke, farStrokeSamples };
96
+ export { drawFarBars, drawFarPlate, drawFarStroke, farPictureTone, farStrokeSamples };
@@ -1,12 +1,14 @@
1
1
  import { BOARD_FONT_STACK, BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { fileCategory, fileStem } from "../../model/file-snapshot.js";
3
- import { fileCategoryAccent, fileMetaLine, filePreviewKind, fileTypeLabel } from "../../model/file-preview.js";
2
+ import { boardItemPreview } from "../../../protocol/dist/board-model.js";
3
+ import { boardCardDetailed } from "../lod.js";
4
4
  import { fitTextToLines } from "../text-fit.js";
5
- import { boardCardDetailed, syncTextResolution } from "../text-resolution.js";
5
+ import { syncTextResolution } from "../text-resolution.js";
6
6
  import { createCardTag, syncCardTag, zoomCardTag } from "../card-tag.js";
7
7
  import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.js";
8
8
  import { positionShell } from "./base-card-renderer.js";
9
- import { drawFarPlate } from "./far-plate.js";
9
+ import { drawFarPlate, farPictureTone } from "./far-plate.js";
10
+ import { fileCategory, fileStem } from "../../model/file-snapshot.js";
11
+ import { fileCategoryAccent, fileMetaLine, filePreviewKind, fileTypeLabel } from "../../model/file-preview.js";
10
12
  import { Container, Graphics, Sprite, Text, Texture } from "pixi.js";
11
13
  //#region src/board/render/renderers/file-card-renderer.ts
12
14
  const PADDING = 10;
@@ -26,8 +28,34 @@ const partsByContainer = /* @__PURE__ */ new WeakMap();
26
28
  function detailFor(zoom) {
27
29
  return boardCardDetailed(zoom) ? "full" : "title";
28
30
  }
29
- function coverHeight(item, height) {
30
- if (filePreviewKind(item.props.snapshot) !== "cover") return 0;
31
+ function viewOf(item) {
32
+ if (item.type === "file") {
33
+ const { src, snapshot } = item.props;
34
+ return {
35
+ src,
36
+ title: snapshot?.title || fileStem(src),
37
+ excerpt: snapshot?.excerpt ?? "",
38
+ kind: filePreviewKind(snapshot),
39
+ meta: fileMetaLine(src, snapshot?.size),
40
+ mark: fileTypeLabel(src),
41
+ category: fileCategory(src, snapshot?.mimeType)
42
+ };
43
+ }
44
+ const preview = boardItemPreview(item);
45
+ if (!preview) return null;
46
+ const label = (item.type.split(".").pop() ?? item.type).toUpperCase();
47
+ return {
48
+ src: preview.src ?? null,
49
+ title: preview.title || item.type,
50
+ excerpt: preview.excerpt ?? "",
51
+ kind: preview.cover ? "cover" : preview.excerpt ? "text" : "blank",
52
+ meta: label,
53
+ mark: label,
54
+ category: preview.src ? fileCategory(preview.src) : "other"
55
+ };
56
+ }
57
+ function coverHeight(view, height) {
58
+ if (view.kind !== "cover") return 0;
31
59
  const ideal = Math.round(height * COVER_RATIO);
32
60
  return Math.max(0, Math.min(ideal, height - MIN_BODY_FOR_COVER));
33
61
  }
@@ -46,31 +74,31 @@ function syncClip(parts, rect, style) {
46
74
  }
47
75
  function sync(container, item, context) {
48
76
  const parts = partsByContainer.get(container);
49
- if (!parts) return;
50
- syncContent(parts, item, context);
77
+ const view = viewOf(item);
78
+ if (!parts || !view) return;
79
+ syncContent(parts, item, view, context);
51
80
  for (const text of [
52
81
  parts.title,
53
82
  parts.excerpt,
54
83
  parts.typeMark
55
84
  ]) syncTextResolution(text, context.textResolution);
56
85
  }
57
- function syncContent(parts, item, context) {
86
+ function syncContent(parts, item, view, context) {
58
87
  positionShell(parts.root, item);
59
88
  const { width, height } = item.frame;
60
89
  const detail = detailFor(context.zoom);
61
90
  const elevation = cardElevation(context, item.id);
62
91
  syncCardTag(parts.tag, {
63
92
  glyph: "file",
64
- text: fileMetaLine(item.props.src, item.props.snapshot?.size),
93
+ text: view.meta,
65
94
  width
66
95
  }, context);
67
96
  const key = context.assetKey(item);
68
97
  const texture = key ? context.getTexture(key) : null;
69
98
  const coverFailed = Boolean(key && !texture && context.hasError(key));
70
- const fileState = context.fileState(item.props.src);
71
- const band = coverHeight(item, height);
72
- const kind = filePreviewKind(item.props.snapshot);
73
- const category = fileCategory(item.props.src, item.props.snapshot?.mimeType);
99
+ const fileState = view.src ? context.fileState(view.src) : "ok";
100
+ const band = coverHeight(view, height);
101
+ const { kind, category, title, excerpt, mark } = view;
74
102
  const accent = fileCategoryAccent(category, context.palette);
75
103
  const visualSig = [
76
104
  key ?? "",
@@ -129,9 +157,6 @@ function syncContent(parts, item, context) {
129
157
  parts.excerpt.visible = detail === "full";
130
158
  parts.typeMark.visible = kind === "blank";
131
159
  }
132
- const title = item.props.snapshot?.title || fileStem(item.props.src);
133
- const excerpt = item.props.snapshot?.excerpt ?? "";
134
- const mark = fileTypeLabel(item.props.src);
135
160
  const innerWidth = Math.max(1, width - 20);
136
161
  const showTypeMark = kind === "blank";
137
162
  const textSig = [
@@ -146,6 +171,7 @@ function syncContent(parts, item, context) {
146
171
  context.palette.text,
147
172
  context.palette.muted,
148
173
  context.style.font,
174
+ context.themeKey,
149
175
  accent
150
176
  ].join("|");
151
177
  if (textSig === parts.textSig) return;
@@ -186,7 +212,7 @@ function syncContent(parts, item, context) {
186
212
  }
187
213
  const fileCardRenderer = {
188
214
  id: "file-card",
189
- canRender: (item) => item.type === "file",
215
+ canRender: (item) => item.type === "file" || boardItemPreview(item) !== null,
190
216
  create: (item, context) => {
191
217
  const root = new Container();
192
218
  const plate = new Graphics();
@@ -203,8 +229,6 @@ const fileCardRenderer = {
203
229
  fontFamily: BOARD_FONT_STACK,
204
230
  fontSize: TITLE_SIZE,
205
231
  fontWeight: "600",
206
- wordWrap: true,
207
- breakWords: true,
208
232
  lineHeight: TITLE_LINE
209
233
  },
210
234
  resolution,
@@ -217,8 +241,6 @@ const fileCardRenderer = {
217
241
  fontFamily: BOARD_FONT_STACK,
218
242
  fontSize: EXCERPT_SIZE,
219
243
  fontWeight: "400",
220
- wordWrap: true,
221
- breakWords: true,
222
244
  lineHeight: EXCERPT_LINE
223
245
  },
224
246
  resolution,
@@ -254,23 +276,19 @@ const fileCardRenderer = {
254
276
  visualSig: "",
255
277
  textSig: ""
256
278
  });
257
- if (item.type === "file") sync(root, item, context);
279
+ sync(root, item, context);
258
280
  return root;
259
281
  },
260
- update: (container, item, context) => {
261
- if (item.type === "file") sync(container, item, context);
262
- },
263
- resolution: (container, item, context) => {
264
- if (item.type === "file") sync(container, item, context);
265
- },
282
+ update: sync,
283
+ resolution: sync,
266
284
  zoom: (container, zoom) => {
267
285
  const tag = partsByContainer.get(container)?.tag;
268
286
  if (tag) zoomCardTag(tag, zoom);
269
287
  },
270
288
  renderFar: (graphics, item, context) => {
271
- const category = fileCategory(item.type === "file" ? item.props.src : "", item.type === "file" ? item.props.snapshot?.mimeType : void 0);
289
+ const category = viewOf(item)?.category ?? "other";
272
290
  drawFarPlate(graphics, item.frame, {
273
- fill: context.palette.surface,
291
+ fill: farPictureTone(item, context) ?? context.palette.surface,
274
292
  fillAlpha: .96,
275
293
  accent: fileCategoryAccent(category, context.palette),
276
294
  accentAlpha: .45
@@ -1,9 +1,11 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
2
  import { itemAlpha, itemColor } from "../palette.js";
3
+ import { BOARD_FRAME_LABEL_LINE_HEIGHT, frameLabelOffset } from "../../model/text-metrics.js";
3
4
  import { syncTextResolution } from "../text-resolution.js";
4
5
  import { dashPattern, roundRectPoints, tracePolyline, trimPolyline } from "../stroke.js";
5
6
  import { createLabel, positionShell } from "./base-card-renderer.js";
6
7
  import { drawFarPlate } from "./far-plate.js";
8
+ import "../labels.js";
7
9
  import { Container, Graphics } from "pixi.js";
8
10
  //#region src/board/render/renderers/frame-card-renderer.ts
9
11
  const partsByContainer = /* @__PURE__ */ new WeakMap();
@@ -57,19 +59,24 @@ function sync(container, item, context) {
57
59
  parts.label.visible = decorated;
58
60
  const title = locked ? `🔒 ${props.label}`.trim() : props.label;
59
61
  const labelColor = style.stroke ? baseStroke : context.palette.muted;
62
+ const size = context.style.frameLabelSize;
60
63
  const textSig = [
61
64
  title,
62
65
  labelColor,
63
- context.style.font
66
+ context.style.font,
67
+ size
64
68
  ].join("|");
65
69
  if (textSig !== parts.textSig) {
66
70
  parts.textSig = textSig;
67
71
  parts.label.text = title;
68
72
  parts.label.style.fill = labelColor;
69
73
  parts.label.style.fontFamily = context.style.font;
74
+ parts.label.style.fontSize = size;
75
+ parts.label.style.lineHeight = size * BOARD_FRAME_LABEL_LINE_HEIGHT;
76
+ const offset = frameLabelOffset(size);
77
+ parts.label.position.set(offset.x, offset.y);
70
78
  }
71
79
  syncTextResolution(parts.label, context.textResolution);
72
- parts.label.position.set(4, -18);
73
80
  }
74
81
  const frameCardRenderer = {
75
82
  id: "frame-card",
@@ -80,7 +87,6 @@ const frameCardRenderer = {
80
87
  const label = createLabel("", {
81
88
  fill: context.palette.muted,
82
89
  fontFamily: BOARD_FONT_STACK,
83
- fontSize: 12,
84
90
  fontWeight: "600"
85
91
  }, context.textResolution);
86
92
  root.addChild(box, label);