@neta-art/cohub 12.3.0 → 12.4.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 (36) hide show
  1. package/README.md +14 -4
  2. package/dist/board/editor/clipboard.js +1 -1
  3. package/dist/board/editor/context.d.ts +2 -0
  4. package/dist/board/editor/creation.js +1 -1
  5. package/dist/board/editor/editor.js +8 -3
  6. package/dist/board/editor/interaction.js +6 -1
  7. package/dist/board/editor/selection.js +14 -2
  8. package/dist/board/export/index.js +1 -1
  9. package/dist/board/export/node/scripts.js +1 -1
  10. package/dist/board/export/scene.js +1 -1
  11. package/dist/board/model/asset-key.d.ts +3 -3
  12. package/dist/board/model/asset-key.js +22 -14
  13. package/dist/board/model/index.js +16 -16
  14. package/dist/board/model/items/create.js +1 -1
  15. package/dist/board/model/sampling.js +1 -1
  16. package/dist/board/model/themes.d.ts +34 -34
  17. package/dist/board/model/themes.js +34 -34
  18. package/dist/board/render/media-interaction.js +1 -1
  19. package/dist/board/render/renderers/arrow-card-renderer.js +1 -1
  20. package/dist/board/render/renderers/audio-card-renderer.js +1 -1
  21. package/dist/board/render/renderers/draw-card-renderer.js +1 -1
  22. package/dist/board/render/renderers/file-card-renderer.js +2 -2
  23. package/dist/board/render/renderers/frame-card-renderer.js +1 -1
  24. package/dist/board/render/renderers/model-card-renderer.js +3 -3
  25. package/dist/board/render/renderers/shape-card-renderer.js +1 -1
  26. package/dist/board/render/renderers/video-card-renderer.js +1 -1
  27. package/dist/board/render/script-export.js +1 -1
  28. package/dist/board/render/script-host.js +3 -3
  29. package/dist/board/replica/index.js +12 -10
  30. package/dist/board/stage/assets.js +1 -1
  31. package/dist/board/stage/stage.d.ts +4 -0
  32. package/dist/board/stage/stage.js +10 -9
  33. package/dist/board/stage/views.d.ts +1 -1
  34. package/dist/board/stage/views.js +2 -2
  35. package/dist/protocol/dist/board-patch.js +1 -1
  36. package/package.json +1 -1
package/README.md CHANGED
@@ -244,7 +244,10 @@ detail and text work reaches your Board without code changes.
244
244
  Pictures your own items show go through `itemAsset`. They share the built-in
245
245
  loader: CDN variants sized to the screen, loads ordered by where the view is
246
246
  heading, prefetch, compact copies when panned away, device budgets, one cache
247
- and exports. Call `invalidateItemAssets()` when the data it reads changes:
247
+ and exports. `src` is a Space path, resolved like an image item's, or a URL;
248
+ `fit: "cover"` sizes pictures cropped to fill their box by the short edge. Call
249
+ `invalidateItemAssets()` when the data it reads changes, and `invalidatePath`
250
+ when a file changes:
248
251
 
249
252
  ```ts
250
253
  const assets = createBoardAssetManager({
@@ -252,8 +255,8 @@ const assets = createBoardAssetManager({
252
255
  // undefined keeps the built-in rule; null shows no picture.
253
256
  itemAsset: (item) => {
254
257
  if (item.type !== "acme.order") return undefined;
255
- const cover = covers.get(item.props.orderId as string);
256
- return cover ? { url: cover, fit: "cover" } : null;
258
+ const cover = covers.get(item.props.orderId as string); // "orders/o-1.webp"
259
+ return cover ? { src: cover, fit: "cover" } : null;
257
260
  },
258
261
  });
259
262
  ```
