@vibecook/ice 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -2
- package/dist/chunk-5SJYHQI4.js +636 -0
- package/dist/chunk-5SJYHQI4.js.map +1 -0
- package/dist/{chunk-5S7GSXJG.js → chunk-DXU3RZZS.js} +2913 -1180
- package/dist/chunk-DXU3RZZS.js.map +1 -0
- package/dist/{chunk-FIAXPNNY.js → chunk-IASTQMU5.js} +130 -551
- package/dist/chunk-IASTQMU5.js.map +1 -0
- package/dist/{chunk-BCJ47SX7.js → chunk-OR5FNVUE.js} +460 -1
- package/dist/chunk-OR5FNVUE.js.map +1 -0
- package/dist/devtools.js +508 -372
- package/dist/devtools.js.map +1 -1
- package/dist/dom.js +3 -11
- package/dist/ground.js +715 -0
- package/dist/ground.js.map +1 -0
- package/dist/index.js +70 -2
- package/dist/kernel.js +31 -1
- package/dist/r3f.js +599 -62
- package/dist/r3f.js.map +1 -1
- package/dist/react.js +34 -418
- package/dist/react.js.map +1 -1
- package/dist/types/packages/core/src/catalog/camera-derived.d.ts +41 -3
- package/dist/types/packages/core/src/catalog/gesture.d.ts +39 -3
- package/dist/types/packages/core/src/catalog/graph.d.ts +7 -6
- package/dist/types/packages/core/src/catalog/index.d.ts +1 -0
- package/dist/types/packages/core/src/catalog/insert.d.ts +31 -0
- package/dist/types/packages/core/src/catalog/pointer.d.ts +11 -0
- package/dist/types/packages/core/src/catalog/scene.d.ts +37 -4
- package/dist/types/packages/core/src/catalog/selection-presence.d.ts +7 -0
- package/dist/types/packages/core/src/catalog/settings-resources.d.ts +21 -0
- package/dist/types/packages/core/src/doc/autosave.d.ts +15 -2
- package/dist/types/packages/core/src/doc/bootstrap.d.ts +29 -0
- package/dist/types/packages/core/src/doc/channels.d.ts +9 -0
- package/dist/types/packages/core/src/doc/doc-commit-sink.d.ts +2 -1
- package/dist/types/packages/core/src/doc/doc-kit.d.ts +16 -1
- package/dist/types/packages/core/src/doc/envelope.d.ts +2 -1
- package/dist/types/packages/core/src/doc/migrate.d.ts +8 -6
- package/dist/types/packages/core/src/doc/schema-migrate.d.ts +50 -0
- package/dist/types/packages/core/src/doc/version-gate.d.ts +3 -0
- package/dist/types/packages/core/src/engine/commit-sink.d.ts +24 -2
- package/dist/types/packages/core/src/engine/frame-info.d.ts +16 -1
- package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +70 -6
- package/dist/types/packages/core/src/guards/guarded-tx.d.ts +4 -2
- package/dist/types/packages/core/src/helpers/churn-guard.d.ts +40 -0
- package/dist/types/packages/core/src/index.d.ts +13 -7
- package/dist/types/packages/core/src/input/queue.d.ts +11 -0
- package/dist/types/packages/core/src/nav/nested-canvas.d.ts +47 -11
- package/dist/types/packages/core/src/ops/arrange.d.ts +15 -0
- package/dist/types/packages/core/src/ops/insert.d.ts +62 -0
- package/dist/types/packages/core/src/ops/point-pick.d.ts +11 -7
- package/dist/types/packages/core/src/ops/sibling-order.d.ts +70 -0
- package/dist/types/packages/core/src/schema/meta.d.ts +1 -0
- package/dist/types/packages/core/src/settings/defaults.d.ts +45 -0
- package/dist/types/packages/core/src/settings/ground-config.d.ts +55 -0
- package/dist/types/packages/core/src/systems/chrome.d.ts +6 -2
- package/dist/types/packages/core/src/systems/insert-ghost.d.ts +25 -0
- package/dist/types/packages/core/src/systems/l1-pick.d.ts +25 -11
- package/dist/types/packages/core/src/systems/l2-recognize.d.ts +10 -4
- package/dist/types/packages/core/src/systems/l3-behave.d.ts +6 -4
- package/dist/types/packages/core/src/systems/l3-claim.d.ts +7 -3
- package/dist/types/packages/core/src/systems/l3-drop.d.ts +3 -1
- package/dist/types/packages/core/src/systems/l3-resize.d.ts +3 -1
- package/dist/types/packages/core/src/systems/l3-snap.d.ts +25 -7
- package/dist/types/packages/core/src/systems/nav-flight.d.ts +95 -0
- package/dist/types/packages/core/src/widget/define-widget.d.ts +39 -0
- package/dist/types/packages/core/src/widget/mount-store.d.ts +11 -3
- package/dist/types/packages/core/src/widget/set-props.d.ts +16 -0
- package/dist/types/packages/core/src/widget/spawn.d.ts +21 -1
- package/dist/types/packages/devtools/src/attach.d.ts +77 -0
- package/dist/types/packages/devtools/src/dock.d.ts +38 -0
- package/dist/types/packages/devtools/src/gl-panel.d.ts +69 -0
- package/dist/types/packages/devtools/src/index.d.ts +8 -6
- package/dist/types/packages/dom/src/index.d.ts +1 -3
- package/dist/types/packages/dom/src/measure-wiring.d.ts +2 -2
- package/dist/types/packages/dom/src/pointer-adapter.d.ts +21 -1
- package/dist/types/packages/dom/src/reflectors/dom-widgets.d.ts +5 -0
- package/dist/types/packages/ground/src/index.d.ts +52 -0
- package/dist/types/packages/ground/src/layer.d.ts +40 -0
- package/dist/types/packages/ground/src/pass.d.ts +41 -0
- package/dist/types/packages/ground/src/passes/grid.d.ts +21 -0
- package/dist/types/packages/ground/src/passes/guides-collect.d.ts +14 -0
- package/dist/types/packages/ground/src/passes/guides.d.ts +3 -0
- package/dist/types/packages/ground/src/passes/soup-collect.d.ts +35 -0
- package/dist/types/packages/ground/src/passes/soup-mesh.d.ts +8 -0
- package/dist/types/packages/ground/src/passes/wires-collect.d.ts +31 -0
- package/dist/types/packages/ground/src/passes/wires.d.ts +10 -0
- package/dist/types/packages/ground/src/renderer.d.ts +15 -0
- package/dist/types/packages/ice/src/ground.d.ts +1 -0
- package/dist/types/packages/kernel/src/bezier.d.ts +15 -0
- package/dist/types/packages/kernel/src/coords.d.ts +15 -0
- package/dist/types/packages/kernel/src/easing.d.ts +11 -0
- package/dist/types/packages/kernel/src/index.d.ts +3 -0
- package/dist/types/packages/kernel/src/layout.d.ts +118 -0
- package/dist/types/packages/kernel/src/nav-flight.d.ts +93 -0
- package/dist/types/packages/r3f/src/bridge.d.ts +73 -12
- package/dist/types/packages/r3f/src/composite-material.d.ts +9 -0
- package/dist/types/packages/r3f/src/compositor-pass.d.ts +22 -0
- package/dist/types/packages/r3f/src/gl-root.d.ts +76 -1
- package/dist/types/packages/r3f/src/gl-router.d.ts +10 -0
- package/dist/types/packages/r3f/src/index.d.ts +3 -2
- package/dist/types/packages/r3f/src/island-state.d.ts +44 -0
- package/dist/types/packages/r3f/src/preview-capture.d.ts +19 -0
- package/dist/types/packages/r3f/src/self-sustain.d.ts +39 -0
- package/dist/types/packages/r3f/src/use-island-frame.d.ts +16 -1
- package/dist/types/packages/react/src/engine-context.d.ts +8 -0
- package/dist/types/packages/react/src/index.d.ts +4 -2
- package/dist/types/packages/react/src/infinite-canvas.d.ts +40 -6
- package/dist/types/packages/react/src/preview-snapshots.d.ts +17 -0
- package/dist/types/packages/react/src/widget-preview.d.ts +14 -0
- package/package.json +13 -8
- package/dist/chunk-5S7GSXJG.js.map +0 -1
- package/dist/chunk-BCJ47SX7.js.map +0 -1
- package/dist/chunk-FIAXPNNY.js.map +0 -1
- package/dist/types/packages/devtools/src/panel.d.ts +0 -48
- package/dist/types/packages/dom/src/reflectors/grid.d.ts +0 -63
- package/dist/types/packages/dom/src/reflectors/wires.d.ts +0 -88
|
@@ -6,28 +6,21 @@ import {
|
|
|
6
6
|
HandleSpec,
|
|
7
7
|
MeasuredSize,
|
|
8
8
|
NO_MODS,
|
|
9
|
-
|
|
10
|
-
PortAnchor,
|
|
9
|
+
Opacity,
|
|
11
10
|
Position,
|
|
12
11
|
PrefabId,
|
|
13
12
|
PresenceInfo,
|
|
14
|
-
RoutedConnect,
|
|
15
|
-
Selected,
|
|
16
13
|
SelectionBox,
|
|
17
14
|
Size,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
WirePorts,
|
|
21
|
-
WireTo,
|
|
15
|
+
compareStackOrder,
|
|
16
|
+
createSiblingOrderIndex,
|
|
22
17
|
defineQuery,
|
|
23
18
|
widgets
|
|
24
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-DXU3RZZS.js";
|
|
25
20
|
import {
|
|
26
21
|
planeCssTransform,
|
|
27
|
-
portAnchor,
|
|
28
|
-
wireCubic,
|
|
29
22
|
worldToScreen
|
|
30
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-OR5FNVUE.js";
|
|
31
24
|
|
|
32
25
|
// ../dom/src/host.ts
|
|
33
26
|
var CONTAINER_STYLE = {
|
|
@@ -47,6 +40,10 @@ function createCanvasHost(container) {
|
|
|
47
40
|
const position = container.style.position !== "" ? container.style.position : view?.getComputedStyle(container).position ?? "";
|
|
48
41
|
const promoteToRelative = position === "" || position === "static";
|
|
49
42
|
if (promoteToRelative) container.style.position = "relative";
|
|
43
|
+
const priorContainerStyle = Object.keys(CONTAINER_STYLE).map((prop) => {
|
|
44
|
+
const cssName = prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
45
|
+
return [cssName, container.style.getPropertyValue(cssName)];
|
|
46
|
+
});
|
|
50
47
|
Object.assign(container.style, CONTAINER_STYLE);
|
|
51
48
|
const contentPlane = container.ownerDocument.createElement("div");
|
|
52
49
|
Object.assign(contentPlane.style, PLANE_STYLE);
|
|
@@ -57,11 +54,9 @@ function createCanvasHost(container) {
|
|
|
57
54
|
dispose() {
|
|
58
55
|
contentPlane.remove();
|
|
59
56
|
if (promoteToRelative) container.style.removeProperty("position");
|
|
60
|
-
for (const
|
|
61
|
-
container.style.
|
|
62
|
-
|
|
63
|
-
prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`)
|
|
64
|
-
);
|
|
57
|
+
for (const [cssName, prior] of priorContainerStyle) {
|
|
58
|
+
if (prior !== "") container.style.setProperty(cssName, prior);
|
|
59
|
+
else container.style.removeProperty(cssName);
|
|
65
60
|
}
|
|
66
61
|
}
|
|
67
62
|
};
|
|
@@ -73,7 +68,12 @@ var LIFTED_PLANE_STYLE = {
|
|
|
73
68
|
left: "0",
|
|
74
69
|
top: "0",
|
|
75
70
|
transformOrigin: "0 0",
|
|
76
|
-
willChange: "transform"
|
|
71
|
+
willChange: "transform",
|
|
72
|
+
// The ONE explicit z in the plane sandwich (2026-07-19): in-container app
|
|
73
|
+
// chrome may slot BETWEEN the planes with z-index 1 — resting widgets
|
|
74
|
+
// slide under it while the dragged (promoted) widget floats over it. DOM
|
|
75
|
+
// order alone leaves no gap for that; everything else stays order-stacked.
|
|
76
|
+
zIndex: "2"
|
|
77
77
|
};
|
|
78
78
|
function createPlanes(host) {
|
|
79
79
|
const lifted = host.container.ownerDocument.createElement("div");
|
|
@@ -191,6 +191,7 @@ function createGrayboxReflector(host) {
|
|
|
191
191
|
var geometryQuery = defineQuery([Position, Size]);
|
|
192
192
|
var measuredQuery = defineQuery([MeasuredSize]);
|
|
193
193
|
var grabQuery = defineQuery([Grab]);
|
|
194
|
+
var opacityQuery = defineQuery([Opacity]);
|
|
194
195
|
function writeGeom2(el, x, y, w, h) {
|
|
195
196
|
el.style.left = `${x}px`;
|
|
196
197
|
el.style.top = `${y}px`;
|
|
@@ -200,11 +201,14 @@ function writeGeom2(el, x, y, w, h) {
|
|
|
200
201
|
function createDomWidgetsReflector(host, world, store) {
|
|
201
202
|
const doc = host.contentPlane.ownerDocument;
|
|
202
203
|
const hosts = /* @__PURE__ */ new Map();
|
|
204
|
+
const order = createSiblingOrderIndex(world);
|
|
203
205
|
let lastSnapshot;
|
|
204
206
|
let geometryWrites = 0;
|
|
205
207
|
let inert = false;
|
|
206
208
|
let geometryDirty = false;
|
|
207
209
|
let promoteDirty = false;
|
|
210
|
+
let opacityDirty = false;
|
|
211
|
+
let orderDirty = false;
|
|
208
212
|
const unsubs = [
|
|
209
213
|
world.reactive.observeQuery(geometryQuery, () => {
|
|
210
214
|
geometryDirty = true;
|
|
@@ -216,14 +220,35 @@ function createDomWidgetsReflector(host, world, store) {
|
|
|
216
220
|
}, { cols: [MeasuredSize] }),
|
|
217
221
|
world.reactive.observeQuery(grabQuery, () => {
|
|
218
222
|
promoteDirty = true;
|
|
219
|
-
}, { cols: [] })
|
|
223
|
+
}, { cols: [] }),
|
|
224
|
+
// Opacity is an optional rider like MeasuredSize: membership (attach/detach)
|
|
225
|
+
// and value changes both arm the flag; detach resets the host to the
|
|
226
|
+
// default via the `?? 1` read.
|
|
227
|
+
world.reactive.observeQuery(opacityQuery, () => {
|
|
228
|
+
opacityDirty = true;
|
|
229
|
+
}, { cols: [Opacity] }),
|
|
230
|
+
// Within-plane stacking IS the frame's ChildOf sibling sequence (petition
|
|
231
|
+
// 8, superseding the StackZ sort that fixed the 2026-07-18 comment-box
|
|
232
|
+
// paint bug). The wake names the relation (Related grammar — pure
|
|
233
|
+
// reorders fire it); the ordinal cache's stamp check in updateOrder
|
|
234
|
+
// keeps other-frame churn cheap.
|
|
235
|
+
order.observe(() => {
|
|
236
|
+
orderDirty = true;
|
|
237
|
+
})
|
|
220
238
|
];
|
|
239
|
+
function promotable(e) {
|
|
240
|
+
const type = world.get(e, PrefabId)?.id;
|
|
241
|
+
return typeof type !== "string" || widgets.get(type)?.surface !== "gl";
|
|
242
|
+
}
|
|
221
243
|
function readGeom(e) {
|
|
222
244
|
const p = world.get(e, Position);
|
|
223
245
|
const measured = world.get(e, MeasuredSize);
|
|
224
246
|
const s = measured !== void 0 && measured.w > 0 ? measured : world.get(e, Size);
|
|
225
247
|
return { x: p?.x ?? 0, y: p?.y ?? 0, w: s?.w ?? 0, h: s?.h ?? 0 };
|
|
226
248
|
}
|
|
249
|
+
function readOpacity(e) {
|
|
250
|
+
return world.get(e, Opacity)?.a ?? 1;
|
|
251
|
+
}
|
|
227
252
|
function createHost(e) {
|
|
228
253
|
const el = doc.createElement("div");
|
|
229
254
|
el.style.position = "absolute";
|
|
@@ -236,9 +261,11 @@ function createDomWidgetsReflector(host, world, store) {
|
|
|
236
261
|
const g = readGeom(e);
|
|
237
262
|
writeGeom2(el, g.x, g.y, g.w, g.h);
|
|
238
263
|
geometryWrites++;
|
|
239
|
-
const
|
|
264
|
+
const opacity = readOpacity(e);
|
|
265
|
+
if (opacity !== 1) el.style.opacity = String(opacity);
|
|
266
|
+
const lifted = world.has(e, Grab) && promotable(e);
|
|
240
267
|
(lifted ? host.liftedPlane : host.contentPlane).appendChild(el);
|
|
241
|
-
return { host: el, content, x: g.x, y: g.y, w: g.w, h: g.h, hidden: false, lifted };
|
|
268
|
+
return { host: el, content, x: g.x, y: g.y, w: g.w, h: g.h, hidden: false, lifted, opacity };
|
|
242
269
|
}
|
|
243
270
|
function reconcile(snapshot) {
|
|
244
271
|
let membershipChanged = false;
|
|
@@ -277,14 +304,57 @@ function createDomWidgetsReflector(host, world, store) {
|
|
|
277
304
|
}
|
|
278
305
|
}
|
|
279
306
|
}
|
|
307
|
+
function updateOrder() {
|
|
308
|
+
const ordinals = order.ordinals();
|
|
309
|
+
for (const plane of [host.contentPlane, host.liftedPlane]) {
|
|
310
|
+
const active = doc.activeElement;
|
|
311
|
+
if (active !== null && active !== doc.body && plane.contains(active)) continue;
|
|
312
|
+
const mine = [];
|
|
313
|
+
for (const [e, rec] of hosts) {
|
|
314
|
+
if (rec.host.parentNode !== plane) continue;
|
|
315
|
+
mine.push({ el: rec.host, e });
|
|
316
|
+
}
|
|
317
|
+
if (mine.length < 2) continue;
|
|
318
|
+
const target = [...mine].sort((a, b) => compareStackOrder(world, ordinals, a.e, b.e));
|
|
319
|
+
let cursor = 0;
|
|
320
|
+
let inOrder = true;
|
|
321
|
+
for (let i = 0; i < plane.children.length; i++) {
|
|
322
|
+
const child = plane.children.item(i);
|
|
323
|
+
if (cursor >= target.length || child === null) break;
|
|
324
|
+
if (child === target[cursor].el) cursor += 1;
|
|
325
|
+
else if (mine.some((m) => m.el === child)) {
|
|
326
|
+
inOrder = false;
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (inOrder && cursor === target.length) continue;
|
|
331
|
+
for (const m of target) plane.appendChild(m.el);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function updateOpacity() {
|
|
335
|
+
for (const [e, rec] of hosts) {
|
|
336
|
+
const o = readOpacity(e);
|
|
337
|
+
if (o !== rec.opacity) {
|
|
338
|
+
rec.host.style.opacity = o === 1 ? "" : String(o);
|
|
339
|
+
rec.opacity = o;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
280
343
|
function updatePromote() {
|
|
281
344
|
let anyLifted = false;
|
|
282
345
|
for (const [e, rec] of hosts) {
|
|
283
|
-
const
|
|
346
|
+
const grabbed = world.has(e, Grab);
|
|
347
|
+
const shouldLift = grabbed && promotable(e);
|
|
284
348
|
if (shouldLift) anyLifted = true;
|
|
285
349
|
if (shouldLift !== rec.lifted) {
|
|
286
350
|
rec.lifted = shouldLift;
|
|
287
351
|
(shouldLift ? host.liftedPlane : host.contentPlane).appendChild(rec.host);
|
|
352
|
+
orderDirty = true;
|
|
353
|
+
}
|
|
354
|
+
if (grabbed && !shouldLift) {
|
|
355
|
+
if (rec.host.style.zIndex !== "1000") rec.host.style.zIndex = "1000";
|
|
356
|
+
} else if (rec.host.style.zIndex !== "") {
|
|
357
|
+
rec.host.style.zIndex = "";
|
|
288
358
|
}
|
|
289
359
|
}
|
|
290
360
|
if (anyLifted !== inert) {
|
|
@@ -308,10 +378,18 @@ function createDomWidgetsReflector(host, world, store) {
|
|
|
308
378
|
geometryDirty = false;
|
|
309
379
|
updateGeometry();
|
|
310
380
|
}
|
|
381
|
+
if (opacityDirty) {
|
|
382
|
+
opacityDirty = false;
|
|
383
|
+
updateOpacity();
|
|
384
|
+
}
|
|
311
385
|
if (promoteDirty || membershipChanged) {
|
|
312
386
|
promoteDirty = false;
|
|
313
387
|
updatePromote();
|
|
314
388
|
}
|
|
389
|
+
if (orderDirty || membershipChanged) {
|
|
390
|
+
orderDirty = false;
|
|
391
|
+
updateOrder();
|
|
392
|
+
}
|
|
315
393
|
},
|
|
316
394
|
hostFor: (entity) => hosts.get(entity)?.content,
|
|
317
395
|
hostCount: () => hosts.size,
|
|
@@ -340,6 +418,7 @@ function startRafLoop(engine) {
|
|
|
340
418
|
}
|
|
341
419
|
|
|
342
420
|
// ../dom/src/pointer-adapter.ts
|
|
421
|
+
var asVerdict = (v) => typeof v === "object" ? v : { handled: v === true };
|
|
343
422
|
var WHEEL_LINE_PX = 16;
|
|
344
423
|
var INTERACTIVE_SELECTOR = 'input, textarea, select, button, a[href], [contenteditable=""], [contenteditable="true"], audio[controls], video[controls], [data-canvas-interactive]';
|
|
345
424
|
function crossesInteractive(target, container) {
|
|
@@ -388,7 +467,8 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
388
467
|
const device = deviceOf(e);
|
|
389
468
|
const { x, y } = relative(e.clientX, e.clientY);
|
|
390
469
|
const native = crossesInteractive(e.target, container);
|
|
391
|
-
const
|
|
470
|
+
const gl = asVerdict(glRoute?.("down", x, y, e));
|
|
471
|
+
const glClaimed = gl.handled;
|
|
392
472
|
live.set(id, { device, x, y, downX: x, downY: y, native, captured: glClaimed });
|
|
393
473
|
if (glClaimed) capture(e.pointerId);
|
|
394
474
|
const surfaceHandled = native || glClaimed;
|
|
@@ -401,14 +481,21 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
401
481
|
buttons: e.buttons,
|
|
402
482
|
mods: pointerMods(e),
|
|
403
483
|
tMs: e.timeStamp,
|
|
404
|
-
...surfaceHandled ? { surfaceHandled: true } : {}
|
|
484
|
+
...surfaceHandled ? { surfaceHandled: true } : {},
|
|
485
|
+
// The down IS a hover-bearing fact: a touch's first event must seed the
|
|
486
|
+
// pointer's OverInteractive truth (no prior moves exist to).
|
|
487
|
+
overInteractive: surfaceHandled || gl.overInteractive === true
|
|
405
488
|
});
|
|
406
489
|
};
|
|
407
490
|
const onPointerMove = (e) => {
|
|
408
491
|
const id = pointerIdOf(e);
|
|
409
492
|
const device = deviceOf(e);
|
|
410
493
|
const { x, y } = relative(e.clientX, e.clientY);
|
|
411
|
-
|
|
494
|
+
let seen = live.get(id);
|
|
495
|
+
if (seen === void 0 && e.buttons !== 0 && !crossesInteractive(e.target, container)) {
|
|
496
|
+
seen = { device, x, y, downX: x, downY: y, native: false, captured: false };
|
|
497
|
+
live.set(id, seen);
|
|
498
|
+
}
|
|
412
499
|
if (seen !== void 0) {
|
|
413
500
|
seen.x = x;
|
|
414
501
|
seen.y = y;
|
|
@@ -417,7 +504,7 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
417
504
|
seen.captured = true;
|
|
418
505
|
}
|
|
419
506
|
}
|
|
420
|
-
const
|
|
507
|
+
const gl = asVerdict(glRoute?.("move", x, y, e));
|
|
421
508
|
queue.enqueue({
|
|
422
509
|
kind: "move",
|
|
423
510
|
pointerId: id,
|
|
@@ -427,7 +514,10 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
427
514
|
buttons: e.buttons,
|
|
428
515
|
mods: pointerMods(e),
|
|
429
516
|
tMs: e.timeStamp,
|
|
430
|
-
...
|
|
517
|
+
...gl.handled ? { surfaceHandled: true } : {},
|
|
518
|
+
// Hover fact, every move: DOM chain check ∪ GL verdict. A gl-captured
|
|
519
|
+
// move (island drag) counts — the widget owns the pointer right now.
|
|
520
|
+
overInteractive: crossesInteractive(e.target, container) || gl.handled || gl.overInteractive === true
|
|
431
521
|
});
|
|
432
522
|
};
|
|
433
523
|
const endPointer = (kind) => (e) => {
|
|
@@ -441,7 +531,7 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
441
531
|
} catch {
|
|
442
532
|
}
|
|
443
533
|
}
|
|
444
|
-
const
|
|
534
|
+
const gl = asVerdict(glRoute?.(kind, x, y, e));
|
|
445
535
|
queue.enqueue({
|
|
446
536
|
kind,
|
|
447
537
|
pointerId: id,
|
|
@@ -450,7 +540,9 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
450
540
|
screenY: y,
|
|
451
541
|
buttons: e.buttons,
|
|
452
542
|
mods: pointerMods(e),
|
|
453
|
-
...
|
|
543
|
+
...gl.handled ? { surfaceHandled: true } : {}
|
|
544
|
+
// No overInteractive stamp: a capture-retargeted up reads the container,
|
|
545
|
+
// not the content under the pointer — the next real move re-truths it.
|
|
454
546
|
});
|
|
455
547
|
};
|
|
456
548
|
const onPointerUp = endPointer("up");
|
|
@@ -485,7 +577,7 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
485
577
|
}
|
|
486
578
|
emitKeyIfChanged(e);
|
|
487
579
|
};
|
|
488
|
-
const
|
|
580
|
+
const cancelAllInput = () => {
|
|
489
581
|
for (const [id, s] of live) {
|
|
490
582
|
queue.enqueue({ kind: "cancel", pointerId: id, device: s.device, screenX: s.x, screenY: s.y, buttons: 0, mods: { ...NO_MODS, space: spaceHeld } });
|
|
491
583
|
}
|
|
@@ -504,6 +596,9 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
504
596
|
});
|
|
505
597
|
}
|
|
506
598
|
};
|
|
599
|
+
const onBlur = () => {
|
|
600
|
+
cancelAllInput();
|
|
601
|
+
};
|
|
507
602
|
container.addEventListener("pointerdown", onPointerDown);
|
|
508
603
|
container.addEventListener("pointermove", onPointerMove);
|
|
509
604
|
container.addEventListener("pointerup", onPointerUp);
|
|
@@ -513,6 +608,7 @@ function attachPointerAdapter(host, queue, opts = {}) {
|
|
|
513
608
|
view?.addEventListener("keyup", onKeyUp);
|
|
514
609
|
view?.addEventListener("blur", onBlur);
|
|
515
610
|
return () => {
|
|
611
|
+
cancelAllInput();
|
|
516
612
|
container.removeEventListener("pointerdown", onPointerDown);
|
|
517
613
|
container.removeEventListener("pointermove", onPointerMove);
|
|
518
614
|
container.removeEventListener("pointerup", onPointerUp);
|
|
@@ -647,519 +743,6 @@ function createRemoteCursorsReflector(host, world) {
|
|
|
647
743
|
};
|
|
648
744
|
}
|
|
649
745
|
|
|
650
|
-
// ../dom/src/reflectors/grid.ts
|
|
651
|
-
var DEFAULT_GRID_CONFIG = {
|
|
652
|
-
spacings: [20, 100, 500],
|
|
653
|
-
dotColor: [0.75, 0.77, 0.8],
|
|
654
|
-
dotAlpha: 1,
|
|
655
|
-
fadeIn: [8, 16],
|
|
656
|
-
fadeOut: [120, 200],
|
|
657
|
-
dotRadius: [0.75, 0.75],
|
|
658
|
-
levelWeight: [1, 0]
|
|
659
|
-
};
|
|
660
|
-
var VERTEX_SHADER = (
|
|
661
|
-
/* glsl */
|
|
662
|
-
`
|
|
663
|
-
attribute vec2 position;
|
|
664
|
-
void main() {
|
|
665
|
-
gl_Position = vec4(position, 0.0, 1.0);
|
|
666
|
-
}
|
|
667
|
-
`
|
|
668
|
-
);
|
|
669
|
-
var FRAGMENT_SHADER = (
|
|
670
|
-
/* glsl */
|
|
671
|
-
`
|
|
672
|
-
precision highp float;
|
|
673
|
-
|
|
674
|
-
uniform vec2 u_resolution; // device pixels
|
|
675
|
-
uniform vec2 u_camera; // world-space top-left
|
|
676
|
-
uniform float u_zoom; // CSS zoom
|
|
677
|
-
uniform float u_dpr; // device pixel ratio
|
|
678
|
-
uniform vec3 u_spacings; // world-unit grid spacings
|
|
679
|
-
uniform vec3 u_dotColor; // dot RGB
|
|
680
|
-
uniform float u_dotAlpha; // dot base alpha
|
|
681
|
-
uniform vec2 u_fadeIn; // CSS-px [start, end]
|
|
682
|
-
uniform vec2 u_fadeOut; // CSS-px [start, end]
|
|
683
|
-
uniform vec2 u_dotRadius; // CSS-px [min, max]
|
|
684
|
-
uniform vec2 u_levelWeight; // [base, step]
|
|
685
|
-
|
|
686
|
-
void main() {
|
|
687
|
-
vec2 devicePos = gl_FragCoord.xy;
|
|
688
|
-
devicePos.y = u_resolution.y - devicePos.y;
|
|
689
|
-
|
|
690
|
-
float effectiveZoom = u_zoom * u_dpr;
|
|
691
|
-
vec2 worldPos = devicePos / effectiveZoom + u_camera;
|
|
692
|
-
|
|
693
|
-
float totalAlpha = 0.0;
|
|
694
|
-
|
|
695
|
-
for (int i = 0; i < 3; i++) {
|
|
696
|
-
float spacing;
|
|
697
|
-
if (i == 0) spacing = u_spacings.x;
|
|
698
|
-
else if (i == 1) spacing = u_spacings.y;
|
|
699
|
-
else spacing = u_spacings.z;
|
|
700
|
-
|
|
701
|
-
// Screen spacing in CSS pixels (DPR-independent for consistent fading)
|
|
702
|
-
float cssSpacing = spacing * u_zoom;
|
|
703
|
-
|
|
704
|
-
// Fade curve
|
|
705
|
-
float opacity = 0.0;
|
|
706
|
-
if (cssSpacing >= u_fadeIn.x && cssSpacing < u_fadeIn.y) {
|
|
707
|
-
opacity = (cssSpacing - u_fadeIn.x) / (u_fadeIn.y - u_fadeIn.x);
|
|
708
|
-
} else if (cssSpacing >= u_fadeIn.y && cssSpacing < u_fadeOut.x) {
|
|
709
|
-
opacity = 1.0;
|
|
710
|
-
} else if (cssSpacing >= u_fadeOut.x && cssSpacing < u_fadeOut.y) {
|
|
711
|
-
opacity = 1.0 - (cssSpacing - u_fadeOut.x) / (u_fadeOut.y - u_fadeOut.x);
|
|
712
|
-
}
|
|
713
|
-
if (opacity <= 0.001) continue;
|
|
714
|
-
|
|
715
|
-
// Distance to nearest grid intersection in device pixels
|
|
716
|
-
vec2 f = fract(worldPos / spacing + 0.5) - 0.5;
|
|
717
|
-
float dist = length(f) * spacing * effectiveZoom;
|
|
718
|
-
|
|
719
|
-
// Dot radius in device pixels \u2014 optionally grows for sparser levels
|
|
720
|
-
// (set u_dotRadius.x == u_dotRadius.y for Freeform/FigJam-style
|
|
721
|
-
// constant-size dots)
|
|
722
|
-
float t = clamp((cssSpacing - u_fadeIn.x) / 40.0, 0.0, 1.0);
|
|
723
|
-
float radius = mix(u_dotRadius.x, u_dotRadius.y, t) * u_dpr;
|
|
724
|
-
|
|
725
|
-
// Anti-aliased dot (0.5 device pixel smoothstep)
|
|
726
|
-
float dot = 1.0 - smoothstep(radius - 0.5, radius + 0.5, dist);
|
|
727
|
-
|
|
728
|
-
// Per-level weight: base + i * step. Step=0 keeps all levels at equal
|
|
729
|
-
// intensity; positive step emphasizes coarser levels (CAD feel).
|
|
730
|
-
float weight = u_levelWeight.x + float(i) * u_levelWeight.y;
|
|
731
|
-
|
|
732
|
-
// Composite with max, not sum. Additive compositing causes anti-
|
|
733
|
-
// aliased dot rims to stack at joint intersections (every N-th dot
|
|
734
|
-
// visibly fatter \u2014 a CAD tell). max() guarantees a joint intersection
|
|
735
|
-
// looks identical to a single-level dot, matching Freeform / FigJam.
|
|
736
|
-
totalAlpha = max(totalAlpha, dot * opacity * weight);
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
gl_FragColor = vec4(u_dotColor, clamp(totalAlpha * u_dotAlpha, 0.0, 1.0));
|
|
740
|
-
}
|
|
741
|
-
`
|
|
742
|
-
);
|
|
743
|
-
var FULLSCREEN_TRIANGLE = new Float32Array([-1, -1, 3, -1, -1, 3]);
|
|
744
|
-
var UNIFORM_NAMES = [
|
|
745
|
-
"u_resolution",
|
|
746
|
-
"u_camera",
|
|
747
|
-
"u_zoom",
|
|
748
|
-
"u_dpr",
|
|
749
|
-
"u_spacings",
|
|
750
|
-
"u_dotColor",
|
|
751
|
-
"u_dotAlpha",
|
|
752
|
-
"u_fadeIn",
|
|
753
|
-
"u_fadeOut",
|
|
754
|
-
"u_dotRadius",
|
|
755
|
-
"u_levelWeight"
|
|
756
|
-
];
|
|
757
|
-
function compileShader(gl, type, source) {
|
|
758
|
-
const shader = gl.createShader(type);
|
|
759
|
-
if (shader === null) return null;
|
|
760
|
-
gl.shaderSource(shader, source);
|
|
761
|
-
gl.compileShader(shader);
|
|
762
|
-
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) !== true) {
|
|
763
|
-
gl.deleteShader(shader);
|
|
764
|
-
return null;
|
|
765
|
-
}
|
|
766
|
-
return shader;
|
|
767
|
-
}
|
|
768
|
-
function linkProgram(gl) {
|
|
769
|
-
const vs = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
|
|
770
|
-
const fs = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
|
|
771
|
-
if (vs === null || fs === null) return null;
|
|
772
|
-
const program = gl.createProgram();
|
|
773
|
-
if (program === null) return null;
|
|
774
|
-
gl.attachShader(program, vs);
|
|
775
|
-
gl.attachShader(program, fs);
|
|
776
|
-
gl.linkProgram(program);
|
|
777
|
-
const linked = gl.getProgramParameter(program, gl.LINK_STATUS) === true;
|
|
778
|
-
gl.deleteShader(vs);
|
|
779
|
-
gl.deleteShader(fs);
|
|
780
|
-
if (!linked) {
|
|
781
|
-
gl.deleteProgram(program);
|
|
782
|
-
return null;
|
|
783
|
-
}
|
|
784
|
-
return program;
|
|
785
|
-
}
|
|
786
|
-
function setupGeometry(gl, program) {
|
|
787
|
-
const buffer = gl.createBuffer();
|
|
788
|
-
if (buffer === null) return false;
|
|
789
|
-
const loc = gl.getAttribLocation(program, "position");
|
|
790
|
-
if (loc < 0) return false;
|
|
791
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
792
|
-
gl.bufferData(gl.ARRAY_BUFFER, FULLSCREEN_TRIANGLE, gl.STATIC_DRAW);
|
|
793
|
-
gl.enableVertexAttribArray(loc);
|
|
794
|
-
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
|
|
795
|
-
return true;
|
|
796
|
-
}
|
|
797
|
-
function collectUniforms(gl, program) {
|
|
798
|
-
const out = {};
|
|
799
|
-
for (const name of UNIFORM_NAMES) out[name] = gl.getUniformLocation(program, name);
|
|
800
|
-
return out;
|
|
801
|
-
}
|
|
802
|
-
function createGridReflector(host, opts = {}) {
|
|
803
|
-
const config = { ...DEFAULT_GRID_CONFIG, ...opts };
|
|
804
|
-
const doc = host.container.ownerDocument;
|
|
805
|
-
const canvas = doc.createElement("canvas");
|
|
806
|
-
canvas.style.position = "absolute";
|
|
807
|
-
canvas.style.left = "0";
|
|
808
|
-
canvas.style.top = "0";
|
|
809
|
-
canvas.style.width = "100%";
|
|
810
|
-
canvas.style.height = "100%";
|
|
811
|
-
canvas.style.display = "block";
|
|
812
|
-
canvas.style.pointerEvents = "none";
|
|
813
|
-
host.container.insertBefore(canvas, host.container.firstChild);
|
|
814
|
-
let gl = null;
|
|
815
|
-
let program = null;
|
|
816
|
-
let uniforms = null;
|
|
817
|
-
let dpr = 1;
|
|
818
|
-
let lastCamera = { x: 0, y: 0, zoom: 1 };
|
|
819
|
-
try {
|
|
820
|
-
const attrs = { alpha: true, antialias: false, premultipliedAlpha: false };
|
|
821
|
-
gl = canvas.getContext("webgl2", attrs) ?? canvas.getContext("webgl", attrs);
|
|
822
|
-
if (gl !== null) {
|
|
823
|
-
const prog = linkProgram(gl);
|
|
824
|
-
if (prog !== null && setupGeometry(gl, prog)) {
|
|
825
|
-
program = prog;
|
|
826
|
-
uniforms = collectUniforms(gl, prog);
|
|
827
|
-
} else {
|
|
828
|
-
gl = null;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
} catch {
|
|
832
|
-
gl = null;
|
|
833
|
-
program = null;
|
|
834
|
-
uniforms = null;
|
|
835
|
-
}
|
|
836
|
-
function draw(camera) {
|
|
837
|
-
if (gl === null || program === null || uniforms === null) return;
|
|
838
|
-
lastCamera = camera;
|
|
839
|
-
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
840
|
-
gl.useProgram(program);
|
|
841
|
-
gl.uniform2f(uniforms.u_resolution, canvas.width, canvas.height);
|
|
842
|
-
gl.uniform2f(uniforms.u_camera, camera.x, camera.y);
|
|
843
|
-
gl.uniform1f(uniforms.u_zoom, camera.zoom);
|
|
844
|
-
gl.uniform1f(uniforms.u_dpr, dpr);
|
|
845
|
-
gl.uniform3f(uniforms.u_spacings, ...config.spacings);
|
|
846
|
-
gl.uniform3f(uniforms.u_dotColor, ...config.dotColor);
|
|
847
|
-
gl.uniform1f(uniforms.u_dotAlpha, config.dotAlpha);
|
|
848
|
-
gl.uniform2f(uniforms.u_fadeIn, ...config.fadeIn);
|
|
849
|
-
gl.uniform2f(uniforms.u_fadeOut, ...config.fadeOut);
|
|
850
|
-
gl.uniform2f(uniforms.u_dotRadius, ...config.dotRadius);
|
|
851
|
-
gl.uniform2f(uniforms.u_levelWeight, ...config.levelWeight);
|
|
852
|
-
gl.clearColor(0, 0, 0, 0);
|
|
853
|
-
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
854
|
-
gl.enable(gl.BLEND);
|
|
855
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
856
|
-
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
857
|
-
}
|
|
858
|
-
function applySize(cssWidth, cssHeight) {
|
|
859
|
-
dpr = doc.defaultView?.devicePixelRatio ?? 1;
|
|
860
|
-
const bufW = Math.max(1, Math.round(cssWidth * dpr));
|
|
861
|
-
const bufH = Math.max(1, Math.round(cssHeight * dpr));
|
|
862
|
-
if (canvas.width !== bufW) canvas.width = bufW;
|
|
863
|
-
if (canvas.height !== bufH) canvas.height = bufH;
|
|
864
|
-
try {
|
|
865
|
-
draw(lastCamera);
|
|
866
|
-
} catch {
|
|
867
|
-
gl = null;
|
|
868
|
-
program = null;
|
|
869
|
-
uniforms = null;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
const initialRect = host.container.getBoundingClientRect();
|
|
873
|
-
applySize(initialRect.width, initialRect.height);
|
|
874
|
-
let ro;
|
|
875
|
-
try {
|
|
876
|
-
ro = new ResizeObserver((entries) => {
|
|
877
|
-
const entry = entries[0];
|
|
878
|
-
if (entry === void 0) return;
|
|
879
|
-
applySize(entry.contentRect.width, entry.contentRect.height);
|
|
880
|
-
});
|
|
881
|
-
ro.observe(host.container);
|
|
882
|
-
} catch {
|
|
883
|
-
}
|
|
884
|
-
return {
|
|
885
|
-
name: "grid",
|
|
886
|
-
observe: { resources: [Camera] },
|
|
887
|
-
flush(world) {
|
|
888
|
-
if (gl === null) return;
|
|
889
|
-
const camera = world.getResource(Camera);
|
|
890
|
-
if (camera === void 0) return;
|
|
891
|
-
try {
|
|
892
|
-
draw(camera);
|
|
893
|
-
} catch {
|
|
894
|
-
gl = null;
|
|
895
|
-
program = null;
|
|
896
|
-
uniforms = null;
|
|
897
|
-
}
|
|
898
|
-
},
|
|
899
|
-
available: () => gl !== null,
|
|
900
|
-
// Live re-tune (theme switches, settings panels): draw() uploads every
|
|
901
|
-
// config uniform per call, so a merge + one redraw at the last camera is
|
|
902
|
-
// the whole story. Outside the frame contract by design — config is host
|
|
903
|
-
// input, not world state (same class as the RO resize path).
|
|
904
|
-
configure(next) {
|
|
905
|
-
Object.assign(config, next);
|
|
906
|
-
if (gl !== null) {
|
|
907
|
-
try {
|
|
908
|
-
draw(lastCamera);
|
|
909
|
-
} catch {
|
|
910
|
-
gl = null;
|
|
911
|
-
program = null;
|
|
912
|
-
uniforms = null;
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
},
|
|
916
|
-
// Unregistering a reflector only stops its flushes — the canvas this
|
|
917
|
-
// factory inserted (and its ResizeObserver) must be torn down explicitly,
|
|
918
|
-
// or a React StrictMode remount stacks a second frozen grid under the
|
|
919
|
-
// live one (field report 2026-07-11).
|
|
920
|
-
dispose() {
|
|
921
|
-
ro?.disconnect();
|
|
922
|
-
gl = null;
|
|
923
|
-
program = null;
|
|
924
|
-
uniforms = null;
|
|
925
|
-
canvas.remove();
|
|
926
|
-
}
|
|
927
|
-
};
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
// ../dom/src/reflectors/wires.ts
|
|
931
|
-
var INACTIVE_PREVIEW = { sx: 0, sy: 0, tx: 0, ty: 0, active: false, compatible: false };
|
|
932
|
-
var DEFAULT_WIRES_CONFIG = {
|
|
933
|
-
wireColor: "rgba(120, 132, 145, 0.9)",
|
|
934
|
-
selectedColor: "#4a90d9",
|
|
935
|
-
wireWidth: 1.5,
|
|
936
|
-
selectedWidth: 2,
|
|
937
|
-
portRadius: 4,
|
|
938
|
-
portColor: "rgba(120, 132, 145, 0.9)",
|
|
939
|
-
portActiveColor: "#4a90d9"
|
|
940
|
-
};
|
|
941
|
-
var wireQ = defineQuery([Wire]);
|
|
942
|
-
var geometryQ = defineQuery([Position, Size]);
|
|
943
|
-
var selectedQ = defineQuery([Selected]);
|
|
944
|
-
var portQ = defineQuery([Port, PortAnchor]);
|
|
945
|
-
var routedConnectQ = defineQuery([RoutedConnect]);
|
|
946
|
-
function readRect(world, e) {
|
|
947
|
-
const p = world.get(e, Position);
|
|
948
|
-
if (p === void 0) return void 0;
|
|
949
|
-
const measured = world.get(e, MeasuredSize);
|
|
950
|
-
const s = measured !== void 0 && measured.w > 0 ? measured : world.get(e, Size);
|
|
951
|
-
if (s === void 0) return void 0;
|
|
952
|
-
return { x: p.x, y: p.y, width: s.w, height: s.h };
|
|
953
|
-
}
|
|
954
|
-
function makePortSlotResolver() {
|
|
955
|
-
const cache = /* @__PURE__ */ new Map();
|
|
956
|
-
const build = (wt) => {
|
|
957
|
-
const bySide = /* @__PURE__ */ new Map();
|
|
958
|
-
for (const d of wt.ports) {
|
|
959
|
-
let list = bySide.get(d.side);
|
|
960
|
-
if (list === void 0) {
|
|
961
|
-
list = [];
|
|
962
|
-
bySide.set(d.side, list);
|
|
963
|
-
}
|
|
964
|
-
list.push(d);
|
|
965
|
-
}
|
|
966
|
-
const out = /* @__PURE__ */ new Map();
|
|
967
|
-
for (const [side, list] of bySide) {
|
|
968
|
-
for (let i = 0; i < list.length; i++) {
|
|
969
|
-
const d = list[i];
|
|
970
|
-
if (d === void 0) continue;
|
|
971
|
-
out.set(d.id, { side, index: d.index ?? i, count: list.length });
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
return out;
|
|
975
|
-
};
|
|
976
|
-
return (wt, portId) => {
|
|
977
|
-
let slots = cache.get(wt.type);
|
|
978
|
-
if (slots === void 0) {
|
|
979
|
-
slots = build(wt);
|
|
980
|
-
cache.set(wt.type, slots);
|
|
981
|
-
}
|
|
982
|
-
return slots.get(portId);
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
function cubicToScreen(c, cam) {
|
|
986
|
-
const p0 = worldToScreen(c.x0, c.y0, cam);
|
|
987
|
-
const p1 = worldToScreen(c.x1, c.y1, cam);
|
|
988
|
-
const p2 = worldToScreen(c.x2, c.y2, cam);
|
|
989
|
-
const p3 = worldToScreen(c.x3, c.y3, cam);
|
|
990
|
-
return { x0: p0.x, y0: p0.y, x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y, x3: p3.x, y3: p3.y };
|
|
991
|
-
}
|
|
992
|
-
function createWiresReflector(host, world, opts = {}) {
|
|
993
|
-
const config = { ...DEFAULT_WIRES_CONFIG, ...opts.config };
|
|
994
|
-
const readPreview = opts.readPreview ?? (() => INACTIVE_PREVIEW);
|
|
995
|
-
const doc = host.container.ownerDocument;
|
|
996
|
-
const canvas = doc.createElement("canvas");
|
|
997
|
-
canvas.style.position = "absolute";
|
|
998
|
-
canvas.style.left = "0";
|
|
999
|
-
canvas.style.top = "0";
|
|
1000
|
-
canvas.style.width = "100%";
|
|
1001
|
-
canvas.style.height = "100%";
|
|
1002
|
-
canvas.style.display = "block";
|
|
1003
|
-
canvas.style.pointerEvents = "none";
|
|
1004
|
-
host.container.insertBefore(canvas, host.contentPlane);
|
|
1005
|
-
let ctx = null;
|
|
1006
|
-
try {
|
|
1007
|
-
ctx = canvas.getContext("2d");
|
|
1008
|
-
} catch {
|
|
1009
|
-
ctx = null;
|
|
1010
|
-
}
|
|
1011
|
-
let dpr = 1;
|
|
1012
|
-
const slotOf = makePortSlotResolver();
|
|
1013
|
-
let dirty = true;
|
|
1014
|
-
let lastPreviewKey = "";
|
|
1015
|
-
let redraws = 0;
|
|
1016
|
-
const wake = () => {
|
|
1017
|
-
dirty = true;
|
|
1018
|
-
};
|
|
1019
|
-
const unsubs = [
|
|
1020
|
-
world.reactive.observeResource(Camera, wake),
|
|
1021
|
-
world.reactive.observeQuery(wireQ, wake, { cols: [] }),
|
|
1022
|
-
world.reactive.observeQuery(geometryQ, wake, { cols: [Position, Size] }),
|
|
1023
|
-
world.reactive.observeQuery(selectedQ, wake, { cols: [] }),
|
|
1024
|
-
world.reactive.observeQuery(portQ, wake, { cols: [PortAnchor] }),
|
|
1025
|
-
world.reactive.observeQuery(routedConnectQ, wake, { cols: [] })
|
|
1026
|
-
];
|
|
1027
|
-
function applySize(cssWidth, cssHeight) {
|
|
1028
|
-
dpr = doc.defaultView?.devicePixelRatio ?? 1;
|
|
1029
|
-
const bufW = Math.max(1, Math.round(cssWidth * dpr));
|
|
1030
|
-
const bufH = Math.max(1, Math.round(cssHeight * dpr));
|
|
1031
|
-
if (canvas.width !== bufW) canvas.width = bufW;
|
|
1032
|
-
if (canvas.height !== bufH) canvas.height = bufH;
|
|
1033
|
-
dirty = true;
|
|
1034
|
-
}
|
|
1035
|
-
const initialRect = host.container.getBoundingClientRect();
|
|
1036
|
-
applySize(initialRect.width, initialRect.height);
|
|
1037
|
-
let ro = null;
|
|
1038
|
-
try {
|
|
1039
|
-
ro = new ResizeObserver((entries) => {
|
|
1040
|
-
const entry = entries[0];
|
|
1041
|
-
if (entry === void 0) return;
|
|
1042
|
-
applySize(entry.contentRect.width, entry.contentRect.height);
|
|
1043
|
-
});
|
|
1044
|
-
ro.observe(host.container);
|
|
1045
|
-
} catch {
|
|
1046
|
-
ro = null;
|
|
1047
|
-
}
|
|
1048
|
-
function strokeCubic(c2d, s) {
|
|
1049
|
-
c2d.beginPath();
|
|
1050
|
-
c2d.moveTo(s.x0, s.y0);
|
|
1051
|
-
c2d.bezierCurveTo(s.x1, s.y1, s.x2, s.y2, s.x3, s.y3);
|
|
1052
|
-
c2d.stroke();
|
|
1053
|
-
}
|
|
1054
|
-
function endpointAnchor(widget, portId) {
|
|
1055
|
-
if (widget === void 0) return void 0;
|
|
1056
|
-
const rect = readRect(world, widget);
|
|
1057
|
-
if (rect === void 0) return void 0;
|
|
1058
|
-
const type = world.get(widget, PrefabId)?.id;
|
|
1059
|
-
if (typeof type !== "string") return void 0;
|
|
1060
|
-
const wt = widgets.get(type);
|
|
1061
|
-
if (wt === void 0) return void 0;
|
|
1062
|
-
const slot = slotOf(wt, portId);
|
|
1063
|
-
if (slot === void 0) return void 0;
|
|
1064
|
-
return { anchor: rect, slot };
|
|
1065
|
-
}
|
|
1066
|
-
function drawWires(c2d, cam) {
|
|
1067
|
-
world.query(wireQ).each((batch) => {
|
|
1068
|
-
for (const r of batch) {
|
|
1069
|
-
const wire = batch.entity(r);
|
|
1070
|
-
const ports = world.get(wire, WirePorts);
|
|
1071
|
-
if (ports === void 0) continue;
|
|
1072
|
-
const from = endpointAnchor(world.getRelation(wire, WireFrom), ports.from ?? "");
|
|
1073
|
-
const to = endpointAnchor(world.getRelation(wire, WireTo), ports.to ?? "");
|
|
1074
|
-
if (from === void 0 || to === void 0) continue;
|
|
1075
|
-
const a0 = portAnchor(from.anchor, from.slot);
|
|
1076
|
-
const a1 = portAnchor(to.anchor, to.slot);
|
|
1077
|
-
const cubic = wireCubic(a0, from.slot.side, a1, to.slot.side);
|
|
1078
|
-
const selected = world.hasTag(wire, Selected);
|
|
1079
|
-
c2d.strokeStyle = selected ? config.selectedColor : config.wireColor;
|
|
1080
|
-
c2d.lineWidth = selected ? config.selectedWidth : config.wireWidth;
|
|
1081
|
-
c2d.setLineDash([]);
|
|
1082
|
-
strokeCubic(c2d, cubicToScreen(cubic, cam));
|
|
1083
|
-
}
|
|
1084
|
-
});
|
|
1085
|
-
}
|
|
1086
|
-
function drawPreview(c2d, cam, preview) {
|
|
1087
|
-
if (!preview.active) return;
|
|
1088
|
-
const stub = Math.max(24, Math.abs(preview.tx - preview.sx) * 0.5);
|
|
1089
|
-
const cubic = {
|
|
1090
|
-
x0: preview.sx,
|
|
1091
|
-
y0: preview.sy,
|
|
1092
|
-
x1: preview.sx + stub,
|
|
1093
|
-
y1: preview.sy,
|
|
1094
|
-
x2: preview.tx - stub,
|
|
1095
|
-
y2: preview.ty,
|
|
1096
|
-
x3: preview.tx,
|
|
1097
|
-
y3: preview.ty
|
|
1098
|
-
};
|
|
1099
|
-
c2d.strokeStyle = preview.compatible ? config.selectedColor : config.wireColor;
|
|
1100
|
-
c2d.lineWidth = config.wireWidth;
|
|
1101
|
-
c2d.setLineDash(preview.compatible ? [] : [6, 4]);
|
|
1102
|
-
strokeCubic(c2d, cubicToScreen(cubic, cam));
|
|
1103
|
-
c2d.setLineDash([]);
|
|
1104
|
-
}
|
|
1105
|
-
function drawPorts(c2d, cam) {
|
|
1106
|
-
const connecting = world.firstOf(routedConnectQ) !== void 0;
|
|
1107
|
-
c2d.fillStyle = connecting ? config.portActiveColor : config.portColor;
|
|
1108
|
-
world.query(portQ).each((batch) => {
|
|
1109
|
-
const ax = batch.col(PortAnchor).x;
|
|
1110
|
-
const ay = batch.col(PortAnchor).y;
|
|
1111
|
-
for (const r of batch) {
|
|
1112
|
-
const s = worldToScreen(ax[r], ay[r], cam);
|
|
1113
|
-
c2d.beginPath();
|
|
1114
|
-
c2d.arc(s.x, s.y, config.portRadius, 0, Math.PI * 2);
|
|
1115
|
-
c2d.fill();
|
|
1116
|
-
}
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
1119
|
-
function redraw(c2d, cam, preview) {
|
|
1120
|
-
c2d.setTransform(1, 0, 0, 1, 0, 0);
|
|
1121
|
-
c2d.clearRect(0, 0, canvas.width, canvas.height);
|
|
1122
|
-
c2d.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
1123
|
-
redraws++;
|
|
1124
|
-
drawWires(c2d, cam);
|
|
1125
|
-
drawPreview(c2d, cam, preview);
|
|
1126
|
-
drawPorts(c2d, cam);
|
|
1127
|
-
}
|
|
1128
|
-
return {
|
|
1129
|
-
name: "wires",
|
|
1130
|
-
// The preview buffer has no ECS stamp; self-gate on a private dirty flag
|
|
1131
|
-
// (chrome/dom-widgets pattern) rather than the registry's observe dirt.
|
|
1132
|
-
always: true,
|
|
1133
|
-
flush(w) {
|
|
1134
|
-
if (ctx === null) return;
|
|
1135
|
-
const cam = w.getResource(Camera);
|
|
1136
|
-
if (cam === void 0) return;
|
|
1137
|
-
const preview = readPreview();
|
|
1138
|
-
const previewKey = preview.active ? `${preview.sx},${preview.sy},${preview.tx},${preview.ty},${preview.compatible ? 1 : 0}` : "";
|
|
1139
|
-
if (previewKey !== lastPreviewKey) {
|
|
1140
|
-
lastPreviewKey = previewKey;
|
|
1141
|
-
dirty = true;
|
|
1142
|
-
}
|
|
1143
|
-
if (!dirty) return;
|
|
1144
|
-
dirty = false;
|
|
1145
|
-
try {
|
|
1146
|
-
redraw(ctx, cam, preview);
|
|
1147
|
-
} catch {
|
|
1148
|
-
ctx = null;
|
|
1149
|
-
}
|
|
1150
|
-
},
|
|
1151
|
-
available: () => ctx !== null,
|
|
1152
|
-
redraws: () => redraws,
|
|
1153
|
-
dispose() {
|
|
1154
|
-
for (const u of unsubs) u();
|
|
1155
|
-
unsubs.length = 0;
|
|
1156
|
-
ro?.disconnect();
|
|
1157
|
-
ro = null;
|
|
1158
|
-
canvas.remove();
|
|
1159
|
-
}
|
|
1160
|
-
};
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
746
|
// ../dom/src/reflectors/chrome.ts
|
|
1164
747
|
var HANDLE_DRAW_PX = 8;
|
|
1165
748
|
var boxQ = defineQuery([SelectionBox]);
|
|
@@ -1219,7 +802,7 @@ function createChromeReflector(host, _world, marqueeBuffer) {
|
|
|
1219
802
|
const tl = worldToScreen(bx[r], by[r], cam);
|
|
1220
803
|
const sw = bw[r] * cam.zoom;
|
|
1221
804
|
const sh = bh[r] * cam.zoom;
|
|
1222
|
-
const key = `${tl.x}:${tl.y}:${sw}:${sh}`;
|
|
805
|
+
const key = `${tl.x}:${tl.y}:${sw}:${sh}:${cam.zoom}`;
|
|
1223
806
|
let node = boxNodes.get(e);
|
|
1224
807
|
if (node === void 0) {
|
|
1225
808
|
node = makeNode(doc, { border: "1px solid #4a90d9" });
|
|
@@ -1229,6 +812,7 @@ function createChromeReflector(host, _world, marqueeBuffer) {
|
|
|
1229
812
|
}
|
|
1230
813
|
if (boxCache.get(e) !== key) {
|
|
1231
814
|
writeRect(node, tl.x, tl.y, sw, sh);
|
|
815
|
+
node.style.borderRadius = `calc(var(--ic-selection-radius, 0px) * ${cam.zoom})`;
|
|
1232
816
|
boxCache.set(e, key);
|
|
1233
817
|
}
|
|
1234
818
|
}
|
|
@@ -1361,8 +945,7 @@ function attachMeasureAdapter(hostFor, queue) {
|
|
|
1361
945
|
|
|
1362
946
|
// ../dom/src/measure-wiring.ts
|
|
1363
947
|
function defaultMeasure(el) {
|
|
1364
|
-
|
|
1365
|
-
return { w: rect.width, h: rect.height };
|
|
948
|
+
return { w: el.offsetWidth, h: el.offsetHeight };
|
|
1366
949
|
}
|
|
1367
950
|
function wireMeasurement(store, hosts, queue, opts = {}) {
|
|
1368
951
|
const adapter = attachMeasureAdapter((e) => hosts.hostFor(e), queue);
|
|
@@ -1434,13 +1017,9 @@ export {
|
|
|
1434
1017
|
attachPointerAdapter,
|
|
1435
1018
|
createCursorReflector,
|
|
1436
1019
|
createRemoteCursorsReflector,
|
|
1437
|
-
DEFAULT_GRID_CONFIG,
|
|
1438
|
-
createGridReflector,
|
|
1439
|
-
DEFAULT_WIRES_CONFIG,
|
|
1440
|
-
createWiresReflector,
|
|
1441
1020
|
createChromeReflector,
|
|
1442
1021
|
attachMeasureAdapter,
|
|
1443
1022
|
wireMeasurement,
|
|
1444
1023
|
DOM_VERSION
|
|
1445
1024
|
};
|
|
1446
|
-
//# sourceMappingURL=chunk-
|
|
1025
|
+
//# sourceMappingURL=chunk-IASTQMU5.js.map
|