@scrawl-board/board 0.1.0-beta.1 → 0.1.0-beta.3
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/dist/browser.d.ts +32 -16
- package/dist/browser.js +163 -118
- package/dist/core.d.ts +16 -3
- package/dist/core.js +31 -23
- package/dist/index.d.ts +110 -20
- package/dist/index.js +216 -136
- package/dist/react.d.ts +101 -19
- package/dist/react.js +215 -135
- package/dist/styles.css +2 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
2
2
|
import { createPortal } from "react-dom";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
//#region src/core
|
|
4
|
+
//#region src/core/shapes/assets.ts
|
|
5
5
|
var ASSET_REF_PATTERN = /^asset:[a-z0-9](?:[a-z0-9.-]{0,61}[a-z0-9])?:[A-Za-z0-9._~-]+$/;
|
|
6
6
|
/** Hard ceiling on a reference's own wire length — independent of any resource limit below. */
|
|
7
7
|
var ASSET_REF_MAX_BYTES = 512;
|
|
@@ -41,7 +41,7 @@ function clampAssetCacheBytes(value) {
|
|
|
41
41
|
return Math.min(ASSET_CACHE_BYTES_MAX, Math.max(ASSET_CACHE_BYTES_MIN, Math.floor(value)));
|
|
42
42
|
}
|
|
43
43
|
//#endregion
|
|
44
|
-
//#region src/core
|
|
44
|
+
//#region src/core/document/identifiers.ts
|
|
45
45
|
function documentId(value) {
|
|
46
46
|
if (!value) throw new TypeError("DocumentId cannot be empty");
|
|
47
47
|
return value;
|
|
@@ -51,7 +51,7 @@ function strokeId(value) {
|
|
|
51
51
|
return value;
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
|
-
//#region src/document-schema.ts
|
|
54
|
+
//#region src/core/document/document-schema.ts
|
|
55
55
|
var CURRENT_DOCUMENT_SCHEMA_VERSION = 1;
|
|
56
56
|
var DocumentRecoveryError = class extends Error {
|
|
57
57
|
constructor(code, message, originalBytes, path) {
|
|
@@ -259,7 +259,7 @@ function validation(message, path) {
|
|
|
259
259
|
return new DocumentRecoveryError("DOCUMENT_VALIDATION_FAILED", message, void 0, path);
|
|
260
260
|
}
|
|
261
261
|
//#endregion
|
|
262
|
-
//#region src/core
|
|
262
|
+
//#region src/core/shapes/affine2d.ts
|
|
263
263
|
var IDENTITY = [
|
|
264
264
|
1,
|
|
265
265
|
0,
|
|
@@ -343,7 +343,7 @@ function avgScale(m) {
|
|
|
343
343
|
return (Math.hypot(m[0], m[1]) + Math.hypot(m[2], m[3])) / 2;
|
|
344
344
|
}
|
|
345
345
|
//#endregion
|
|
346
|
-
//#region src/core
|
|
346
|
+
//#region src/core/document/boardSearch.ts
|
|
347
347
|
function hay(s) {
|
|
348
348
|
return s.toLowerCase();
|
|
349
349
|
}
|
|
@@ -408,7 +408,7 @@ function searchBoard(query, board) {
|
|
|
408
408
|
return hits;
|
|
409
409
|
}
|
|
410
410
|
//#endregion
|
|
411
|
-
//#region src/core
|
|
411
|
+
//#region src/core/shapes/types.ts
|
|
412
412
|
/** Erasure level at which a point counts as fully erased. */
|
|
413
413
|
var ERASE_THRESHOLD = .95;
|
|
414
414
|
function cloneStroke(stroke) {
|
|
@@ -484,7 +484,7 @@ function cloneImage(img) {
|
|
|
484
484
|
return { ...img };
|
|
485
485
|
}
|
|
486
486
|
//#endregion
|
|
487
|
-
//#region src/core
|
|
487
|
+
//#region src/core/document/clusterStore.ts
|
|
488
488
|
/** A stroke joins a cluster last written to within this window at full reach. */
|
|
489
489
|
var RECENT_MS = 8e3;
|
|
490
490
|
/** Older clusters are still joinable, at half the gap threshold. */
|
|
@@ -655,7 +655,7 @@ function clamp$3(v, lo, hi) {
|
|
|
655
655
|
return Math.min(hi, Math.max(lo, v));
|
|
656
656
|
}
|
|
657
657
|
//#endregion
|
|
658
|
-
//#region src/core
|
|
658
|
+
//#region src/core/shapes/extensionTypes.ts
|
|
659
659
|
function cloneCustomObject(object) {
|
|
660
660
|
return {
|
|
661
661
|
...object,
|
|
@@ -665,7 +665,7 @@ function cloneCustomObject(object) {
|
|
|
665
665
|
};
|
|
666
666
|
}
|
|
667
667
|
//#endregion
|
|
668
|
-
//#region src/core
|
|
668
|
+
//#region src/core/shapes/kitchenTimer.ts
|
|
669
669
|
var TIMER_DEFAULT_SIZE = 12;
|
|
670
670
|
var TIMER_DEFAULT_DURATION_MS = 300 * 1e3;
|
|
671
671
|
var TIMER_PRESETS_MS = [
|
|
@@ -722,7 +722,7 @@ function formatTimer(ms) {
|
|
|
722
722
|
return `${Math.floor(total / 60)}:${(total % 60).toString().padStart(2, "0")}`;
|
|
723
723
|
}
|
|
724
724
|
//#endregion
|
|
725
|
-
//#region src/core
|
|
725
|
+
//#region src/core/shapes/itemLock.ts
|
|
726
726
|
/**
|
|
727
727
|
* Apply or clear a lock in place. Unlock always drops the holder so a stale
|
|
728
728
|
* name cannot linger on an unlocked item.
|
|
@@ -759,7 +759,7 @@ function serializeLock(item) {
|
|
|
759
759
|
};
|
|
760
760
|
}
|
|
761
761
|
//#endregion
|
|
762
|
-
//#region src/core
|
|
762
|
+
//#region src/core/document/document.ts
|
|
763
763
|
/**
|
|
764
764
|
* The one place a live Stroke becomes its wire representation — in
|
|
765
765
|
* particular, points collapse from {x,y,pressure,erase?} objects into
|
|
@@ -1318,7 +1318,7 @@ function computeBBox(stroke) {
|
|
|
1318
1318
|
return world;
|
|
1319
1319
|
}
|
|
1320
1320
|
//#endregion
|
|
1321
|
-
//#region src/core
|
|
1321
|
+
//#region src/core/commands/commands.ts
|
|
1322
1322
|
/** One drawing action — a marker stroke, or a shape's strokes as one unit. */
|
|
1323
1323
|
var AddStrokesCommand = class {
|
|
1324
1324
|
constructor(strokes) {
|
|
@@ -1660,7 +1660,7 @@ var LockItemsCommand = class {
|
|
|
1660
1660
|
}
|
|
1661
1661
|
};
|
|
1662
1662
|
//#endregion
|
|
1663
|
-
//#region src/core
|
|
1663
|
+
//#region src/core/history/history.ts
|
|
1664
1664
|
var LIMIT = 200;
|
|
1665
1665
|
var History = class {
|
|
1666
1666
|
constructor(doc) {
|
|
@@ -1721,7 +1721,7 @@ var History = class {
|
|
|
1721
1721
|
}
|
|
1722
1722
|
};
|
|
1723
1723
|
//#endregion
|
|
1724
|
-
//#region src/core
|
|
1724
|
+
//#region src/core/events/ops.ts
|
|
1725
1725
|
var ADDED = [
|
|
1726
1726
|
["added", "strokes"],
|
|
1727
1727
|
["notesAdded", "notes"],
|
|
@@ -1775,10 +1775,18 @@ function changeToOps(change, restoring = false) {
|
|
|
1775
1775
|
return ops;
|
|
1776
1776
|
}
|
|
1777
1777
|
//#endregion
|
|
1778
|
-
//#region src/core
|
|
1778
|
+
//#region src/core/shapes/ribbonEdges.ts
|
|
1779
1779
|
var MIN_WIDTH_FACTOR = .35;
|
|
1780
1780
|
var END_TAPER = .55;
|
|
1781
|
-
|
|
1781
|
+
/**
|
|
1782
|
+
* @param handDrawn Default `true`: ink's organic feel — width follows
|
|
1783
|
+
* per-point pressure, and both ends taper. Pass `false` for a geometric
|
|
1784
|
+
* shape outline, which has no real pressure signal and isn't a pen stroke
|
|
1785
|
+
* with a lift-off: it renders at the exact `baseWidth`, uniformly, with no
|
|
1786
|
+
* taper at its start/end (which, for a closed shape, is the same point —
|
|
1787
|
+
* tapering it would visibly pinch just that one corner).
|
|
1788
|
+
*/
|
|
1789
|
+
function ribbonEdges(points, baseWidth, handDrawn = true) {
|
|
1782
1790
|
const pts = points.length === 1 ? [points[0], {
|
|
1783
1791
|
...points[0],
|
|
1784
1792
|
x: points[0].x + baseWidth * .05
|
|
@@ -1793,8 +1801,8 @@ function ribbonEdges(points, baseWidth) {
|
|
|
1793
1801
|
const len = Math.hypot(dx, dy) || 1;
|
|
1794
1802
|
dx /= len;
|
|
1795
1803
|
dy /= len;
|
|
1796
|
-
let width = baseWidth * (MIN_WIDTH_FACTOR + (1 - MIN_WIDTH_FACTOR) * pts[i].pressure);
|
|
1797
|
-
if (i === 0 || i === n - 1) width *= END_TAPER;
|
|
1804
|
+
let width = handDrawn ? baseWidth * (MIN_WIDTH_FACTOR + (1 - MIN_WIDTH_FACTOR) * pts[i].pressure) : baseWidth;
|
|
1805
|
+
if (handDrawn && (i === 0 || i === n - 1)) width *= END_TAPER;
|
|
1798
1806
|
const hw = width / 2;
|
|
1799
1807
|
out[i] = {
|
|
1800
1808
|
lx: pts[i].x - dy * hw,
|
|
@@ -1807,7 +1815,7 @@ function ribbonEdges(points, baseWidth) {
|
|
|
1807
1815
|
return out;
|
|
1808
1816
|
}
|
|
1809
1817
|
//#endregion
|
|
1810
|
-
//#region src/core
|
|
1818
|
+
//#region src/core/document/spatialIndex.ts
|
|
1811
1819
|
var CELL = 8;
|
|
1812
1820
|
var SpatialIndex = class {
|
|
1813
1821
|
constructor(doc) {
|
|
@@ -1880,7 +1888,7 @@ function cellsOf(box) {
|
|
|
1880
1888
|
return keys;
|
|
1881
1889
|
}
|
|
1882
1890
|
//#endregion
|
|
1883
|
-
//#region src/core
|
|
1891
|
+
//#region src/core/shapes/stamps.ts
|
|
1884
1892
|
var STAMP_SIZE = 6;
|
|
1885
1893
|
var STAMPS = [
|
|
1886
1894
|
{
|
|
@@ -1929,7 +1937,7 @@ function isStampKind(value) {
|
|
|
1929
1937
|
return typeof value === "string" && STAMPS.some((s) => s.kind === value);
|
|
1930
1938
|
}
|
|
1931
1939
|
//#endregion
|
|
1932
|
-
//#region src/
|
|
1940
|
+
//#region src/collaboration/presence/presence.ts
|
|
1933
1941
|
/** Keep beacons clear of typical chrome at the top and bottom of the Board. */
|
|
1934
1942
|
var BEACON_INSET = {
|
|
1935
1943
|
top: 72,
|
|
@@ -1965,7 +1973,7 @@ function clamp$2(value, min, max) {
|
|
|
1965
1973
|
return Math.min(max, Math.max(min, value));
|
|
1966
1974
|
}
|
|
1967
1975
|
//#endregion
|
|
1968
|
-
//#region src/
|
|
1976
|
+
//#region src/persistence/serialization/svg.ts
|
|
1969
1977
|
/** Matches the key light used by the board shader and note shadows. */
|
|
1970
1978
|
var LIGHT = {
|
|
1971
1979
|
x: -.25,
|
|
@@ -2107,7 +2115,7 @@ function strokeToPaths(stroke) {
|
|
|
2107
2115
|
y,
|
|
2108
2116
|
pressure,
|
|
2109
2117
|
...erase > 0 ? { erase } : {}
|
|
2110
|
-
})), stroke.baseWidth);
|
|
2118
|
+
})), stroke.baseWidth, stroke.tool !== "shape");
|
|
2111
2119
|
const transform = stroke.matrix ? ` transform="matrix(${fmt(stroke.matrix[0])} ${fmt(-stroke.matrix[1])} ${fmt(-stroke.matrix[2])} ${fmt(stroke.matrix[3])} ${fmt(stroke.matrix[4])} ${fmt(-stroke.matrix[5])})"` : "";
|
|
2112
2120
|
const baseOpacity = stroke.tool === "highlighter" ? .4 : 1;
|
|
2113
2121
|
const paths = [];
|
|
@@ -2336,7 +2344,7 @@ function fmt(n) {
|
|
|
2336
2344
|
var SDK_PACKAGE_NAME = "@scrawl-board/board";
|
|
2337
2345
|
var SDK_DEVELOPMENT_VERSION = "0.0.0-development";
|
|
2338
2346
|
//#endregion
|
|
2339
|
-
//#region src/core
|
|
2347
|
+
//#region src/core/shapes/sceneGeometry.ts
|
|
2340
2348
|
var EMPTY_BOUNDS = {
|
|
2341
2349
|
x: 0,
|
|
2342
2350
|
y: 0,
|
|
@@ -2400,7 +2408,7 @@ function textCorners(x, y, text, fontSize, align, m) {
|
|
|
2400
2408
|
return rectCorners(x + (align === "center" ? -width / 2 : align === "end" ? -width : 0), y, width, height, m);
|
|
2401
2409
|
}
|
|
2402
2410
|
//#endregion
|
|
2403
|
-
//#region src/core
|
|
2411
|
+
//#region src/core/shapes/customObjects.ts
|
|
2404
2412
|
var FALLBACK_LABEL_MAX_LENGTH = 80;
|
|
2405
2413
|
function toReadonly(object) {
|
|
2406
2414
|
return object;
|
|
@@ -2529,7 +2537,7 @@ function extensionIdFromType(type) {
|
|
|
2529
2537
|
return slash === -1 ? type : type.slice(0, slash);
|
|
2530
2538
|
}
|
|
2531
2539
|
//#endregion
|
|
2532
|
-
//#region src/core
|
|
2540
|
+
//#region src/core/shapes/extensionRegistry.ts
|
|
2533
2541
|
function buildExtensionRegistry(extensions) {
|
|
2534
2542
|
const list = extensions ?? [];
|
|
2535
2543
|
const diagnostics = [];
|
|
@@ -2626,7 +2634,7 @@ function isWellFormedNamespacedId(id) {
|
|
|
2626
2634
|
return isWellFormedId(id) && id.includes("/") && !id.startsWith("/") && !id.endsWith("/");
|
|
2627
2635
|
}
|
|
2628
2636
|
//#endregion
|
|
2629
|
-
//#region src/
|
|
2637
|
+
//#region src/persistence/adapters/assetValidation.ts
|
|
2630
2638
|
function sniffImageMediaType(bytes) {
|
|
2631
2639
|
if (bytes.length >= 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10) return "image/png";
|
|
2632
2640
|
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "image/jpeg";
|
|
@@ -2713,7 +2721,7 @@ function validateDecodedDimensions(width, height) {
|
|
|
2713
2721
|
};
|
|
2714
2722
|
}
|
|
2715
2723
|
//#endregion
|
|
2716
|
-
//#region src/assetController.ts
|
|
2724
|
+
//#region src/persistence/adapters/assetController.ts
|
|
2717
2725
|
var FAILURE_COALESCE_MS = 4e3;
|
|
2718
2726
|
var AssetController = class {
|
|
2719
2727
|
constructor(resolver, options) {
|
|
@@ -2892,7 +2900,7 @@ function toAssetResolutionError(cause, ref) {
|
|
|
2892
2900
|
return new AssetResolutionError("unknown", true, cause instanceof Error ? cause.message : String(cause), ref);
|
|
2893
2901
|
}
|
|
2894
2902
|
//#endregion
|
|
2895
|
-
//#region src/
|
|
2903
|
+
//#region src/persistence/serialization/assetRefCollector.ts
|
|
2896
2904
|
/** Every unique Asset reference in the document, and which object(s) use it. */
|
|
2897
2905
|
function collectDocumentAssetRefs(doc, registry) {
|
|
2898
2906
|
const refs = /* @__PURE__ */ new Map();
|
|
@@ -2919,7 +2927,7 @@ function collectSceneAssetRefs(node, objectId, add) {
|
|
|
2919
2927
|
if (node.kind === "group") for (const child of node.children) collectSceneAssetRefs(child, objectId, add);
|
|
2920
2928
|
}
|
|
2921
2929
|
//#endregion
|
|
2922
|
-
//#region src/assetExport.ts
|
|
2930
|
+
//#region src/persistence/serialization/assetExport.ts
|
|
2923
2931
|
/** Strict mode's rejection — never contains credentials, a fetchable location, or a raw resolver message. */
|
|
2924
2932
|
var SvgAssetExportError = class extends Error {
|
|
2925
2933
|
constructor(missingAssets) {
|
|
@@ -2975,7 +2983,7 @@ function toDataUri(bytes, mediaType) {
|
|
|
2975
2983
|
return `data:${mediaType};base64,${btoa(binary)}`;
|
|
2976
2984
|
}
|
|
2977
2985
|
//#endregion
|
|
2978
|
-
//#region src/assetIngestion.ts
|
|
2986
|
+
//#region src/persistence/adapters/assetIngestion.ts
|
|
2979
2987
|
async function decodeDimensionsWithImageBitmap(bytes, mediaType) {
|
|
2980
2988
|
const blob = new Blob([bytes], { type: mediaType });
|
|
2981
2989
|
let bitmap;
|
|
@@ -35621,7 +35629,7 @@ var WebGLRenderer = class {
|
|
|
35621
35629
|
}
|
|
35622
35630
|
};
|
|
35623
35631
|
//#endregion
|
|
35624
|
-
//#region
|
|
35632
|
+
//#region src/core/events/auditEvents.ts
|
|
35625
35633
|
var BY_LABEL = {
|
|
35626
35634
|
draw: {
|
|
35627
35635
|
action: "create",
|
|
@@ -35741,7 +35749,7 @@ function lowerFirst(s) {
|
|
|
35741
35749
|
return s.charAt(0).toLowerCase() + s.slice(1);
|
|
35742
35750
|
}
|
|
35743
35751
|
//#endregion
|
|
35744
|
-
//#region
|
|
35752
|
+
//#region src/renderer/shapes/AssetTextureCache.ts
|
|
35745
35753
|
var AssetTextureCache = class {
|
|
35746
35754
|
constructor(assetController) {
|
|
35747
35755
|
this.assetController = assetController;
|
|
@@ -35832,7 +35840,7 @@ function toDecodeError(cause, ref) {
|
|
|
35832
35840
|
return new AssetResolutionError("decode-failed", false, cause instanceof Error ? cause.message : String(cause), ref);
|
|
35833
35841
|
}
|
|
35834
35842
|
//#endregion
|
|
35835
|
-
//#region
|
|
35843
|
+
//#region src/renderer/canvas/raycast.ts
|
|
35836
35844
|
var origin$1 = new Vector3();
|
|
35837
35845
|
var target = new Vector3();
|
|
35838
35846
|
function pointerToBoard(clientX, clientY, canvas, camera) {
|
|
@@ -35863,7 +35871,7 @@ function pointerToPlane(clientX, clientY, canvas, camera, z) {
|
|
|
35863
35871
|
};
|
|
35864
35872
|
}
|
|
35865
35873
|
//#endregion
|
|
35866
|
-
//#region
|
|
35874
|
+
//#region src/renderer/canvas/fog.ts
|
|
35867
35875
|
function createFogUniforms(color) {
|
|
35868
35876
|
return {
|
|
35869
35877
|
uFogColor: { value: new Color(color) },
|
|
@@ -35884,18 +35892,24 @@ var FOG_GLSL = `
|
|
|
35884
35892
|
}
|
|
35885
35893
|
`;
|
|
35886
35894
|
//#endregion
|
|
35887
|
-
//#region
|
|
35895
|
+
//#region src/renderer/canvas/boardSurface.ts
|
|
35888
35896
|
var GRID_MODE_CODE = {
|
|
35889
35897
|
none: 0,
|
|
35890
35898
|
line: 1,
|
|
35891
35899
|
dot: 2
|
|
35892
35900
|
};
|
|
35901
|
+
var TEXTURE_CODE = {
|
|
35902
|
+
flat: 0,
|
|
35903
|
+
textured: 1
|
|
35904
|
+
};
|
|
35893
35905
|
/** Used when a caller doesn't supply one (e.g. ScrawlEngine constructed without a Host theme). */
|
|
35894
35906
|
var DEFAULT_BOARD_SURFACE_THEME = {
|
|
35895
35907
|
color: "#f5f5f3",
|
|
35896
35908
|
gridMode: "none",
|
|
35897
35909
|
gridColor: "#deded8",
|
|
35898
|
-
gridSpacing: 5
|
|
35910
|
+
gridSpacing: 5,
|
|
35911
|
+
gridLineWidth: 1,
|
|
35912
|
+
surfaceTexture: "flat"
|
|
35899
35913
|
};
|
|
35900
35914
|
/** Grid alpha fades out below this on-screen spacing (px) — otherwise it aliases into a solid wash when zoomed out. */
|
|
35901
35915
|
var GRID_FADE_MIN_PX = 3;
|
|
@@ -35916,8 +35930,10 @@ var FRAGMENT = `
|
|
|
35916
35930
|
uniform float uGridMode;
|
|
35917
35931
|
uniform vec3 uGridColor;
|
|
35918
35932
|
uniform float uGridSpacing;
|
|
35919
|
-
uniform float
|
|
35933
|
+
uniform float uWorldPerPixel;
|
|
35934
|
+
uniform float uGridLineWidthPx;
|
|
35920
35935
|
uniform float uGridFade;
|
|
35936
|
+
uniform float uSurfaceTexture;
|
|
35921
35937
|
varying vec3 vWorldPos;
|
|
35922
35938
|
|
|
35923
35939
|
float hash(vec2 p) {
|
|
@@ -35937,37 +35953,45 @@ var FRAGMENT = `
|
|
|
35937
35953
|
${FOG_GLSL}
|
|
35938
35954
|
|
|
35939
35955
|
// Distance from p's nearest axis-aligned grid line, in world units.
|
|
35956
|
+
// A crisp, ~uGridLineWidthPx-wide line: full alpha to its half-width, a
|
|
35957
|
+
// ~1px anti-aliased falloff beyond that — not a wide, soft-edged band.
|
|
35940
35958
|
float gridLineAlpha(vec2 p) {
|
|
35941
35959
|
vec2 cell = mod(p, uGridSpacing);
|
|
35942
35960
|
vec2 distToLine = min(cell, uGridSpacing - cell);
|
|
35943
|
-
|
|
35961
|
+
float halfWidth = 0.5 * uGridLineWidthPx * uWorldPerPixel;
|
|
35962
|
+
float aa = uWorldPerPixel;
|
|
35963
|
+
vec2 lineAlpha2 = 1.0 - smoothstep(halfWidth - aa * 0.5, halfWidth + aa * 0.5, distToLine);
|
|
35944
35964
|
return max(lineAlpha2.x, lineAlpha2.y);
|
|
35945
35965
|
}
|
|
35946
35966
|
|
|
35947
|
-
// Distance from p's nearest grid intersection, in world units.
|
|
35967
|
+
// Distance from p's nearest grid intersection, in world units. Dot radius
|
|
35968
|
+
// matches the configured line width in pixels, same anti-aliasing.
|
|
35948
35969
|
float gridDotAlpha(vec2 p) {
|
|
35949
35970
|
vec2 cell = mod(p, uGridSpacing) - uGridSpacing * 0.5;
|
|
35950
35971
|
float dist = length(cell);
|
|
35951
|
-
float radius =
|
|
35952
|
-
|
|
35972
|
+
float radius = uGridLineWidthPx * uWorldPerPixel;
|
|
35973
|
+
float aa = uWorldPerPixel;
|
|
35974
|
+
return 1.0 - smoothstep(radius - aa * 0.5, radius + aa * 0.5, dist);
|
|
35953
35975
|
}
|
|
35954
35976
|
|
|
35955
35977
|
void main() {
|
|
35956
35978
|
vec3 col = uColor;
|
|
35957
35979
|
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
35980
|
+
if (uSurfaceTexture > 0.5) {
|
|
35981
|
+
// Melamine micro-texture: two octaves of value noise, +-1.75% brightness.
|
|
35982
|
+
float n = vnoise(vWorldPos.xy * 2.3) * 0.6 + vnoise(vWorldPos.xy * 9.7) * 0.4;
|
|
35983
|
+
col *= 1.0 + (n - 0.5) * 0.035;
|
|
35961
35984
|
|
|
35962
|
-
|
|
35963
|
-
|
|
35964
|
-
|
|
35965
|
-
|
|
35966
|
-
|
|
35967
|
-
|
|
35968
|
-
|
|
35969
|
-
|
|
35970
|
-
|
|
35985
|
+
// Satin sheen: Fresnel rim + a specular band from the key light. Both
|
|
35986
|
+
// are ~zero in the straight-on working view and bloom as the camera tilts.
|
|
35987
|
+
vec3 V = normalize(cameraPosition - vWorldPos);
|
|
35988
|
+
vec3 N = vec3(0.0, 0.0, 1.0);
|
|
35989
|
+
float fres = pow(1.0 - max(dot(N, V), 0.0), 3.0);
|
|
35990
|
+
vec3 L = normalize(vec3(-0.25, 0.4, 0.88));
|
|
35991
|
+
vec3 H = normalize(L + V);
|
|
35992
|
+
float spec = pow(max(dot(N, H), 0.0), 90.0);
|
|
35993
|
+
col += (fres * 0.18 + spec * 0.06) * vec3(1.0);
|
|
35994
|
+
}
|
|
35971
35995
|
|
|
35972
35996
|
if (uGridMode > 0.5 && uGridFade > 0.001) {
|
|
35973
35997
|
float gridAlpha = (uGridMode < 1.5 ? gridLineAlpha(vWorldPos.xy) : gridDotAlpha(vWorldPos.xy)) * uGridFade;
|
|
@@ -35987,8 +36011,10 @@ function createBoardSurface(fog, theme) {
|
|
|
35987
36011
|
uGridMode: { value: GRID_MODE_CODE[theme.gridMode] },
|
|
35988
36012
|
uGridColor: { value: new Color(theme.gridColor) },
|
|
35989
36013
|
uGridSpacing: { value: Math.max(.001, theme.gridSpacing) },
|
|
35990
|
-
|
|
36014
|
+
uGridLineWidthPx: { value: Math.max(.1, theme.gridLineWidth) },
|
|
36015
|
+
uWorldPerPixel: { value: .05 },
|
|
35991
36016
|
uGridFade: { value: 0 },
|
|
36017
|
+
uSurfaceTexture: { value: TEXTURE_CODE[theme.surfaceTexture] },
|
|
35992
36018
|
...fog
|
|
35993
36019
|
}
|
|
35994
36020
|
});
|
|
@@ -35996,13 +36022,15 @@ function createBoardSurface(fog, theme) {
|
|
|
35996
36022
|
mesh.name = "board-surface";
|
|
35997
36023
|
return mesh;
|
|
35998
36024
|
}
|
|
35999
|
-
/** Applies a theme change (initial or live) — everything except the per-frame fade/
|
|
36025
|
+
/** Applies a theme change (initial or live) — everything except the per-frame fade/pixel-ratio. */
|
|
36000
36026
|
function setBoardSurfaceTheme(mesh, theme) {
|
|
36001
36027
|
const uniforms = mesh.material.uniforms;
|
|
36002
36028
|
uniforms.uColor.value.set(theme.color);
|
|
36003
36029
|
uniforms.uGridMode.value = GRID_MODE_CODE[theme.gridMode];
|
|
36004
36030
|
uniforms.uGridColor.value.set(theme.gridColor);
|
|
36005
36031
|
uniforms.uGridSpacing.value = Math.max(.001, theme.gridSpacing);
|
|
36032
|
+
uniforms.uGridLineWidthPx.value = Math.max(.1, theme.gridLineWidth);
|
|
36033
|
+
uniforms.uSurfaceTexture.value = TEXTURE_CODE[theme.surfaceTexture];
|
|
36006
36034
|
}
|
|
36007
36035
|
/** Keep the plane centered under the view, larger than the fog horizon, and the grid's on-screen weight/fade current. */
|
|
36008
36036
|
function updateBoardSurface(mesh, centerX, centerY, fogFar, worldPerPixel) {
|
|
@@ -36010,7 +36038,7 @@ function updateBoardSurface(mesh, centerX, centerY, fogFar, worldPerPixel) {
|
|
|
36010
36038
|
const size = fogFar * 2.5;
|
|
36011
36039
|
mesh.scale.set(size, size, 1);
|
|
36012
36040
|
const uniforms = mesh.material.uniforms;
|
|
36013
|
-
uniforms.
|
|
36041
|
+
uniforms.uWorldPerPixel.value = worldPerPixel;
|
|
36014
36042
|
const t = (uniforms.uGridSpacing.value / Math.max(1e-6, worldPerPixel) - GRID_FADE_MIN_PX) / (GRID_FADE_MAX_PX - GRID_FADE_MIN_PX);
|
|
36015
36043
|
uniforms.uGridFade.value = MathUtils.clamp(t, 0, 1);
|
|
36016
36044
|
}
|
|
@@ -36183,7 +36211,7 @@ var CameraRig = class {
|
|
|
36183
36211
|
}
|
|
36184
36212
|
};
|
|
36185
36213
|
//#endregion
|
|
36186
|
-
//#region
|
|
36214
|
+
//#region src/renderer/canvas/scene.ts
|
|
36187
36215
|
var SceneRig = class {
|
|
36188
36216
|
constructor(canvas, boardTheme) {
|
|
36189
36217
|
this.renderer = new WebGLRenderer({
|
|
@@ -36230,7 +36258,7 @@ var SceneRig = class {
|
|
|
36230
36258
|
}
|
|
36231
36259
|
};
|
|
36232
36260
|
//#endregion
|
|
36233
|
-
//#region
|
|
36261
|
+
//#region src/renderer/shapes/inkMaterial.ts
|
|
36234
36262
|
var VERTEX = `
|
|
36235
36263
|
attribute float aAlpha;
|
|
36236
36264
|
varying vec2 vUv;
|
|
@@ -36361,15 +36389,15 @@ var InkMaterials = class {
|
|
|
36361
36389
|
}
|
|
36362
36390
|
};
|
|
36363
36391
|
//#endregion
|
|
36364
|
-
//#region
|
|
36392
|
+
//#region src/renderer/shapes/ribbonGeometry.ts
|
|
36365
36393
|
/** Ink floats a hair above the board to avoid z-fighting with the surface. */
|
|
36366
36394
|
var INK_Z = .02;
|
|
36367
36395
|
/** Highlighter always renders under opaque ink (build prompt §4.1). */
|
|
36368
36396
|
var HIGHLIGHT_Z = .016;
|
|
36369
36397
|
/** Ghosts sit under everything so live strokes always read on top. */
|
|
36370
36398
|
var GHOST_Z = .012;
|
|
36371
|
-
function buildRibbonGeometry(points, baseWidth, z = INK_Z) {
|
|
36372
|
-
const edges = ribbonEdges(points, baseWidth);
|
|
36399
|
+
function buildRibbonGeometry(points, baseWidth, z = INK_Z, handDrawn = true) {
|
|
36400
|
+
const edges = ribbonEdges(points, baseWidth, handDrawn);
|
|
36373
36401
|
const n = edges.length;
|
|
36374
36402
|
const positions = new Float32Array(n * 2 * 3);
|
|
36375
36403
|
const uvs = new Float32Array(n * 2 * 2);
|
|
@@ -36412,8 +36440,10 @@ function buildRibbonGeometry(points, baseWidth, z = INK_Z) {
|
|
|
36412
36440
|
return geometry;
|
|
36413
36441
|
}
|
|
36414
36442
|
//#endregion
|
|
36415
|
-
//#region
|
|
36443
|
+
//#region src/renderer/shapes/strokeRenderer.ts
|
|
36416
36444
|
var strokeZ = (stroke) => stroke.tool === "highlighter" ? HIGHLIGHT_Z : INK_Z;
|
|
36445
|
+
/** Shapes (rect/ellipse/line/arrow/...) are geometric outlines, not pressure-sensitive ink. */
|
|
36446
|
+
var handDrawn = (stroke) => stroke.tool !== "shape";
|
|
36417
36447
|
/**
|
|
36418
36448
|
* Derives ink meshes from the document by subscription — the document never
|
|
36419
36449
|
* knows the renderer exists. Also hosts session-only ghosts (decision Q7)
|
|
@@ -36438,12 +36468,12 @@ var StrokeRenderer = class {
|
|
|
36438
36468
|
this.ghostGroup.visible = visible;
|
|
36439
36469
|
}
|
|
36440
36470
|
/** Leave a smeared residue of an erased span (never persisted). */
|
|
36441
|
-
addGhost(points, color, baseWidth) {
|
|
36471
|
+
addGhost(points, color, baseWidth, handDrawn = true) {
|
|
36442
36472
|
if (points.length < 2) return;
|
|
36443
36473
|
const mesh = new Mesh(buildRibbonGeometry(points.map((p) => ({
|
|
36444
36474
|
...p,
|
|
36445
36475
|
erase: 0
|
|
36446
|
-
})), baseWidth * 1.7, GHOST_Z), this.materials.ghost(color));
|
|
36476
|
+
})), baseWidth * 1.7, GHOST_Z, handDrawn), this.materials.ghost(color));
|
|
36447
36477
|
this.ghostGroup.add(mesh);
|
|
36448
36478
|
}
|
|
36449
36479
|
/**
|
|
@@ -36455,7 +36485,7 @@ var StrokeRenderer = class {
|
|
|
36455
36485
|
if (this.meshes.has(stroke.id) || this.retiredLive.has(stroke.id) || stroke.points.length < 2) return;
|
|
36456
36486
|
this.liveUser.set(stroke.id, userId);
|
|
36457
36487
|
const existing = this.liveMeshes.get(stroke.id);
|
|
36458
|
-
const geometry = buildRibbonGeometry(stroke.points, stroke.baseWidth, strokeZ(stroke));
|
|
36488
|
+
const geometry = buildRibbonGeometry(stroke.points, stroke.baseWidth, strokeZ(stroke), handDrawn(stroke));
|
|
36459
36489
|
if (existing) {
|
|
36460
36490
|
existing.geometry.dispose();
|
|
36461
36491
|
existing.geometry = geometry;
|
|
@@ -36515,7 +36545,7 @@ var StrokeRenderer = class {
|
|
|
36515
36545
|
const mesh = this.meshes.get(stroke.id);
|
|
36516
36546
|
if (mesh) {
|
|
36517
36547
|
mesh.geometry.dispose();
|
|
36518
|
-
mesh.geometry = buildRibbonGeometry(stroke.points, stroke.baseWidth, strokeZ(stroke));
|
|
36548
|
+
mesh.geometry = buildRibbonGeometry(stroke.points, stroke.baseWidth, strokeZ(stroke), handDrawn(stroke));
|
|
36519
36549
|
}
|
|
36520
36550
|
}
|
|
36521
36551
|
for (const stroke of change.transformed) {
|
|
@@ -36524,7 +36554,7 @@ var StrokeRenderer = class {
|
|
|
36524
36554
|
}
|
|
36525
36555
|
}
|
|
36526
36556
|
create(stroke) {
|
|
36527
|
-
const mesh = new Mesh(buildRibbonGeometry(stroke.points, stroke.baseWidth, strokeZ(stroke)), stroke.tool === "highlighter" ? this.materials.highlight(stroke.color) : this.materials.get(stroke.color));
|
|
36557
|
+
const mesh = new Mesh(buildRibbonGeometry(stroke.points, stroke.baseWidth, strokeZ(stroke), handDrawn(stroke)), stroke.tool === "highlighter" ? this.materials.highlight(stroke.color) : this.materials.get(stroke.color));
|
|
36528
36558
|
mesh.matrixAutoUpdate = false;
|
|
36529
36559
|
syncMatrix(mesh, stroke);
|
|
36530
36560
|
this.meshes.set(stroke.id, mesh);
|
|
@@ -36545,7 +36575,7 @@ function syncMatrix(mesh, stroke) {
|
|
|
36545
36575
|
mesh.matrixWorldNeedsUpdate = true;
|
|
36546
36576
|
}
|
|
36547
36577
|
//#endregion
|
|
36548
|
-
//#region
|
|
36578
|
+
//#region src/renderer/shapes/markerProp.ts
|
|
36549
36579
|
var BODY_LENGTH = 11;
|
|
36550
36580
|
var BODY_RADIUS = .85;
|
|
36551
36581
|
var TIP_LENGTH = 1.6;
|
|
@@ -36641,7 +36671,7 @@ var MarkerProp = class {
|
|
|
36641
36671
|
}
|
|
36642
36672
|
};
|
|
36643
36673
|
//#endregion
|
|
36644
|
-
//#region
|
|
36674
|
+
//#region src/renderer/shapes/noteGeometry.ts
|
|
36645
36675
|
/**
|
|
36646
36676
|
* Height of the sheet above the board at (u, v) ∈ [0,1]².
|
|
36647
36677
|
* v = 1 is the adhesive edge (always 0); u = 1 is the peel corner side.
|
|
@@ -36685,7 +36715,7 @@ function applyCurl(geometry, curl, peel) {
|
|
|
36685
36715
|
color.needsUpdate = true;
|
|
36686
36716
|
}
|
|
36687
36717
|
//#endregion
|
|
36688
|
-
//#region
|
|
36718
|
+
//#region src/renderer/shapes/stickyNotes.ts
|
|
36689
36719
|
var TEXTURE_SIZE = 512;
|
|
36690
36720
|
var FOCUS_COLOR$4 = 2450411;
|
|
36691
36721
|
var CURL = .3;
|
|
@@ -43261,7 +43291,7 @@ SYNCABLE_PROPS.forEach((prop) => {
|
|
|
43261
43291
|
new Box3();
|
|
43262
43292
|
new Color();
|
|
43263
43293
|
//#endregion
|
|
43264
|
-
//#region
|
|
43294
|
+
//#region src/renderer/shapes/tables.ts
|
|
43265
43295
|
var FONT_URL$2 = "/fonts/inter-medium.woff";
|
|
43266
43296
|
var TABLE_Z = .012;
|
|
43267
43297
|
var HEADER_Z = .014;
|
|
@@ -43610,7 +43640,7 @@ var TablesRenderer = class {
|
|
|
43610
43640
|
}
|
|
43611
43641
|
};
|
|
43612
43642
|
//#endregion
|
|
43613
|
-
//#region
|
|
43643
|
+
//#region src/renderer/text/textBlocks.ts
|
|
43614
43644
|
var FONT_URL$1 = "/fonts/inter-medium.woff";
|
|
43615
43645
|
var TEXT_Z = .02;
|
|
43616
43646
|
var FOCUS_COLOR$2 = 2450411;
|
|
@@ -43714,7 +43744,7 @@ var TextBlocksRenderer = class {
|
|
|
43714
43744
|
}
|
|
43715
43745
|
};
|
|
43716
43746
|
//#endregion
|
|
43717
|
-
//#region
|
|
43747
|
+
//#region src/renderer/shapes/comments.ts
|
|
43718
43748
|
var PIN_Z = .04;
|
|
43719
43749
|
var PIN_WIDTH = 3.6;
|
|
43720
43750
|
var PIN_HEIGHT = 3.6;
|
|
@@ -43882,7 +43912,7 @@ function drawBubblePath(ctx, x, y, w, h, r, tailX, tailY, tailW) {
|
|
|
43882
43912
|
ctx.closePath();
|
|
43883
43913
|
}
|
|
43884
43914
|
//#endregion
|
|
43885
|
-
//#region
|
|
43915
|
+
//#region src/renderer/shapes/images.ts
|
|
43886
43916
|
var IMAGE_Z = .015;
|
|
43887
43917
|
var FRAME_BORDER = .4;
|
|
43888
43918
|
var FOCUS_COLOR$1 = 2450411;
|
|
@@ -44092,7 +44122,7 @@ function applyPlaceholderTexture(visual, label) {
|
|
|
44092
44122
|
visual.imageMesh.material.needsUpdate = true;
|
|
44093
44123
|
}
|
|
44094
44124
|
//#endregion
|
|
44095
|
-
//#region
|
|
44125
|
+
//#region src/renderer/shapes/kitchenTimers.ts
|
|
44096
44126
|
var FACE_SIZE = 256;
|
|
44097
44127
|
var BODY_COLOR = 14753096;
|
|
44098
44128
|
var KNOB_COLOR = 16448250;
|
|
@@ -44290,7 +44320,7 @@ function renderTimerFace(timer, canvas, now = Date.now()) {
|
|
|
44290
44320
|
return c;
|
|
44291
44321
|
}
|
|
44292
44322
|
//#endregion
|
|
44293
|
-
//#region
|
|
44323
|
+
//#region src/renderer/shapes/customObjects.ts
|
|
44294
44324
|
var FONT_URL = "/fonts/inter-medium.woff";
|
|
44295
44325
|
var CUSTOM_Z = .02;
|
|
44296
44326
|
var FOCUS_COLOR = 2450411;
|
|
@@ -44652,7 +44682,7 @@ function disposeObject3D(obj) {
|
|
|
44652
44682
|
});
|
|
44653
44683
|
}
|
|
44654
44684
|
//#endregion
|
|
44655
|
-
//#region
|
|
44685
|
+
//#region src/interaction/pointer/hitTest.ts
|
|
44656
44686
|
/** Topmost (most recently added) stroke under the point, or null. */
|
|
44657
44687
|
function hitStroke(doc, index, p, slop) {
|
|
44658
44688
|
const candidates = index.query(p.x - slop, p.y - slop, p.x + slop, p.y + slop);
|
|
@@ -44663,9 +44693,10 @@ function hitStroke(doc, index, p, slop) {
|
|
|
44663
44693
|
const scale = m ? avgScale(m) : 1;
|
|
44664
44694
|
let prev = null;
|
|
44665
44695
|
let prevWidth = 0;
|
|
44696
|
+
const handDrawn = stroke.tool !== "shape";
|
|
44666
44697
|
for (const point of stroke.points) {
|
|
44667
44698
|
const world = m ? apply(m, point) : point;
|
|
44668
|
-
const width = stroke.baseWidth * (MIN_WIDTH_FACTOR + (1 - MIN_WIDTH_FACTOR) * point.pressure) * scale;
|
|
44699
|
+
const width = (handDrawn ? stroke.baseWidth * (MIN_WIDTH_FACTOR + (1 - MIN_WIDTH_FACTOR) * point.pressure) : stroke.baseWidth) * scale;
|
|
44669
44700
|
if (prev) {
|
|
44670
44701
|
const reach = Math.max(width, prevWidth) / 2 + slop;
|
|
44671
44702
|
if (distToSegmentSq(p, prev, world) <= reach * reach) {
|
|
@@ -44693,7 +44724,7 @@ function distToSegmentSq(p, a, b) {
|
|
|
44693
44724
|
return dx * dx + dy * dy;
|
|
44694
44725
|
}
|
|
44695
44726
|
//#endregion
|
|
44696
|
-
//#region
|
|
44727
|
+
//#region src/interaction/tools/eraserTool.ts
|
|
44697
44728
|
var DECAY_PER_PASS = .4;
|
|
44698
44729
|
/** A point can take another decay pass after this long — rubbing works. */
|
|
44699
44730
|
var REARM_MS = 250;
|
|
@@ -44799,7 +44830,7 @@ var EraserTool = class {
|
|
|
44799
44830
|
...p,
|
|
44800
44831
|
...apply(m, p)
|
|
44801
44832
|
})) : run.points;
|
|
44802
|
-
this.ctx.renderer.addGhost(world, current.color, current.baseWidth * (m ? avgScale(m) : 1));
|
|
44833
|
+
this.ctx.renderer.addGhost(world, current.color, current.baseWidth * (m ? avgScale(m) : 1), current.tool !== "shape");
|
|
44803
44834
|
}
|
|
44804
44835
|
}
|
|
44805
44836
|
doc.removeStrokes(before.map((s) => s.id));
|
|
@@ -44821,7 +44852,7 @@ function partitionByErasure(points) {
|
|
|
44821
44852
|
return runs;
|
|
44822
44853
|
}
|
|
44823
44854
|
//#endregion
|
|
44824
|
-
//#region
|
|
44855
|
+
//#region src/interaction/tools/noteDrag.ts
|
|
44825
44856
|
/**
|
|
44826
44857
|
* Drag the focused note in X/Y. The grab is resolved on the note's own
|
|
44827
44858
|
* z-plane, not the board, so the note doesn't jump under a tilted ray.
|
|
@@ -44888,7 +44919,7 @@ var NoteDragState = class {
|
|
|
44888
44919
|
}
|
|
44889
44920
|
};
|
|
44890
44921
|
//#endregion
|
|
44891
|
-
//#region
|
|
44922
|
+
//#region src/interaction/tools/imageDrag.ts
|
|
44892
44923
|
/** Drag the focused image in X/Y; one command per drag. */
|
|
44893
44924
|
var ImageDragState = class {
|
|
44894
44925
|
constructor(ctx) {
|
|
@@ -44940,7 +44971,7 @@ var ImageDragState = class {
|
|
|
44940
44971
|
}
|
|
44941
44972
|
};
|
|
44942
44973
|
//#endregion
|
|
44943
|
-
//#region
|
|
44974
|
+
//#region src/interaction/tools/timerDrag.ts
|
|
44944
44975
|
/** Drag the focused timer in X/Y; one command per drag. */
|
|
44945
44976
|
var TimerDragState = class {
|
|
44946
44977
|
constructor(ctx) {
|
|
@@ -44992,7 +45023,7 @@ var TimerDragState = class {
|
|
|
44992
45023
|
}
|
|
44993
45024
|
};
|
|
44994
45025
|
//#endregion
|
|
44995
|
-
//#region
|
|
45026
|
+
//#region src/interaction/tools/shapeGeometry.ts
|
|
44996
45027
|
/** Uniform synthetic pressure; the ink shader supplies the hand-drawn feel. */
|
|
44997
45028
|
var PRESSURE = .7;
|
|
44998
45029
|
var MIN_ELLIPSE_SEGMENTS = 24;
|
|
@@ -45032,10 +45063,7 @@ function rect(a, b, step) {
|
|
|
45032
45063
|
a
|
|
45033
45064
|
];
|
|
45034
45065
|
const out = [];
|
|
45035
|
-
for (let i = 0; i < corners.length - 1; i++)
|
|
45036
|
-
const edge = sampleSegment(corners[i], corners[i + 1], step);
|
|
45037
|
-
out.push(...i === 0 ? edge : edge.slice(1));
|
|
45038
|
-
}
|
|
45066
|
+
for (let i = 0; i < corners.length - 1; i++) out.push(...sampleSegment(corners[i], corners[i + 1], step));
|
|
45039
45067
|
return out;
|
|
45040
45068
|
}
|
|
45041
45069
|
function ellipse(a, b, step) {
|
|
@@ -45106,10 +45134,7 @@ function polygon(sides, a, b, step, startAngle = -Math.PI / 2) {
|
|
|
45106
45134
|
}
|
|
45107
45135
|
vertices.push(vertices[0]);
|
|
45108
45136
|
const out = [];
|
|
45109
|
-
for (let i = 0; i < vertices.length - 1; i++)
|
|
45110
|
-
const edge = sampleSegment(vertices[i], vertices[i + 1], step);
|
|
45111
|
-
out.push(...i === 0 ? edge : edge.slice(1));
|
|
45112
|
-
}
|
|
45137
|
+
for (let i = 0; i < vertices.length - 1; i++) out.push(...sampleSegment(vertices[i], vertices[i + 1], step));
|
|
45113
45138
|
return out;
|
|
45114
45139
|
}
|
|
45115
45140
|
function star(points, a, b, step) {
|
|
@@ -45133,10 +45158,7 @@ function star(points, a, b, step) {
|
|
|
45133
45158
|
}
|
|
45134
45159
|
vertices.push(vertices[0]);
|
|
45135
45160
|
const out = [];
|
|
45136
|
-
for (let i = 0; i < vertices.length - 1; i++)
|
|
45137
|
-
const edge = sampleSegment(vertices[i], vertices[i + 1], step);
|
|
45138
|
-
out.push(...i === 0 ? edge : edge.slice(1));
|
|
45139
|
-
}
|
|
45161
|
+
for (let i = 0; i < vertices.length - 1; i++) out.push(...sampleSegment(vertices[i], vertices[i + 1], step));
|
|
45140
45162
|
return out;
|
|
45141
45163
|
}
|
|
45142
45164
|
function heart(a, b, step) {
|
|
@@ -45181,7 +45203,7 @@ function snappedEnd(a, b) {
|
|
|
45181
45203
|
};
|
|
45182
45204
|
}
|
|
45183
45205
|
//#endregion
|
|
45184
|
-
//#region
|
|
45206
|
+
//#region src/interaction/tools/shapeTool.ts
|
|
45185
45207
|
var MIN_DRAG_PX$1 = 4;
|
|
45186
45208
|
/** Drag out a shape; live preview through the real ink material. */
|
|
45187
45209
|
var ShapeTool = class {
|
|
@@ -45212,7 +45234,8 @@ var ShapeTool = class {
|
|
|
45212
45234
|
const strokes = this.polylines.map((points) => ({
|
|
45213
45235
|
id: crypto.randomUUID(),
|
|
45214
45236
|
color: this.ctx.inkColor(),
|
|
45215
|
-
baseWidth: this.ctx.
|
|
45237
|
+
baseWidth: this.ctx.shapeStrokeWidth(),
|
|
45238
|
+
tool: "shape",
|
|
45216
45239
|
points
|
|
45217
45240
|
}));
|
|
45218
45241
|
this.ctx.clusters.assign(strokes[0]);
|
|
@@ -45246,13 +45269,13 @@ var ShapeTool = class {
|
|
|
45246
45269
|
this.previews[i].visible = polyline !== void 0;
|
|
45247
45270
|
if (polyline) {
|
|
45248
45271
|
this.previews[i].geometry.dispose();
|
|
45249
|
-
this.previews[i].geometry = buildRibbonGeometry(polyline, this.ctx.
|
|
45272
|
+
this.previews[i].geometry = buildRibbonGeometry(polyline, this.ctx.shapeStrokeWidth(), void 0, false);
|
|
45250
45273
|
}
|
|
45251
45274
|
}
|
|
45252
45275
|
}
|
|
45253
45276
|
};
|
|
45254
45277
|
//#endregion
|
|
45255
|
-
//#region
|
|
45278
|
+
//#region src/interaction/tools/tableDrag.ts
|
|
45256
45279
|
function getHandleCursor(handle) {
|
|
45257
45280
|
switch (handle) {
|
|
45258
45281
|
case "nw":
|
|
@@ -45372,7 +45395,7 @@ var TableDragState = class {
|
|
|
45372
45395
|
}
|
|
45373
45396
|
};
|
|
45374
45397
|
//#endregion
|
|
45375
|
-
//#region
|
|
45398
|
+
//#region src/interaction/tools/tableTool.ts
|
|
45376
45399
|
var MIN_DRAG_PX = 6;
|
|
45377
45400
|
var TableTool = class {
|
|
45378
45401
|
constructor(ctx) {
|
|
@@ -45503,7 +45526,7 @@ var TableTool = class {
|
|
|
45503
45526
|
}
|
|
45504
45527
|
};
|
|
45505
45528
|
//#endregion
|
|
45506
|
-
//#region
|
|
45529
|
+
//#region src/interaction/tools/commentTool.ts
|
|
45507
45530
|
/** Click on the board to drop a new comment pin or open an existing one. */
|
|
45508
45531
|
var CommentTool = class {
|
|
45509
45532
|
constructor(ctx) {
|
|
@@ -45538,7 +45561,7 @@ var CommentTool = class {
|
|
|
45538
45561
|
}
|
|
45539
45562
|
};
|
|
45540
45563
|
//#endregion
|
|
45541
|
-
//#region
|
|
45564
|
+
//#region src/interaction/tools/textDrag.ts
|
|
45542
45565
|
/** Drag the focused text block in X/Y; one command per drag. */
|
|
45543
45566
|
var TextDragState = class {
|
|
45544
45567
|
constructor(ctx) {
|
|
@@ -45590,7 +45613,7 @@ var TextDragState = class {
|
|
|
45590
45613
|
}
|
|
45591
45614
|
};
|
|
45592
45615
|
//#endregion
|
|
45593
|
-
//#region
|
|
45616
|
+
//#region src/interaction/tools/fsm.ts
|
|
45594
45617
|
var ToolStateMachine = class {
|
|
45595
45618
|
constructor() {
|
|
45596
45619
|
this.states = /* @__PURE__ */ new Map();
|
|
@@ -45792,7 +45815,7 @@ var IdleState = class {
|
|
|
45792
45815
|
}
|
|
45793
45816
|
};
|
|
45794
45817
|
//#endregion
|
|
45795
|
-
//#region
|
|
45818
|
+
//#region src/renderer/selection/gizmo.ts
|
|
45796
45819
|
var GIZMO_Z = .05;
|
|
45797
45820
|
var HANDLE_PX = 9;
|
|
45798
45821
|
var HANDLE_HIT_PX = 12;
|
|
@@ -46023,7 +46046,7 @@ function boxesEqual(a, b) {
|
|
|
46023
46046
|
return a.minX === b.minX && a.minY === b.minY && a.maxX === b.maxX && a.maxY === b.maxY;
|
|
46024
46047
|
}
|
|
46025
46048
|
//#endregion
|
|
46026
|
-
//#region
|
|
46049
|
+
//#region src/interaction/tools/pressure.ts
|
|
46027
46050
|
var SIM_MAX = 1;
|
|
46028
46051
|
var SIM_MIN = .3;
|
|
46029
46052
|
var SMOOTHING = .25;
|
|
@@ -46045,7 +46068,7 @@ function clamp(v, lo, hi) {
|
|
|
46045
46068
|
return Math.min(hi, Math.max(lo, v));
|
|
46046
46069
|
}
|
|
46047
46070
|
//#endregion
|
|
46048
|
-
//#region
|
|
46071
|
+
//#region src/interaction/tools/strokeBuilder.ts
|
|
46049
46072
|
var StrokeBuilder = class {
|
|
46050
46073
|
constructor() {
|
|
46051
46074
|
this.points = [];
|
|
@@ -46095,7 +46118,7 @@ function catmullRom(v0, v1, v2, v3, t) {
|
|
|
46095
46118
|
return .5 * (2 * v1 + (-v0 + v2) * t + (2 * v0 - 5 * v1 + 4 * v2 - v3) * t2 + (-v0 + 3 * v1 - 3 * v2 + v3) * t3);
|
|
46096
46119
|
}
|
|
46097
46120
|
//#endregion
|
|
46098
|
-
//#region
|
|
46121
|
+
//#region src/interaction/tools/markerTool.ts
|
|
46099
46122
|
/** Sample spacing while drawing, in screen pixels. */
|
|
46100
46123
|
var MIN_SAMPLE_PX = 1.5;
|
|
46101
46124
|
/** A highlighter is a chisel tip: near-constant width, little pressure play. */
|
|
@@ -46198,7 +46221,7 @@ var MarkerTool = class {
|
|
|
46198
46221
|
}
|
|
46199
46222
|
};
|
|
46200
46223
|
//#endregion
|
|
46201
|
-
//#region
|
|
46224
|
+
//#region src/interaction/tools/orbitTool.ts
|
|
46202
46225
|
/**
|
|
46203
46226
|
* Orbit-preview (build prompt §4.2): alt-drag tilts the camera off-axis to
|
|
46204
46227
|
* read the board's material and depth; releasing eases back to the working
|
|
@@ -46233,7 +46256,7 @@ var OrbitTool = class {
|
|
|
46233
46256
|
}
|
|
46234
46257
|
};
|
|
46235
46258
|
//#endregion
|
|
46236
|
-
//#region
|
|
46259
|
+
//#region src/interaction/tools/panTool.ts
|
|
46237
46260
|
/** Grab-pan: content follows the pointer. */
|
|
46238
46261
|
var PanTool = class {
|
|
46239
46262
|
constructor(ctx) {
|
|
@@ -46263,7 +46286,7 @@ var PanTool = class {
|
|
|
46263
46286
|
}
|
|
46264
46287
|
};
|
|
46265
46288
|
//#endregion
|
|
46266
|
-
//#region
|
|
46289
|
+
//#region src/renderer/selection/selection.ts
|
|
46267
46290
|
/** The set of selected stroke ids. Drops ids the document no longer has. */
|
|
46268
46291
|
var SelectionManager = class {
|
|
46269
46292
|
constructor(doc) {
|
|
@@ -46314,7 +46337,7 @@ var SelectionManager = class {
|
|
|
46314
46337
|
}
|
|
46315
46338
|
};
|
|
46316
46339
|
//#endregion
|
|
46317
|
-
//#region
|
|
46340
|
+
//#region src/interaction/tools/selectTool.ts
|
|
46318
46341
|
var HIT_SLOP_PX = 4;
|
|
46319
46342
|
var CLICK_TOLERANCE_PX = 3;
|
|
46320
46343
|
var MIN_SCALE = .05;
|
|
@@ -46530,7 +46553,7 @@ function safeRatio(numerator, denominator) {
|
|
|
46530
46553
|
return raw;
|
|
46531
46554
|
}
|
|
46532
46555
|
//#endregion
|
|
46533
|
-
//#region
|
|
46556
|
+
//#region src/interaction/tools/customTool.ts
|
|
46534
46557
|
function extensionIdFromToolId(toolId) {
|
|
46535
46558
|
const slash = toolId.indexOf("/");
|
|
46536
46559
|
return slash === -1 ? toolId : toolId.slice(0, slash);
|
|
@@ -46645,12 +46668,19 @@ var ExtensionCommandBatch = class {
|
|
|
46645
46668
|
}
|
|
46646
46669
|
};
|
|
46647
46670
|
//#endregion
|
|
46648
|
-
//#region
|
|
46671
|
+
//#region src/composition/ScrawlEngine.ts
|
|
46649
46672
|
/** Marker stroke width in board units (~1% of the default view height). */
|
|
46650
46673
|
var BASE_WIDTH = .5;
|
|
46651
46674
|
/** Highlighter chisel width — wide enough to cover a line of handwriting. */
|
|
46652
46675
|
var HIGHLIGHT_WIDTH = 2.2;
|
|
46653
46676
|
/**
|
|
46677
|
+
* Shape (rectangle, ellipse, arrow, ...) border width in board units.
|
|
46678
|
+
* Deliberately thinner than BASE_WIDTH: a shape border reads as a crisp,
|
|
46679
|
+
* structural line, not an expressive marker stroke — this is also the
|
|
46680
|
+
* fallback when no Host theme configures ScrawlTheme.shapeStrokeWidth.
|
|
46681
|
+
*/
|
|
46682
|
+
var DEFAULT_SHAPE_STROKE_WIDTH = .15;
|
|
46683
|
+
/**
|
|
46654
46684
|
* Identity of a rendered selection badge: which item, its lock state, and
|
|
46655
46685
|
* where it sits on screen (rounded to the pixel, so sub-pixel camera drift
|
|
46656
46686
|
* does not churn React).
|
|
@@ -46671,10 +46701,11 @@ function emptyExtensionRegistry() {
|
|
|
46671
46701
|
* React never reaches past this class.
|
|
46672
46702
|
*/
|
|
46673
46703
|
var ScrawlEngine = class {
|
|
46674
|
-
constructor(canvas, documentId$1, extensionRegistry = emptyExtensionRegistry(), assetController = new AssetController(void 0), boardTheme = DEFAULT_BOARD_SURFACE_THEME) {
|
|
46704
|
+
constructor(canvas, documentId$1, extensionRegistry = emptyExtensionRegistry(), assetController = new AssetController(void 0), boardTheme = DEFAULT_BOARD_SURFACE_THEME, shapeStrokeWidth = DEFAULT_SHAPE_STROKE_WIDTH) {
|
|
46675
46705
|
this.canvas = canvas;
|
|
46676
46706
|
this.extensionRegistry = extensionRegistry;
|
|
46677
46707
|
this.boardTheme = boardTheme;
|
|
46708
|
+
this.shapeStrokeWidth = shapeStrokeWidth;
|
|
46678
46709
|
this.onToolChange = null;
|
|
46679
46710
|
this.onZoomChange = null;
|
|
46680
46711
|
this.onAuditEvent = null;
|
|
@@ -46769,6 +46800,7 @@ var ScrawlEngine = class {
|
|
|
46769
46800
|
setTool: (t) => this.setTool(t),
|
|
46770
46801
|
inkColor: () => this.tool === "highlighter" ? this.highlightColor : this.color,
|
|
46771
46802
|
baseWidth: () => this.tool === "highlighter" ? HIGHLIGHT_WIDTH : BASE_WIDTH,
|
|
46803
|
+
shapeStrokeWidth: () => this.shapeStrokeWidth,
|
|
46772
46804
|
activeTool: () => this.tool,
|
|
46773
46805
|
isSpaceHeld: () => this.spaceHeld,
|
|
46774
46806
|
pointerToBoard: (e) => pointerToBoard(e.clientX, e.clientY, canvas, this.scene.cameraRig.camera),
|
|
@@ -47033,6 +47065,10 @@ var ScrawlEngine = class {
|
|
|
47033
47065
|
this.boardTheme = theme;
|
|
47034
47066
|
this.scene.applyBoardTheme(theme);
|
|
47035
47067
|
}
|
|
47068
|
+
/** Live update of the shape tool's border width (board units). Already-drawn shapes keep the width they were drawn with. */
|
|
47069
|
+
setShapeStrokeWidth(width) {
|
|
47070
|
+
this.shapeStrokeWidth = width;
|
|
47071
|
+
}
|
|
47036
47072
|
/**
|
|
47037
47073
|
* Snap to a peer's camera. No-op while drawing so pointer-to-board
|
|
47038
47074
|
* mapping does not warp the in-progress stroke.
|
|
@@ -48094,7 +48130,7 @@ var ScrawlEngine = class {
|
|
|
48094
48130
|
}
|
|
48095
48131
|
};
|
|
48096
48132
|
//#endregion
|
|
48097
|
-
//#region src/controller-internal.ts
|
|
48133
|
+
//#region src/composition/controller-internal.ts
|
|
48098
48134
|
function createBoardController(options) {
|
|
48099
48135
|
return createBoardControllerWithEngine(options);
|
|
48100
48136
|
}
|
|
@@ -48112,9 +48148,12 @@ function createBoardControllerWithEngine(options, existingEngine) {
|
|
|
48112
48148
|
color: options.boardTheme?.surface ?? DEFAULT_BOARD_SURFACE_THEME.color,
|
|
48113
48149
|
gridMode: options.boardTheme?.gridMode ?? DEFAULT_BOARD_SURFACE_THEME.gridMode,
|
|
48114
48150
|
gridColor: options.boardTheme?.gridColor ?? DEFAULT_BOARD_SURFACE_THEME.gridColor,
|
|
48115
|
-
gridSpacing: options.boardTheme?.gridSpacing ?? DEFAULT_BOARD_SURFACE_THEME.gridSpacing
|
|
48151
|
+
gridSpacing: options.boardTheme?.gridSpacing ?? DEFAULT_BOARD_SURFACE_THEME.gridSpacing,
|
|
48152
|
+
gridLineWidth: options.boardTheme?.gridLineWidth ?? DEFAULT_BOARD_SURFACE_THEME.gridLineWidth,
|
|
48153
|
+
surfaceTexture: options.boardTheme?.surfaceTexture ?? DEFAULT_BOARD_SURFACE_THEME.surfaceTexture
|
|
48116
48154
|
};
|
|
48117
|
-
|
|
48155
|
+
let currentShapeStrokeWidth = options.boardTheme?.shapeStrokeWidth ?? .15;
|
|
48156
|
+
const engine = existingEngine ?? (options.canvas ? new ScrawlEngine(options.canvas, options.document.id, extensionRegistry, assetController, currentBoardTheme, currentShapeStrokeWidth) : null);
|
|
48118
48157
|
const document = engine?.document ?? new BoardDocument(documentId(options.document.id));
|
|
48119
48158
|
const history = engine?.history ?? new History(document);
|
|
48120
48159
|
const createId = options.createId ?? (() => crypto.randomUUID());
|
|
@@ -48603,9 +48642,15 @@ function createBoardControllerWithEngine(options, existingEngine) {
|
|
|
48603
48642
|
color: theme.surface ?? currentBoardTheme.color,
|
|
48604
48643
|
gridMode: theme.gridMode ?? currentBoardTheme.gridMode,
|
|
48605
48644
|
gridColor: theme.gridColor ?? currentBoardTheme.gridColor,
|
|
48606
|
-
gridSpacing: theme.gridSpacing ?? currentBoardTheme.gridSpacing
|
|
48645
|
+
gridSpacing: theme.gridSpacing ?? currentBoardTheme.gridSpacing,
|
|
48646
|
+
gridLineWidth: theme.gridLineWidth ?? currentBoardTheme.gridLineWidth,
|
|
48647
|
+
surfaceTexture: theme.surfaceTexture ?? currentBoardTheme.surfaceTexture
|
|
48607
48648
|
};
|
|
48608
48649
|
engine?.applyBoardTheme(currentBoardTheme);
|
|
48650
|
+
if (theme.shapeStrokeWidth !== void 0) {
|
|
48651
|
+
currentShapeStrokeWidth = theme.shapeStrokeWidth;
|
|
48652
|
+
engine?.setShapeStrokeWidth(currentShapeStrokeWidth);
|
|
48653
|
+
}
|
|
48609
48654
|
} },
|
|
48610
48655
|
view: {
|
|
48611
48656
|
fit() {
|
|
@@ -49376,7 +49421,7 @@ function createLocalBoard(options) {
|
|
|
49376
49421
|
};
|
|
49377
49422
|
}
|
|
49378
49423
|
//#endregion
|
|
49379
|
-
//#region src/theme.ts
|
|
49424
|
+
//#region src/ui/theme.ts
|
|
49380
49425
|
var scrawlThemePresets = Object.freeze({
|
|
49381
49426
|
light: Object.freeze({
|
|
49382
49427
|
surface: "#ffffff",
|
|
@@ -49385,6 +49430,7 @@ var scrawlThemePresets = Object.freeze({
|
|
|
49385
49430
|
text: "#1c1c1a",
|
|
49386
49431
|
textMuted: "#62625c",
|
|
49387
49432
|
edge: "#d4d4cc",
|
|
49433
|
+
primary: "#1856a3",
|
|
49388
49434
|
focus: "#1856a3",
|
|
49389
49435
|
selection: "#d9e8f7",
|
|
49390
49436
|
danger: "#a3302b",
|
|
@@ -49403,9 +49449,12 @@ var scrawlThemePresets = Object.freeze({
|
|
|
49403
49449
|
motionEasing: "cubic-bezier(0.2, 0, 0, 1)",
|
|
49404
49450
|
density: "comfortable",
|
|
49405
49451
|
boardSurface: "#f5f5f3",
|
|
49452
|
+
boardSurfaceTexture: "flat",
|
|
49406
49453
|
gridMode: "none",
|
|
49407
49454
|
gridColor: "#deded8",
|
|
49408
|
-
gridSpacing: 5
|
|
49455
|
+
gridSpacing: 5,
|
|
49456
|
+
gridLineWidth: 1,
|
|
49457
|
+
shapeStrokeWidth: .15
|
|
49409
49458
|
}),
|
|
49410
49459
|
dark: Object.freeze({
|
|
49411
49460
|
surface: "#171816",
|
|
@@ -49414,6 +49463,7 @@ var scrawlThemePresets = Object.freeze({
|
|
|
49414
49463
|
text: "#f4f4ee",
|
|
49415
49464
|
textMuted: "#b7b8ae",
|
|
49416
49465
|
edge: "#484a42",
|
|
49466
|
+
primary: "#9dc8ef",
|
|
49417
49467
|
focus: "#9dc8ef",
|
|
49418
49468
|
selection: "#314b63",
|
|
49419
49469
|
danger: "#ffaaa3",
|
|
@@ -49432,9 +49482,12 @@ var scrawlThemePresets = Object.freeze({
|
|
|
49432
49482
|
motionEasing: "cubic-bezier(0.2, 0, 0, 1)",
|
|
49433
49483
|
density: "comfortable",
|
|
49434
49484
|
boardSurface: "#232420",
|
|
49485
|
+
boardSurfaceTexture: "flat",
|
|
49435
49486
|
gridMode: "none",
|
|
49436
49487
|
gridColor: "#33352f",
|
|
49437
|
-
gridSpacing: 5
|
|
49488
|
+
gridSpacing: 5,
|
|
49489
|
+
gridLineWidth: 1,
|
|
49490
|
+
shapeStrokeWidth: .15
|
|
49438
49491
|
})
|
|
49439
49492
|
});
|
|
49440
49493
|
var variableNames = {
|
|
@@ -49444,6 +49497,7 @@ var variableNames = {
|
|
|
49444
49497
|
text: "--scrawl-color-text",
|
|
49445
49498
|
textMuted: "--scrawl-color-text-muted",
|
|
49446
49499
|
edge: "--scrawl-color-edge",
|
|
49500
|
+
primary: "--scrawl-color-primary",
|
|
49447
49501
|
focus: "--scrawl-color-focus",
|
|
49448
49502
|
selection: "--scrawl-color-selection",
|
|
49449
49503
|
danger: "--scrawl-color-danger",
|
|
@@ -49462,9 +49516,12 @@ var variableNames = {
|
|
|
49462
49516
|
motionEasing: "--scrawl-motion-easing",
|
|
49463
49517
|
density: "--scrawl-density",
|
|
49464
49518
|
boardSurface: "--scrawl-board-surface",
|
|
49519
|
+
boardSurfaceTexture: "--scrawl-board-surface-texture",
|
|
49465
49520
|
gridMode: "--scrawl-grid-mode",
|
|
49466
49521
|
gridColor: "--scrawl-grid-color",
|
|
49467
|
-
gridSpacing: "--scrawl-grid-spacing"
|
|
49522
|
+
gridSpacing: "--scrawl-grid-spacing",
|
|
49523
|
+
gridLineWidth: "--scrawl-grid-line-width",
|
|
49524
|
+
shapeStrokeWidth: "--scrawl-shape-stroke-width"
|
|
49468
49525
|
};
|
|
49469
49526
|
var colorTokens = /* @__PURE__ */ new Set([
|
|
49470
49527
|
"surface",
|
|
@@ -49473,6 +49530,7 @@ var colorTokens = /* @__PURE__ */ new Set([
|
|
|
49473
49530
|
"text",
|
|
49474
49531
|
"textMuted",
|
|
49475
49532
|
"edge",
|
|
49533
|
+
"primary",
|
|
49476
49534
|
"focus",
|
|
49477
49535
|
"selection",
|
|
49478
49536
|
"danger",
|
|
@@ -49520,10 +49578,22 @@ function validateScrawlTheme(theme) {
|
|
|
49520
49578
|
token,
|
|
49521
49579
|
message: "Expected none, line, or dot"
|
|
49522
49580
|
});
|
|
49581
|
+
else if (token === "boardSurfaceTexture" && value !== "flat" && value !== "textured") diagnostics.push({
|
|
49582
|
+
token,
|
|
49583
|
+
message: "Expected flat or textured"
|
|
49584
|
+
});
|
|
49523
49585
|
else if (token === "gridSpacing" && (!finiteNumber(value) || value < .5 || value > 50)) diagnostics.push({
|
|
49524
49586
|
token,
|
|
49525
49587
|
message: "Expected spacing 0.5-50 board units"
|
|
49526
49588
|
});
|
|
49589
|
+
else if (token === "gridLineWidth" && (!finiteNumber(value) || value < .5 || value > 8)) diagnostics.push({
|
|
49590
|
+
token,
|
|
49591
|
+
message: "Expected line width 0.5-8px"
|
|
49592
|
+
});
|
|
49593
|
+
else if (token === "shapeStrokeWidth" && (!finiteNumber(value) || value < .01 || value > 5)) diagnostics.push({
|
|
49594
|
+
token,
|
|
49595
|
+
message: "Expected stroke width 0.01-5 board units"
|
|
49596
|
+
});
|
|
49527
49597
|
else if ((token.endsWith("Family") || token.startsWith("elevation") || token === "motionEasing") && (typeof value !== "string" || !value.trim() || /[;{}]/.test(value))) diagnostics.push({
|
|
49528
49598
|
token,
|
|
49529
49599
|
message: "Expected a safe CSS value"
|
|
@@ -49594,12 +49664,12 @@ function luminance(color) {
|
|
|
49594
49664
|
return channels[0] * .2126 + channels[1] * .7152 + channels[2] * .0722;
|
|
49595
49665
|
}
|
|
49596
49666
|
function formatValue(token, value) {
|
|
49597
|
-
if (token === "baseFontSize" || token === "controlRadius" || token === "panelRadius") return `${value}px`;
|
|
49667
|
+
if (token === "baseFontSize" || token === "controlRadius" || token === "panelRadius" || token === "gridLineWidth") return `${value}px`;
|
|
49598
49668
|
if (token === "motionDuration") return `${value}ms`;
|
|
49599
49669
|
return String(value);
|
|
49600
49670
|
}
|
|
49601
49671
|
//#endregion
|
|
49602
|
-
//#region src/inline-editing.tsx
|
|
49672
|
+
//#region src/ui/dialogs/inline-editing.tsx
|
|
49603
49673
|
/** Inline note, text, and table-cell editors — driven entirely by public controller events and commands. */
|
|
49604
49674
|
function InlineEditors({ controller, renderPortal }) {
|
|
49605
49675
|
const [editor, setEditor] = useState(null);
|
|
@@ -49830,7 +49900,7 @@ function InlineEditors({ controller, renderPortal }) {
|
|
|
49830
49900
|
}))] });
|
|
49831
49901
|
}
|
|
49832
49902
|
//#endregion
|
|
49833
|
-
//#region src/style-shelf.tsx
|
|
49903
|
+
//#region src/ui/toolbar/style-shelf.tsx
|
|
49834
49904
|
var ERASER_RADII = [
|
|
49835
49905
|
["Fine", 1],
|
|
49836
49906
|
["Medium", 2],
|
|
@@ -49993,7 +50063,7 @@ function StyleShelf({ controller, snapshot }) {
|
|
|
49993
50063
|
});
|
|
49994
50064
|
}
|
|
49995
50065
|
//#endregion
|
|
49996
|
-
//#region src/default-ui.tsx
|
|
50066
|
+
//#region src/ui/default-ui.tsx
|
|
49997
50067
|
var PRIMARY_TOOLS = [
|
|
49998
50068
|
{
|
|
49999
50069
|
tool: "select",
|
|
@@ -50102,7 +50172,7 @@ var INKS = [
|
|
|
50102
50172
|
["Forest", "#315d46"],
|
|
50103
50173
|
["Oxblood", "#773f3b"]
|
|
50104
50174
|
];
|
|
50105
|
-
function DefaultBoardChrome({ controller, snapshot, renderPortal, className, style, regions, slots }) {
|
|
50175
|
+
function DefaultBoardChrome({ controller, snapshot, renderPortal, className, style, regions, slots, icons }) {
|
|
50106
50176
|
const [panel, setPanel] = useState(null);
|
|
50107
50177
|
const [query, setQuery] = useState("");
|
|
50108
50178
|
const [announcement, setAnnouncement] = useState("Board controls ready");
|
|
@@ -50256,7 +50326,10 @@ function DefaultBoardChrome({ controller, snapshot, renderPortal, className, sty
|
|
|
50256
50326
|
onClick: () => chooseTool(tool),
|
|
50257
50327
|
title: `${label} (${key})`,
|
|
50258
50328
|
type: "button",
|
|
50259
|
-
children:
|
|
50329
|
+
children: icons?.[tool] ? /* @__PURE__ */ jsx("span", {
|
|
50330
|
+
"aria-hidden": "true",
|
|
50331
|
+
children: icons[tool]
|
|
50332
|
+
}) : label
|
|
50260
50333
|
}, tool)), /* @__PURE__ */ jsxs("label", {
|
|
50261
50334
|
className: "scrawl-board__tool-select",
|
|
50262
50335
|
children: [/* @__PURE__ */ jsx("span", { children: "More tools" }), /* @__PURE__ */ jsxs("select", {
|
|
@@ -50522,7 +50595,7 @@ function download(blob, name) {
|
|
|
50522
50595
|
URL.revokeObjectURL(url);
|
|
50523
50596
|
}
|
|
50524
50597
|
//#endregion
|
|
50525
|
-
//#region src/presence.tsx
|
|
50598
|
+
//#region src/ui/panels/presence.tsx
|
|
50526
50599
|
var labelStyle = {
|
|
50527
50600
|
borderRadius: 999,
|
|
50528
50601
|
color: "#fff",
|
|
@@ -50682,9 +50755,12 @@ function ScrawlProvider({ controller, children, preset = "light", theme, portalC
|
|
|
50682
50755
|
useEffect(() => {
|
|
50683
50756
|
controller.boardTheme.set({
|
|
50684
50757
|
surface: resolved.values.boardSurface,
|
|
50758
|
+
surfaceTexture: resolved.values.boardSurfaceTexture,
|
|
50685
50759
|
gridMode: resolved.values.gridMode,
|
|
50686
50760
|
gridColor: resolved.values.gridColor,
|
|
50687
|
-
gridSpacing: resolved.values.gridSpacing
|
|
50761
|
+
gridSpacing: resolved.values.gridSpacing,
|
|
50762
|
+
gridLineWidth: resolved.values.gridLineWidth,
|
|
50763
|
+
shapeStrokeWidth: resolved.values.shapeStrokeWidth
|
|
50688
50764
|
});
|
|
50689
50765
|
}, [controller, resolved]);
|
|
50690
50766
|
useDeferredDisposal(controller, disposeOnUnmount);
|
|
@@ -50716,7 +50792,7 @@ function ScrawlProvider({ controller, children, preset = "light", theme, portalC
|
|
|
50716
50792
|
})
|
|
50717
50793
|
});
|
|
50718
50794
|
}
|
|
50719
|
-
function Scrawl({ children, preset, theme, portalContainer, className, style, onReady, onError, onThemeDiagnostic, canvas: suppliedCanvas, ...options }) {
|
|
50795
|
+
function Scrawl({ children, preset, theme, portalContainer, className, style, onReady, onError, onThemeDiagnostic, canvas: suppliedCanvas, icons, ...options }) {
|
|
50720
50796
|
const [runtime, setRuntime] = useState(null);
|
|
50721
50797
|
const runtimeRef = useRef(null);
|
|
50722
50798
|
const ownedCanvasRef = useRef(null);
|
|
@@ -50737,9 +50813,12 @@ function Scrawl({ children, preset, theme, portalContainer, className, style, on
|
|
|
50737
50813
|
const resolved = resolveScrawlTheme(preset, theme);
|
|
50738
50814
|
const boardTheme = {
|
|
50739
50815
|
surface: resolved.values.boardSurface,
|
|
50816
|
+
surfaceTexture: resolved.values.boardSurfaceTexture,
|
|
50740
50817
|
gridMode: resolved.values.gridMode,
|
|
50741
50818
|
gridColor: resolved.values.gridColor,
|
|
50742
|
-
gridSpacing: resolved.values.gridSpacing
|
|
50819
|
+
gridSpacing: resolved.values.gridSpacing,
|
|
50820
|
+
gridLineWidth: resolved.values.gridLineWidth,
|
|
50821
|
+
shapeStrokeWidth: resolved.values.shapeStrokeWidth
|
|
50743
50822
|
};
|
|
50744
50823
|
controller = createBoardController({
|
|
50745
50824
|
...options,
|
|
@@ -50809,7 +50888,7 @@ function Scrawl({ children, preset, theme, portalContainer, className, style, on
|
|
|
50809
50888
|
onThemeDiagnostic,
|
|
50810
50889
|
className,
|
|
50811
50890
|
style,
|
|
50812
|
-
children: [runtime.canvas && /* @__PURE__ */ jsx(ScrawlCanvas, { element: runtime.canvas }), children ?? /* @__PURE__ */ jsx(ScrawlDefaultUI, {})]
|
|
50891
|
+
children: [runtime.canvas && /* @__PURE__ */ jsx(ScrawlCanvas, { element: runtime.canvas }), children ?? /* @__PURE__ */ jsx(ScrawlDefaultUI, { icons })]
|
|
50813
50892
|
});
|
|
50814
50893
|
}
|
|
50815
50894
|
function ScrawlCanvas({ element, className, style, "aria-label": ariaLabel = "Scrawl Board" }) {
|
|
@@ -50845,10 +50924,11 @@ function ScrawlCanvas({ element, className, style, "aria-label": ariaLabel = "Sc
|
|
|
50845
50924
|
style
|
|
50846
50925
|
});
|
|
50847
50926
|
}
|
|
50848
|
-
function ScrawlDefaultUI({ className, style, regions, slots }) {
|
|
50927
|
+
function ScrawlDefaultUI({ className, style, regions, slots, icons }) {
|
|
50849
50928
|
return /* @__PURE__ */ jsx(DefaultBoardChrome, {
|
|
50850
50929
|
className,
|
|
50851
50930
|
controller: useScrawlController(),
|
|
50931
|
+
icons,
|
|
50852
50932
|
regions,
|
|
50853
50933
|
renderPortal: (children) => /* @__PURE__ */ jsx(ScrawlPortal, { children }),
|
|
50854
50934
|
slots,
|