@neta-art/cohub 11.5.0 → 12.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/dist/board/editor/animation.js +2 -1
- package/dist/board/editor/clipboard.js +1 -1
- package/dist/board/editor/creation.js +2 -2
- package/dist/board/editor/document-edits.d.ts +1 -1
- package/dist/board/editor/document-edits.js +1 -19
- package/dist/board/editor/document.js +2 -1
- package/dist/board/editor/editor.js +2 -2
- package/dist/board/editor/index.d.ts +2 -1
- package/dist/board/editor/index.js +2 -1
- package/dist/board/editor/selection.js +1 -1
- package/dist/board/editor/snapshots.js +11 -13
- package/dist/board/export/index.js +2 -2
- package/dist/board/export/node/scripts.js +1 -1
- package/dist/board/export/scene.js +2 -2
- package/dist/board/model/client-geometry.d.ts +22 -0
- package/dist/board/model/client-geometry.js +94 -0
- package/dist/board/model/document-share.d.ts +5 -0
- package/dist/board/model/document-share.js +27 -0
- package/dist/board/model/index.d.ts +5 -4
- package/dist/board/model/index.js +19 -18
- package/dist/board/model/items/create.d.ts +5 -1
- package/dist/board/model/items/create.js +30 -59
- package/dist/board/model/items/index.d.ts +2 -2
- package/dist/board/model/items/index.js +2 -2
- package/dist/board/model/items/registry.js +2 -5
- package/dist/board/model/json.d.ts +4 -0
- package/dist/board/model/json.js +22 -0
- package/dist/board/model/media-playback.d.ts +6 -3
- package/dist/board/model/sampling.js +1 -1
- package/dist/board/player/index.d.ts +6 -2
- package/dist/board/player/index.js +33 -15
- package/dist/board/render/index.d.ts +2 -2
- package/dist/board/render/index.js +6 -6
- package/dist/board/render/media-interaction.js +1 -1
- package/dist/board/render/renderers/arrow-card-renderer.js +5 -1
- package/dist/board/render/renderers/audio-card-renderer.js +5 -2
- package/dist/board/render/renderers/base-card-renderer.js +2 -5
- package/dist/board/render/renderers/board-renderer-registry.d.ts +4 -2
- package/dist/board/render/renderers/custom-card-renderer.js +7 -3
- package/dist/board/render/renderers/draw-card-renderer.js +1 -1
- package/dist/board/render/renderers/file-card-renderer.js +6 -3
- package/dist/board/render/renderers/frame-card-renderer.js +5 -1
- package/dist/board/render/renderers/image-card-renderer.js +13 -49
- package/dist/board/render/renderers/model-card-renderer.js +7 -4
- package/dist/board/render/renderers/shape-card-renderer.js +5 -1
- package/dist/board/render/renderers/task-card-renderer.js +6 -3
- package/dist/board/render/renderers/text-card-renderer.js +6 -2
- package/dist/board/render/renderers/unknown-card-renderer.js +4 -0
- package/dist/board/render/renderers/video-card-renderer.js +20 -19
- package/dist/board/render/script-export.js +1 -1
- package/dist/board/render/script-host.d.ts +2 -0
- package/dist/board/render/script-host.js +45 -10
- package/dist/board/render/script-resolution.d.ts +4 -0
- package/dist/board/render/script-resolution.js +18 -0
- package/dist/board/render/surface.d.ts +9 -2
- package/dist/board/render/surface.js +15 -1
- package/dist/board/render/text-resolution.d.ts +4 -1
- package/dist/board/render/text-resolution.js +10 -5
- package/dist/board/replica/index.js +4 -1
- package/dist/board/stage/assets.d.ts +12 -8
- package/dist/board/stage/assets.js +174 -89
- package/dist/board/stage/display-density.d.ts +4 -0
- package/dist/board/stage/display-density.js +25 -0
- package/dist/board/stage/index.d.ts +3 -3
- package/dist/board/stage/index.js +3 -3
- package/dist/board/stage/lru.d.ts +3 -2
- package/dist/board/stage/lru.js +8 -4
- package/dist/board/stage/pointer.d.ts +1 -1
- package/dist/board/stage/pointer.js +4 -5
- package/dist/board/stage/scene.d.ts +3 -0
- package/dist/board/stage/scene.js +44 -8
- package/dist/board/stage/stage.d.ts +1 -0
- package/dist/board/stage/stage.js +152 -69
- package/dist/board/stage/views.d.ts +7 -2
- package/dist/board/stage/views.js +50 -21
- package/dist/chunks/environment.d.ts +16 -2
- package/dist/chunks/http.d.ts +6 -2
- package/dist/index.js +65 -22
- package/dist/protocol/dist/board-constants.js +56 -1
- package/dist/protocol/dist/board-layout.d.ts +8 -1
- package/dist/protocol/dist/board-layout.js +16 -4
- package/dist/protocol/dist/board-model.js +13 -19
- package/dist/protocol/dist/board-patch.js +1 -1
- package/dist/protocol/dist/board-schema.d.ts +52 -0
- package/dist/protocol/dist/board-schema.js +8 -0
- package/dist/protocol/dist/core/media.js +1 -0
- package/dist/protocol/dist/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parseBoardItem } from "../../protocol/dist/board-model.js";
|
|
2
2
|
import { drawPointsBounds } from "../../protocol/dist/board-layout.js";
|
|
3
|
+
import { getBoardResolution, textZoomBucket } from "../render/text-resolution.js";
|
|
3
4
|
import { clippingAncestor, isClippingFrame, syncClipGroup } from "../render/clip.js";
|
|
4
5
|
import { Graphics } from "pixi.js";
|
|
5
6
|
//#region src/board/stage/scene.ts
|
|
@@ -12,6 +13,7 @@ const Z_LIFTED = 1e9;
|
|
|
12
13
|
const Z_LIVE_STROKE = Number.MAX_SAFE_INTEGER - 1;
|
|
13
14
|
const Z_OVERLAY = Number.MAX_SAFE_INTEGER;
|
|
14
15
|
const POOL_LIMIT_PER_RENDERER = 48;
|
|
16
|
+
const EMPTY_IDS = /* @__PURE__ */ new Set();
|
|
15
17
|
function idSetSignature(ids) {
|
|
16
18
|
let hash = ids.size;
|
|
17
19
|
for (const id of ids) {
|
|
@@ -31,20 +33,33 @@ function createBoardScene(options) {
|
|
|
31
33
|
const tickingIds = /* @__PURE__ */ new Set();
|
|
32
34
|
const pools = /* @__PURE__ */ new Map();
|
|
33
35
|
const heldKeys = /* @__PURE__ */ new Map();
|
|
36
|
+
const holders = /* @__PURE__ */ new Map();
|
|
34
37
|
let orderById = /* @__PURE__ */ new Map();
|
|
35
38
|
let farSig = null;
|
|
36
39
|
let farActive = false;
|
|
37
40
|
let lastStructureVersion = -1;
|
|
38
41
|
let lastZoom = NaN;
|
|
42
|
+
let lastResolution = "";
|
|
43
|
+
let liveVersion = 0;
|
|
39
44
|
let lifted = /* @__PURE__ */ new Set();
|
|
40
45
|
const liveStrokes = /* @__PURE__ */ new Map();
|
|
41
|
-
function setHeldKey(context, cardId,
|
|
46
|
+
function setHeldKey(context, cardId, item) {
|
|
47
|
+
const desiredKey = item ? context.assetKey(item) : null;
|
|
42
48
|
const heldKey = heldKeys.get(cardId) ?? null;
|
|
43
49
|
if (desiredKey === heldKey) return;
|
|
44
|
-
if (heldKey)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
if (heldKey) {
|
|
51
|
+
context.releaseTexture(heldKey);
|
|
52
|
+
const ids = holders.get(heldKey);
|
|
53
|
+
ids?.delete(cardId);
|
|
54
|
+
if (ids?.size === 0) holders.delete(heldKey);
|
|
55
|
+
}
|
|
56
|
+
if (desiredKey && item) {
|
|
57
|
+
heldKeys.set(cardId, desiredKey);
|
|
58
|
+
const ids = holders.get(desiredKey);
|
|
59
|
+
if (ids) ids.add(cardId);
|
|
60
|
+
else holders.set(desiredKey, /* @__PURE__ */ new Set([cardId]));
|
|
61
|
+
context.acquireTexture(desiredKey, item);
|
|
62
|
+
} else heldKeys.delete(cardId);
|
|
48
63
|
}
|
|
49
64
|
function takeFromPool(rendererId) {
|
|
50
65
|
const pool = pools.get(rendererId);
|
|
@@ -119,7 +134,7 @@ function createBoardScene(options) {
|
|
|
119
134
|
scriptRevision: context.scripts?.revision?.(item.id) ?? 0
|
|
120
135
|
};
|
|
121
136
|
cards.set(item.id, entry);
|
|
122
|
-
setHeldKey(context, item.id,
|
|
137
|
+
setHeldKey(context, item.id, item);
|
|
123
138
|
renderer.zoom?.(container, context.zoom);
|
|
124
139
|
return entry;
|
|
125
140
|
}
|
|
@@ -277,6 +292,9 @@ function createBoardScene(options) {
|
|
|
277
292
|
}
|
|
278
293
|
function sync(input) {
|
|
279
294
|
const { items, scene, context, getItem, visibleIds, pinnedIds, globalSig, structureVersion, geometryVersion, gestureActive } = input;
|
|
295
|
+
const resolution = `${textZoomBucket(context.zoom)}:${getBoardResolution()}`;
|
|
296
|
+
const resolutionChanged = resolution !== lastResolution;
|
|
297
|
+
lastResolution = resolution;
|
|
280
298
|
const structureChanged = structureVersion !== lastStructureVersion;
|
|
281
299
|
if (structureChanged) {
|
|
282
300
|
lastStructureVersion = structureVersion;
|
|
@@ -304,7 +322,14 @@ function createBoardScene(options) {
|
|
|
304
322
|
if (farActive) {
|
|
305
323
|
const { orderedIds, unbatched } = visibleFacts(input);
|
|
306
324
|
for (const id of unbatched) wanted.add(id);
|
|
307
|
-
let
|
|
325
|
+
let retained = 0;
|
|
326
|
+
if (!farPainted) {
|
|
327
|
+
for (const id of cards.keys()) if ((!visibleIds || visibleIds.has(id)) && !farCovered.has(id) && !wanted.has(id)) {
|
|
328
|
+
wanted.add(id);
|
|
329
|
+
retained++;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
let budget = Math.max(0, FAR_LIVE_LIMIT - retained);
|
|
308
333
|
for (const id of orderedIds) {
|
|
309
334
|
if (budget === 0) break;
|
|
310
335
|
if (farCovered.has(id) || wanted.has(id)) continue;
|
|
@@ -346,13 +371,17 @@ function createBoardScene(options) {
|
|
|
346
371
|
entry.hovered = hovered;
|
|
347
372
|
entry.resizing = resizing;
|
|
348
373
|
entry.globalSig = globalSig;
|
|
349
|
-
setHeldKey(context, id,
|
|
374
|
+
setHeldKey(context, id, item);
|
|
350
375
|
if (changed) {
|
|
351
376
|
entry.renderer.update(entry.container, item, context);
|
|
352
377
|
entry.container.alpha = scene.opacity(id);
|
|
353
378
|
if (entry.renderer.tick) tickingIds.add(id);
|
|
379
|
+
} else if (resolutionChanged && entry.renderer.resolution) {
|
|
380
|
+
entry.renderer.resolution(entry.container, item, context);
|
|
381
|
+
if (entry.renderer.tick) tickingIds.add(id);
|
|
354
382
|
}
|
|
355
383
|
}
|
|
384
|
+
if (liveSetChanged) liveVersion += 1;
|
|
356
385
|
if (structureChanged || liveSetChanged) syncClips(scene);
|
|
357
386
|
if (context.zoom !== lastZoom) {
|
|
358
387
|
lastZoom = context.zoom;
|
|
@@ -391,6 +420,7 @@ function createBoardScene(options) {
|
|
|
391
420
|
pools.clear();
|
|
392
421
|
for (const key of heldKeys.values()) context.releaseTexture(key);
|
|
393
422
|
heldKeys.clear();
|
|
423
|
+
holders.clear();
|
|
394
424
|
orderById = /* @__PURE__ */ new Map();
|
|
395
425
|
for (const entry of clips.values()) entry.group.destroy({ children: true });
|
|
396
426
|
clips.clear();
|
|
@@ -402,6 +432,7 @@ function createBoardScene(options) {
|
|
|
402
432
|
visibleMemo = null;
|
|
403
433
|
lastStructureVersion = -1;
|
|
404
434
|
lastZoom = NaN;
|
|
435
|
+
lastResolution = "";
|
|
405
436
|
}
|
|
406
437
|
return {
|
|
407
438
|
sync,
|
|
@@ -412,6 +443,11 @@ function createBoardScene(options) {
|
|
|
412
443
|
container: entry.container
|
|
413
444
|
} : null;
|
|
414
445
|
},
|
|
446
|
+
holders: (key) => holders.get(key) ?? EMPTY_IDS,
|
|
447
|
+
get liveVersion() {
|
|
448
|
+
return liveVersion;
|
|
449
|
+
},
|
|
450
|
+
liveIds: () => new Set(cards.keys()),
|
|
415
451
|
get animated() {
|
|
416
452
|
return animatedIds.size > 0;
|
|
417
453
|
},
|
|
@@ -56,6 +56,7 @@ type BoardStageOptions = {
|
|
|
56
56
|
height: number;
|
|
57
57
|
}) => void;
|
|
58
58
|
onVisibleChange?: (ids: ReadonlySet<string> | null) => void;
|
|
59
|
+
onLiveChange?: (ids: ReadonlySet<string>) => void;
|
|
59
60
|
safeRect?: () => Rect;
|
|
60
61
|
scriptCapabilities?: Record<string, (id: string, input: unknown) => Promise<unknown>>;
|
|
61
62
|
};
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import { applyMatrix, invertMatrix } from "../../protocol/dist/board-layout.js";
|
|
2
2
|
import { featuredTaskArtifact } from "../../protocol/dist/board-task.js";
|
|
3
|
-
import {
|
|
3
|
+
import { pointToWorld, stableCullRect, visibleWorldRect, worldPoint } from "../model/geometry.js";
|
|
4
|
+
import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
|
|
5
|
+
import { boardScriptTarget } from "../model/script-hit.js";
|
|
4
6
|
import { createBoardAnimationSampler, resolveBoardAnimationCamera } from "../model/sampling.js";
|
|
7
|
+
import { resolveSceneArrow } from "../model/arrow-geometry.js";
|
|
5
8
|
import { buildFallbackShapeColors, pickBoardColor, resolveItemColor } from "../model/palette.js";
|
|
9
|
+
import { elementClientToLocal } from "../model/client-geometry.js";
|
|
10
|
+
import { isCreationBoardTool } from "../editor/tool.js";
|
|
11
|
+
import { resizeCursorForHandle } from "../editor/selection-transform.js";
|
|
12
|
+
import { createBoardPlayer } from "../player/index.js";
|
|
13
|
+
import { createBoardScriptObservers } from "../model/script-observers.js";
|
|
6
14
|
import { parseBoardCssColor } from "../render/css-color.js";
|
|
7
|
-
import { defaultBoardPalette, itemAlpha } from "../render/palette.js";
|
|
8
|
-
import { resolveSceneArrow } from "../model/arrow-geometry.js";
|
|
9
15
|
import { createBoardBackground, updateBoardBackground } from "../render/board-background.js";
|
|
10
|
-
import { getBoardResolution
|
|
16
|
+
import { getBoardResolution } from "../render/text-resolution.js";
|
|
17
|
+
import { defaultBoardPalette, itemAlpha } from "../render/palette.js";
|
|
11
18
|
import { DEFAULT_BOARD_RENDER_LABELS, getBoardCardRenderer } from "../render/renderers/board-renderer-registry.js";
|
|
12
|
-
import { boardScriptScope, composeBoardScriptItems, prepareBoardScriptOutput, validateBoardScriptCommit } from "../model/script-scene.js";
|
|
13
|
-
import { boardScriptTarget } from "../model/script-hit.js";
|
|
14
19
|
import { createBoardScriptHost } from "../render/script-host.js";
|
|
15
20
|
import { defaultBoardRenderStyle } from "../render/style.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { createBoardScriptObservers } from "../model/script-observers.js";
|
|
19
|
-
import { createBoardPlayer } from "../player/index.js";
|
|
21
|
+
import { boardTextureEdge } from "./assets.js";
|
|
22
|
+
import { observeDisplayDensity } from "./display-density.js";
|
|
20
23
|
import { toBoardPointerEvent } from "./pointer.js";
|
|
21
24
|
import { createBoardPointerGestures } from "./pointer-gestures.js";
|
|
22
25
|
import { createBoardScene } from "./scene.js";
|
|
@@ -48,6 +51,7 @@ function defaultTheme() {
|
|
|
48
51
|
const NO_IDS = /* @__PURE__ */ new Set();
|
|
49
52
|
const MARCH_STEP_MS = 160;
|
|
50
53
|
const MARCH_SMOOTH_MS = 40;
|
|
54
|
+
const TEXTURE_SETTLE_MS = 150;
|
|
51
55
|
const ROTATE_CURSOR = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M21 12a9 9 0 1 1-2.64-6.36L21 8M21 3v5h-5' fill='none' stroke='%23fff' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M21 12a9 9 0 1 1-2.64-6.36L21 8M21 3v5h-5' fill='none' stroke='%231d1d1f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") 12 12, crosshair`;
|
|
52
56
|
const defaultStyles = /* @__PURE__ */ new Map();
|
|
53
57
|
function styleOf(theme) {
|
|
@@ -96,17 +100,18 @@ function mountBoardStage(host, options) {
|
|
|
96
100
|
let scriptHover = null;
|
|
97
101
|
const scriptPointers = createBoardScriptPointerRouter();
|
|
98
102
|
let stopMaintenance = null;
|
|
103
|
+
let stopDensity = null;
|
|
99
104
|
let active = true;
|
|
100
105
|
let disposed = false;
|
|
101
106
|
let renderFrame = 0;
|
|
102
107
|
let tickFrame = 0;
|
|
108
|
+
let scriptTickFrame = 0;
|
|
103
109
|
let cardTickFrame = 0;
|
|
104
110
|
let cardTickTimer = null;
|
|
105
111
|
let cardTickDue = 0;
|
|
106
112
|
const staleIds = /* @__PURE__ */ new Set();
|
|
107
113
|
let resizeFrame = 0;
|
|
108
114
|
let cardEpoch = 0;
|
|
109
|
-
let assetVersion = 0;
|
|
110
115
|
let surface = {
|
|
111
116
|
width: 0,
|
|
112
117
|
height: 0
|
|
@@ -114,7 +119,7 @@ function mountBoardStage(host, options) {
|
|
|
114
119
|
let playbackCamera = null;
|
|
115
120
|
let cursor = "";
|
|
116
121
|
const renderCamera = () => playbackCamera ?? editor.camera;
|
|
117
|
-
const views = createBoardItemViewLayer(host, editor, options.views ?? [], renderCamera);
|
|
122
|
+
const views = createBoardItemViewLayer(host, editor, options.views ?? [], renderCamera, scheduleTick);
|
|
118
123
|
const player = createBoardPlayer({ resolveColor: (color) => {
|
|
119
124
|
const current = theme();
|
|
120
125
|
return {
|
|
@@ -138,29 +143,70 @@ function mountBoardStage(host, options) {
|
|
|
138
143
|
scene: editor.scene
|
|
139
144
|
};
|
|
140
145
|
options.onVisibleChange?.(cull.ids);
|
|
141
|
-
requestAssets = true;
|
|
142
146
|
return cull.ids;
|
|
143
147
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
const textureScale = () => renderCamera().zoom * (app?.renderer.resolution ?? 1);
|
|
149
|
+
let refined = {
|
|
150
|
+
scale: 0,
|
|
151
|
+
geometry: 0
|
|
152
|
+
};
|
|
153
|
+
let pendingRefine = "";
|
|
154
|
+
let refineTimer = null;
|
|
155
|
+
function stopRefine() {
|
|
156
|
+
if (refineTimer !== null) clearTimeout(refineTimer);
|
|
157
|
+
refineTimer = null;
|
|
158
|
+
refined = {
|
|
159
|
+
scale: 0,
|
|
160
|
+
geometry: 0
|
|
161
|
+
};
|
|
162
|
+
pendingRefine = "";
|
|
163
|
+
}
|
|
164
|
+
function scheduleRefine() {
|
|
165
|
+
const scale = textureScale();
|
|
166
|
+
const geometry = editor.geometryVersion;
|
|
167
|
+
const key = `${scale}:${geometry}`;
|
|
168
|
+
if (key === pendingRefine) return;
|
|
169
|
+
pendingRefine = key;
|
|
170
|
+
if (refineTimer !== null) clearTimeout(refineTimer);
|
|
171
|
+
refineTimer = null;
|
|
172
|
+
if (refined.scale === 0 || scale <= refined.scale && geometry === refined.geometry) {
|
|
173
|
+
refined = {
|
|
174
|
+
scale,
|
|
175
|
+
geometry
|
|
176
|
+
};
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
refineTimer = setTimeout(() => {
|
|
180
|
+
refineTimer = null;
|
|
181
|
+
refined = {
|
|
182
|
+
scale,
|
|
183
|
+
geometry
|
|
184
|
+
};
|
|
185
|
+
for (const id of scene?.liveIds() ?? []) {
|
|
186
|
+
const item = editor.scene.get(id);
|
|
187
|
+
if (item) assets.requestItem(item, boardTextureEdge(item, scale));
|
|
188
|
+
}
|
|
189
|
+
}, TEXTURE_SETTLE_MS);
|
|
190
|
+
}
|
|
191
|
+
const naturalIds = /* @__PURE__ */ new Set();
|
|
192
|
+
let liveVersion = -1;
|
|
193
|
+
function adoptNaturalSizes() {
|
|
194
|
+
if (naturalIds.size === 0) return;
|
|
148
195
|
const sizes = [];
|
|
149
|
-
for (const id of
|
|
196
|
+
for (const id of naturalIds) {
|
|
150
197
|
const item = editor.itemById(id);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (!key) continue;
|
|
154
|
-
assets.requestItem(item);
|
|
198
|
+
const key = item && assets.assetKey(item);
|
|
199
|
+
if (!item || !key) continue;
|
|
155
200
|
const artifact = item.type === "task" ? featuredTaskArtifact(item.props.snapshot.artifacts) : null;
|
|
156
201
|
const recorded = artifact?.type === "image" || artifact?.type === "video" ? artifact : item.type === "image" || item.type === "video" ? item.props.snapshot : null;
|
|
157
202
|
if (!recorded || recorded.naturalWidth && recorded.naturalHeight) continue;
|
|
158
203
|
const natural = assets.getNaturalSize(key);
|
|
159
204
|
if (natural?.width && natural.height) sizes.push({
|
|
160
|
-
id
|
|
205
|
+
id,
|
|
161
206
|
...natural
|
|
162
207
|
});
|
|
163
208
|
}
|
|
209
|
+
naturalIds.clear();
|
|
164
210
|
if (sizes.length > 0) editor.adoptMediaNaturalSizes(sizes);
|
|
165
211
|
}
|
|
166
212
|
let lifted = null;
|
|
@@ -201,7 +247,11 @@ function mountBoardStage(host, options) {
|
|
|
201
247
|
getTexture: (key) => assets.getTexture(key),
|
|
202
248
|
hasError: (key) => assets.hasError(key),
|
|
203
249
|
fileState: (path) => options.fileState?.(path) ?? "ok",
|
|
204
|
-
acquireTexture: (key) =>
|
|
250
|
+
acquireTexture: (key, item) => {
|
|
251
|
+
assets.acquire(key);
|
|
252
|
+
assets.requestItem(item, boardTextureEdge(item, textureScale()));
|
|
253
|
+
if (assets.getTexture(key)) naturalIds.add(item.id);
|
|
254
|
+
},
|
|
205
255
|
releaseTexture: (key) => assets.release(key)
|
|
206
256
|
};
|
|
207
257
|
}
|
|
@@ -440,9 +490,37 @@ function mountBoardStage(host, options) {
|
|
|
440
490
|
}, owner, retained);
|
|
441
491
|
if (!retained || scriptHover && scriptHover.owner === owner && !Object.hasOwn(retained, scriptHover.target)) scriptHover = null;
|
|
442
492
|
}
|
|
493
|
+
function syncScripts() {
|
|
494
|
+
if (!scripts) return;
|
|
495
|
+
const now = performance.now();
|
|
496
|
+
if (scriptMode !== "paused") scriptTime += Math.min(250, Math.max(0, now - scriptLastTick));
|
|
497
|
+
scriptLastTick = now;
|
|
498
|
+
const camera = renderCamera();
|
|
499
|
+
if (scriptMode !== "paused" && scriptObservers.size) scriptObservers.sync(editor.document, editor.selection, () => ({
|
|
500
|
+
camera: { ...camera },
|
|
501
|
+
...surface,
|
|
502
|
+
safeRect: options.safeRect?.() ?? {
|
|
503
|
+
x: 0,
|
|
504
|
+
y: 0,
|
|
505
|
+
...surface
|
|
506
|
+
}
|
|
507
|
+
}));
|
|
508
|
+
scripts.sync(editor.document, editor.scene, camera, scriptTime, scriptMode === "interact", visibleIds());
|
|
509
|
+
}
|
|
510
|
+
function scheduleScriptTick() {
|
|
511
|
+
if (scriptTickFrame || !active || disposed) return;
|
|
512
|
+
scriptTickFrame = requestAnimationFrame(() => {
|
|
513
|
+
scriptTickFrame = 0;
|
|
514
|
+
if (tickFrame) return;
|
|
515
|
+
syncScripts();
|
|
516
|
+
if (scriptMode !== "paused" && scripts?.animated) scheduleScriptTick();
|
|
517
|
+
});
|
|
518
|
+
}
|
|
443
519
|
function createScripts() {
|
|
444
520
|
return createBoardScriptHost({
|
|
445
521
|
host,
|
|
522
|
+
isMaterialized: (id) => Boolean(scene?.getNode(id)),
|
|
523
|
+
onSchedule: scheduleScriptTick,
|
|
446
524
|
capabilities: {
|
|
447
525
|
...options.scriptCapabilities,
|
|
448
526
|
"board.emit": async (id, value) => {
|
|
@@ -550,25 +628,9 @@ function mountBoardStage(host, options) {
|
|
|
550
628
|
}
|
|
551
629
|
}
|
|
552
630
|
const renderScene = editor.scene;
|
|
553
|
-
if (scripts) {
|
|
554
|
-
const now = performance.now();
|
|
555
|
-
if (scriptMode !== "paused") scriptTime += Math.min(250, Math.max(0, now - scriptLastTick));
|
|
556
|
-
scriptLastTick = now;
|
|
557
|
-
if (scriptMode !== "paused" && scriptObservers.size) scriptObservers.sync(editor.document, editor.selection, () => ({
|
|
558
|
-
camera: { ...camera },
|
|
559
|
-
...surface,
|
|
560
|
-
safeRect: options.safeRect?.() ?? {
|
|
561
|
-
x: 0,
|
|
562
|
-
y: 0,
|
|
563
|
-
...surface
|
|
564
|
-
}
|
|
565
|
-
}));
|
|
566
|
-
scripts.sync(editor.document, renderScene, camera, scriptTime, scriptMode === "interact", visibleIds());
|
|
567
|
-
}
|
|
568
631
|
world.position.set(camera.x, camera.y);
|
|
569
632
|
world.scale.set(camera.zoom);
|
|
570
633
|
const ids = visibleIds();
|
|
571
|
-
syncAssets(ids);
|
|
572
634
|
const context = renderContext(current, renderScene, frame.time);
|
|
573
635
|
if (animationId && effectSampler) {
|
|
574
636
|
context.time = editor.playhead?.time ?? frame.time;
|
|
@@ -591,18 +653,20 @@ function mountBoardStage(host, options) {
|
|
|
591
653
|
getItem: (id) => renderScene.get(id) ?? null,
|
|
592
654
|
visibleIds: ids,
|
|
593
655
|
pinnedIds,
|
|
594
|
-
globalSig: [
|
|
595
|
-
assetVersion,
|
|
596
|
-
cardEpoch,
|
|
597
|
-
current.key,
|
|
598
|
-
textZoomBucket(camera.zoom)
|
|
599
|
-
].join("|"),
|
|
656
|
+
globalSig: [cardEpoch, current.key].join("|"),
|
|
600
657
|
staleIds,
|
|
601
658
|
structureVersion: editor.structureVersion,
|
|
602
659
|
geometryVersion: editor.geometryVersion,
|
|
603
660
|
gestureActive: editor.gestureActive && editor.interaction.type !== "panning"
|
|
604
661
|
});
|
|
605
662
|
staleIds.clear();
|
|
663
|
+
if (scene.liveVersion !== liveVersion) {
|
|
664
|
+
liveVersion = scene.liveVersion;
|
|
665
|
+
options.onLiveChange?.(scene.liveIds());
|
|
666
|
+
}
|
|
667
|
+
adoptNaturalSizes();
|
|
668
|
+
scheduleRefine();
|
|
669
|
+
syncScripts();
|
|
606
670
|
drawInteraction();
|
|
607
671
|
views.sync({
|
|
608
672
|
ids,
|
|
@@ -614,28 +678,35 @@ function mountBoardStage(host, options) {
|
|
|
614
678
|
const nextCursor = cursorFor();
|
|
615
679
|
if (nextCursor !== cursor) host.style.cursor = cursor = nextCursor;
|
|
616
680
|
scheduleRender();
|
|
617
|
-
if (frame.running || scene.animated
|
|
681
|
+
if (frame.running || scene.animated) scheduleTick();
|
|
682
|
+
if (scriptMode !== "paused" && scripts?.animated) scheduleScriptTick();
|
|
618
683
|
const cardWait = scene.tick(performance.now());
|
|
619
684
|
if (cardWait !== null) scheduleCardTick(cardWait);
|
|
620
685
|
}
|
|
621
686
|
function resize() {
|
|
622
687
|
cancelAnimationFrame(resizeFrame);
|
|
623
688
|
resizeFrame = requestAnimationFrame(() => {
|
|
624
|
-
if (!app) return;
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
height: app.screen.height
|
|
689
|
+
if (!app || !active) return;
|
|
690
|
+
const size = {
|
|
691
|
+
width: host.clientWidth,
|
|
692
|
+
height: host.clientHeight
|
|
629
693
|
};
|
|
630
|
-
|
|
631
|
-
|
|
694
|
+
if (size.width <= 0 || size.height <= 0) return;
|
|
695
|
+
const resolution = getBoardResolution(size);
|
|
696
|
+
const sizeChanged = size.width !== surface.width || size.height !== surface.height;
|
|
697
|
+
if (sizeChanged || app.renderer.resolution !== resolution) app.renderer.resize(size.width, size.height, resolution);
|
|
698
|
+
if (sizeChanged) {
|
|
699
|
+
surface = size;
|
|
700
|
+
editor.surfaceSize = surface;
|
|
701
|
+
options.onSurfaceChange?.(surface);
|
|
702
|
+
}
|
|
632
703
|
sync();
|
|
633
704
|
});
|
|
634
705
|
}
|
|
635
|
-
const
|
|
706
|
+
const localPoint = (x, y) => elementClientToLocal(host)(x, y);
|
|
636
707
|
const inViews = (event) => event.target instanceof Node && views.element.contains(event.target);
|
|
637
708
|
function toInput(event) {
|
|
638
|
-
return toBoardPointerEvent(event,
|
|
709
|
+
return toBoardPointerEvent(event, host, renderCamera(), event.type === "pointermove" && editor.interaction.type === "drawing");
|
|
639
710
|
}
|
|
640
711
|
function scriptTarget(input) {
|
|
641
712
|
if (!scriptOutputs.size) return null;
|
|
@@ -742,13 +813,12 @@ function mountBoardStage(host, options) {
|
|
|
742
813
|
if (inViews(event)) return;
|
|
743
814
|
event.preventDefault();
|
|
744
815
|
editor.takeCameraControl();
|
|
745
|
-
const
|
|
746
|
-
const point = screenPoint(event.clientX - rect.left, event.clientY - rect.top);
|
|
816
|
+
const point = localPoint(event.clientX, event.clientY);
|
|
747
817
|
editor.wheel(point, event.deltaX, event.deltaY, event.ctrlKey || event.metaKey, event.deltaMode);
|
|
748
818
|
}
|
|
749
819
|
function handleDoubleClick(event) {
|
|
750
820
|
if (inViews(event)) return;
|
|
751
|
-
const point =
|
|
821
|
+
const point = pointToWorld(localPoint(event.clientX, event.clientY), renderCamera());
|
|
752
822
|
const item = editor.itemAt(point);
|
|
753
823
|
if (options.onDoubleClick?.(item, point) === true || editor.readonly) return;
|
|
754
824
|
if (item && !item.locked && editor.registry.capabilities(item).canEdit) {
|
|
@@ -774,9 +844,13 @@ function mountBoardStage(host, options) {
|
|
|
774
844
|
["dblclick", handleDoubleClick]
|
|
775
845
|
];
|
|
776
846
|
const stopEditor = editor.subscribe(LIVE_CHANNELS, scheduleTick);
|
|
777
|
-
const stopAssets = assets.subscribe(() => {
|
|
778
|
-
|
|
779
|
-
|
|
847
|
+
const stopAssets = assets.subscribe((key) => {
|
|
848
|
+
const ids = scene?.holders(key);
|
|
849
|
+
if (!ids?.size) return;
|
|
850
|
+
for (const id of ids) {
|
|
851
|
+
staleIds.add(id);
|
|
852
|
+
naturalIds.add(id);
|
|
853
|
+
}
|
|
780
854
|
scheduleTick();
|
|
781
855
|
});
|
|
782
856
|
const resizeObserver = new ResizeObserver(resize);
|
|
@@ -788,8 +862,12 @@ function mountBoardStage(host, options) {
|
|
|
788
862
|
antialias: true,
|
|
789
863
|
autoDensity: true,
|
|
790
864
|
backgroundAlpha: 0,
|
|
791
|
-
|
|
792
|
-
|
|
865
|
+
width: host.clientWidth,
|
|
866
|
+
height: host.clientHeight,
|
|
867
|
+
resolution: getBoardResolution({
|
|
868
|
+
width: host.clientWidth,
|
|
869
|
+
height: host.clientHeight
|
|
870
|
+
}),
|
|
793
871
|
autoStart: false
|
|
794
872
|
});
|
|
795
873
|
} catch (error) {
|
|
@@ -829,6 +907,8 @@ function mountBoardStage(host, options) {
|
|
|
829
907
|
});
|
|
830
908
|
for (const [type, listener, listenerOptions] of listeners) host.addEventListener(type, listener, listenerOptions);
|
|
831
909
|
resizeObserver.observe(host);
|
|
910
|
+
const window = host.ownerDocument.defaultView;
|
|
911
|
+
if (window) stopDensity = observeDisplayDensity(window, resize);
|
|
832
912
|
resize();
|
|
833
913
|
return true;
|
|
834
914
|
})(),
|
|
@@ -880,7 +960,10 @@ function mountBoardStage(host, options) {
|
|
|
880
960
|
if (!active) {
|
|
881
961
|
pointers.cancel();
|
|
882
962
|
stopMarch();
|
|
963
|
+
stopRefine();
|
|
883
964
|
cancelScriptPointers();
|
|
965
|
+
cancelAnimationFrame(scriptTickFrame);
|
|
966
|
+
scriptTickFrame = 0;
|
|
884
967
|
cancelAnimationFrame(renderFrame);
|
|
885
968
|
cancelAnimationFrame(tickFrame);
|
|
886
969
|
cancelAnimationFrame(cardTickFrame);
|
|
@@ -896,27 +979,27 @@ function mountBoardStage(host, options) {
|
|
|
896
979
|
resize();
|
|
897
980
|
},
|
|
898
981
|
invalidate(invalidation) {
|
|
899
|
-
if (invalidation?.cards)
|
|
900
|
-
cardEpoch += 1;
|
|
901
|
-
requestAssets = true;
|
|
902
|
-
}
|
|
982
|
+
if (invalidation?.cards) cardEpoch += 1;
|
|
903
983
|
for (const id of invalidation?.items ?? []) staleIds.add(id);
|
|
904
984
|
scheduleTick();
|
|
905
985
|
},
|
|
906
986
|
isMaterialized: (id) => Boolean(scene?.getNode(id)),
|
|
907
|
-
toWorld: (clientX, clientY) =>
|
|
987
|
+
toWorld: (clientX, clientY) => pointToWorld(localPoint(clientX, clientY), renderCamera()),
|
|
908
988
|
destroy() {
|
|
909
989
|
disposed = true;
|
|
910
990
|
pointers.cancel();
|
|
911
991
|
stopMarch();
|
|
992
|
+
stopRefine();
|
|
912
993
|
scriptPointers.clear();
|
|
913
994
|
stopTransforms?.();
|
|
914
995
|
scriptObservers.clear();
|
|
915
996
|
scriptListeners.clear();
|
|
916
997
|
stopMaintenance?.();
|
|
998
|
+
stopDensity?.();
|
|
917
999
|
stopEditor();
|
|
918
1000
|
stopAssets();
|
|
919
1001
|
resizeObserver.disconnect();
|
|
1002
|
+
cancelAnimationFrame(scriptTickFrame);
|
|
920
1003
|
cancelAnimationFrame(resizeFrame);
|
|
921
1004
|
cancelAnimationFrame(renderFrame);
|
|
922
1005
|
cancelAnimationFrame(tickFrame);
|
|
@@ -7,7 +7,7 @@ import "../editor/index.js";
|
|
|
7
7
|
//#region src/board/stage/views.d.ts
|
|
8
8
|
type BoardItemViewContext = {
|
|
9
9
|
editor: BoardEditor;
|
|
10
|
-
|
|
10
|
+
detailed: boolean;
|
|
11
11
|
selected: boolean;
|
|
12
12
|
toPointerEvent(event: PointerEvent): BoardPointerEvent;
|
|
13
13
|
};
|
|
@@ -17,6 +17,11 @@ type BoardItemViewInstance = {
|
|
|
17
17
|
};
|
|
18
18
|
type BoardItemView = {
|
|
19
19
|
type: string | ((item: BoardSceneItem) => boolean);
|
|
20
|
+
/** Optional screen-pixel threshold for expensive content, with built-in hysteresis. */
|
|
21
|
+
contentSize?: {
|
|
22
|
+
width: number;
|
|
23
|
+
height: number;
|
|
24
|
+
};
|
|
20
25
|
mount(element: HTMLElement, item: BoardSceneItem, context: BoardItemViewContext): BoardItemViewInstance;
|
|
21
26
|
};
|
|
22
27
|
type BoardItemViewLayer = {
|
|
@@ -33,6 +38,6 @@ type BoardItemViewLayer = {
|
|
|
33
38
|
}): void;
|
|
34
39
|
destroy(): void;
|
|
35
40
|
};
|
|
36
|
-
declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport): BoardItemViewLayer;
|
|
41
|
+
declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport, onInvalidate?: () => void): BoardItemViewLayer;
|
|
37
42
|
//#endregion
|
|
38
43
|
export { BoardItemView, BoardItemViewContext, BoardItemViewInstance, BoardItemViewLayer, createBoardItemViewLayer };
|