@neta-art/cohub 3.1.0 → 4.0.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 +33 -2
- package/dist/{board.d.ts → board/animation.d.ts} +4 -2
- package/dist/{chunks/board.js → board/animation.js} +5 -44
- package/dist/board/codec.d.ts +25 -0
- package/dist/board/codec.js +243 -0
- package/dist/board/core/bindings.d.ts +45 -0
- package/dist/board/core/bindings.js +162 -0
- package/dist/board/core/draw-geometry.d.ts +30 -0
- package/dist/board/core/draw-geometry.js +175 -0
- package/dist/board/core/export-assets.d.ts +14 -0
- package/dist/board/core/export-assets.js +22 -0
- package/dist/board/core/export-plan.d.ts +84 -0
- package/dist/board/core/export-plan.js +128 -0
- package/dist/board/core/file-preview.d.ts +178 -0
- package/dist/board/core/file-preview.js +282 -0
- package/dist/board/core/palette.d.ts +42 -0
- package/dist/board/core/palette.js +166 -0
- package/dist/board/core/shape-definition.d.ts +35 -0
- package/dist/board/core/shape-definition.js +64 -0
- package/dist/board/core/shape-types.d.ts +140 -0
- package/dist/board/core/shape-types.js +27 -0
- package/dist/board/core/text-metrics.d.ts +18 -0
- package/dist/board/core/text-metrics.js +43 -0
- package/dist/board/core/tool-styles.d.ts +52 -0
- package/dist/board/core/tool-styles.js +51 -0
- package/dist/board/export/index.d.ts +56 -0
- package/dist/board/export/index.js +86 -0
- package/dist/board/export/scene.d.ts +35 -0
- package/dist/board/export/scene.js +69 -0
- package/dist/board/geometry.d.ts +139 -0
- package/dist/board/geometry.js +492 -0
- package/dist/board/headless/index.d.ts +69 -0
- package/dist/board/headless/index.js +150 -0
- package/dist/board/image-key.d.ts +19 -0
- package/dist/board/image-key.js +34 -0
- package/dist/board/index.d.ts +17 -0
- package/dist/board/index.js +17 -0
- package/dist/board/render/index.d.ts +6 -0
- package/dist/board/render/index.js +6 -0
- package/dist/board/render/palette.d.ts +5 -0
- package/dist/board/render/palette.js +30 -0
- package/dist/board/render/renderers/arrow-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/arrow-card-renderer.js +157 -0
- package/dist/board/render/renderers/base-card-renderer.d.ts +46 -0
- package/dist/board/render/renderers/base-card-renderer.js +153 -0
- package/dist/board/render/renderers/board-renderer-registry.d.ts +85 -0
- package/dist/board/render/renderers/board-renderer-registry.js +41 -0
- package/dist/board/render/renderers/draw-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/draw-card-renderer.js +82 -0
- package/dist/board/render/renderers/far-plate.d.ts +39 -0
- package/dist/board/render/renderers/far-plate.js +92 -0
- package/dist/board/render/renderers/file-card-renderer.d.ts +40 -0
- package/dist/board/render/renderers/file-card-renderer.js +350 -0
- package/dist/board/render/renderers/frame-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/frame-card-renderer.js +99 -0
- package/dist/board/render/renderers/geo-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/geo-card-renderer.js +128 -0
- package/dist/board/render/renderers/image-card-renderer.d.ts +8 -0
- package/dist/board/render/renderers/image-card-renderer.js +138 -0
- package/dist/board/render/renderers/text-card-renderer.d.ts +7 -0
- package/dist/board/render/renderers/text-card-renderer.js +94 -0
- package/dist/board/render/renderers/unknown-card-renderer.d.ts +5 -0
- package/dist/board/render/renderers/unknown-card-renderer.js +102 -0
- package/dist/board/render/renderers/video-card-renderer.d.ts +7 -0
- package/dist/board/render/renderers/video-card-renderer.js +146 -0
- package/dist/board/render/text-measurement.d.ts +30 -0
- package/dist/board/render/text-measurement.js +57 -0
- package/dist/board/render/text-resolution.d.ts +16 -0
- package/dist/board/render/text-resolution.js +43 -0
- package/dist/board/render/themes/board-theme-registry.d.ts +22 -0
- package/dist/board/render/themes/board-theme-registry.js +13 -0
- package/dist/board/render/themes/clean-theme.d.ts +5 -0
- package/dist/board/render/themes/clean-theme.js +105 -0
- package/dist/chunks/http.d.ts +2 -3
- package/dist/chunks/http.js +4 -0
- package/dist/chunks/websocket.d.ts +851 -353
- package/dist/http.d.ts +1 -2
- package/dist/index.d.ts +100 -5
- package/dist/index.js +391 -1
- package/dist/protocol/dist/board-constants.d.ts +23 -0
- package/dist/protocol/dist/board-constants.js +61 -0
- package/dist/protocol/dist/board-document.d.ts +1047 -0
- package/dist/protocol/dist/board-document.js +321 -0
- package/dist/protocol/dist/board.d.ts +186 -0
- package/dist/protocol/dist/board.js +207 -0
- package/dist/protocol/dist/index.d.ts +5 -0
- package/dist/protocol/dist/index.js +5 -0
- package/dist/protocol/dist/provenance.js +12 -0
- package/dist/protocol/dist/realtime/board-awareness.d.ts +1 -0
- package/dist/protocol/dist/realtime/board-awareness.js +119 -0
- package/dist/protocol/dist/realtime/types.d.ts +2 -0
- package/package.json +40 -4
- package/dist/board.js +0 -2
- package/dist/chunks/board.d.ts +0 -2589
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import "../../protocol/dist/board-constants.js";
|
|
2
|
+
import { installBoardTextMeasurement } from "../render/text-measurement.js";
|
|
3
|
+
import { renderBoardExport } from "../export/index.js";
|
|
4
|
+
//#region src/board/headless/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* A minimal WebGL stand-in.
|
|
7
|
+
*
|
|
8
|
+
* `ParticleContainerPipe` builds a `GlProgram` when the renderer registers its
|
|
9
|
+
* pipes, and that probes shader precision through a throwaway context — even
|
|
10
|
+
* though the Canvas2D backend never draws with it. Returning a stub keeps
|
|
11
|
+
* registration working; nothing here is ever used to render.
|
|
12
|
+
*/
|
|
13
|
+
const WEBGL_PROBE_STUB = {
|
|
14
|
+
getShaderPrecisionFormat: () => ({
|
|
15
|
+
precision: 1,
|
|
16
|
+
rangeMin: 1,
|
|
17
|
+
rangeMax: 1
|
|
18
|
+
}),
|
|
19
|
+
getExtension: () => null,
|
|
20
|
+
getParameter: () => 0
|
|
21
|
+
};
|
|
22
|
+
function isWebGLContext(kind) {
|
|
23
|
+
return kind.startsWith("webgl") || kind === "experimental-webgl";
|
|
24
|
+
}
|
|
25
|
+
async function loadCanvasModule() {
|
|
26
|
+
try {
|
|
27
|
+
return await import("@napi-rs/canvas");
|
|
28
|
+
} catch (cause) {
|
|
29
|
+
throw new Error("Board image export needs the optional '@napi-rs/canvas' package. Install it with: npm i @napi-rs/canvas", { cause });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Node has no rAF; Pixi's scheduler only needs a callback pump. */
|
|
33
|
+
function installAnimationFrameShim() {
|
|
34
|
+
const globals = globalThis;
|
|
35
|
+
if (globals.requestAnimationFrame) return () => {};
|
|
36
|
+
const timers = /* @__PURE__ */ new Set();
|
|
37
|
+
globals.requestAnimationFrame = (cb) => {
|
|
38
|
+
const timer = setTimeout(() => {
|
|
39
|
+
timers.delete(timer);
|
|
40
|
+
cb(Date.now());
|
|
41
|
+
}, 16);
|
|
42
|
+
timer.unref?.();
|
|
43
|
+
timers.add(timer);
|
|
44
|
+
return timer;
|
|
45
|
+
};
|
|
46
|
+
globals.cancelAnimationFrame = (id) => {
|
|
47
|
+
clearTimeout(id);
|
|
48
|
+
timers.delete(id);
|
|
49
|
+
};
|
|
50
|
+
return () => {
|
|
51
|
+
for (const timer of timers) clearTimeout(timer);
|
|
52
|
+
timers.clear();
|
|
53
|
+
globals.requestAnimationFrame = void 0;
|
|
54
|
+
globals.cancelAnimationFrame = void 0;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create a Canvas2D renderer backed by Skia.
|
|
59
|
+
*
|
|
60
|
+
* `skipExtensionImports` is essential: it stops Pixi from auto-loading its
|
|
61
|
+
* browser environment bundle, which would pull in DOM-only pipes.
|
|
62
|
+
*/
|
|
63
|
+
async function createBoardHeadlessRenderer(options = {}) {
|
|
64
|
+
const canvasModule = options.canvasModule ?? await loadCanvasModule();
|
|
65
|
+
const { CanvasGraphicsContextSystem, CanvasGraphicsPipe, CanvasRenderer, CanvasRendererTextSystem, CanvasTextPipe, CanvasTextSystem, DOMAdapter, extensions, GraphicsContextSystem, GraphicsPipe, ImageSource, Texture } = await import("pixi.js");
|
|
66
|
+
extensions.add(CanvasGraphicsPipe, GraphicsPipe, CanvasGraphicsContextSystem, GraphicsContextSystem, CanvasRendererTextSystem, CanvasTextSystem, CanvasTextPipe);
|
|
67
|
+
for (const font of options.fonts ?? []) canvasModule.GlobalFonts.registerFromPath(font.path, font.family ?? "Geist");
|
|
68
|
+
function createCanvas(width = 1, height = 1) {
|
|
69
|
+
const canvas = canvasModule.createCanvas(Math.max(1, Math.ceil(width)), Math.max(1, Math.ceil(height)));
|
|
70
|
+
const nativeGetContext = canvas.getContext.bind(canvas);
|
|
71
|
+
canvas.getContext = (kind, ...rest) => isWebGLContext(String(kind)) ? WEBGL_PROBE_STUB : nativeGetContext(kind, ...rest);
|
|
72
|
+
return canvas;
|
|
73
|
+
}
|
|
74
|
+
DOMAdapter.set({
|
|
75
|
+
createCanvas: (width, height) => createCanvas(width, height),
|
|
76
|
+
createImage: () => new canvasModule.Image(),
|
|
77
|
+
getCanvasRenderingContext2D: () => createCanvas(1, 1).getContext("2d").constructor,
|
|
78
|
+
getWebGLRenderingContext: () => WEBGL_PROBE_STUB,
|
|
79
|
+
getNavigator: () => ({
|
|
80
|
+
userAgent: "cohub-board-headless",
|
|
81
|
+
gpu: null
|
|
82
|
+
}),
|
|
83
|
+
getBaseUrl: () => "file://",
|
|
84
|
+
getFontFaceSet: () => null,
|
|
85
|
+
fetch: (url, init) => fetch(url, init),
|
|
86
|
+
parseXML: () => {
|
|
87
|
+
throw new Error("XML parsing is not available in headless board export.");
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
installBoardTextMeasurement();
|
|
91
|
+
const restoreAnimationFrame = installAnimationFrameShim();
|
|
92
|
+
const renderer = new CanvasRenderer();
|
|
93
|
+
await renderer.init({
|
|
94
|
+
width: 1,
|
|
95
|
+
height: 1,
|
|
96
|
+
backgroundAlpha: 0,
|
|
97
|
+
antialias: true,
|
|
98
|
+
resolution: 1,
|
|
99
|
+
skipExtensionImports: true
|
|
100
|
+
});
|
|
101
|
+
return {
|
|
102
|
+
renderer,
|
|
103
|
+
canvasModule,
|
|
104
|
+
decodeImage: async (bytes, mimeType = "image/png") => {
|
|
105
|
+
const image = new canvasModule.Image();
|
|
106
|
+
const base64 = Buffer.from(bytes).toString("base64");
|
|
107
|
+
await new Promise((resolve, reject) => {
|
|
108
|
+
image.onload = () => resolve();
|
|
109
|
+
image.onerror = (error) => reject(error);
|
|
110
|
+
image.src = `data:${mimeType};base64,${base64}`;
|
|
111
|
+
});
|
|
112
|
+
return new Texture({ source: new ImageSource({
|
|
113
|
+
resource: image,
|
|
114
|
+
width: image.width,
|
|
115
|
+
height: image.height
|
|
116
|
+
}) });
|
|
117
|
+
},
|
|
118
|
+
destroy: () => {
|
|
119
|
+
renderer.destroy();
|
|
120
|
+
restoreAnimationFrame();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const MIME = {
|
|
125
|
+
png: "image/png",
|
|
126
|
+
jpeg: "image/jpeg",
|
|
127
|
+
webp: "image/webp"
|
|
128
|
+
};
|
|
129
|
+
function boardHeadlessMimeType(format) {
|
|
130
|
+
return MIME[format];
|
|
131
|
+
}
|
|
132
|
+
/** Render a document to encoded image bytes. Returns null for an empty region. */
|
|
133
|
+
function exportBoardImageBytes(headless, document, options = {}) {
|
|
134
|
+
const { format = "png", quality = .92, textures, ...rest } = options;
|
|
135
|
+
const result = renderBoardExport(headless.renderer, document, {
|
|
136
|
+
...rest,
|
|
137
|
+
...textures ? { textures } : {}
|
|
138
|
+
});
|
|
139
|
+
if (!result) return null;
|
|
140
|
+
const canvas = result.canvas;
|
|
141
|
+
const bytes = format === "png" ? canvas.toBuffer(MIME.png) : canvas.toBuffer(MIME[format], Math.round(quality * 100));
|
|
142
|
+
return {
|
|
143
|
+
bytes: new Uint8Array(bytes),
|
|
144
|
+
plan: result.plan,
|
|
145
|
+
warnings: result.warnings,
|
|
146
|
+
format
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
export { boardHeadlessMimeType, createBoardHeadlessRenderer, exportBoardImageBytes };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BoardItem } from "../protocol/dist/board-document.js";
|
|
2
|
+
//#region src/board/image-key.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Stable cache key for an item's image resource, or null when it has none.
|
|
5
|
+
*
|
|
6
|
+
* Space files and remote URLs are namespaced so they can never collide, and file
|
|
7
|
+
* cards contribute their cover image — which means covers ride the exact same
|
|
8
|
+
* reference counting, LRU cooling pool and viewport preloading as image nodes,
|
|
9
|
+
* with no second loader to keep in step. The exporter resolves the same keys, so
|
|
10
|
+
* an exported card shows the same picture the editor does.
|
|
11
|
+
*/
|
|
12
|
+
declare function imageAssetKey(item: BoardItem): string | null;
|
|
13
|
+
/** The source a key resolves from, recovered from its namespace prefix. */
|
|
14
|
+
declare function boardImageKeySource(key: string): {
|
|
15
|
+
kind: "file" | "url";
|
|
16
|
+
value: string;
|
|
17
|
+
} | null;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { boardImageKeySource, imageAssetKey };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/board/image-key.ts
|
|
2
|
+
/**
|
|
3
|
+
* Stable cache key for an item's image resource, or null when it has none.
|
|
4
|
+
*
|
|
5
|
+
* Space files and remote URLs are namespaced so they can never collide, and file
|
|
6
|
+
* cards contribute their cover image — which means covers ride the exact same
|
|
7
|
+
* reference counting, LRU cooling pool and viewport preloading as image nodes,
|
|
8
|
+
* with no second loader to keep in step. The exporter resolves the same keys, so
|
|
9
|
+
* an exported card shows the same picture the editor does.
|
|
10
|
+
*/
|
|
11
|
+
function imageAssetKey(item) {
|
|
12
|
+
if (item.type === "image") return `file:${item.ref.path}`;
|
|
13
|
+
if (item.type === "file") {
|
|
14
|
+
const snapshot = item.snapshot;
|
|
15
|
+
if (snapshot?.coverPath) return `file:${snapshot.coverPath}`;
|
|
16
|
+
if (snapshot?.coverUrl) return `url:${snapshot.coverUrl}`;
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
/** The source a key resolves from, recovered from its namespace prefix. */
|
|
22
|
+
function boardImageKeySource(key) {
|
|
23
|
+
if (key.startsWith("file:")) return {
|
|
24
|
+
kind: "file",
|
|
25
|
+
value: key.slice(5)
|
|
26
|
+
};
|
|
27
|
+
if (key.startsWith("url:")) return {
|
|
28
|
+
kind: "url",
|
|
29
|
+
value: key.slice(4)
|
|
30
|
+
};
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { boardImageKeySource, imageAssetKey };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BOARD_DOCUMENT_KIND, BOARD_EXTENSION, BoardManifest, BoardNodeRecord, BoardRecord, InvalidBoardFileError, isBoardPath, parseBoardManifest, serializeBoardManifest } from "../protocol/dist/board.js";
|
|
2
|
+
import { BoardExtensionDefinition, BoardExtensionRegistry, BoardPresetDefinition, CompiledSequence, DEFAULT_BOARD_LIMITS, QualityProfile, RenderBounds, TimelineClipInput, TimelineInput, clip, compileSequence, createBoardExtensionRegistry, timeline } from "./animation.js";
|
|
3
|
+
import { ArrowEndpoint, ArrowEndpointSchema, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardTextItem, BoardTextItemSchema, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, DrawPoint, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, SpaceFileRef, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardItemLoose, unknownRealType } from "../protocol/dist/board-document.js";
|
|
4
|
+
import { BOARD_NODE_SOURCE, DEFAULT_BOARD_APPEARANCE, ITEM_BASE_KEYS, WireBackedBoardItem, boardBootstrapToDocument, boardNodeToItem, isRecord, nodeInputFromRecord, sourceForItem } from "./codec.js";
|
|
5
|
+
import { CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CornerResizeHandle, EDGE_RESIZE_HANDLES, FIT_PADDING, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, ResizeHandle, ScreenPoint, Size, VIEWPORT_MARGIN_RATIO, WorldPoint, angleFromCenter, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, panBy, pointToWorld, radToDeg, rectCenter, rectContainsPoint, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenPoint, screenToWorld, selectionBounds, unionRects, visibleWorldRect, worldPoint, worldToScreen, zoomAround } from "./geometry.js";
|
|
6
|
+
import { FrameLookup, ResolvedArrow, anchorToWorld, arrowBounds, bindEndpointAt, distanceToArrow, resolveArrow, resolveEndpoint, sampleQuadratic, translateArrow, worldToAnchor } from "./core/bindings.js";
|
|
7
|
+
import { buildStrokeOutline, computeDrawBounds, distanceToStroke, sampleRadius, simplifyDrawIndices } from "./core/draw-geometry.js";
|
|
8
|
+
import { BOARD_EXPORT_MAX_TEXTURES, BoardExportAssetSelection, selectBoardExportAssets } from "./core/export-assets.js";
|
|
9
|
+
import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, boardFrameLookup, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
|
|
10
|
+
import { BoardFileSnapshotFacts, BuildSnapshotInput, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FileAvailability, FilePreviewKind, ResolvedCover, availabilityFromError, buildFileExcerpt, buildFileSnapshot, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot, readCoverFromFrontmatter, readTitleFromFrontmatter, resolveCoverRef, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./core/file-preview.js";
|
|
11
|
+
import { BOARD_COLORS, BoardColorEntry, BoardColorId, BoardColorValue, BoardShapeColors, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor } from "./core/palette.js";
|
|
12
|
+
import { ArrowShapeProps, DrawShapeProps, FULL_CAPABILITIES, GEO_KINDS, GeoKind, GeoShapeProps, HandleDragResult, ImageShapeProps, ShapeCapabilities, ShapeGeometry, ShapeHandle, ShapeHandleId, ShapeResizeMode, TextShapeProps, VideoShapeProps, isGeoKind, resizeModeForCapabilities } from "./core/shape-types.js";
|
|
13
|
+
import { ShapeDefinition, definitionForItem, getShapeDefinition, registerShapeDefinition, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, unknownShapeDefinition } from "./core/shape-definition.js";
|
|
14
|
+
import { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardTextLineHeight, clampBoardTextFontSize, measureBoardText, setBoardTextMeasurer } from "./core/text-metrics.js";
|
|
15
|
+
import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardStyledToolId, BoardToolStyleMap, BoardToolStylePatch, DEFAULT_BOARD_TOOL_STYLES, clampBoardStrokeSize, createBoardToolStyles } from "./core/tool-styles.js";
|
|
16
|
+
import { boardImageKeySource, imageAssetKey } from "./image-key.js";
|
|
17
|
+
export { ArrowEndpoint, ArrowEndpointSchema, type ArrowShapeProps, BOARD_COLORS, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearance, BoardAppearanceSchema, BoardArrowItem, BoardArrowItemSchema, BoardColorEntry, BoardColorId, BoardColorValue, BoardDocument, BoardDocumentSchema, BoardDrawItem, BoardDrawItemSchema, BoardExportAssetSelection, BoardExportPlan, BoardExportPlanInput, BoardExportRegion, BoardExtensionDefinition, BoardExtensionRegistry, BoardFileItem, BoardFileItemSchema, BoardFileSnapshot, BoardFileSnapshotFacts, BoardFileSnapshotSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItem, BoardGeoItemSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemSchema, BoardItemStyle, BoardItemStyleSchema, BoardKnownItem, type BoardManifest, BoardMediaSnapshot, BoardMediaSnapshotSchema, type BoardNodeRecord, BoardPresetDefinition, type BoardRecord, BoardShapeColors, BoardStyledToolId, BoardTextItem, BoardTextItemSchema, BoardToolStyleMap, BoardToolStylePatch, BoardUnknownItem, BoardVideoItem, BoardVideoItemSchema, BoardViewport, BoardViewportSchema, BuildSnapshotInput, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, CompiledSequence, CornerResizeHandle, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_TOOL_STYLES, DrawPoint, DrawPointSchema, type DrawShapeProps, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, FileAvailability, FilePreviewKind, FrameLookup, GEO_KINDS, type GeoKind, type GeoShapeProps, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, type HandleDragResult, ITEM_BASE_KEYS, type ImageShapeProps, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, KnownBoardItemType, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, Point, QualityProfile, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, Rect, RenderBounds, ResizeHandle, ResolvedArrow, ResolvedCover, ScreenPoint, type ShapeCapabilities, ShapeDefinition, type ShapeGeometry, type ShapeHandle, type ShapeHandleId, type ShapeResizeMode, Size, SpaceFileRef, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, type TextShapeProps, TimelineClipInput, TimelineInput, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, type VideoShapeProps, WireBackedBoardItem, WorldPoint, anchorToWorld, angleFromCenter, arrowBounds, availabilityFromError, bindEndpointAt, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, createBoardExtensionRegistry, createBoardToolStyles, definitionForItem, degToRad, distanceToArrow, distanceToStroke, expandRect, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardItemLoose, parseBoardManifest, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveCoverRef, resolveEndpoint, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleQuadratic, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, worldPoint, worldToAnchor, worldToScreen, zoomAround };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BoardExtensionRegistry, DEFAULT_BOARD_LIMITS, clip, compileSequence, createBoardExtensionRegistry, timeline } from "./animation.js";
|
|
2
|
+
import { BOARD_DOCUMENT_KIND, BOARD_EXTENSION, InvalidBoardFileError, isBoardPath, parseBoardManifest, serializeBoardManifest } from "../protocol/dist/board.js";
|
|
3
|
+
import { ArrowEndpointSchema, BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, DrawPointSchema, KNOWN_BOARD_ITEM_TYPES, SpaceFileRefSchema, UNKNOWN_BOARD_ITEM_TYPE, isFileBackedItem, isMediaItem, isUnknownItem, parseBoardItemLoose, unknownRealType } from "../protocol/dist/board-document.js";
|
|
4
|
+
import { TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, boardTextLineHeight, clampBoardTextFontSize, measureBoardText, setBoardTextMeasurer } from "./core/text-metrics.js";
|
|
5
|
+
import { BOARD_NODE_SOURCE, DEFAULT_BOARD_APPEARANCE, ITEM_BASE_KEYS, boardBootstrapToDocument, boardNodeToItem, isRecord, nodeInputFromRecord, sourceForItem } from "./codec.js";
|
|
6
|
+
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, clamp, clampZoom, degToRad, expandRect, fitToContent, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, handlePosition, itemBounds, normalizeRotation, normalizeViewport, panBy, pointToWorld, radToDeg, rectCenter, rectContainsPoint, rectsIntersect, resizeFrame, resizeFrameToSize, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, scaleFrames, screenPoint, screenToWorld, selectionBounds, unionRects, visibleWorldRect, worldPoint, worldToScreen, zoomAround } from "./geometry.js";
|
|
7
|
+
import { boardImageKeySource, imageAssetKey } from "./image-key.js";
|
|
8
|
+
import { anchorToWorld, arrowBounds, bindEndpointAt, distanceToArrow, resolveArrow, resolveEndpoint, sampleQuadratic, translateArrow, worldToAnchor } from "./core/bindings.js";
|
|
9
|
+
import { buildStrokeOutline, computeDrawBounds, distanceToStroke, sampleRadius, simplifyDrawIndices } from "./core/draw-geometry.js";
|
|
10
|
+
import { BOARD_EXPORT_MAX_TEXTURES, selectBoardExportAssets } from "./core/export-assets.js";
|
|
11
|
+
import { BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, boardFrameLookup, exportItemBounds, normalizeBoardDocument, planBoardExport } from "./core/export-plan.js";
|
|
12
|
+
import { FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, availabilityFromError, buildFileExcerpt, buildFileSnapshot, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, formatFileSize, isFileSnapshotFresh, mergeFileSnapshot, readCoverFromFrontmatter, readTitleFromFrontmatter, resolveCoverRef, resolveSpacePath, shouldFetchFileExcerpt, splitFrontmatter } from "./core/file-preview.js";
|
|
13
|
+
import { BOARD_COLORS, DEFAULT_BOARD_COLOR, boardColorCssVar, buildFallbackShapeColors, isBoardColorId, pickBoardColor, resolveBoardColor } from "./core/palette.js";
|
|
14
|
+
import { FULL_CAPABILITIES, GEO_KINDS, isGeoKind, resizeModeForCapabilities } from "./core/shape-types.js";
|
|
15
|
+
import { definitionForItem, getShapeDefinition, registerShapeDefinition, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, unknownShapeDefinition } from "./core/shape-definition.js";
|
|
16
|
+
import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, DEFAULT_BOARD_TOOL_STYLES, clampBoardStrokeSize, createBoardToolStyles } from "./core/tool-styles.js";
|
|
17
|
+
export { ArrowEndpointSchema, BOARD_COLORS, BOARD_DOCUMENT_KIND, BOARD_EXPORT_DEFAULT_PADDING, BOARD_EXPORT_DEFAULT_SCALE, BOARD_EXPORT_ITEM_WARN_THRESHOLD, BOARD_EXPORT_MAX_EDGE, BOARD_EXPORT_MAX_PIXELS, BOARD_EXPORT_MAX_TEXTURES, BOARD_EXTENSION, BOARD_NODE_SOURCE, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BoardAppearanceSchema, BoardArrowItemSchema, BoardDocumentSchema, BoardDrawItemSchema, BoardExtensionRegistry, BoardFileItemSchema, BoardFileSnapshotSchema, BoardFrameItemSchema, BoardFrameSchema, BoardGeoItemSchema, BoardImageItemSchema, BoardItemSchema, BoardItemStyleSchema, BoardMediaSnapshotSchema, BoardTextItemSchema, BoardVideoItemSchema, BoardViewportSchema, CORNER_RESIZE_HANDLES, CORNER_ROTATION_ZONE_WIDTH, DEFAULT_BOARD_APPEARANCE, DEFAULT_BOARD_COLOR, DEFAULT_BOARD_LIMITS, DEFAULT_BOARD_TOOL_STYLES, DrawPointSchema, EDGE_RESIZE_HANDLES, FILE_EXCERPT_MAX_BYTES, FILE_EXCERPT_MAX_CHARS, FIT_PADDING, FULL_CAPABILITIES, GEO_KINDS, HANDLE_DIRECTION, HANDLE_HIT_RADIUS, ITEM_BASE_KEYS, InvalidBoardFileError, KNOWN_BOARD_ITEM_TYPES, MAX_BOARD_ZOOM, MIN_BOARD_ZOOM, MIN_ITEM_SIZE, RESIZE_HANDLES, ROTATION_HANDLE_OFFSET, SpaceFileRefSchema, TEXT_FONT_FAMILY, TEXT_FONT_SIZE, TEXT_LINE_HEIGHT, TEXT_MAX_FONT_SIZE, TEXT_MIN_FONT_SIZE, UNKNOWN_BOARD_ITEM_TYPE, VIEWPORT_MARGIN_RATIO, anchorToWorld, angleFromCenter, arrowBounds, availabilityFromError, bindEndpointAt, boardBootstrapToDocument, boardColorCssVar, boardFrameLookup, boardImageKeySource, boardNodeToItem, boardTextLineHeight, buildFallbackShapeColors, buildFileExcerpt, buildFileSnapshot, buildStrokeOutline, clamp, clampBoardStrokeSize, clampBoardTextFontSize, clampZoom, clip, compileSequence, computeDrawBounds, createBoardExtensionRegistry, createBoardToolStyles, definitionForItem, degToRad, distanceToArrow, distanceToStroke, expandRect, exportItemBounds, fileBaseName, filePreviewKind, filePreviewMemoKey, filePreviewScope, fileTypeLabel, fitToContent, formatFileSize, frameContainsPoint, frameCornerRotationHandleAt, frameCorners, frameEdgeHandleAt, frameHandlePosition, frameRayIntersection, frameRect, getShapeDefinition, handlePosition, imageAssetKey, isBoardColorId, isBoardPath, isFileBackedItem, isFileSnapshotFresh, isGeoKind, isMediaItem, isRecord, isUnknownItem, itemBounds, measureBoardText, mergeFileSnapshot, nodeInputFromRecord, normalizeBoardDocument, normalizeRotation, normalizeViewport, panBy, parseBoardItemLoose, parseBoardManifest, pickBoardColor, planBoardExport, pointToWorld, radToDeg, readCoverFromFrontmatter, readTitleFromFrontmatter, rectCenter, rectContainsPoint, rectsIntersect, registerShapeDefinition, resizeFrame, resizeFrameToSize, resizeModeForCapabilities, resolveArrow, resolveBoardColor, resolveCoverRef, resolveEndpoint, resolveSpacePath, rotateFrames, rotatePointAround, rotationHandleAnchor, rotationHandlePosition, sampleQuadratic, sampleRadius, scaleFrames, screenPoint, screenToWorld, selectBoardExportAssets, selectionBounds, serializeBoardManifest, setBoardTextMeasurer, shapeBounds, shapeCapabilities, shapeHandles, shapeHitTest, shapeResizeMode, shouldFetchFileExcerpt, simplifyDrawIndices, sourceForItem, splitFrontmatter, timeline, translateArrow, unionRects, unknownRealType, unknownShapeDefinition, visibleWorldRect, worldPoint, worldToAnchor, worldToScreen, zoomAround };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
2
|
+
import { defaultBoardPalette } from "./palette.js";
|
|
3
|
+
import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
4
|
+
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
5
|
+
import { BoardThemeContext, BoardThemeRenderer, getBoardThemeRenderer, registerBoardThemeRenderer } from "./themes/board-theme-registry.js";
|
|
6
|
+
export { BoardCardRenderer, BoardRenderContext, BoardRenderPalette, BoardThemeContext, BoardThemeRenderer, boardCardRenderersForTest, defaultBoardPalette, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { defaultBoardPalette } from "./palette.js";
|
|
2
|
+
import { ensureBoardTextMeasurement, installBoardTextMeasurement } from "./text-measurement.js";
|
|
3
|
+
import { getBoardResolution, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket } from "./text-resolution.js";
|
|
4
|
+
import { boardCardRenderersForTest, getBoardCardRenderer, registerBoardCardRenderer } from "./renderers/board-renderer-registry.js";
|
|
5
|
+
import { getBoardThemeRenderer, registerBoardThemeRenderer } from "./themes/board-theme-registry.js";
|
|
6
|
+
export { boardCardRenderersForTest, defaultBoardPalette, ensureBoardTextMeasurement, getBoardCardRenderer, getBoardResolution, getBoardThemeRenderer, installBoardTextMeasurement, registerBoardCardRenderer, registerBoardThemeRenderer, syncTextResolution, syncTextWrapWidth, textResolutionForZoom, textZoomBucket };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/board/render/palette.ts
|
|
2
|
+
const DARK = {
|
|
3
|
+
bg: 1315860,
|
|
4
|
+
surface: 2105376,
|
|
5
|
+
hover: 2763306,
|
|
6
|
+
border: 3815994,
|
|
7
|
+
brand: 16734751,
|
|
8
|
+
text: 16053492,
|
|
9
|
+
muted: 9211020,
|
|
10
|
+
rare: 3718648,
|
|
11
|
+
epic: 10980346,
|
|
12
|
+
legendary: 16096779
|
|
13
|
+
};
|
|
14
|
+
const LIGHT = {
|
|
15
|
+
bg: 16777215,
|
|
16
|
+
surface: 16053493,
|
|
17
|
+
hover: 15329772,
|
|
18
|
+
border: 14079706,
|
|
19
|
+
brand: 15222030,
|
|
20
|
+
text: 1579035,
|
|
21
|
+
muted: 7041664,
|
|
22
|
+
rare: 2450411,
|
|
23
|
+
epic: 8141549,
|
|
24
|
+
legendary: 11817737
|
|
25
|
+
};
|
|
26
|
+
function defaultBoardPalette(mode) {
|
|
27
|
+
return { ...mode === "light" ? LIGHT : DARK };
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { defaultBoardPalette };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { BOARD_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
|
+
import { resolveArrow, sampleQuadratic } from "../../core/bindings.js";
|
|
3
|
+
import { pickBoardColor } from "../../core/palette.js";
|
|
4
|
+
import { syncTextResolution, textResolutionForZoom } from "../text-resolution.js";
|
|
5
|
+
import { drawFarStroke } from "./far-plate.js";
|
|
6
|
+
import { Container, Graphics, Text } from "pixi.js";
|
|
7
|
+
//#region src/board/render/renderers/arrow-card-renderer.ts
|
|
8
|
+
const partsByContainer = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
/**
|
|
10
|
+
* Frame lookup for resolving bindings.
|
|
11
|
+
*
|
|
12
|
+
* Routed through the context's id index rather than scanning the document: an
|
|
13
|
+
* arrow re-resolves its endpoints on every sync, and a per-arrow O(items) scan
|
|
14
|
+
* would make a board with many arrows quadratic per frame.
|
|
15
|
+
*/
|
|
16
|
+
function frameLookup(context) {
|
|
17
|
+
return (id) => context.getItem(id)?.frame;
|
|
18
|
+
}
|
|
19
|
+
/** Open chevron arrowhead — clearly directional, not a tiny filled nub. */
|
|
20
|
+
function drawArrowhead(graphics, tip, angle, size, color, strokeWidth) {
|
|
21
|
+
const spread = Math.PI / 6;
|
|
22
|
+
const left = {
|
|
23
|
+
x: tip.x - size * Math.cos(angle - spread),
|
|
24
|
+
y: tip.y - size * Math.sin(angle - spread)
|
|
25
|
+
};
|
|
26
|
+
const right = {
|
|
27
|
+
x: tip.x - size * Math.cos(angle + spread),
|
|
28
|
+
y: tip.y - size * Math.sin(angle + spread)
|
|
29
|
+
};
|
|
30
|
+
graphics.moveTo(left.x, left.y).lineTo(tip.x, tip.y).lineTo(right.x, right.y).stroke({
|
|
31
|
+
color,
|
|
32
|
+
width: Math.max(1.5, strokeWidth),
|
|
33
|
+
alpha: 1,
|
|
34
|
+
cap: "round",
|
|
35
|
+
join: "round"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function sync(container, item, context) {
|
|
39
|
+
const parts = partsByContainer.get(container);
|
|
40
|
+
if (!parts) return;
|
|
41
|
+
parts.root.position.set(0, 0);
|
|
42
|
+
parts.root.rotation = 0;
|
|
43
|
+
const selected = context.selectedIds.has(item.id);
|
|
44
|
+
const hovered = context.hoveredId === item.id;
|
|
45
|
+
const color = pickBoardColor(context.colors, item.color, context.colorScheme);
|
|
46
|
+
syncTextResolution(parts.label, parts, context.zoom);
|
|
47
|
+
const resolved = resolveArrow(item, frameLookup(context));
|
|
48
|
+
const lineSig = resolved ? [
|
|
49
|
+
resolved.start.x,
|
|
50
|
+
resolved.start.y,
|
|
51
|
+
resolved.end.x,
|
|
52
|
+
resolved.end.y,
|
|
53
|
+
resolved.control.x,
|
|
54
|
+
resolved.control.y,
|
|
55
|
+
selected,
|
|
56
|
+
hovered,
|
|
57
|
+
color.stroke,
|
|
58
|
+
item.size,
|
|
59
|
+
item.arrowStart,
|
|
60
|
+
item.arrowEnd
|
|
61
|
+
].join("|") : `empty|${item.id}`;
|
|
62
|
+
if (lineSig !== parts.lineSig) {
|
|
63
|
+
parts.lineSig = lineSig;
|
|
64
|
+
parts.line.clear();
|
|
65
|
+
if (resolved) {
|
|
66
|
+
const strokeColor = color.stroke;
|
|
67
|
+
const width = selected ? item.size + 1 : item.size;
|
|
68
|
+
const samples = sampleQuadratic(resolved, 24);
|
|
69
|
+
const head = samples[0];
|
|
70
|
+
const tail = samples[samples.length - 1];
|
|
71
|
+
if (head && tail) {
|
|
72
|
+
parts.line.moveTo(head.x, head.y);
|
|
73
|
+
for (let i = 1; i < samples.length; i += 1) {
|
|
74
|
+
const point = samples[i];
|
|
75
|
+
if (point) parts.line.lineTo(point.x, point.y);
|
|
76
|
+
}
|
|
77
|
+
parts.line.stroke({
|
|
78
|
+
color: strokeColor,
|
|
79
|
+
width,
|
|
80
|
+
alpha: selected || hovered ? 1 : .92,
|
|
81
|
+
cap: "round",
|
|
82
|
+
join: "round"
|
|
83
|
+
});
|
|
84
|
+
const span = Math.hypot(tail.x - head.x, tail.y - head.y);
|
|
85
|
+
const headSize = Math.min(Math.max(14, item.size * 5.5), Math.max(10, span * .28));
|
|
86
|
+
if (item.arrowEnd) {
|
|
87
|
+
const prev = samples[samples.length - 2];
|
|
88
|
+
if (prev) drawArrowhead(parts.line, tail, Math.atan2(tail.y - prev.y, tail.x - prev.x), headSize, strokeColor, width);
|
|
89
|
+
}
|
|
90
|
+
if (item.arrowStart) {
|
|
91
|
+
const next = samples[1];
|
|
92
|
+
if (next) drawArrowhead(parts.line, head, Math.atan2(head.y - next.y, head.x - next.x), headSize, strokeColor, width);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const labelSig = [item.label, color.label].join("|");
|
|
98
|
+
if (labelSig !== parts.labelSig) {
|
|
99
|
+
parts.labelSig = labelSig;
|
|
100
|
+
parts.label.text = item.label;
|
|
101
|
+
parts.label.style.fill = color.label;
|
|
102
|
+
}
|
|
103
|
+
parts.label.visible = Boolean(resolved && item.label.length > 0);
|
|
104
|
+
if (resolved) parts.label.position.copyFrom(resolved.control);
|
|
105
|
+
}
|
|
106
|
+
const arrowCardRenderer = {
|
|
107
|
+
id: "arrow-card",
|
|
108
|
+
canRender: (item) => item.type === "arrow",
|
|
109
|
+
create: (item, context) => {
|
|
110
|
+
const root = new Container();
|
|
111
|
+
const line = new Graphics();
|
|
112
|
+
const resolution = textResolutionForZoom(context.zoom);
|
|
113
|
+
const label = new Text({
|
|
114
|
+
text: "",
|
|
115
|
+
style: {
|
|
116
|
+
fill: 16777215,
|
|
117
|
+
fontFamily: BOARD_FONT_STACK,
|
|
118
|
+
fontSize: 12,
|
|
119
|
+
fontWeight: "500"
|
|
120
|
+
},
|
|
121
|
+
resolution,
|
|
122
|
+
roundPixels: true
|
|
123
|
+
});
|
|
124
|
+
label.anchor.set(.5);
|
|
125
|
+
root.addChild(line, label);
|
|
126
|
+
partsByContainer.set(root, {
|
|
127
|
+
root,
|
|
128
|
+
line,
|
|
129
|
+
label,
|
|
130
|
+
lineSig: "",
|
|
131
|
+
labelSig: "",
|
|
132
|
+
resolution
|
|
133
|
+
});
|
|
134
|
+
if (item.type === "arrow") sync(root, item, context);
|
|
135
|
+
return root;
|
|
136
|
+
},
|
|
137
|
+
update: (container, item, context) => {
|
|
138
|
+
if (item.type === "arrow") sync(container, item, context);
|
|
139
|
+
},
|
|
140
|
+
renderFar: (graphics, item, context) => {
|
|
141
|
+
if (item.type !== "arrow") return;
|
|
142
|
+
const resolved = resolveArrow(item, frameLookup(context));
|
|
143
|
+
if (!resolved) return;
|
|
144
|
+
const color = pickBoardColor(context.colors, item.color, context.colorScheme);
|
|
145
|
+
drawFarStroke(graphics, sampleQuadratic(resolved, 12), {
|
|
146
|
+
color: color.stroke,
|
|
147
|
+
width: item.size,
|
|
148
|
+
alpha: .85
|
|
149
|
+
});
|
|
150
|
+
},
|
|
151
|
+
destroy: (container) => {
|
|
152
|
+
partsByContainer.get(container)?.root.destroy({ children: true });
|
|
153
|
+
partsByContainer.delete(container);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
//#endregion
|
|
157
|
+
export { arrowCardRenderer };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { BoardItem } from "../../../protocol/dist/board-document.js";
|
|
2
|
+
import { BoardRenderPalette } from "./board-renderer-registry.js";
|
|
3
|
+
import { Container, Text } from "pixi.js";
|
|
4
|
+
//#region src/board/render/renderers/base-card-renderer.d.ts
|
|
5
|
+
declare const CARD_RADIUS = 10;
|
|
6
|
+
declare const CARD_PADDING = 12;
|
|
7
|
+
declare const FOOTER_HEIGHT = 34;
|
|
8
|
+
declare function emphasisColor(item: BoardItem, palette: BoardRenderPalette): number;
|
|
9
|
+
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 positioned by the item frame. */
|
|
20
|
+
root: Container;
|
|
21
|
+
/** Masked container for renderer-specific content. */
|
|
22
|
+
content: Container;
|
|
23
|
+
/** Rectangle (local coords) available for content. */
|
|
24
|
+
contentRect: () => {
|
|
25
|
+
x: number;
|
|
26
|
+
y: number;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
};
|
|
30
|
+
update: (state: CardShellState, palette: BoardRenderPalette, footer: boolean) => void;
|
|
31
|
+
destroy: () => void;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Shared card chrome: rounded background, selection/hover border, optional
|
|
35
|
+
* footer with title, and a masked content region. Tracks the last rendered
|
|
36
|
+
* state so unchanged attributes are not redrawn.
|
|
37
|
+
*/
|
|
38
|
+
declare function createCardShell(): CardShell;
|
|
39
|
+
/**
|
|
40
|
+
* Position a shell root at an item frame. The container pivots around its
|
|
41
|
+
* center so that Pixi's rotation matches the geometry model (which treats
|
|
42
|
+
* `frame.rotation` as a rotation about the frame center).
|
|
43
|
+
*/
|
|
44
|
+
declare function positionShell(root: Container, item: BoardItem): void;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { CARD_PADDING, CARD_RADIUS, CardShell, CardShellState, FOOTER_HEIGHT, createCardShell, createLabel, emphasisColor, positionShell };
|