@@ -276,7 +279,14 @@ const assets = createBoardAssetManager({
276
279
  - **Card keys.** A renderer's `hitAt(item, point, context)` returns `{ action, cursor? }`
277
280
  for keys it draws; the stage shows the cursor, passes the hovered key to renderers as
278
281
  `context.hoveredHit` and sends presses to `onHit` (return `false` to let the editor
279
- have them). Media cards report `BOARD_PLAY_MEDIA` this way.
282
+ have them). Media cards report `BOARD_PLAY_MEDIA` this way. `handlesHit(item, action)`
283
+ names the keys you act on; the rest show no cursor and go to the editor.
284
+ - **Touch.** A touch on the selected item drags it, never a port. Pass
285
+ `touchRotation: false` to `createBoardEditor` to move and resize by touch and pen
286
+ without a rotation handle.
287
+ - **DOM views.** `viewLayer: "below"` puts them under the canvas, so selection and
288
+ strokes draw over them; views there get no input. Use a theme with `imageBackground`
289
+ and paint the Board background behind the host, or the canvas covers them.
280
290
  - **Previews.** Write `preview: { title, excerpt, cover, src }` on your items so
281
291
  clients without your renderer, exports and agents show them as cards. Keep it out
282
292
  of undo with `editor.commitPatch(patch, { record: false })`.
@@ -1,6 +1,6 @@
1
1
  import { parseBoardItem } from "../../protocol/dist/board-model.js";
2
- import { BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME } from "../../protocol/dist/board.js";
3
2
  import { arrowBindings, isArrowBinding } from "../../protocol/dist/board-layout.js";
3
+ import { BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME } from "../../protocol/dist/board.js";
4
4
  import { createBoardItemId } from "../model/items/id.js";
5
5
  //#region src/board/editor/clipboard.ts
6
6
  /** How far a duplicate or repeated paste lands from its source. */
@@ -84,6 +84,8 @@ type BoardEditorOptions = {
84
84
  initialTool?: BoardToolId;
85
85
  key?: string;
86
86
  readonly?: boolean;
87
+ /** false: touch and pen move and resize the selection but never rotate it. */
88
+ touchRotation?: boolean;
87
89
  preferences?: Partial<BoardEditorPreferences>;
88
90
  onPreferencesChange?: (preferences: BoardEditorPreferences) => void;
89
91
  onCommit: (patch: BoardPatch) => void | Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import { IDENTITY_MATRIX, applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
2
- import { buildBoardScene } from "../model/scene.js";
3
2
  import { rectCenter } from "../model/geometry.js";
3
+ import { buildBoardScene } from "../model/scene.js";
4
4
  import { isShapeKind } from "../model/shape-types.js";
5
5
  import { createBoardItemId } from "../model/items/id.js";
6
6
  import { createAppBoardItem, createArrowBoardItem, createDrawBoardItem, createFileNodeForPath, createFrameBoardItem, createMediaBoardItem, createShapeBoardItem, createTaskBoardItem, createTextBoardItem } from "../model/items/create.js";
@@ -1,8 +1,8 @@
1
1
  import { clampBoardStrokeSize } from "../../protocol/dist/board-constants.js";
2
- import { buildBoardScene } from "../model/scene.js";
2
+ import { hasBoardScripts } from "../model/script-index.js";
3
3
  import { normalizeViewport } from "../model/geometry.js";
4
+ import { buildBoardScene } from "../model/scene.js";
4
5
  import { isBoardColorId } from "../model/palette.js";
5
- import { hasBoardScripts } from "../model/script-index.js";
6
6
  import { isShapeKind } from "../model/shape-types.js";
7
7
  import { createBoardToolStyles } from "../model/tool-styles.js";
8
8
  import { titleForBoardItem } from "../model/items/create.js";
@@ -96,6 +96,11 @@ function createBoardEditor(options) {
96
96
  ctx.snapshots = createSnapshotsModule(ctx);
97
97
  ctx.remote = createRemoteModule(ctx);
98
98
  const { document, query, camera, selection, creation, deletion, copy, interaction, animation, snapshots, remote } = ctx;
99
+ const transformChannels = options.touchRotation === false ? [
100
+ "scene",
101
+ "selection",
102
+ "hover"
103
+ ] : ["scene", "selection"];
99
104
  let viewStateQueued = false;
100
105
  function emitViewState() {
101
106
  viewStateQueued = false;
@@ -193,7 +198,7 @@ function createBoardEditor(options) {
193
198
  return read(["scene", "selection"], selection.bounds);
194
199
  },
195
200
  get selectionTransform() {
196
- return read(["scene", "selection"], selection.transform);
201
+ return read(transformChannels, selection.transform);
197
202
  },
198
203
  get camera() {
199
204
  return read("camera", () => state.camera);
@@ -170,6 +170,11 @@ function createInteractionModule(ctx) {
170
170
  size: arrow.size
171
171
  };
172
172
  }
173
+ function onSelectedItem(event) {
174
+ if (!canTapSelectWithHand(event.pointerType)) return false;
175
+ const item = ctx.query.itemAt(event.world);
176
+ return item !== null && state.selection.includes(item.id);
177
+ }
173
178
  function plainPrimary(event) {
174
179
  return event.button === 0 && !event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey;
175
180
  }
@@ -296,7 +301,7 @@ function createInteractionModule(ctx) {
296
301
  ctx.creation.beginTextDraft(event.world);
297
302
  return;
298
303
  }
299
- const port = connectionPortAt$1(event.world, event.pointerType);
304
+ const port = onSelectedItem(event) ? null : connectionPortAt$1(event.world, event.pointerType);
300
305
  if (port) {
301
306
  state.interaction = arrowGesture(port.point, event.world, port.itemId, port.side);
302
307
  return;
@@ -1,6 +1,7 @@
1
- import { sceneItemToItem } from "../model/scene.js";
2
1
  import { selectionBounds } from "../model/geometry.js";
2
+ import { sceneItemToItem } from "../model/scene.js";
3
3
  import { alignFrames, distributeFrames } from "./align.js";
4
+ import { canTapSelectWithHand } from "./tool.js";
4
5
  import { resolveSelectionTransform } from "./selection-transform.js";
5
6
  import { memo } from "./state.js";
6
7
  //#region src/board/editor/selection.ts
@@ -17,7 +18,18 @@ function createSelectionModule(ctx) {
17
18
  return result;
18
19
  });
19
20
  const bounds = memo(() => [items()], (selected) => selectionBounds(selected.map((item) => item.frame)));
20
- const transform = memo(() => [items(), bounds()], (selected, rect) => resolveSelectionTransform(registry, selected, rect));
21
+ const rotatesOnTouch = ctx.options.touchRotation !== false;
22
+ const transform = memo(() => [
23
+ items(),
24
+ bounds(),
25
+ rotatesOnTouch || !canTapSelectWithHand(state.hoverPointerType)
26
+ ], (selected, rect, rotates) => {
27
+ const resolved = resolveSelectionTransform(registry, selected, rect);
28
+ return resolved && !rotates ? {
29
+ ...resolved,
30
+ canRotate: false
31
+ } : resolved;
32
+ });
21
33
  function set(ids) {
22
34
  state.selection = ids.filter((id) => Boolean(state.base.items[id]));
23
35
  }
@@ -1,9 +1,9 @@
1
1
  import { buildBoardScene } from "../model/scene.js";
2
2
  import { resolveBoardAnimationCamera } from "../model/sampling.js";
3
+ import { normalizeBoardDocument, planBoardExport } from "../model/export-plan.js";
3
4
  import { parseBoardCssColor } from "../render/css-color.js";
4
5
  import { defaultBoardPalette } from "../render/palette.js";
5
6
  import { createBoardRenderSampler } from "../render/sampling.js";
6
- import { normalizeBoardDocument, planBoardExport } from "../model/export-plan.js";
7
7
  import { ensureBoardTextMeasurement } from "../render/text-measurement.js";
8
8
  import { createBoardExportScene } from "./scene.js";
9
9
  import { Rectangle, RendererType } from "pixi.js";
@@ -1,5 +1,5 @@
1
- import { buildBoardScene } from "../../model/scene.js";
2
1
  import { boardScriptScope, composeBoardScriptItems } from "../../model/script-scene.js";
2
+ import { buildBoardScene } from "../../model/scene.js";
3
3
  import { createBoardScriptModuleReader, loadBoardScriptSources } from "../../../protocol/dist/board-script-modules.js";
4
4
  import { createScriptRuntime } from "../../render/script-runtime.js";
5
5
  import { initializeBoardFonts } from "./fonts.js";
@@ -1,9 +1,9 @@
1
+ import { boardAssetKey } from "../model/asset-key.js";
1
2
  import { buildFallbackShapeColors } from "../model/palette.js";
2
3
  import { defaultBoardPalette } from "../render/palette.js";
3
4
  import { clippingAncestor, isClippingFrame, syncClipGroup } from "../render/clip.js";
4
5
  import { DEFAULT_BOARD_RENDER_LABELS, getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
5
6
  import { resolveBoardRenderStyle } from "../render/style.js";
6
- import { boardAssetKey } from "../model/asset-key.js";
7
7
  import { Container, Graphics, Sprite, TilingSprite } from "pixi.js";
8
8
  //#region src/board/export/scene.ts
9
9
  function buildContext(input) {
@@ -7,13 +7,13 @@ type BoardAssetKeySource = {
7
7
  value: string;
8
8
  fit?: "cover";
9
9
  };
10
- /** `fit` applies to images: `cover` bounds the short edge instead of the long one. */
10
+ /** `src` is a Space file path or a URL; `fit: "cover"` sizes an image by its short edge. */
11
11
  type BoardAssetRef = {
12
- url: string;
12
+ src: string;
13
13
  media?: "image" | "video";
14
14
  fit?: "contain" | "cover";
15
15
  };
16
- declare function boardAssetRefKey({ url, media, fit }: BoardAssetRef): string;
16
+ declare function boardAssetRefKey({ src, media, fit }: BoardAssetRef): string | null;
17
17
  declare function imageAssetKey(item: BoardSceneItem): string | null;
18
18
  declare function boardAssetKey(item: BoardSceneItem): string | null;
19
19
  declare function boardAssetKeySource(key: string): BoardAssetKeySource | null;
@@ -1,11 +1,18 @@
1
1
  import { mediaVariantSize, videoFrameUrl } from "../../media.js";
2
- import { boardItemPreview, parseBoardMediaSource } from "../../protocol/dist/board-model.js";
2
+ import { boardItemPreview, isSafeBoardSourcePath, parseBoardMediaSource } from "../../protocol/dist/board-model.js";
3
3
  import { featuredTaskArtifact, taskArtifactPreviewUrl } from "../../protocol/dist/board-task.js";
4
4
  import { isBoardModelItem } from "./media.js";
5
5
  //#region src/board/model/asset-key.ts
6
- function boardAssetRefKey({ url, media = "image", fit }) {
7
- if (media === "video") return `video-url:${encodeURIComponent(url)}`;
8
- return fit === "cover" ? `cover-url:${url}` : `url:${url}`;
6
+ const COVER = "cover:";
7
+ function boardAssetRefKey({ src, media = "image", fit }) {
8
+ if (!src) return null;
9
+ const source = {
10
+ kind: isSafeBoardSourcePath(src) ? "file" : "url",
11
+ value: src
12
+ };
13
+ if (media === "video") return stillKey("video", source, void 0);
14
+ const key = `${source.kind}:${source.value}`;
15
+ return fit === "cover" ? COVER + key : key;
9
16
  }
10
17
  function imageAssetKey(item) {
11
18
  if (item.type === "image") {
@@ -27,8 +34,7 @@ function imageAssetKey(item) {
27
34
  return source ? `${source.kind}:${source.value}` : null;
28
35
  }
29
36
  const STILL_MEDIA = ["video", "model"];
30
- function stillKey(media, src, mtimeMs) {
31
- const source = parseBoardMediaSource(src);
37
+ function stillKey(media, source, mtimeMs) {
32
38
  if (!source) return null;
33
39
  return source.kind === "url" ? `${media}-url:${encodeURIComponent(source.value)}` : `${media}:${encodeURIComponent(source.value)}:${mtimeMs ?? "unknown"}`;
34
40
  }
@@ -42,8 +48,8 @@ function taskPreviewKey(item) {
42
48
  }
43
49
  function boardAssetKey(item) {
44
50
  if (item.type === "task") return taskPreviewKey(item);
45
- if (item.type === "video") return stillKey("video", item.props.src, item.props.snapshot?.mtimeMs);
46
- if (item.type === "file" && isBoardModelItem(item)) return stillKey("model", item.props.src, item.props.snapshot?.mtimeMs);
51
+ if (item.type === "video") return stillKey("video", parseBoardMediaSource(item.props.src), item.props.snapshot?.mtimeMs);
52
+ if (item.type === "file" && isBoardModelItem(item)) return stillKey("model", parseBoardMediaSource(item.props.src), item.props.snapshot?.mtimeMs);
47
53
  return imageAssetKey(item);
48
54
  }
49
55
  function boardAssetKeySource(key) {
@@ -53,6 +59,14 @@ function boardAssetKeySource(key) {
53
59
  if (separator < 0) return null;
54
60
  base = key.slice(separator + 1);
55
61
  }
62
+ if (!base.startsWith(COVER)) return sourceOf(base);
63
+ const source = sourceOf(base.slice(6));
64
+ return source?.media === "image" ? {
65
+ ...source,
66
+ fit: "cover"
67
+ } : null;
68
+ }
69
+ function sourceOf(base) {
56
70
  try {
57
71
  for (const media of STILL_MEDIA) {
58
72
  if (base.startsWith(`${media}-url:`)) return {
@@ -82,12 +96,6 @@ function boardAssetKeySource(key) {
82
96
  media: "image",
83
97
  value: base.slice(4)
84
98
  };
85
- if (base.startsWith("cover-url:")) return {
86
- kind: "url",
87
- media: "image",
88
- value: base.slice(10),
89
- fit: "cover"
90
- };
91
99
  return null;
92
100
  }
93
101
  function boardTexturePixels(item, scale) {
@@ -1,36 +1,36 @@
1
1
  import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "../../protocol/dist/board-constants.js";
2
2
  import { isPublicBoardRemoteAddress, normalizeBoardRemoteUrl } from "../../protocol/dist/board-url.js";
3
3
  import { BOARD_ANCHOR_SIDES, BOARD_ARROW_ROUTES, BOARD_CAMERA_TARGET, BOARD_COLOR_TOKENS, BOARD_DASHES, BOARD_DERIVED_SIZE_TYPES, BOARD_EFFECT_KINDS, BOARD_EFFECT_KIND_INFO, BOARD_ENTER_PRESETS, BOARD_EXTENSION_TYPE_PATTERN, BOARD_GRID_DEFAULT_SIZE, BOARD_GRID_MAX_SIZE, BOARD_GRID_MIN_SIZE, BOARD_ID_MAX_LENGTH, BOARD_ITEM_SCHEMAS, BOARD_ITEM_TYPES, BOARD_PLAY_MODES, BOARD_SHAPE_GEOMETRIES, BOARD_TASK_ARTIFACT_LIMIT, BOARD_TEXT_ALIGNS, BoardAnimationHeaderSchema, BoardAnimationSchema, BoardArrowAnchorSchema, BoardArrowBindingSchema, BoardArrowEndSchema, BoardArrowItemSchema, BoardAudioItemSchema, BoardBackgroundSchema, BoardColorSchema, BoardCropSchema, BoardCustomItemSchema, BoardDrawItemSchema, BoardDrawPointSchema, BoardEaseSchema, BoardEffectItemSchema, BoardExtensionItemSchema, BoardFileItemSchema, BoardFrameItemSchema, BoardIdSchema, BoardImageItemSchema, BoardItemPreviewSchema, BoardKeySchema, BoardKeyframeSchema, BoardMarkerSchema, BoardMediaOriginSchema, BoardMediaSnapshotSchema, BoardMediaSourceSchema, BoardPatchSchema, BoardScriptSchema, BoardSettingsSchema, BoardShapeItemSchema, BoardSizeSchema, BoardStyleSchema, BoardTaskArtifactSchema, BoardTaskItemSchema, BoardTaskSnapshotSchema, BoardTextItemSchema, BoardTrackSchema, BoardVec2Schema, BoardVideoItemSchema, boardItemPreview, boardItemSchema, emptyBoardDocument, hasAuthoredSize, isBoardColorString, isBoardEase, isBuiltinItem, isBuiltinItemType, isEmptyBoardDelta, isFileBackedItem, isMediaItem, isSafeBoardSourcePath, parseBoardItem, parseBoardMediaSource } from "../../protocol/dist/board-model.js";
4
- import { isBoardPath, parseBoardManifest, serializeBoardManifest } from "../../protocol/dist/board.js";
5
4
  import { BOARD_TASK_SOURCE_PREFIX, boardTaskSource, featuredTaskArtifact, rankedTaskArtifacts, taskArtifactPreviewUrl, taskArtifacts, taskRunArtifacts, taskRunToBoardTaskSnapshot, withObservedArtifactFacts } from "../../protocol/dist/board-task.js";
6
5
  import { IDENTITY_MATRIX, adoptBoardNaturalSize, anchorPoint, applyMatrix, arrowBindings, autoAnchorSide, bendControl, clampBoardFontSize, createBoardLayout, createDocumentLayout, drawPointsBounds, drawSampleRadius, estimateTextWidth, fitBoardMediaSize, framePoint, invertMatrix, isArrowBinding, layoutBoardText, multiplyMatrix, pointsRect, rotateAround, scaleVector, setBoardTextLayouter, sideAnchor } from "../../protocol/dist/board-layout.js";
7
6
  import { applyBoardDelta, applyBoardPatch, applyBoardPatchToDocument, boardPatchTouches, createDocumentState, diffBoardDocuments, diffMergePatch, isEmptyBoardPatch, listBoardProperties, mergePatch, parseBoardDocument, pruneBoardTrack, resolveBoardProperty, trackReferences } from "../../protocol/dist/board-patch.js";
7
+ import { isBoardPath, parseBoardManifest, serializeBoardManifest } from "../../protocol/dist/board.js";
8
8
  import { BOARD_SCHEMA_TARGETS, boardJsonSchema, boardSchemaOverview } from "../../protocol/dist/board-schema.js";
9
- import { applyBoardEvaluation, boardAnimationTime, boardDocumentAt, boardEase, compileBoardAnimations, evaluateBoardAnimations, parseHexColor, sampleBoardTrack } from "./animation.js";
10
- import { buildBoardScene, orderBoardItems, placeItem, refreshBoardScene, sceneItemToItem, sceneItemsToRecord, toSceneItem } from "./scene.js";
11
- import { CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, VIEWPORT_MARGIN_RATIO, angleFromCenter, cameraForFocus, cameraForRect, cameraForState, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, normalizedPoint, panBy, pointToWorld, pointsBounds, radToDeg, rectCenter, rectContainsPoint, rectForCameraFocus, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenOffset, screenPoint, screenToWorld, selectionBounds, stableCullRect, unionRects, visibleWorldRect, worldOffset, worldPoint, worldRect, worldToScreen, zoomAround } from "./geometry.js";
12
- import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "./sampling.js";
13
- import { BOARD_THEME_IDS } from "./themes.js";
14
- import { BOARD_COLORS, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor, resolveItemColor } from "./palette.js";
15
- import { ARROW_BINDING_GAP, arrowHitRadius, arrowPathBounds, distanceToArrow, pathMidpoint, pathPointAt, resolveAnchor, resolveArrow, resolveSceneArrow } from "./arrow-geometry.js";
16
- import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./export-plan.js";
17
- import { BOARD_FRAME_LABEL_LINE_HEIGHT, BOARD_FRAME_LABEL_SIZE, SHAPE_LABEL_PADDING, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardEditableText, boardFontFamily, frameLabelHitRect, frameLabelOffset, layoutShapeLabel } from "./text-metrics.js";
18
- import { boardModelFormat, getMediaExtension, getMediaResourceTitle, inferBoardMediaKind, isBoardModelItem } from "./media.js";
19
- import { FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, buildCodeExcerpt, buildFileExcerpt, buildFileSnapshot, fileBaseName, fileCategory, fileStem, readCoverFromFrontmatter, readFrontmatterScalars, readTitleFromFrontmatter, resolveCoverRef, resolveFileTitle, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./file-snapshot.js";
20
- import { availabilityFromError, fileCategoryAccent, fileMetaLine, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot } from "./file-preview.js";
21
- import { buildStrokeOutline, buildStrokeRibbonGeometry, computeDrawBounds, createStrokeRibbonBuilder, distanceToStroke, isStrokeCorner, sampleRadius, simplifyDrawIndices, trimDrawPoints } from "./draw-geometry.js";
9
+ import { placeBoardOverlay } from "./overlay-placement.js";
22
10
  import { boardScriptItems, hasBoardScripts } from "./script-index.js";
11
+ import { CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, VIEWPORT_MARGIN_RATIO, angleFromCenter, cameraForFocus, cameraForRect, cameraForState, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, normalizedPoint, panBy, pointToWorld, pointsBounds, radToDeg, rectCenter, rectContainsPoint, rectForCameraFocus, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenOffset, screenPoint, screenToWorld, selectionBounds, stableCullRect, unionRects, visibleWorldRect, worldOffset, worldPoint, worldRect, worldToScreen, zoomAround } from "./geometry.js";
23
12
  import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, scriptTemporaryPrefix, validateBoardScriptCommit, validateBoardScriptOutput } from "./script-scene.js";
24
13
  import { boardScriptHitVisible, boardScriptTarget, resolveBoardScriptHit } from "./script-hit.js";
25
- import { BOARD_THUMBNAIL_EDGE, boardAssetKey, boardAssetKeySource, boardAssetRefKey, boardTextureEdge, boardTexturePixels, imageAssetKey } from "./asset-key.js";
26
- import { placeBoardOverlay } from "./overlay-placement.js";
27
14
  import { BOARD_SCRIPT_API } from "./script-api.js";
28
15
  import { BOARD_SCRIPT_DRAWING_EXAMPLE } from "./script-example.js";
16
+ import { applyBoardEvaluation, boardAnimationTime, boardDocumentAt, boardEase, compileBoardAnimations, evaluateBoardAnimations, parseHexColor, sampleBoardTrack } from "./animation.js";
17
+ import { buildBoardScene, orderBoardItems, placeItem, refreshBoardScene, sceneItemToItem, sceneItemsToRecord, toSceneItem } from "./scene.js";
18
+ import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "./sampling.js";
29
19
  import { boardPathTrack, boardSequence, boardSequencePatch } from "./authoring.js";
30
20
  import { BOARD_PRESET_NAMES, boardNestedAnimation, boardNestedAnimationTrack, boardPresetTracks, isBoardPresetName, listBoardPresets } from "./presets.js";
21
+ import { ARROW_BINDING_GAP, arrowHitRadius, arrowPathBounds, distanceToArrow, pathMidpoint, pathPointAt, resolveAnchor, resolveArrow, resolveSceneArrow } from "./arrow-geometry.js";
22
+ import { buildStrokeOutline, buildStrokeRibbonGeometry, computeDrawBounds, createStrokeRibbonBuilder, distanceToStroke, isStrokeCorner, sampleRadius, simplifyDrawIndices, trimDrawPoints } from "./draw-geometry.js";
31
23
  import { appendBoardDrawSamples, quantizeDrawCoordinate } from "./draw-input.js";
24
+ import { boardModelFormat, getMediaExtension, getMediaResourceTitle, inferBoardMediaKind, isBoardModelItem } from "./media.js";
25
+ import { BOARD_THUMBNAIL_EDGE, boardAssetKey, boardAssetKeySource, boardAssetRefKey, boardTextureEdge, boardTexturePixels, imageAssetKey } from "./asset-key.js";
32
26
  import { BOARD_EXPORT_TEXTURE_BYTES, boardTextureBytes, selectBoardExportAssets } from "./export-assets.js";
27
+ import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./export-plan.js";
28
+ import { FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, buildCodeExcerpt, buildFileExcerpt, buildFileSnapshot, fileBaseName, fileCategory, fileStem, readCoverFromFrontmatter, readFrontmatterScalars, readTitleFromFrontmatter, resolveCoverRef, resolveFileTitle, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./file-snapshot.js";
29
+ import { availabilityFromError, fileCategoryAccent, fileMetaLine, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot } from "./file-preview.js";
30
+ import { BOARD_THEME_IDS } from "./themes.js";
31
+ import { BOARD_COLORS, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor, resolveItemColor } from "./palette.js";
33
32
  import { SHAPE_KINDS, isShapeKind } from "./shape-types.js";
33
+ import { BOARD_FRAME_LABEL_LINE_HEIGHT, BOARD_FRAME_LABEL_SIZE, SHAPE_LABEL_PADDING, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardEditableText, boardFontFamily, frameLabelHitRect, frameLabelOffset, layoutShapeLabel } from "./text-metrics.js";
34
34
  import { DEFAULT_BOARD_TOOL_STYLES, createBoardToolStyles } from "./tool-styles.js";
35
35
  import { clientToLocal, elementClientToLocal } from "./client-geometry.js";
36
36
  import { boardMediaTarget, probeBoardMediaSize, settleBoardMediaSizes } from "./media-sizes.js";
@@ -3,10 +3,10 @@ import { BoardMediaOriginSchema, parseBoardItem } from "../../../protocol/dist/b
3
3
  import { featuredTaskArtifact } from "../../../protocol/dist/board-task.js";
4
4
  import { fitBoardMediaSize, pointsRect } from "../../../protocol/dist/board-layout.js";
5
5
  import "../geometry.js";
6
+ import { quantizeDrawCoordinate } from "../draw-input.js";
6
7
  import { boardModelFormat, getMediaResourceTitle, inferBoardMediaKind } from "../media.js";
7
8
  import { fileStem } from "../file-snapshot.js";
8
9
  import { filePreviewKind } from "../file-preview.js";
9
- import { quantizeDrawCoordinate } from "../draw-input.js";
10
10
  import { DEFAULT_BOARD_TOOL_STYLES } from "../tool-styles.js";
11
11
  import { createBoardItemId } from "./id.js";
12
12
  //#region src/board/model/items/create.ts
@@ -1,7 +1,7 @@
1
1
  import { arrowBindings } from "../../protocol/dist/board-layout.js";
2
+ import { cameraForFocus, cameraForState } from "./geometry.js";
2
3
  import { applyBoardEvaluation, boardAnimationTime, compileBoardAnimations, evaluateBoardAnimations } from "./animation.js";
3
4
  import { buildBoardScene } from "./scene.js";
4
- import { cameraForFocus, cameraForState } from "./geometry.js";
5
5
  //#region src/board/model/sampling.ts
6
6
  function createBoardAnimationSampler(document, animation, options = {}) {
7
7
  const selected = animation ? document.animations[animation] : void 0;
@@ -258,12 +258,12 @@ declare const BOARD_THEME_DATA: {
258
258
  readonly colorScheme: "dark";
259
259
  readonly palette: {
260
260
  readonly bg: 329221;
261
- readonly surface: 2039072;
262
- readonly hover: 1842202;
261
+ readonly surface: 1249814;
262
+ readonly hover: 1973788;
263
263
  readonly border: 1842202;
264
264
  readonly brand: 3900150;
265
- readonly text: 15920612;
266
- readonly muted: 9999759;
265
+ readonly text: 16314853;
266
+ readonly muted: 7630695;
267
267
  readonly rare: 9235170;
268
268
  readonly epic: 7266776;
269
269
  readonly legendary: 15449187;
@@ -272,47 +272,47 @@ declare const BOARD_THEME_DATA: {
272
272
  readonly brand: {
273
273
  readonly stroke: 15524306;
274
274
  readonly fill: 15524306;
275
- readonly label: 15920612;
275
+ readonly label: 16314853;
276
276
  };
277
277
  readonly neutral: {
278
- readonly stroke: 15920612;
279
- readonly fill: 15920612;
280
- readonly label: 15920612;
278
+ readonly stroke: 15524306;
279
+ readonly fill: 15524306;
280
+ readonly label: 16314853;
281
281
  };
282
282
  readonly black: {
283
283
  readonly stroke: 0;
284
284
  readonly fill: 0;
285
- readonly label: 15920612;
285
+ readonly label: 16314853;
286
286
  };
287
287
  readonly white: {
288
288
  readonly stroke: 16777215;
289
289
  readonly fill: 16777215;
290
- readonly label: 15920612;
290
+ readonly label: 16314853;
291
291
  };
292
292
  readonly blue: {
293
293
  readonly stroke: 9235170;
294
294
  readonly fill: 9235170;
295
- readonly label: 15920612;
295
+ readonly label: 16314853;
296
296
  };
297
297
  readonly green: {
298
298
  readonly stroke: 8177036;
299
299
  readonly fill: 8177036;
300
- readonly label: 15920612;
300
+ readonly label: 16314853;
301
301
  };
302
302
  readonly amber: {
303
303
  readonly stroke: 15449187;
304
304
  readonly fill: 15449187;
305
- readonly label: 15920612;
305
+ readonly label: 16314853;
306
306
  };
307
307
  readonly violet: {
308
308
  readonly stroke: 11971327;
309
309
  readonly fill: 11971327;
310
- readonly label: 15920612;
310
+ readonly label: 16314853;
311
311
  };
312
312
  readonly rose: {
313
313
  readonly stroke: 15562341;
314
314
  readonly fill: 15562341;
315
- readonly label: 15920612;
315
+ readonly label: 16314853;
316
316
  };
317
317
  };
318
318
  readonly style: {
@@ -327,8 +327,8 @@ declare const BOARD_THEME_DATA: {
327
327
  readonly palette: {
328
328
  readonly bg: 16185078;
329
329
  readonly surface: 16777215;
330
- readonly hover: 15461355;
331
- readonly border: 14935011;
330
+ readonly hover: 16185078;
331
+ readonly border: 15527149;
332
332
  readonly brand: 1824230;
333
333
  readonly text: 1447704;
334
334
  readonly muted: 7566452;
@@ -409,13 +409,13 @@ declare const BOARD_THEME_DATA: {
409
409
  readonly "neta-pixel-dark": {
410
410
  readonly colorScheme: "dark";
411
411
  readonly palette: {
412
- readonly bg: 1447704;
413
- readonly surface: 2631979;
414
- readonly hover: 3224115;
415
- readonly border: 3618875;
412
+ readonly bg: 1118739;
413
+ readonly surface: 1842463;
414
+ readonly hover: 2237220;
415
+ readonly border: 2763565;
416
416
  readonly brand: 1824230;
417
- readonly text: 15921907;
418
- readonly muted: 9408656;
417
+ readonly text: 16185078;
418
+ readonly muted: 9079436;
419
419
  readonly rare: 1824230;
420
420
  readonly epic: 1824230;
421
421
  readonly legendary: 16766287;
@@ -424,47 +424,47 @@ declare const BOARD_THEME_DATA: {
424
424
  readonly brand: {
425
425
  readonly stroke: 16185078;
426
426
  readonly fill: 16185078;
427
- readonly label: 15921907;
427
+ readonly label: 16185078;
428
428
  };
429
429
  readonly neutral: {
430
- readonly stroke: 9408656;
431
- readonly fill: 9408656;
432
- readonly label: 15921907;
430
+ readonly stroke: 9079436;
431
+ readonly fill: 9079436;
432
+ readonly label: 16185078;
433
433
  };
434
434
  readonly black: {
435
435
  readonly stroke: 0;
436
436
  readonly fill: 0;
437
- readonly label: 15921907;
437
+ readonly label: 16185078;
438
438
  };
439
439
  readonly white: {
440
440
  readonly stroke: 16777215;
441
441
  readonly fill: 16777215;
442
- readonly label: 15921907;
442
+ readonly label: 16185078;
443
443
  };
444
444
  readonly blue: {
445
445
  readonly stroke: 6010853;
446
446
  readonly fill: 6010853;
447
- readonly label: 15921907;
447
+ readonly label: 16185078;
448
448
  };
449
449
  readonly green: {
450
450
  readonly stroke: 9683613;
451
451
  readonly fill: 9683613;
452
- readonly label: 15921907;
452
+ readonly label: 16185078;
453
453
  };
454
454
  readonly amber: {
455
455
  readonly stroke: 14264410;
456
456
  readonly fill: 14264410;
457
- readonly label: 15921907;
457
+ readonly label: 16185078;
458
458
  };
459
459
  readonly violet: {
460
460
  readonly stroke: 11441117;
461
461
  readonly fill: 11441117;
462
- readonly label: 15921907;
462
+ readonly label: 16185078;
463
463
  };
464
464
  readonly rose: {
465
465
  readonly stroke: 15043210;
466
466
  readonly fill: 15043210;
467
- readonly label: 15921907;
467
+ readonly label: 16185078;
468
468
  };
469
469
  };
470
470
  readonly style: {
@@ -265,12 +265,12 @@ const BOARD_THEME_DATA = {
265
265
  colorScheme: "dark",
266
266
  palette: {
267
267
  bg: 329221,
268
- surface: 2039072,
269
- hover: 1842202,
268
+ surface: 1249814,
269
+ hover: 1973788,
270
270
  border: 1842202,
271
271
  brand: 3900150,
272
- text: 15920612,
273
- muted: 9999759,
272
+ text: 16314853,
273
+ muted: 7630695,
274
274
  rare: 9235170,
275
275
  epic: 7266776,
276
276
  legendary: 15449187
@@ -279,47 +279,47 @@ const BOARD_THEME_DATA = {
279
279
  brand: {
280
280
  stroke: 15524306,
281
281
  fill: 15524306,
282
- label: 15920612
282
+ label: 16314853
283
283
  },
284
284
  neutral: {
285
- stroke: 15920612,
286
- fill: 15920612,
287
- label: 15920612
285
+ stroke: 15524306,
286
+ fill: 15524306,
287
+ label: 16314853
288
288
  },
289
289
  black: {
290
290
  stroke: 0,
291
291
  fill: 0,
292
- label: 15920612
292
+ label: 16314853
293
293
  },
294
294
  white: {
295
295
  stroke: 16777215,
296
296
  fill: 16777215,
297
- label: 15920612
297
+ label: 16314853
298
298
  },
299
299
  blue: {
300
300
  stroke: 9235170,
301
301
  fill: 9235170,
302
- label: 15920612
302
+ label: 16314853
303
303
  },
304
304
  green: {
305
305
  stroke: 8177036,
306
306
  fill: 8177036,
307
- label: 15920612
307
+ label: 16314853
308
308
  },
309
309
  amber: {
310
310
  stroke: 15449187,
311
311
  fill: 15449187,
312
- label: 15920612
312
+ label: 16314853
313
313
  },
314
314
  violet: {
315
315
  stroke: 11971327,
316
316
  fill: 11971327,
317
- label: 15920612
317
+ label: 16314853
318
318
  },
319
319
  rose: {
320
320
  stroke: 15562341,
321
321
  fill: 15562341,
322
- label: 15920612
322
+ label: 16314853
323
323
  }
324
324
  },
325
325
  style: {
@@ -332,8 +332,8 @@ const BOARD_THEME_DATA = {
332
332
  palette: {
333
333
  bg: 16185078,
334
334
  surface: 16777215,
335
- hover: 15461355,
336
- border: 14935011,
335
+ hover: 16185078,
336
+ border: 15527149,
337
337
  brand: 1824230,
338
338
  text: 1447704,
339
339
  muted: 7566452,
@@ -414,13 +414,13 @@ const BOARD_THEME_DATA = {
414
414
  "neta-pixel-dark": {
415
415
  colorScheme: "dark",
416
416
  palette: {
417
- bg: 1447704,
418
- surface: 2631979,
419
- hover: 3224115,
420
- border: 3618875,
417
+ bg: 1118739,
418
+ surface: 1842463,
419
+ hover: 2237220,
420
+ border: 2763565,
421
421
  brand: 1824230,
422
- text: 15921907,
423
- muted: 9408656,
422
+ text: 16185078,
423
+ muted: 9079436,
424
424
  rare: 1824230,
425
425
  epic: 1824230,
426
426
  legendary: 16766287
@@ -429,47 +429,47 @@ const BOARD_THEME_DATA = {
429
429
  brand: {
430
430
  stroke: 16185078,
431
431
  fill: 16185078,
432
- label: 15921907
432
+ label: 16185078
433
433
  },
434
434
  neutral: {
435
- stroke: 9408656,
436
- fill: 9408656,
437
- label: 15921907
435
+ stroke: 9079436,
436
+ fill: 9079436,
437
+ label: 16185078
438
438
  },
439
439
  black: {
440
440
  stroke: 0,
441
441
  fill: 0,
442
- label: 15921907
442
+ label: 16185078
443
443
  },
444
444
  white: {
445
445
  stroke: 16777215,
446
446
  fill: 16777215,
447
- label: 15921907
447
+ label: 16185078
448
448
  },
449
449
  blue: {
450
450
  stroke: 6010853,
451
451
  fill: 6010853,
452
- label: 15921907
452
+ label: 16185078
453
453
  },
454
454
  green: {
455
455
  stroke: 9683613,
456
456
  fill: 9683613,
457
- label: 15921907
457
+ label: 16185078
458
458
  },
459
459
  amber: {
460
460
  stroke: 14264410,
461
461
  fill: 14264410,
462
- label: 15921907
462
+ label: 16185078
463
463
  },
464
464
  violet: {
465
465
  stroke: 11441117,
466
466
  fill: 11441117,
467
- label: 15921907
467
+ label: 16185078
468
468
  },
469
469
  rose: {
470
470
  stroke: 15043210,
471
471
  fill: 15043210,
472
- label: 15921907
472
+ label: 16185078
473
473
  }
474
474
  },
475
475
  style: {
@@ -1,7 +1,7 @@
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";
4
3
  import { isBoardModelItem } from "../model/media.js";
4
+ import { boardCardDetailed } from "./lod.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
@@ -1,6 +1,6 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { itemAlpha, itemColor } from "../palette.js";
3
2
  import { resolveSceneArrow } from "../../model/arrow-geometry.js";
3
+ import { itemAlpha, itemColor } from "../palette.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";
@@ -1,8 +1,8 @@
1
+ import { getMediaResourceTitle } from "../../model/media.js";
1
2
  import { boardCardDetailed } from "../lod.js";
2
3
  import { fitTextToWidth } from "../text-fit.js";
3
4
  import { syncTextResolution } from "../text-resolution.js";
4
5
  import { formatBoardDuration } from "../card-tag.js";
5
- import { getMediaResourceTitle } from "../../model/media.js";
6
6
  import { drawAudioWaveform } from "../audio-waveform.js";
7
7
  import { cardElevation, drawCardSurface } from "../surface.js";
8
8
  import { positionShell } from "./base-card-renderer.js";
@@ -1,8 +1,8 @@
1
1
  import { applyMatrix } from "../../../protocol/dist/board-layout.js";
2
+ import { computeDrawBounds, createStrokeRibbonBuilder, trimDrawPoints } from "../../model/draw-geometry.js";
2
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 { 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,5 +1,7 @@
1
1
  import { BOARD_FONT_STACK, BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
2
  import { boardItemPreview } from "../../../protocol/dist/board-model.js";
3
+ import { fileCategory, fileStem } from "../../model/file-snapshot.js";
4
+ import { fileCategoryAccent, fileMetaLine, filePreviewKind, fileTypeLabel } from "../../model/file-preview.js";
3
5
  import { boardCardDetailed } from "../lod.js";
4
6
  import { fitTextToLines } from "../text-fit.js";
5
7
  import { syncTextResolution } from "../text-resolution.js";
@@ -7,8 +9,6 @@ import { createCardTag, syncCardTag, zoomCardTag } from "../card-tag.js";
7
9
  import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.js";
8
10
  import { positionShell } from "./base-card-renderer.js";
9
11
  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";
12
12
  import { Container, Graphics, Sprite, Text, Texture } from "pixi.js";
13
13
  //#region src/board/render/renderers/file-card-renderer.ts
14
14
  const PADDING = 10;
@@ -1,6 +1,6 @@
1
1
  import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
2
- import { itemAlpha, itemColor } from "../palette.js";
3
2
  import { BOARD_FRAME_LABEL_LINE_HEIGHT, frameLabelOffset } from "../../model/text-metrics.js";
3
+ import { itemAlpha, itemColor } from "../palette.js";
4
4
  import { syncTextResolution } from "../text-resolution.js";
5
5
  import { dashPattern, roundRectPoints, tracePolyline, trimPolyline } from "../stroke.js";
6
6
  import { createLabel, positionShell } from "./base-card-renderer.js";
@@ -1,12 +1,12 @@
1
+ import { isBoardModelItem } from "../../model/media.js";
2
+ import { fileStem } from "../../model/file-snapshot.js";
3
+ import { fileMetaLine } from "../../model/file-preview.js";
1
4
  import { boardCardDetailed } from "../lod.js";
2
5
  import { createCardTag, syncCardTag, traceCube, zoomCardTag } from "../card-tag.js";
3
- import { isBoardModelItem } from "../../model/media.js";
4
6
  import { cardElevation, containRect, drawCardSurface } from "../surface.js";
5
7
  import { positionShell } from "./base-card-renderer.js";
6
8
  import { drawFarPlate, farPictureTone } from "./far-plate.js";
7
9
  import { drawModelKey } from "./media-key.js";
8
- import { fileStem } from "../../model/file-snapshot.js";
9
- import { fileMetaLine } from "../../model/file-preview.js";
10
10
  import { Container, Graphics, Sprite, Texture } from "pixi.js";
11
11
  //#region src/board/render/renderers/model-card-renderer.ts
12
12
  const partsByContainer = /* @__PURE__ */ new WeakMap();
@@ -1,6 +1,6 @@
1
1
  import { worldPoint } from "../../model/geometry.js";
2
- import { itemAlpha, itemColor } from "../palette.js";
3
2
  import { layoutShapeLabel } from "../../model/text-metrics.js";
3
+ import { itemAlpha, itemColor } from "../palette.js";
4
4
  import { boardTextStyle, cssBaselineShift } from "../text-measurement.js";
5
5
  import { syncTextResolution } from "../text-resolution.js";
6
6
  import { dashPattern, roundRectPoints, tracePolyline, trimPolyline } from "../stroke.js";
@@ -1,6 +1,6 @@
1
+ import { getMediaResourceTitle } from "../../model/media.js";
1
2
  import { boardCardDetailed } from "../lod.js";
2
3
  import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
3
- import { getMediaResourceTitle } from "../../model/media.js";
4
4
  import { cardElevation, containRect, drawCardSurface, fillCardPicture } from "../surface.js";
5
5
  import { positionShell } from "./base-card-renderer.js";
6
6
  import { drawFarPlate, farPictureTone } from "./far-plate.js";
@@ -1,5 +1,5 @@
1
- import { buildBoardScene } from "../model/scene.js";
2
1
  import { composeBoardScriptItems } from "../model/script-scene.js";
2
+ import { buildBoardScene } from "../model/scene.js";
3
3
  import { createBoardScriptHost } from "./script-host.js";
4
4
  //#region src/board/render/script-export.ts
5
5
  async function prepareBrowserBoardScripts(document, time, readModule, snapshots) {
@@ -1,9 +1,9 @@
1
- import { getBoardResolution } from "./text-resolution.js";
2
- import { BoardScriptTexture } from "./script-texture.js";
3
- import { scriptResolution } from "./script-resolution.js";
4
1
  import { boardScriptItems } from "../model/script-index.js";
5
2
  import { boardScriptScope } from "../model/script-scene.js";
6
3
  import { boardScriptHitVisible, resolveBoardScriptHit } from "../model/script-hit.js";
4
+ import { getBoardResolution } from "./text-resolution.js";
5
+ import { BoardScriptTexture } from "./script-texture.js";
6
+ import { scriptResolution } from "./script-resolution.js";
7
7
  import { createBoardScriptModuleReader, loadBoardScriptSources } from "../../protocol/dist/board-script-modules.js";
8
8
  import { boardScriptFrameSource } from "./script-sandbox.js";
9
9
  //#region src/board/render/script-host.ts
@@ -233,6 +233,17 @@ function createBoardReplica(options) {
233
233
  function onOnline() {
234
234
  if (pending.length || readError || writeError) retry();
235
235
  }
236
+ async function restore() {
237
+ const [cached, stored] = await Promise.all([storage.readDocument().catch(() => null), storage.listPending().catch(() => [])]);
238
+ if (disposed) return;
239
+ const known = new Set(stored.map((entry) => entry.mutationId));
240
+ pending = [...stored, ...pending.filter((entry) => !known.has(entry.mutationId))];
241
+ restored = true;
242
+ const parsed = cached && !server ? parseBoardDocument(cached.document) : null;
243
+ if (cached && parsed?.ok) adoptServer(parsed.document, cached.version, false);
244
+ else recompute();
245
+ emit();
246
+ }
236
247
  function receivePlayback(next) {
237
248
  playbackRevision += 1;
238
249
  playback = next;
@@ -249,16 +260,7 @@ function createBoardReplica(options) {
249
260
  async start() {
250
261
  unsubscribeRemote ??= subscribeRemote();
251
262
  globalThis.addEventListener?.("online", onOnline);
252
- const [cached, stored] = await Promise.all([storage.readDocument().catch(() => null), storage.listPending().catch(() => [])]);
253
- if (disposed) return;
254
- const known = new Set(stored.map((entry) => entry.mutationId));
255
- pending = [...stored, ...pending.filter((entry) => !known.has(entry.mutationId))];
256
- restored = true;
257
- const parsed = cached && !server ? parseBoardDocument(cached.document) : null;
258
- if (cached && parsed?.ok) adoptServer(parsed.document, cached.version, false);
259
- else recompute();
260
- emit();
261
- await refresh();
263
+ await Promise.all([restore(), refresh()]);
262
264
  await flush();
263
265
  },
264
266
  apply(patch) {
@@ -1,8 +1,8 @@
1
1
  import { probeMediaInfo } from "../../protocol/dist/core/media.js";
2
2
  import { MEDIA_VARIANT_SIZES, imageVariantUrl, variantSource } from "../../media.js";
3
3
  import { boardModelFormat } from "../model/media.js";
4
- import { loadVideoThumbnailTexture, videoTextureNaturalSize } from "../render/video-thumbnail.js";
5
4
  import { boardAssetKey, boardAssetKeySource, boardAssetRefKey } from "../model/asset-key.js";
5
+ import { loadVideoThumbnailTexture, videoTextureNaturalSize } from "../render/video-thumbnail.js";
6
6
  import { planLruTrim } from "./lru.js";
7
7
  import { defaultBoardDeviceBudget } from "./device.js";
8
8
  import { scheduleBoardIdle } from "./idle.js";
@@ -35,6 +35,8 @@ type BoardStageOptions = {
35
35
  source: BoardAssetSource;
36
36
  renderers?: BoardCardRendererResolver;
37
37
  views?: readonly BoardItemView[];
38
+ /** `below` needs a theme with `imageBackground`; views there get no input. */
39
+ viewLayer?: "above" | "below";
38
40
  theme?: () => BoardStageTheme;
39
41
  labels?: () => BoardRenderLabels;
40
42
  taskRun?: (taskRunId: string) => {
@@ -56,6 +58,8 @@ type BoardStageOptions = {
56
58
  onLongPress?: (item: BoardSceneItem, press: BoardStagePress) => void;
57
59
  /** A press on a card key (`BoardCardRenderer.hitAt`); return false to leave it to the editor. */
58
60
  onHit?: (item: BoardSceneItem, action: string, press: BoardStagePress) => boolean | undefined;
61
+ /** Card keys `onHit` acts on; others go to the editor. */
62
+ handlesHit?: (item: BoardSceneItem, action: string) => boolean;
59
63
  onDoubleClick?: (item: BoardSceneItem | null, point: WorldPoint) => boolean | undefined;
60
64
  onSurfaceChange?: (size: {
61
65
  width: number;
@@ -1,25 +1,25 @@
1
1
  import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
2
2
  import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
3
3
  import { itemBounds, pointToWorld, rectsIntersect, screenPoint, stableCullRect, visibleWorldRect, worldPoint } from "../model/geometry.js";
4
+ import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
5
+ import { boardScriptTarget } from "../model/script-hit.js";
4
6
  import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "../model/sampling.js";
7
+ import { resolveSceneArrow } from "../model/arrow-geometry.js";
8
+ import { boardTextureEdge } from "../model/asset-key.js";
5
9
  import { pickBoardColor, resolveItemColor } from "../model/palette.js";
10
+ import { elementClientToLocal } from "../model/client-geometry.js";
11
+ import { isCreationBoardTool } from "../editor/tool.js";
12
+ import { resizeCursorForHandle } from "../editor/selection-transform.js";
6
13
  import { parseBoardCssColor } from "../render/css-color.js";
7
14
  import { itemAlpha } from "../render/palette.js";
8
- import { resolveSceneArrow } from "../model/arrow-geometry.js";
9
15
  import { onBoardTextFontsChange } from "../render/text-measurement.js";
10
16
  import { boardLodRatio, boardLodSize } from "../render/lod.js";
11
17
  import { createBoardBackground, updateBoardBackground } from "../render/board-background.js";
12
18
  import { getBoardResolution } from "../render/text-resolution.js";
13
19
  import { DEFAULT_BOARD_RENDER_LABELS, getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
14
- import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
15
- import { boardScriptTarget } from "../model/script-hit.js";
16
20
  import { createBoardScriptHost } from "../render/script-host.js";
17
21
  import { defaultBoardRenderStyle } from "../render/style.js";
18
22
  import { boardRenderTheme } from "../render/theme.js";
19
- import { boardTextureEdge } from "../model/asset-key.js";
20
- import { elementClientToLocal } from "../model/client-geometry.js";
21
- import { isCreationBoardTool } from "../editor/tool.js";
22
- import { resizeCursorForHandle } from "../editor/selection-transform.js";
23
23
  import { createBoardPlayer } from "../player/index.js";
24
24
  import { createBoardScriptObservers } from "../model/script-observers.js";
25
25
  import { defaultBoardDeviceBudget } from "./device.js";
@@ -155,7 +155,7 @@ function mountBoardStage(host, options) {
155
155
  if (item) options.onLongPress?.(item, press);
156
156
  });
157
157
  const renderCamera = () => playbackCamera ?? editor.camera;
158
- const views = createBoardItemViewLayer(host, editor, options.views ?? [], renderCamera, scheduleTick);
158
+ const views = createBoardItemViewLayer(host, editor, options.views ?? [], renderCamera, scheduleTick, options.viewLayer);
159
159
  const player = createBoardPlayer({ resolveColor: (color) => {
160
160
  const current = theme();
161
161
  return {
@@ -512,7 +512,8 @@ function mountBoardStage(host, options) {
512
512
  }
513
513
  function hitAt(item, point) {
514
514
  if (!lastContext || !scene?.getNode(item.id)) return null;
515
- return resolveRenderer(item, lastContext).hitAt?.(item, point, lastContext) ?? null;
515
+ const hit = resolveRenderer(item, lastContext).hitAt?.(item, point, lastContext);
516
+ return hit && (options.handlesHit?.(item, hit.action) ?? true) ? hit : null;
516
517
  }
517
518
  function hoverHit(input) {
518
519
  if (!options.onHit) return;
@@ -38,6 +38,6 @@ type BoardItemViewLayer = {
38
38
  }): void;
39
39
  destroy(): void;
40
40
  };
41
- declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport, onInvalidate?: () => void): BoardItemViewLayer;
41
+ declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport, onInvalidate?: () => void, layer?: "above" | "below"): BoardItemViewLayer;
42
42
  //#endregion
43
43
  export { BoardItemView, BoardItemViewContext, BoardItemViewInstance, BoardItemViewLayer, createBoardItemViewLayer };
@@ -18,10 +18,10 @@ function onScreen(frame, camera, surface) {
18
18
  const top = bounds.y * camera.zoom + camera.y;
19
19
  return left + bounds.width * camera.zoom >= -240 && top + bounds.height * camera.zoom >= -240 && left <= surface.width + VISIBLE_MARGIN && top <= surface.height + VISIBLE_MARGIN;
20
20
  }
21
- function createBoardItemViewLayer(host, editor, views, camera, onInvalidate = () => {}) {
21
+ function createBoardItemViewLayer(host, editor, views, camera, onInvalidate = () => {}, layer = "above") {
22
22
  const element = host.ownerDocument.createElement("div");
23
23
  element.dataset.boardViews = "";
24
- element.style.cssText = "position:absolute;inset:0;z-index:2;overflow:hidden;pointer-events:none";
24
+ element.style.cssText = `position:absolute;inset:0;z-index:${layer === "below" ? 0 : 2};overflow:hidden;pointer-events:none`;
25
25
  host.appendChild(element);
26
26
  const world = host.ownerDocument.createElement("div");
27
27
  world.style.cssText = "position:absolute;inset:0;transform-origin:0 0;pointer-events:none";
@@ -1,6 +1,6 @@
1
1
  import { BOARD_CAMERA_TARGET, BoardAnimationHeaderSchema, BoardColorSchema, BoardPatchSchema, BoardSettingsSchema, BoardTrackSchema, BoardVec2Schema, boardItemSchema, isBuiltinItemType, parseBoardItem } from "./board-model.js";
2
- import { boardJsonEquals } from "./board-json.js";
3
2
  import { applyMatrix, arrowBindings, createBoardLayout, invertMatrix, isArrowBinding } from "./board-layout.js";
3
+ import { boardJsonEquals } from "./board-json.js";
4
4
  import { z } from "zod";
5
5
  //#region ../protocol/dist/board-patch.js
6
6
  function slot(map, key) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub",
3
- "version": "12.3.0",
3
+ "version": "12.4.0",
4
4
  "description": "Cohub SDK for spaces, sessions, boards, and realtime agent collaboration.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,