@vibecook/ice 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +10 -5
  2. package/dist/{chunk-ZTY2VRIS.js → chunk-6W2FPXR7.js} +13 -7
  3. package/dist/chunk-6W2FPXR7.js.map +1 -0
  4. package/dist/{chunk-Y7K6CHSF.js → chunk-LAZIY3J7.js} +286 -189
  5. package/dist/chunk-LAZIY3J7.js.map +1 -0
  6. package/dist/{chunk-REJTEK3V.js → chunk-M2HUDENL.js} +288 -318
  7. package/dist/chunk-M2HUDENL.js.map +1 -0
  8. package/dist/{chunk-BH5AFWJX.js → chunk-VZEZ7CYW.js} +9 -13
  9. package/dist/chunk-VZEZ7CYW.js.map +1 -0
  10. package/dist/desk-kit.js +2 -2
  11. package/dist/desk-objects.js +45 -14
  12. package/dist/desk-objects.js.map +1 -1
  13. package/dist/desk.js +3 -3
  14. package/dist/devtools.js +1 -1
  15. package/dist/dom.js +2 -2
  16. package/dist/index.js +7 -1
  17. package/dist/react.js +2 -2
  18. package/dist/types/packages/core/src/canvas/engine-catalog.d.ts +6 -0
  19. package/dist/types/packages/core/src/catalog/desk.d.ts +6 -6
  20. package/dist/types/packages/core/src/catalog/gesture.d.ts +2 -0
  21. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +2 -0
  22. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +8 -4
  23. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +11 -5
  24. package/dist/types/packages/core/src/index.d.ts +1 -1
  25. package/dist/types/packages/core/src/ops/selection-drag.d.ts +8 -0
  26. package/dist/types/packages/core/src/settings/defaults.d.ts +2 -0
  27. package/dist/types/packages/core/src/systems/camera-sim.d.ts +13 -0
  28. package/dist/types/packages/core/src/systems/tray.d.ts +5 -4
  29. package/dist/types/packages/core/src/tools/define-tool.d.ts +2 -2
  30. package/dist/types/packages/core/src/widget/define-widget.d.ts +2 -1
  31. package/dist/types/packages/desk/src/ground.d.ts +4 -3
  32. package/dist/types/packages/desk/src/host/layer.d.ts +1 -3
  33. package/dist/types/packages/desk/src/mat/layout.d.ts +45 -5
  34. package/dist/types/packages/desk/src/mat/mat-pass.d.ts +7 -0
  35. package/dist/types/packages/desk/src/mat/ruler-regions.d.ts +17 -0
  36. package/dist/types/packages/desk/src/shaders.gen.d.ts +4 -4
  37. package/dist/types/packages/desk/src/theme.d.ts +0 -15
  38. package/dist/types/packages/desk/src/tray/drawer.d.ts +10 -8
  39. package/dist/types/packages/desk/src/tray/flux.d.ts +2 -3
  40. package/dist/types/packages/desk/src/tray/layout.d.ts +1 -6
  41. package/dist/types/packages/desk/src/tray/look.d.ts +0 -9
  42. package/dist/types/packages/desk/src/tray/pass.d.ts +7 -18
  43. package/dist/types/packages/desk/src/tray/specimens.d.ts +2 -19
  44. package/dist/types/packages/dom/src/pointer-adapter.d.ts +1 -1
  45. package/dist/types/packages/objects/src/minimat/layout.d.ts +1 -1
  46. package/dist/types/packages/objects/src/photo/photo.d.ts +2 -2
  47. package/dist/types/packages/objects/src/preset.d.ts +5 -3
  48. package/package.json +15 -16
  49. package/dist/chunk-BH5AFWJX.js.map +0 -1
  50. package/dist/chunk-REJTEK3V.js.map +0 -1
  51. package/dist/chunk-Y7K6CHSF.js.map +0 -1
  52. package/dist/chunk-ZTY2VRIS.js.map +0 -1
@@ -268,14 +268,15 @@ var GESTURE_DEFAULTS = {
268
268
  // so both devices share one feel.
269
269
  wheelZoomSensitivity: 0.01,
270
270
  wheelZoomMaxStep: 10,
271
- // What a PLAIN wheel does (design-015 §9, D-D11 — D2a-core, 2026-09-25).
272
- // "pan" is today's camera, byte for byte: a plain wheel scrolls it and a
273
- // pinch zooms by the curve above. "zoom" is the desk's law — the prototype's
274
- // `zoom · exp(−Δy · wheelZoomRate)` about the pointer, for a plain wheel and
275
- // a pinch alike, Δx ignored (vibe-field/draft/ground/lab/main.ts's wheel).
271
+ // Ordinary wheel / two-finger scrolling pans. Apps can opt into
272
+ // exponential plain-wheel zoom without changing the pinch response.
276
273
  wheel: "pan",
277
- // The desk's zoom rate, per wheel-delta unit (the prototype's 0.0016). Read
278
- // in "zoom" mode only; the pan mode keeps the curve above.
274
+ // Pinch / modifier-wheel response is independent of a plain wheel's job.
275
+ // The desk opts into continuous exponential zoom; the bounded legacy curve
276
+ // remains available to consumers that use notch-sized zoom steps.
277
+ wheelZoomCurve: "clamped",
278
+ // Continuous zoom rate per normalized wheel-delta unit. Used by plain-wheel
279
+ // zoom and by the exponential pinch curve, independently of the wheel mode.
279
280
  wheelZoomRate: 16e-4
280
281
  };
281
282
  var POINTER_DEFAULTS = {
@@ -1391,11 +1392,11 @@ var Tray = defineComponent("Tray", {
1391
1392
  stretch: field3("f64", { default: 0 }),
1392
1393
  wheelAt: field3("f64", { default: 0 }),
1393
1394
  /**
1394
- * K9 (S11, D-K9-c.3): the last wheel `dy` the drawer scrolled by, and how many deltas in a row have SHRUNK while pushing the band
1395
- * further — a fading tail (the OS's momentum decays; a push does not, steadily). At `TRAY_INPUT.fadeDeltas` the band lets go and
1396
- * the rest of that tail is spent — swallowed, scroll and band untouched — until a reversal, a growing delta or quiet.
1395
+ * @deprecated Legacy wheel-tail bookkeeping, retained for component compatibility. Wheel scrolling now stays within its
1396
+ * bounds and consumes the OS's momentum directly; trayInput no longer reads or writes these fields.
1397
1397
  */
1398
1398
  wheelDy: field3("f64", { default: 0 }),
1399
+ /** @deprecated See wheelDy. */
1399
1400
  fade: field3("u32", { default: 0 }),
1400
1401
  /** K5a: the type of the specimen under the mouse while the drawer is out ("" — none): the hover that lifts it (flux). */
1401
1402
  hover: field3("string", { default: "" }),
@@ -1568,6 +1569,7 @@ var GestureCancelled = GesturePhases.tags.Cancelled;
1568
1569
  var GestureSuspended = defineTag("GestureSuspended");
1569
1570
  var HadCapture = defineTag("HadCapture");
1570
1571
  var Simultaneous = defineTag("Simultaneous");
1572
+ var MovesSelection = defineTag("MovesSelection");
1571
1573
  var RoutedMove = defineTag("RoutedMove");
1572
1574
  var RoutedResize = defineTag("RoutedResize");
1573
1575
  var RoutedConnect = defineTag("RoutedConnect");
@@ -1736,6 +1738,7 @@ import { enumOf as enumOf6, field as field9 } from "@vibecook/strata-ecs";
1736
1738
  var Selected = defineTag("Selected");
1737
1739
  var Selectable = defineTag("Selectable");
1738
1740
  var Movable = defineTag("Movable");
1741
+ var SelectionMovable = defineTag("SelectionMovable");
1739
1742
  var Resizable = defineTag("Resizable");
1740
1743
  var SnapSource = defineTag("SnapSource");
1741
1744
  var SnapTarget = defineTag("SnapTarget");
@@ -1778,9 +1781,11 @@ var GestureSettings = defineResource("GestureSettings", {
1778
1781
  multiTapSlopPx: field10("f32", { default: GESTURE_DEFAULTS.multiTapSlopPx }),
1779
1782
  wheelZoomSensitivity: field10("f32", { default: GESTURE_DEFAULTS.wheelZoomSensitivity }),
1780
1783
  wheelZoomMaxStep: field10("f32", { default: GESTURE_DEFAULTS.wheelZoomMaxStep }),
1781
- /** A plain wheel's job (design-015 §9, D-D11): "pan" (default, today) or the desk's "zoom" about the pointer. */
1784
+ /** Ordinary scrolling pans by default; apps can opt into cursor-anchored wheel zoom. */
1782
1785
  wheel: field10(enumOf7(["pan", "zoom"]), { default: GESTURE_DEFAULTS.wheel }),
1783
- /** "zoom" mode's law: `zoom · exp(−Δ · wheelZoomRate)` for a plain wheel and a pinch. f64: the prototype's 0.0016, exactly. */
1786
+ /** Pinch/modifier zoom response, independent of the plain wheel's job. */
1787
+ wheelZoomCurve: field10(enumOf7(["clamped", "exponential"]), { default: GESTURE_DEFAULTS.wheelZoomCurve }),
1788
+ /** Continuous zoom: `zoom · exp(−Δ · wheelZoomRate)`. f64 keeps the configured rate exact. */
1784
1789
  wheelZoomRate: field10("f64", { default: GESTURE_DEFAULTS.wheelZoomRate })
1785
1790
  });
1786
1791
  var PointerSettings = defineResource("PointerSettings", {
@@ -1827,6 +1832,15 @@ var WheelZoomStep = defineResource(
1827
1832
  },
1828
1833
  { durable: false }
1829
1834
  );
1835
+ var CameraZoomStep = defineResource(
1836
+ "CameraZoomStep",
1837
+ {
1838
+ from: field11("f64", { default: 1 }),
1839
+ to: field11("f64", { default: 1 }),
1840
+ tick: field11("u32", { default: 0 })
1841
+ },
1842
+ { durable: false }
1843
+ );
1830
1844
  var panDragQ = defineQuery([Drag, RoutedPan]);
1831
1845
  var wheelPanQ = defineQuery([WheelPan]);
1832
1846
  var wheelZoomQ = defineQuery([WheelZoom]);
@@ -1923,7 +1937,7 @@ function createCameraSystems(world) {
1923
1937
  const wz = world.read(rec, WheelZoom);
1924
1938
  if (wz.pinch === 0) continue;
1925
1939
  let factor;
1926
- if (wheelZooms) {
1940
+ if ((gmode?.wheelZoomCurve ?? GESTURE_DEFAULTS.wheelZoomCurve) === "exponential") {
1927
1941
  factor = Math.exp(-wz.pinch * zoomRate);
1928
1942
  } else {
1929
1943
  const gset = world.getResource(GestureSettings);
@@ -1973,6 +1987,13 @@ function createCameraSystems(world) {
1973
1987
  if (x !== cam0.x || y !== cam0.y || zoom !== cam0.zoom || anyActive !== cam0.gesturing) {
1974
1988
  world.setResource(Camera, { x, y, zoom, gesturing: anyActive });
1975
1989
  }
1990
+ if (zoom !== cam0.zoom) {
1991
+ world.setResource(CameraZoomStep, {
1992
+ from: cam0.zoom,
1993
+ to: zoom,
1994
+ tick: world.getResource(FrameInfo)?.tick ?? 0
1995
+ });
1996
+ }
1976
1997
  if (wheelRatio !== 1) {
1977
1998
  world.setResource(WheelZoomStep, {
1978
1999
  ratio: wheelRatio,
@@ -3266,7 +3287,8 @@ function defineWidget(def) {
3266
3287
  const interaction = def.interaction ?? {};
3267
3288
  const capabilityTags = [];
3268
3289
  if (interaction.selectable !== false) capabilityTags.push(Selectable);
3269
- if (interaction.movable !== false) capabilityTags.push(Movable);
3290
+ if (interaction.movable === "selection") capabilityTags.push(SelectionMovable);
3291
+ else if (interaction.movable !== false) capabilityTags.push(Movable);
3270
3292
  if (interaction.resizable === true) capabilityTags.push(Resizable);
3271
3293
  if (interaction.solid === true) capabilityTags.push(Solid);
3272
3294
  if (interaction.dragOn === "longPress") capabilityTags.push(LongPressDrag);
@@ -3802,6 +3824,11 @@ function compileEngineCatalog(opts = {}) {
3802
3824
  );
3803
3825
  }
3804
3826
  const widgetList = resolveWidgets(opts.widgets);
3827
+ const retiredList = resolveWidgets(opts.retiredWidgets ?? []);
3828
+ const retiredMap = new Map(retiredList.map((w) => [w.type, w]));
3829
+ for (const widget of widgetList) {
3830
+ if (retiredMap.has(widget.type)) throw new Error(`ice: widget "${widget.type}" cannot be both active and retired.`);
3831
+ }
3805
3832
  const toolList = resolveTools(opts.tools, typed);
3806
3833
  const widgetMap = new Map(widgetList.map((w) => [w.type, w]));
3807
3834
  const toolMap = new Map(toolList.map((t) => [t.id, t]));
@@ -4140,16 +4167,16 @@ function compileEngineCatalog(opts = {}) {
4140
4167
  }
4141
4168
  }
4142
4169
  const dataPrefabs = /* @__PURE__ */ new Map();
4143
- for (const widget of widgetList) {
4170
+ for (const widget of [...widgetList, ...retiredList]) {
4144
4171
  for (const d of widget.data) {
4145
4172
  const had = dataPrefabs.get(d.id);
4146
4173
  if (had !== void 0 && had !== d) throw new Error(`ice: data prefab "${d.id}" is declared twice with different definitions.`);
4147
- if (widgetMap.has(d.id) || d.id === WirePrefab.id) throw new Error(`ice: data prefab "${d.id}" collides with a widget's own prefab.`);
4174
+ if (widgetMap.has(d.id) || retiredMap.has(d.id) || d.id === WirePrefab.id) throw new Error(`ice: data prefab "${d.id}" collides with a widget's own prefab.`);
4148
4175
  dataPrefabs.set(d.id, d);
4149
4176
  }
4150
4177
  }
4151
4178
  const localPacks = { [WirePrefab.id]: WirePrefab.version ?? 1 };
4152
- for (const widget of widgetList) localPacks[widget.prefab.id] = widget.prefab.version ?? 1;
4179
+ for (const widget of [...widgetList, ...retiredList]) localPacks[widget.prefab.id] = widget.prefab.version ?? 1;
4153
4180
  for (const d of dataPrefabs.values()) localPacks[d.id] = d.version ?? 1;
4154
4181
  for (const canvas of normalizedCanvasList) {
4155
4182
  localPacks[canvasPackId(canvas.id)] = canvas.semanticVersion;
@@ -4159,7 +4186,7 @@ function compileEngineCatalog(opts = {}) {
4159
4186
  }
4160
4187
  const initialPacks = { [WirePrefab.id]: WirePrefab.version ?? 1 };
4161
4188
  for (const widget of widgetList) initialPacks[widget.prefab.id] = widget.prefab.version ?? 1;
4162
- for (const d of dataPrefabs.values()) initialPacks[d.id] = d.version ?? 1;
4189
+ for (const widget of widgetList) for (const d of widget.data) initialPacks[d.id] = d.version ?? 1;
4163
4190
  for (const id of requiredCanvasIds) {
4164
4191
  const canvas = canvasMap.get(id);
4165
4192
  initialPacks[canvasPackId(id)] = canvas.semanticVersion;
@@ -4197,6 +4224,7 @@ function compileEngineCatalog(opts = {}) {
4197
4224
  rootCanvas,
4198
4225
  presentationFallback,
4199
4226
  widget: (id) => widgetMap.get(id),
4227
+ retiredWidget: (id) => retiredMap.get(id),
4200
4228
  widgetTypes: () => frozenWidgets,
4201
4229
  tool: (id) => toolMap.get(id),
4202
4230
  toolTypes: () => frozenTools,
@@ -4270,7 +4298,7 @@ function resolveToolFor(world, id) {
4270
4298
  function durablePrefabFor(world, id) {
4271
4299
  const catalog = byWorld.get(world);
4272
4300
  if (catalog !== void 0) {
4273
- return catalog.widget(id)?.prefab ?? catalog.dataPrefab(id) ?? (id === WirePrefab.id ? WirePrefab : void 0);
4301
+ return catalog.widget(id)?.prefab ?? catalog.retiredWidget(id)?.prefab ?? catalog.dataPrefab(id) ?? (id === WirePrefab.id ? WirePrefab : void 0);
4274
4302
  }
4275
4303
  return prefabs.get(id);
4276
4304
  }
@@ -6475,6 +6503,7 @@ function firstContainerAncestor(world, e) {
6475
6503
  return void 0;
6476
6504
  }
6477
6505
  function createActiveMembership(world) {
6506
+ const catalog = engineCatalogFor(world);
6478
6507
  let collector;
6479
6508
  let seeded = false;
6480
6509
  let lastFrame;
@@ -6498,7 +6527,9 @@ function createActiveMembership(world) {
6498
6527
  lastFrame = frame2;
6499
6528
  let deselected = false;
6500
6529
  const classify = (e) => {
6501
- const member = firstContainerAncestor(world, e) === frame2;
6530
+ const type = world.get(e, PrefabId)?.id;
6531
+ const retired = typeof type === "string" && catalog?.retiredWidget(type) !== void 0;
6532
+ const member = !retired && firstContainerAncestor(world, e) === frame2;
6502
6533
  if (member) {
6503
6534
  if (!ctx.hasTag(e, Active)) {
6504
6535
  ctx.addTag(e, Active);
@@ -7143,7 +7174,42 @@ function createCanvasSessionController(world) {
7143
7174
  }
7144
7175
 
7145
7176
  // ../core/src/systems/l2-recognize.ts
7146
- import { Any as Any2, Not as Not4, defineQuery as defineQuery10, defineSystem as defineSystem3 } from "@vibecook/strata-ecs";
7177
+ import { Any as Any2, Not as Not4, defineQuery as defineQuery11, defineSystem as defineSystem3 } from "@vibecook/strata-ecs";
7178
+
7179
+ // ../core/src/ops/selection-drag.ts
7180
+ import { defineQuery as defineQuery10 } from "@vibecook/strata-ecs";
7181
+ var selectionQ = defineQuery10([Selected, Position, Size]);
7182
+ function selectionDragAt(ctx, target, sx, sy, tool, shift) {
7183
+ if (!tool.gates.movable || tool.route.widgetDrag !== "move") return false;
7184
+ const onCanvas = target === void 0 || ctx.hasTag(target, CanvasSurface);
7185
+ if (onCanvas) {
7186
+ if (shift || tool.route.canvasDrag !== "marquee") return false;
7187
+ } else if (!ctx.hasTag(target, Selected) || ctx.has(target, HandleSpec) || ctx.has(target, Port) || !ctx.hasTag(target, Movable) && !ctx.hasTag(target, SelectionMovable)) return false;
7188
+ let count = 0;
7189
+ let movable = false;
7190
+ let minX = Number.POSITIVE_INFINITY;
7191
+ let minY = Number.POSITIVE_INFINITY;
7192
+ let maxX = Number.NEGATIVE_INFINITY;
7193
+ let maxY = Number.NEGATIVE_INFINITY;
7194
+ ctx.query(selectionQ).each((b) => {
7195
+ for (const r of b) {
7196
+ const e = b.entity(r);
7197
+ if (ctx.hasTag(e, Culled) && !ctx.hasTag(e, Active)) continue;
7198
+ const p3 = ctx.read(e, Position);
7199
+ const s = ctx.read(e, Size);
7200
+ count++;
7201
+ if (!ctx.hasTag(e, Locked) && (ctx.hasTag(e, Movable) || ctx.hasTag(e, SelectionMovable))) movable = true;
7202
+ minX = Math.min(minX, p3.x);
7203
+ minY = Math.min(minY, p3.y);
7204
+ maxX = Math.max(maxX, p3.x + s.w);
7205
+ maxY = Math.max(maxY, p3.y + s.h);
7206
+ }
7207
+ });
7208
+ if (count < 2 || !movable) return false;
7209
+ if (!onCanvas) return true;
7210
+ const p2 = screenToWorld(sx, sy, ctx.getResource(Camera) ?? { x: 0, y: 0, zoom: 1 });
7211
+ return p2.x >= minX && p2.x <= maxX && p2.y >= minY && p2.y <= maxY;
7212
+ }
7147
7213
 
7148
7214
  // ../core/src/systems/press-button.ts
7149
7215
  function pressButton(buttons) {
@@ -7160,17 +7226,17 @@ var DEFAULT_SPAWN_PROFILES = {
7160
7226
  select: ["tap", "longPress", "drag"],
7161
7227
  pan: ["drag"]
7162
7228
  };
7163
- var anyKindQ = defineQuery10([Any2(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
7164
- var downQ = defineQuery10([Pointer, WentDown, Not4(HandledByWidget), LocalPointer]);
7165
- var heldTouchQ = defineQuery10([Pointer, PointerButtons, LocalPointer]);
7166
- var wheelSourceQ = defineQuery10([Pointer, PointerWheel, LocalPointer, Not4(WheelHandled)]);
7167
- var tapQ = defineQuery10([Tap, Not4(GestureSuspended)]);
7168
- var longPressQ = defineQuery10([LongPress, Not4(GestureSuspended)]);
7169
- var dragQ = defineQuery10([Drag, Not4(GestureSuspended)]);
7170
- var pinchQ2 = defineQuery10([Pinch]);
7171
- var wheelKindQ = defineQuery10([Any2(WheelPan, WheelZoom)]);
7172
- var pendingTapQ = defineQuery10([Tap, GesturePhases.tags.Pending]);
7173
- var pendingQ = defineQuery10([Any2(Tap, LongPress, Drag, Pinch), GesturePhases.tags.Pending]);
7229
+ var anyKindQ = defineQuery11([Any2(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
7230
+ var downQ = defineQuery11([Pointer, WentDown, Not4(HandledByWidget), LocalPointer]);
7231
+ var heldTouchQ = defineQuery11([Pointer, PointerButtons, LocalPointer]);
7232
+ var wheelSourceQ = defineQuery11([Pointer, PointerWheel, LocalPointer, Not4(WheelHandled)]);
7233
+ var tapQ = defineQuery11([Tap, Not4(GestureSuspended)]);
7234
+ var longPressQ = defineQuery11([LongPress, Not4(GestureSuspended)]);
7235
+ var dragQ = defineQuery11([Drag, Not4(GestureSuspended)]);
7236
+ var pinchQ2 = defineQuery11([Pinch]);
7237
+ var wheelKindQ = defineQuery11([Any2(WheelPan, WheelZoom)]);
7238
+ var pendingTapQ = defineQuery11([Tap, GesturePhases.tags.Pending]);
7239
+ var pendingQ = defineQuery11([Any2(Tap, LongPress, Drag, Pinch), GesturePhases.tags.Pending]);
7174
7240
  var P2 = GesturePhases;
7175
7241
  function gs(ctx) {
7176
7242
  return ctx.getResource(GestureSettings) ?? GESTURE_DEFAULTS;
@@ -7221,6 +7287,7 @@ function createL2Systems({ world, profiles = DEFAULT_SPAWN_PROFILES }) {
7221
7287
  const button = pressButton(ctx.get(pointer, PointerButtons)?.buttons ?? 0);
7222
7288
  if (button === "secondary" || button === "middle" && !middlePans(ctx, captureTarget)) continue;
7223
7289
  const downPart = ctx.get(pointer, PointerPart)?.part ?? "";
7290
+ const movesSelection = button === "primary" && downPart === "" && profile.includes("drag") && ctx.read(pointer, Pointer).device !== "touch" && ctx.getResource(Keyboard)?.space !== true && selectionDragAt(ctx, captureTarget, screen.x, screen.y, resolveToolFor(world, tool), ctx.get(pointer, PointerMods)?.shift === true);
7224
7291
  const downMs = now2;
7225
7292
  let pinchPartner;
7226
7293
  if (ctx.read(pointer, Pointer).device === "touch") {
@@ -7300,6 +7367,7 @@ function createL2Systems({ world, profiles = DEFAULT_SPAWN_PROFILES }) {
7300
7367
  tags: [...tags]
7301
7368
  });
7302
7369
  }
7370
+ if (kind === "drag" && movesSelection) ctx.addTag(rec, MovesSelection);
7303
7371
  ctx.addRelation(rec, Watches, pointer);
7304
7372
  if (downPart !== "") ctx.addComponent(rec, DownPart, { part: downPart });
7305
7373
  if (captureTarget !== void 0) {
@@ -7360,24 +7428,36 @@ function createL2Systems({ world, profiles = DEFAULT_SPAWN_PROFILES }) {
7360
7428
  const zooming = wheel.pinch !== 0;
7361
7429
  const panning = wheel.dx !== 0 || wheel.dy !== 0;
7362
7430
  if (!zooming && !panning) continue;
7363
- const hasLive = ctx.getReverse(pointer, Watches).some((rec2) => (ctx.has(rec2, WheelPan) || ctx.has(rec2, WheelZoom)) && !isTerminal(ctx, rec2));
7364
- if (hasLive) continue;
7431
+ let needZoom = zooming;
7432
+ let needPan = panning;
7433
+ for (const rec of ctx.getReverse(pointer, Watches)) {
7434
+ if (isTerminal(ctx, rec)) continue;
7435
+ if (needZoom && ctx.has(rec, WheelZoom)) needZoom = false;
7436
+ if (needPan && ctx.has(rec, WheelPan)) needPan = false;
7437
+ if (!needZoom && !needPan) break;
7438
+ }
7439
+ if (!needZoom && !needPan) continue;
7365
7440
  const screen = ctx.read(pointer, PointerScreen);
7366
- const rec = zooming ? ctx.spawn({
7367
- components: [
7368
- [WheelZoom, { pinch: 0, anchorX: screen.x, anchorY: screen.y }],
7369
- [Down, { x: screen.x, y: screen.y, ms: now2 }]
7370
- // Down.ms = last wheel activity (silence timer)
7371
- ],
7372
- tags: [P2.tags.Possible, Simultaneous]
7373
- }) : ctx.spawn({
7374
- components: [
7375
- [WheelPan, { dx: 0, dy: 0, anchorX: screen.x, anchorY: screen.y }],
7376
- [Down, { x: screen.x, y: screen.y, ms: now2 }]
7377
- ],
7378
- tags: [P2.tags.Possible, Simultaneous]
7379
- });
7380
- ctx.addRelation(rec, Watches, pointer);
7441
+ if (needZoom) {
7442
+ const rec = ctx.spawn({
7443
+ components: [
7444
+ [WheelZoom, { pinch: 0, anchorX: screen.x, anchorY: screen.y }],
7445
+ [Down, { x: screen.x, y: screen.y, ms: now2 }]
7446
+ ],
7447
+ tags: [P2.tags.Possible, Simultaneous]
7448
+ });
7449
+ ctx.addRelation(rec, Watches, pointer);
7450
+ }
7451
+ if (needPan) {
7452
+ const rec = ctx.spawn({
7453
+ components: [
7454
+ [WheelPan, { dx: 0, dy: 0, anchorX: screen.x, anchorY: screen.y }],
7455
+ [Down, { x: screen.x, y: screen.y, ms: now2 }]
7456
+ ],
7457
+ tags: [P2.tags.Possible, Simultaneous]
7458
+ });
7459
+ ctx.addRelation(rec, Watches, pointer);
7460
+ }
7381
7461
  }
7382
7462
  },
7383
7463
  { name: "wheelSpawn" }
@@ -7693,8 +7773,8 @@ function createL2Systems({ world, profiles = DEFAULT_SPAWN_PROFILES }) {
7693
7773
  }
7694
7774
 
7695
7775
  // ../core/src/ops/selection.ts
7696
- import { defineQuery as defineQuery11 } from "@vibecook/strata-ecs";
7697
- var selectedQuery = defineQuery11([Selected]);
7776
+ import { defineQuery as defineQuery12 } from "@vibecook/strata-ecs";
7777
+ var selectedQuery = defineQuery12([Selected]);
7698
7778
  function selectedEntities(world) {
7699
7779
  const out = [];
7700
7780
  world.query(selectedQuery).each((batch) => {
@@ -7750,10 +7830,10 @@ function clearSelection(world, onChange) {
7750
7830
  }
7751
7831
 
7752
7832
  // ../core/src/systems/l3-connect.ts
7753
- import { defineQuery as defineQuery12, defineSystem as defineSystem4, defineTickSystem as defineTickSystem6 } from "@vibecook/strata-ecs";
7833
+ import { defineQuery as defineQuery13, defineSystem as defineSystem4, defineTickSystem as defineTickSystem6 } from "@vibecook/strata-ecs";
7754
7834
  var P3 = GesturePhases;
7755
- var connectClaimQ = defineQuery12([Drag, P3.justTags.Active, RoutedConnect]);
7756
- var connectDragQ = defineQuery12([Drag, RoutedConnect]);
7835
+ var connectClaimQ = defineQuery13([Drag, P3.justTags.Active, RoutedConnect]);
7836
+ var connectDragQ = defineQuery13([Drag, RoutedConnect]);
7757
7837
  function declsOf(world, ctx, e) {
7758
7838
  const type = ctx.get(e, PrefabId)?.id;
7759
7839
  if (typeof type !== "string") return void 0;
@@ -7891,10 +7971,10 @@ function createConnectSystems(world, sink, _index, _wires) {
7891
7971
  }
7892
7972
 
7893
7973
  // ../core/src/systems/l3-ports.ts
7894
- import { defineQuery as defineQuery13, defineTickSystem as defineTickSystem7 } from "@vibecook/strata-ecs";
7974
+ import { defineQuery as defineQuery14, defineTickSystem as defineTickSystem7 } from "@vibecook/strata-ecs";
7895
7975
  var H = GRAPH_PICK_DEFAULTS.portIndexHalfWorld;
7896
- var portedQ = defineQuery13([Pointer, LocalPointer]);
7897
- var connectDragQ2 = defineQuery13([Drag, RoutedConnect, GestureActive]);
7976
+ var portedQ = defineQuery14([Pointer, LocalPointer]);
7977
+ var connectDragQ2 = defineQuery14([Drag, RoutedConnect, GestureActive]);
7898
7978
  function portedDeclsOf(world, ctx, e) {
7899
7979
  const type = ctx.get(e, PrefabId)?.id;
7900
7980
  if (typeof type !== "string") return void 0;
@@ -8103,7 +8183,7 @@ function makeChurnGuard(world, collect, extra) {
8103
8183
  }
8104
8184
 
8105
8185
  // ../core/src/systems/chrome.ts
8106
- import { defineQuery as defineQuery14, defineTickSystem as defineTickSystem8 } from "@vibecook/strata-ecs";
8186
+ import { defineQuery as defineQuery15, defineTickSystem as defineTickSystem8 } from "@vibecook/strata-ecs";
8107
8187
  var HANDLE_PICK_PX = 10;
8108
8188
  var HANDLE_ANCHORS = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
8109
8189
  function anchorPoint(anchor, b) {
@@ -8136,7 +8216,7 @@ function handleRect(anchor, b, worldSize) {
8136
8216
  const p2 = anchorPoint(anchor, b);
8137
8217
  return { x: p2.x - worldSize / 2, y: p2.y - worldSize / 2, w: worldSize, h: worldSize };
8138
8218
  }
8139
- var selectedQ2 = defineQuery14([Selected]);
8219
+ var selectedQ2 = defineQuery15([Selected]);
8140
8220
  function createSelectionChromeSystem(world) {
8141
8221
  let handleEntities = [];
8142
8222
  const handleCache = /* @__PURE__ */ new Map();
@@ -8259,7 +8339,7 @@ function hysteresisTierIndex(w, cur) {
8259
8339
  function clampU16(v) {
8260
8340
  return Math.max(0, Math.min(65535, Math.round(v)));
8261
8341
  }
8262
- var equippedWidgetQ = defineQuery14([Size, WidgetEquipped, Active]);
8342
+ var equippedWidgetQ = defineQuery15([Size, WidgetEquipped, Active]);
8263
8343
  function retier(ctx, e, w, h, zoom) {
8264
8344
  const ew = w;
8265
8345
  const eh = h;
@@ -8318,12 +8398,12 @@ function createBreakpointSystem(world) {
8318
8398
  }
8319
8399
 
8320
8400
  // ../core/src/systems/l3-draw.ts
8321
- import { defineQuery as defineQuery15, defineSystem as defineSystem6 } from "@vibecook/strata-ecs";
8401
+ import { defineQuery as defineQuery16, defineSystem as defineSystem6 } from "@vibecook/strata-ecs";
8322
8402
  var P4 = GesturePhases;
8323
8403
  var IDENTITY_CAM = { x: 0, y: 0, zoom: 1 };
8324
8404
  var DRAW_CLICK_SLOP_PX = 4;
8325
8405
  function createDrawBehavior(world, sink) {
8326
- const drawDragQ = defineQuery15([Drag, RoutedDraw]);
8406
+ const drawDragQ = defineQuery16([Drag, RoutedDraw]);
8327
8407
  return defineSystem6(
8328
8408
  drawDragQ,
8329
8409
  (b, ctx) => {
@@ -8535,12 +8615,12 @@ function createReadOnlyCommitSink() {
8535
8615
  }
8536
8616
 
8537
8617
  // ../core/src/systems/l4-cursor.ts
8538
- import { defineQuery as defineQuery16, defineSystem as defineSystem7 } from "@vibecook/strata-ecs";
8618
+ import { defineQuery as defineQuery17, defineSystem as defineSystem7 } from "@vibecook/strata-ecs";
8539
8619
  var P5 = GesturePhases;
8540
- var anchorQ = defineQuery16([CanvasSurface]);
8541
- var localPointerQ = defineQuery16([Pointer, LocalPointer]);
8542
- var heldQ = defineQuery16([Held]);
8543
- var trayQ = defineQuery16([Tray]);
8620
+ var anchorQ = defineQuery17([CanvasSurface]);
8621
+ var localPointerQ = defineQuery17([Pointer, LocalPointer]);
8622
+ var heldQ = defineQuery17([Held]);
8623
+ var trayQ = defineQuery17([Tray]);
8544
8624
  function heldToolCursor(world) {
8545
8625
  const held = world.firstOf(heldQ);
8546
8626
  if (held === void 0) return void 0;
@@ -8654,10 +8734,10 @@ function createCursorSync(world, opts = {}) {
8654
8734
  }
8655
8735
 
8656
8736
  // ../core/src/systems/held.ts
8657
- import { defineQuery as defineQuery17, defineSystem as defineSystem8 } from "@vibecook/strata-ecs";
8737
+ import { defineQuery as defineQuery18, defineSystem as defineSystem8 } from "@vibecook/strata-ecs";
8658
8738
  var HOLD_INPUT = { zoomMin: 0.72, zoomMax: 3, wheelRate: 0.0105, muteMs: 400, muteMoreMs: 250, slopPx: 3 };
8659
- var heldQ2 = defineQuery17([Held]);
8660
- var localPointerQ2 = defineQuery17([Pointer, PointerScreen, LocalPointer]);
8739
+ var heldQ2 = defineQuery18([Held]);
8740
+ var localPointerQ2 = defineQuery18([Pointer, PointerScreen, LocalPointer]);
8661
8741
  var clamp = (x, a, b) => Math.min(Math.max(x, a), Math.max(a, b));
8662
8742
  function heldEntity(world) {
8663
8743
  return world.firstOf(heldQ2);
@@ -8812,8 +8892,8 @@ function createHeldInput(world, opts) {
8812
8892
  }
8813
8893
 
8814
8894
  // ../core/src/systems/press-wheel.ts
8815
- import { defineQuery as defineQuery18, defineSystem as defineSystem9 } from "@vibecook/strata-ecs";
8816
- var pointersQ = defineQuery18([Pointer, LocalPointer, PointerButtons]);
8895
+ import { defineQuery as defineQuery19, defineSystem as defineSystem9 } from "@vibecook/strata-ecs";
8896
+ var pointersQ = defineQuery19([Pointer, LocalPointer, PointerButtons]);
8817
8897
  function createPressWheel(world) {
8818
8898
  return defineSystem9(
8819
8899
  pointersQ,
@@ -8822,11 +8902,14 @@ function createPressWheel(world) {
8822
8902
  const p2 = b.entity(r);
8823
8903
  let turns = false;
8824
8904
  if ((ctx.read(p2, PointerButtons).buttons & 1) !== 0) {
8825
- for (const rec of world.getReverse(p2, Watches)) {
8826
- const e = world.getRelation(rec, Captures);
8827
- if (e !== void 0 && ctx.isAlive(e) && ctx.hasTag(e, WheelTurns)) {
8828
- turns = true;
8829
- break;
8905
+ const watchers2 = world.getReverse(p2, Watches);
8906
+ if (!watchers2.some((rec) => ctx.hasTag(rec, MovesSelection) || ctx.hasTag(rec, RoutedMove))) {
8907
+ for (const rec of watchers2) {
8908
+ const e = world.getRelation(rec, Captures);
8909
+ if (e !== void 0 && ctx.isAlive(e) && ctx.hasTag(e, WheelTurns)) {
8910
+ turns = true;
8911
+ break;
8912
+ }
8830
8913
  }
8831
8914
  }
8832
8915
  }
@@ -8853,11 +8936,16 @@ function cancelActiveGestures(world) {
8853
8936
  }
8854
8937
 
8855
8938
  // ../core/src/systems/tray.ts
8856
- import { defineQuery as defineQuery19, defineSystem as defineSystem10, defineTickSystem as defineTickSystem9 } from "@vibecook/strata-ecs";
8857
- var TRAY_INPUT = { slopPx: 4, letGoMs: 120, fadeDeltas: 3 };
8858
- var trayQ2 = defineQuery19([Tray]);
8939
+ import { defineQuery as defineQuery20, defineSystem as defineSystem10, defineTickSystem as defineTickSystem9 } from "@vibecook/strata-ecs";
8940
+ var TRAY_INPUT = {
8941
+ slopPx: 4,
8942
+ letGoMs: 120,
8943
+ /** @deprecated Wheel input no longer estimates momentum from shrinking deltas. Kept for source compatibility. */
8944
+ fadeDeltas: 3
8945
+ };
8946
+ var trayQ2 = defineQuery20([Tray]);
8859
8947
  var NO_TAKE = { type: "", u: 0.5, v: 0.5, homeX: 0, homeY: 0 };
8860
- var localPointerQ3 = defineQuery19([Pointer, PointerScreen, LocalPointer]);
8948
+ var localPointerQ3 = defineQuery20([Pointer, PointerScreen, LocalPointer]);
8861
8949
  function specimensOf(world, tray) {
8862
8950
  const out = [];
8863
8951
  for (const c of world.getReverse(tray, ChildOf)) if (world.isAlive(c) && world.hasTag(c, Specimen)) out.push(c);
@@ -8917,8 +9005,6 @@ function createTrayInput(world, opts) {
8917
9005
  let scroll = t.scroll;
8918
9006
  let stretch = t.stretch;
8919
9007
  let wheelAt = t.wheelAt;
8920
- let wheelDy = t.wheelDy;
8921
- let fade = t.fade;
8922
9008
  let hover = "";
8923
9009
  let dragging = false;
8924
9010
  let take = t.take ?? "";
@@ -8962,16 +9048,11 @@ function createTrayInput(world, opts) {
8962
9048
  if (frame2 !== void 0 && over(s.x, s.y, 0) && shows(s.y) && ctx.read(p2, Pointer).device === "mouse") hover = specimenAt(world, tray, s.x - frame2.x, s.y - frame2.y + frame2.scroll)?.type ?? "";
8963
9049
  const w = ctx.get(p2, PointerWheel);
8964
9050
  if (w !== void 0 && (w.dy !== 0 || w.dx !== 0 || w.pinch !== 0)) {
8965
- const quiet = now2 - wheelAt > TRAY_INPUT.letGoMs;
8966
9051
  wheelAt = now2;
8967
9052
  const mods = ctx.get(p2, PointerMods);
8968
9053
  if (over(s.x, s.y, 0) && w.pinch === 0 && mods?.ctrl !== true && mods?.meta !== true && w.dy !== 0) {
8969
- const same = Math.sign(w.dy) === Math.sign(wheelDy);
8970
- if (quiet || !same || Math.abs(w.dy) > Math.abs(wheelDy)) fade = 0;
8971
- ({ scroll, stretch } = scrollBy(scroll, stretch, w.dy, max));
8972
- if (stretch !== 0 && Math.sign(stretch) === Math.sign(w.dy) && same && Math.abs(w.dy) < Math.abs(wheelDy)) fade += 1;
8973
- if (fade >= TRAY_INPUT.fadeDeltas) stretch = 0;
8974
- wheelDy = w.dy;
9054
+ scroll = Math.min(Math.max(Math.min(Math.max(scroll, 0), max) + w.dy, 0), max);
9055
+ stretch = 0;
8975
9056
  }
8976
9057
  }
8977
9058
  if (down) {
@@ -9044,8 +9125,8 @@ function createTrayInput(world, opts) {
9044
9125
  hover = "";
9045
9126
  if (handed === t.handed) take = "";
9046
9127
  }
9047
- if (open !== t.open || scroll !== t.scroll || stretch !== t.stretch || wheelAt !== t.wheelAt || hover !== t.hover || take !== t.take || takeU !== t.takeU || takeV !== t.takeV || takeX !== t.takeX || takeY !== t.takeY || handed !== t.handed || wheelDy !== t.wheelDy || fade !== t.fade) {
9048
- ctx.edit(tray).set(Tray, { ...t, open, scroll, stretch, wheelAt, wheelDy, fade, hover, take, takeU, takeV, takeX, takeY, handed });
9128
+ if (open !== t.open || scroll !== t.scroll || stretch !== t.stretch || wheelAt !== t.wheelAt || hover !== t.hover || take !== t.take || takeU !== t.takeU || takeV !== t.takeV || takeX !== t.takeX || takeY !== t.takeY || handed !== t.handed) {
9129
+ ctx.edit(tray).set(Tray, { ...t, open, scroll, stretch, wheelAt, hover, take, takeU, takeV, takeX, takeY, handed });
9049
9130
  }
9050
9131
  },
9051
9132
  { name: "trayInput", access: { write: [Tray, TrayPress] } }
@@ -9185,8 +9266,8 @@ function createTrayLay(world, opts) {
9185
9266
  }
9186
9267
 
9187
9268
  // ../core/src/ops/tray.ts
9188
- import { defineQuery as defineQuery20 } from "@vibecook/strata-ecs";
9189
- var trayQ3 = defineQuery20([Tray]);
9269
+ import { defineQuery as defineQuery21 } from "@vibecook/strata-ecs";
9270
+ var trayQ3 = defineQuery21([Tray]);
9190
9271
  function ensureTray(world) {
9191
9272
  const existing = world.firstOf(trayQ3);
9192
9273
  if (existing !== void 0) return existing;
@@ -9274,7 +9355,7 @@ function presentOf2(world) {
9274
9355
  }
9275
9356
 
9276
9357
  // ../core/src/systems/nav-tap.ts
9277
- import { defineQuery as defineQuery21, defineSystem as defineSystem11, field as field17 } from "@vibecook/strata-ecs";
9358
+ import { defineQuery as defineQuery22, defineSystem as defineSystem11, field as field17 } from "@vibecook/strata-ecs";
9278
9359
  var NavTapMemo = defineResource(
9279
9360
  "NavTapMemo",
9280
9361
  {
@@ -9287,7 +9368,7 @@ var NavTapMemo = defineResource(
9287
9368
  },
9288
9369
  { durable: false }
9289
9370
  );
9290
- var tapRecognizedQ = defineQuery21([Tap, GesturePhases.justTags.Recognized]);
9371
+ var tapRecognizedQ = defineQuery22([Tap, GesturePhases.justTags.Recognized]);
9291
9372
  function createNavTap(world, opts = {}) {
9292
9373
  const isContainer = opts.isContainer ?? ((e) => world.hasTag(e, Container));
9293
9374
  const isOpenable = opts.isOpenable ?? (() => false);
@@ -9340,8 +9421,8 @@ function createNavTap(world, opts = {}) {
9340
9421
  }
9341
9422
 
9342
9423
  // ../core/src/systems/zoom-through.ts
9343
- import { defineQuery as defineQuery22, defineTickSystem as defineTickSystem10 } from "@vibecook/strata-ecs";
9344
- var activeContainersQ = defineQuery22([Container, Active, Position, Size, PrefabId]);
9424
+ import { defineQuery as defineQuery23, defineTickSystem as defineTickSystem10 } from "@vibecook/strata-ecs";
9425
+ var activeContainersQ = defineQuery23([Container, Active, Position, Size, PrefabId]);
9345
9426
  function createZoomThrough(world, opts = {}) {
9346
9427
  const order = createSiblingOrderIndex(world);
9347
9428
  const isContainer = opts.isContainer ?? (() => true);
@@ -9395,13 +9476,13 @@ function createZoomThrough(world, opts = {}) {
9395
9476
  }
9396
9477
 
9397
9478
  // ../core/src/interaction/install.ts
9398
- import { defineQuery as defineQuery34 } from "@vibecook/strata-ecs";
9479
+ import { defineQuery as defineQuery35 } from "@vibecook/strata-ecs";
9399
9480
 
9400
9481
  // ../core/src/systems/cleanup.ts
9401
- import { Any as Any3, defineQuery as defineQuery23, defineSystem as defineSystem12 } from "@vibecook/strata-ecs";
9482
+ import { Any as Any3, defineQuery as defineQuery24, defineSystem as defineSystem12 } from "@vibecook/strata-ecs";
9402
9483
  var P6 = GesturePhases;
9403
- var anyKindQ2 = defineQuery23([Any3(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
9404
- var pointerQ = defineQuery23([Pointer, PointerWheel]);
9484
+ var anyKindQ2 = defineQuery24([Any3(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
9485
+ var pointerQ = defineQuery24([Pointer, PointerWheel]);
9405
9486
  function createCleanupSystems(world) {
9406
9487
  const recognizerReap = defineSystem12(
9407
9488
  anyKindQ2,
@@ -9444,9 +9525,9 @@ function createCleanupSystems(world) {
9444
9525
  }
9445
9526
 
9446
9527
  // ../core/src/systems/l0-input.ts
9447
- import { defineQuery as defineQuery24, defineSystem as defineSystem13, defineTickSystem as defineTickSystem11 } from "@vibecook/strata-ecs";
9448
- var pointerQ2 = defineQuery24([Pointer, PointerScreen]);
9449
- var touchLifecycleQ = defineQuery24([Pointer, PointerButtons]);
9528
+ import { defineQuery as defineQuery25, defineSystem as defineSystem13, defineTickSystem as defineTickSystem11 } from "@vibecook/strata-ecs";
9529
+ var pointerQ2 = defineQuery25([Pointer, PointerScreen]);
9530
+ var touchLifecycleQ = defineQuery25([Pointer, PointerButtons]);
9450
9531
  function radiusFor(device, ps) {
9451
9532
  if (device === "touch") return (ps ?? POINTER_DEFAULTS).radiusTouchPx;
9452
9533
  if (device === "pen") return (ps ?? POINTER_DEFAULTS).radiusPenPx;
@@ -9622,7 +9703,7 @@ function createL0Systems(world, queue) {
9622
9703
  }
9623
9704
  );
9624
9705
  const pointerWorldSync = defineSystem13(
9625
- defineQuery24([Pointer, PointerScreen, PointerWorld]),
9706
+ defineQuery25([Pointer, PointerScreen, PointerWorld]),
9626
9707
  (b, ctx) => {
9627
9708
  const cam = ctx.getResource(Camera);
9628
9709
  if (cam === void 0) return;
@@ -9639,13 +9720,13 @@ function createL0Systems(world, queue) {
9639
9720
  }
9640
9721
 
9641
9722
  // ../core/src/systems/l1-pick.ts
9642
- import { defineQuery as defineQuery25, defineSystem as defineSystem14, defineTickSystem as defineTickSystem12, Not as Not5 } from "@vibecook/strata-ecs";
9723
+ import { defineQuery as defineQuery26, defineSystem as defineSystem14, defineTickSystem as defineTickSystem12, Not as Not5 } from "@vibecook/strata-ecs";
9643
9724
  var IDENTITY_CAM2 = { x: 0, y: 0, zoom: 1 };
9644
- var canvasSurfaceQ = defineQuery25([CanvasSurface]);
9645
- var trayQ4 = defineQuery25([Tray]);
9646
- var widgetAabbQ = defineQuery25([Position, Size, WidgetEquipped, Active]);
9647
- var chromeAabbQ = defineQuery25([Position, Size, Not5(WidgetEquipped)]);
9648
- var pointerQ3 = defineQuery25([Pointer, PointerScreen, PointerRadius, LocalPointer, Not5(HandledByWidget)]);
9725
+ var canvasSurfaceQ = defineQuery26([CanvasSurface]);
9726
+ var trayQ4 = defineQuery26([Tray]);
9727
+ var widgetAabbQ = defineQuery26([Position, Size, WidgetEquipped, Active]);
9728
+ var chromeAabbQ = defineQuery26([Position, Size, Not5(WidgetEquipped)]);
9729
+ var pointerQ3 = defineQuery26([Pointer, PointerScreen, PointerRadius, LocalPointer, Not5(HandledByWidget)]);
9649
9730
  function createPickingSystems(world, index = new SpatialIndex(), wires, frames = { current: null }) {
9650
9731
  const collector = world.changes.collect({
9651
9732
  components: [Position, Size],
@@ -9849,15 +9930,15 @@ function createPickingSystems(world, index = new SpatialIndex(), wires, frames =
9849
9930
  }
9850
9931
 
9851
9932
  // ../core/src/systems/l2-arbitrate.ts
9852
- import { Any as Any4, Not as Not6, defineQuery as defineQuery26, defineSystem as defineSystem15, defineTickSystem as defineTickSystem13 } from "@vibecook/strata-ecs";
9933
+ import { Any as Any4, Not as Not6, defineQuery as defineQuery27, defineSystem as defineSystem15, defineTickSystem as defineTickSystem13 } from "@vibecook/strata-ecs";
9853
9934
  var P7 = GesturePhases;
9854
- var claimCandidateQ = defineQuery26([
9935
+ var claimCandidateQ = defineQuery27([
9855
9936
  Any4(Tap, LongPress, Drag, Pinch),
9856
9937
  Not6(Simultaneous),
9857
9938
  Not6(GestureSuspended)
9858
9939
  ]);
9859
- var justActiveDragQ = defineQuery26([Drag, P7.justTags.Active]);
9860
- var justClaimQ = defineQuery26([Any4(P7.justTags.Active, P7.justTags.Recognized)]);
9940
+ var justActiveDragQ = defineQuery27([Drag, P7.justTags.Active]);
9941
+ var justClaimQ = defineQuery27([Any4(P7.justTags.Active, P7.justTags.Recognized)]);
9861
9942
  function isTerminal2(ctx, e) {
9862
9943
  if (ctx.hasTag(e, P7.tags.Failed) || ctx.hasTag(e, P7.tags.Cancelled) || ctx.hasTag(e, P7.tags.Ended)) {
9863
9944
  return true;
@@ -9957,7 +10038,7 @@ function createArbitrationSystems(world) {
9957
10038
  const route = tool.route.widgetDrag;
9958
10039
  const onPart = (ctx.get(e, DownPart)?.part ?? "") !== "";
9959
10040
  if (route === "move") {
9960
- if (!onPart && tool.gates.movable && ctx.hasTag(captured, Movable)) ctx.addTag(e, RoutedMove);
10041
+ if (!onPart && tool.gates.movable && (ctx.hasTag(captured, Movable) || ctx.hasTag(e, MovesSelection))) ctx.addTag(e, RoutedMove);
9961
10042
  } else if (!onPart) {
9962
10043
  const t = routeTag(route);
9963
10044
  if (t !== void 0) ctx.addTag(e, t);
@@ -9972,7 +10053,7 @@ function createArbitrationSystems(world) {
9972
10053
  } else {
9973
10054
  const shift = pointer !== void 0 && ctx.get(pointer, PointerMods)?.shift === true;
9974
10055
  const route = shift ? tool.route.canvasDragShift ?? tool.route.canvasDrag : tool.route.canvasDrag;
9975
- const t = routeTag(route);
10056
+ const t = ctx.hasTag(e, MovesSelection) && tool.gates.movable && tool.route.widgetDrag === "move" && route === "marquee" ? RoutedMove : routeTag(route);
9976
10057
  if (t !== void 0) ctx.addTag(e, t);
9977
10058
  }
9978
10059
  }
@@ -9983,10 +10064,10 @@ function createArbitrationSystems(world) {
9983
10064
  }
9984
10065
 
9985
10066
  // ../core/src/systems/l3-behave.ts
9986
- import { defineQuery as defineQuery28, defineSystem as defineSystem17 } from "@vibecook/strata-ecs";
10067
+ import { defineQuery as defineQuery29, defineSystem as defineSystem17 } from "@vibecook/strata-ecs";
9987
10068
 
9988
10069
  // ../core/src/systems/l3-drop.ts
9989
- import { defineQuery as defineQuery27, defineSystem as defineSystem16 } from "@vibecook/strata-ecs";
10070
+ import { defineQuery as defineQuery28, defineSystem as defineSystem16 } from "@vibecook/strata-ecs";
9990
10071
  function objectsOnly(world, entities) {
9991
10072
  if (entities.length === 0) return false;
9992
10073
  for (const e of entities) {
@@ -10002,7 +10083,7 @@ function dropFaceOf(world, container, slot) {
10002
10083
  return f === void 0 ? void 0 : { face: f.face, affine: f.affine };
10003
10084
  }
10004
10085
  var insideRect = (r, x, y) => x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height;
10005
- var dropDragQ = defineQuery27([Drag, GestureActive, RoutedMove]);
10086
+ var dropDragQ = defineQuery28([Drag, GestureActive, RoutedMove]);
10006
10087
  function parseList(raw) {
10007
10088
  if (raw === null || raw === void 0 || raw === "") return [];
10008
10089
  try {
@@ -10138,8 +10219,8 @@ function moveDelta(ctx, rec) {
10138
10219
 
10139
10220
  // ../core/src/systems/l3-behave.ts
10140
10221
  var P8 = GesturePhases;
10141
- var tapRecognizedQ2 = defineQuery28([Tap, P8.justTags.Recognized]);
10142
- var moveDragQ = defineQuery28([Drag, RoutedMove]);
10222
+ var tapRecognizedQ2 = defineQuery29([Tap, P8.justTags.Recognized]);
10223
+ var moveDragQ = defineQuery29([Drag, RoutedMove]);
10143
10224
  var FLY_BACK_MS = 200;
10144
10225
  var CONSUME_GUTTER = 16;
10145
10226
  var IDENTITY_CAM3 = { x: 0, y: 0, zoom: 1 };
@@ -10512,11 +10593,11 @@ function createSelectMoveBehaviors(world, sink, opts = {}) {
10512
10593
  }
10513
10594
 
10514
10595
  // ../core/src/systems/l3-claim.ts
10515
- import { defineQuery as defineQuery29, defineSystem as defineSystem18 } from "@vibecook/strata-ecs";
10596
+ import { defineQuery as defineQuery30, defineSystem as defineSystem18 } from "@vibecook/strata-ecs";
10516
10597
  var P9 = GesturePhases;
10517
- var moveClaimQ = defineQuery29([Drag, P9.justTags.Active, RoutedMove]);
10518
- var resizeClaimQ = defineQuery29([Drag, P9.justTags.Active, RoutedResize]);
10519
- var sweepCandidatesQ = defineQuery29([Position, Size, Movable]);
10598
+ var moveClaimQ = defineQuery30([Drag, P9.justTags.Active, RoutedMove]);
10599
+ var resizeClaimQ = defineQuery30([Drag, P9.justTags.Active, RoutedResize]);
10600
+ var sweepCandidatesQ = defineQuery30([Position, Size, Movable]);
10520
10601
  function expandSweep(world, ctx, dragged) {
10521
10602
  const roots = dragged.filter((w) => ctx.isAlive(w) && ctx.hasTag(w, SweepsContained));
10522
10603
  if (roots.length === 0) return;
@@ -10597,13 +10678,18 @@ function createClaimSystems(world) {
10597
10678
  for (const r of b) {
10598
10679
  const rec = b.entity(r);
10599
10680
  const grabbed = ctx.getRelation(rec, Captures);
10600
- if (grabbed === void 0 || !ctx.has(grabbed, Position)) continue;
10681
+ const fromSelection = ctx.hasTag(rec, MovesSelection);
10682
+ if (!fromSelection && (grabbed === void 0 || !ctx.has(grabbed, Position))) continue;
10601
10683
  const pointer = ctx.getRelations(rec, Watches)[0];
10602
10684
  const shift = pointer !== void 0 && ctx.get(pointer, PointerMods)?.shift === true;
10603
- if (pointer !== void 0 && ctx.get(pointer, PointerMods)?.alt === true && !ctx.has(grabbed, InsertGhost)) ctx.addTag(rec, LeavesCopy);
10685
+ if (pointer !== void 0 && ctx.get(pointer, PointerMods)?.alt === true && (grabbed === void 0 || !ctx.has(grabbed, InsertGhost))) ctx.addTag(rec, LeavesCopy);
10604
10686
  const current = selectedEntities(world);
10605
10687
  let dragged;
10606
- if (ctx.has(grabbed, InsertGhost)) {
10688
+ if (fromSelection) {
10689
+ dragged = current;
10690
+ } else if (grabbed === void 0) {
10691
+ continue;
10692
+ } else if (ctx.has(grabbed, InsertGhost)) {
10607
10693
  for (const s of current) if (s !== grabbed) ctx.removeTag(s, Selected);
10608
10694
  if (!ctx.hasTag(grabbed, Selected)) ctx.addTag(grabbed, Selected);
10609
10695
  bumpVersion(world, SelectionVersion);
@@ -10624,7 +10710,8 @@ function createClaimSystems(world) {
10624
10710
  expandRiders(world, ctx, dragged);
10625
10711
  for (const w of dragged) {
10626
10712
  if (!ctx.isAlive(w) || !ctx.has(w, Position)) continue;
10627
- if (w !== grabbed && !ctx.hasTag(w, Movable)) continue;
10713
+ if (ctx.hasTag(w, Culled) && !ctx.hasTag(w, Active)) continue;
10714
+ if (w !== grabbed && !ctx.hasTag(w, Movable) && !ctx.hasTag(w, SelectionMovable)) continue;
10628
10715
  if (ctx.hasTag(w, Locked)) continue;
10629
10716
  if (!attachRiders(ctx, rec, w, taken)) continue;
10630
10717
  if (ctx.getRelation(w, ChildOf) !== void 0) {
@@ -10654,12 +10741,12 @@ function createClaimSystems(world) {
10654
10741
  }
10655
10742
 
10656
10743
  // ../core/src/systems/l3-marquee.ts
10657
- import { defineQuery as defineQuery30, defineTickSystem as defineTickSystem14 } from "@vibecook/strata-ecs";
10744
+ import { defineQuery as defineQuery31, defineTickSystem as defineTickSystem14 } from "@vibecook/strata-ecs";
10658
10745
  var P10 = GesturePhases;
10659
10746
  var IDENTITY_CAM4 = { x: 0, y: 0, zoom: 1 };
10660
- var canvasSurfaceQ2 = defineQuery30([CanvasSurface]);
10661
- var dragMarqueeQ = defineQuery30([Drag, RoutedMarquee]);
10662
- var longPressQ2 = defineQuery30([LongPress]);
10747
+ var canvasSurfaceQ2 = defineQuery31([CanvasSurface]);
10748
+ var dragMarqueeQ = defineQuery31([Drag, RoutedMarquee]);
10749
+ var longPressQ2 = defineQuery31([LongPress]);
10663
10750
  function createMarqueeBehavior(world, index) {
10664
10751
  const buffer = { rect: null, hits: [] };
10665
10752
  const queryHits = (ctx, rx, ry, rw, rh) => {
@@ -10756,9 +10843,9 @@ function createMarqueeBehavior(world, index) {
10756
10843
  }
10757
10844
 
10758
10845
  // ../core/src/systems/l3-resize.ts
10759
- import { defineQuery as defineQuery31, defineSystem as defineSystem20 } from "@vibecook/strata-ecs";
10846
+ import { defineQuery as defineQuery32, defineSystem as defineSystem20 } from "@vibecook/strata-ecs";
10760
10847
  var P11 = GesturePhases;
10761
- var resizeDragQ = defineQuery31([Drag, RoutedResize]);
10848
+ var resizeDragQ = defineQuery32([Drag, RoutedResize]);
10762
10849
  function computeResize(g, anchor, dx, dy, alt, shift, minW, minH) {
10763
10850
  const affectsLeft = anchor === "w" || anchor === "nw" || anchor === "sw";
10764
10851
  const affectsRight = anchor === "e" || anchor === "ne" || anchor === "se";
@@ -10893,8 +10980,8 @@ function createResizeBehavior(world, sink) {
10893
10980
  }
10894
10981
 
10895
10982
  // ../core/src/systems/l3-snap.ts
10896
- import { defineQuery as defineQuery32, defineTickSystem as defineTickSystem15 } from "@vibecook/strata-ecs";
10897
- var snapDragQ = defineQuery32([Drag, GestureActive, RoutedMove]);
10983
+ import { defineQuery as defineQuery33, defineTickSystem as defineTickSystem15 } from "@vibecook/strata-ecs";
10984
+ var snapDragQ = defineQuery33([Drag, GestureActive, RoutedMove]);
10898
10985
  function createSnapSystem(world, index) {
10899
10986
  const guidePool = [];
10900
10987
  const guideCache = /* @__PURE__ */ new Map();
@@ -11043,9 +11130,9 @@ function createSnapSystem(world, index) {
11043
11130
  }
11044
11131
 
11045
11132
  // ../core/src/systems/insert-ghost.ts
11046
- import { defineQuery as defineQuery33, defineSystem as defineSystem21 } from "@vibecook/strata-ecs";
11133
+ import { defineQuery as defineQuery34, defineSystem as defineSystem21 } from "@vibecook/strata-ecs";
11047
11134
  var P12 = GesturePhases;
11048
- var ghostQ = defineQuery33([InsertGhost]);
11135
+ var ghostQ = defineQuery34([InsertGhost]);
11049
11136
  function isTerminal3(ctx, rec) {
11050
11137
  return ctx.hasTag(rec, P12.tags.Ended) || ctx.hasTag(rec, P12.tags.Failed) || ctx.hasTag(rec, P12.tags.Cancelled) || ctx.hasTag(rec, P12.tags.Recognized);
11051
11138
  }
@@ -11096,7 +11183,7 @@ function createInsertGhostReap(world) {
11096
11183
  }
11097
11184
 
11098
11185
  // ../core/src/interaction/install.ts
11099
- var canvasSurfaceQ3 = defineQuery34([CanvasSurface]);
11186
+ var canvasSurfaceQ3 = defineQuery35([CanvasSurface]);
11100
11187
  function ensureCanvasSurface(world) {
11101
11188
  const existing = world.firstOf(canvasSurfaceQ3);
11102
11189
  if (existing !== void 0) return existing;
@@ -11314,16 +11401,16 @@ function decodeEnvelope(bytes2) {
11314
11401
  }
11315
11402
 
11316
11403
  // ../core/src/doc/migrate.ts
11317
- import { defineQuery as defineQuery35 } from "@vibecook/strata-ecs";
11404
+ import { defineQuery as defineQuery36 } from "@vibecook/strata-ecs";
11318
11405
  var PACK_PREFIX = "engine.pack.";
11319
- var allDurableQ = defineQuery35([PrefabId]);
11406
+ var allDurableQ = defineQuery36([PrefabId]);
11320
11407
  function runMigrations(ctx, report) {
11321
11408
  const { store, world } = ctx;
11322
11409
  const migrated = [];
11323
11410
  const skipped = [];
11324
11411
  const typePlans = [];
11325
11412
  for (const id of report.olderInDoc) {
11326
- const widget = widgetTypeFor(world, id);
11413
+ const widget = widgetTypeFor(world, id) ?? engineCatalogFor(world)?.retiredWidget(id);
11327
11414
  const data = widget === void 0 ? dataPrefabFor(world, id) : void 0;
11328
11415
  const chain = widget?.migrate ?? data?.migrate;
11329
11416
  if (widget === void 0 && data === void 0 || chain === void 0 || Object.keys(chain).length === 0) {
@@ -11612,11 +11699,11 @@ import { attachDurable, createDurableStore } from "@vibecook/strata-ecs/durable"
11612
11699
 
11613
11700
  // ../core/src/canvas/migrate.ts
11614
11701
  import {
11615
- defineQuery as defineQuery36,
11702
+ defineQuery as defineQuery37,
11616
11703
  valueEquals as valueEquals3
11617
11704
  } from "@vibecook/strata-ecs";
11618
11705
  var PACK_PREFIX3 = "engine.pack.";
11619
- var durableQ = defineQuery36([PrefabId]);
11706
+ var durableQ = defineQuery37([PrefabId]);
11620
11707
  function partitionFacets(facets) {
11621
11708
  const components = /* @__PURE__ */ new Set();
11622
11709
  const tags = /* @__PURE__ */ new Set();
@@ -11861,10 +11948,10 @@ function runCanvasSemanticMigrations(store, world, catalog, initialReport) {
11861
11948
  }
11862
11949
 
11863
11950
  // ../core/src/doc/rename.ts
11864
- import { defineQuery as defineQuery37 } from "@vibecook/strata-ecs";
11951
+ import { defineQuery as defineQuery38 } from "@vibecook/strata-ecs";
11865
11952
  var PACK_PREFIX4 = "engine.pack.";
11866
11953
  var RENAMED_PREFIX2 = "engine.renamed.";
11867
- var allDurableQ2 = defineQuery37([PrefabId]);
11954
+ var allDurableQ2 = defineQuery38([PrefabId]);
11868
11955
  function runRenames(ctx, report) {
11869
11956
  const { store, world } = ctx;
11870
11957
  const renamed = [];
@@ -11917,15 +12004,15 @@ function runRenames(ctx, report) {
11917
12004
  }
11918
12005
 
11919
12006
  // ../core/src/doc/rename-sweep.ts
11920
- import { Any as Any5, defineQuery as defineQuery38 } from "@vibecook/strata-ecs";
12007
+ import { Any as Any5, defineQuery as defineQuery39 } from "@vibecook/strata-ecs";
11921
12008
  var RENAMED_PREFIX3 = "engine.renamed.";
11922
- var prefabQ = defineQuery38([PrefabId]);
12009
+ var prefabQ = defineQuery39([PrefabId]);
11923
12010
  var legacyQByEntry = /* @__PURE__ */ new WeakMap();
11924
12011
  function legacyQueryOf(entry) {
11925
12012
  if (entry.legacyGroups.length === 0) return void 0;
11926
12013
  let q = legacyQByEntry.get(entry);
11927
12014
  if (q === void 0) {
11928
- q = entry.legacyGroups.length === 1 ? defineQuery38([entry.legacyGroups[0]]) : defineQuery38([Any5(...entry.legacyGroups)]);
12015
+ q = entry.legacyGroups.length === 1 ? defineQuery39([entry.legacyGroups[0]]) : defineQuery39([Any5(...entry.legacyGroups)]);
11929
12016
  legacyQByEntry.set(entry, q);
11930
12017
  }
11931
12018
  return q;
@@ -12050,11 +12137,11 @@ function armRenameSweep(world, store) {
12050
12137
  }
12051
12138
 
12052
12139
  // ../core/src/doc/schema-migrate.ts
12053
- import { defineQuery as defineQuery39 } from "@vibecook/strata-ecs";
12140
+ import { defineQuery as defineQuery40 } from "@vibecook/strata-ecs";
12054
12141
  var SCHEMA_PREFIX2 = "engine.schema.";
12055
12142
  var PACK_PREFIX5 = "engine.pack.";
12056
12143
  var BOARD_ROOT_META = "engine.boardRoot";
12057
- var allDurableQ3 = defineQuery39([PrefabId]);
12144
+ var allDurableQ3 = defineQuery40([PrefabId]);
12058
12145
  function ensureBoardRoot(world, store) {
12059
12146
  let recorded;
12060
12147
  store.metaTransaction((meta) => {
@@ -12420,7 +12507,7 @@ function openDocSession(world, bytes2, opts = {}) {
12420
12507
  }
12421
12508
 
12422
12509
  // ../core/src/behavior/harness.ts
12423
- import { createWorld, defineQuery as defineQuery40 } from "@vibecook/strata-ecs";
12510
+ import { createWorld, defineQuery as defineQuery41 } from "@vibecook/strata-ecs";
12424
12511
  var HARNESS_PREFAB_ID = "ice.harness.node";
12425
12512
  function harnessPrefab() {
12426
12513
  return prefabs.get(HARNESS_PREFAB_ID) ?? definePrefab(HARNESS_PREFAB_ID, {
@@ -12581,18 +12668,18 @@ var queryCache = /* @__PURE__ */ new WeakMap();
12581
12668
  function behaviorQuery(b) {
12582
12669
  let q = queryCache.get(b);
12583
12670
  if (q === void 0) {
12584
- q = defineQuery40([b.component]);
12671
+ q = defineQuery41([b.component]);
12585
12672
  queryCache.set(b, q);
12586
12673
  }
12587
12674
  return q;
12588
12675
  }
12589
12676
 
12590
12677
  // ../core/src/ops/arrange.ts
12591
- import { defineQuery as defineQuery41 } from "@vibecook/strata-ecs";
12678
+ import { defineQuery as defineQuery42 } from "@vibecook/strata-ecs";
12592
12679
  var ARRANGE_MS = 240;
12593
12680
  var ARRANGE_GUTTER = 24;
12594
- var frameWidgetsQ = defineQuery41([Position, Size, Selectable, Active, WidgetEquipped]);
12595
- var wireQ2 = defineQuery41([Wire]);
12681
+ var frameWidgetsQ = defineQuery42([Position, Size, Selectable, Active, WidgetEquipped]);
12682
+ var wireQ2 = defineQuery42([Wire]);
12596
12683
  function arrangeWidgets(store, liveWriter, world, opts = {}) {
12597
12684
  let targets;
12598
12685
  if (opts.ids !== void 0 && opts.ids.length > 0) {
@@ -12766,8 +12853,8 @@ function cascadeDestroy(tx, world, root) {
12766
12853
  }
12767
12854
 
12768
12855
  // ../core/src/interaction/gesture-status.ts
12769
- import { Any as Any6, defineQuery as defineQuery42 } from "@vibecook/strata-ecs";
12770
- var gestureQ = defineQuery42([Any6(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
12856
+ import { Any as Any6, defineQuery as defineQuery43 } from "@vibecook/strata-ecs";
12857
+ var gestureQ = defineQuery43([Any6(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
12771
12858
  var P13 = GesturePhases;
12772
12859
  function anyGestureNonTerminal(world) {
12773
12860
  let active = false;
@@ -12955,8 +13042,8 @@ function createPlacementAuthority(opts) {
12955
13042
  }
12956
13043
 
12957
13044
  // ../core/src/canvas/diagnostics.ts
12958
- import { defineQuery as defineQuery43 } from "@vibecook/strata-ecs";
12959
- var durableQ2 = defineQuery43([PrefabId]);
13045
+ import { defineQuery as defineQuery44 } from "@vibecook/strata-ecs";
13046
+ var durableQ2 = defineQuery44([PrefabId]);
12960
13047
  function entityKey(store, entity) {
12961
13048
  return String(store.keyOf(entity) ?? `runtime:${entity}`);
12962
13049
  }
@@ -13077,7 +13164,7 @@ function collectCanvasDiagnostics(opts) {
13077
13164
  // ../core/src/canvas/frame-preview.ts
13078
13165
  import {
13079
13166
  Related as Related2,
13080
- defineQuery as defineQuery44
13167
+ defineQuery as defineQuery45
13081
13168
  } from "@vibecook/strata-ecs";
13082
13169
  var FRAME_PREVIEW_DEFAULT_CHILDREN = 128;
13083
13170
  var FRAME_PREVIEW_DEFAULT_BYTES = 256 * 1024;
@@ -13449,7 +13536,7 @@ function createFramePreviewStore(opts) {
13449
13536
  observerCount += 1;
13450
13537
  }
13451
13538
  if (!isContainer(entity)) {
13452
- const membership = defineQuery44([PrefabId, Related2(ChildOf, entity)]);
13539
+ const membership = defineQuery45([PrefabId, Related2(ChildOf, entity)]);
13453
13540
  entry.childUnsubs.push(
13454
13541
  world.reactive.observeQuery(membership, () => schedule(entry), { cols: [] })
13455
13542
  );
@@ -13472,10 +13559,10 @@ function createFramePreviewStore(opts) {
13472
13559
  const def = definition(entry.frame);
13473
13560
  entry.projectionFailed = void 0;
13474
13561
  if (world.isAlive(entry.frame)) world.orderStamp(entry.frame, ChildOf);
13475
- const membership = defineQuery44([PrefabId, Related2(ChildOf, entry.frame)]);
13562
+ const membership = defineQuery45([PrefabId, Related2(ChildOf, entry.frame)]);
13476
13563
  observe(entry, () => world.reactive.observeQuery(membership, () => schedule(entry), { cols: [] }));
13477
13564
  for (const relation of def.projection?.relations ?? []) {
13478
- const relationWake = defineQuery44([Related2(relation)]);
13565
+ const relationWake = defineQuery45([Related2(relation)]);
13479
13566
  observe(
13480
13567
  entry,
13481
13568
  () => world.reactive.observeQuery(relationWake, () => schedule(entry), { cols: [] })
@@ -13865,7 +13952,7 @@ function createPresentationTransitionCoordinator(world, engine, opts = {}) {
13865
13952
  }
13866
13953
 
13867
13954
  // ../core/src/widget/equip.ts
13868
- import { Not as Not7, defineQuery as defineQuery45, defineSystem as defineSystem22 } from "@vibecook/strata-ecs";
13955
+ import { Not as Not7, defineQuery as defineQuery46, defineSystem as defineSystem22 } from "@vibecook/strata-ecs";
13869
13956
  function runtimeBehaviorCell(b, data) {
13870
13957
  const out = { ...b.defaults };
13871
13958
  for (const [k, v] of Object.entries(data)) {
@@ -13874,7 +13961,7 @@ function runtimeBehaviorCell(b, data) {
13874
13961
  }
13875
13962
  return out;
13876
13963
  }
13877
- var unequippedQ = defineQuery45([PrefabId, Not7(WidgetEquipped)]);
13964
+ var unequippedQ = defineQuery46([PrefabId, Not7(WidgetEquipped)]);
13878
13965
  function createWidgetEquipSystem(world) {
13879
13966
  return defineSystem22(
13880
13967
  unequippedQ,
@@ -13948,8 +14035,8 @@ function setWidgetProps(store, world, entity, props, opts) {
13948
14035
  }
13949
14036
 
13950
14037
  // ../core/src/widget/mount-store.ts
13951
- import { defineQuery as defineQuery46, defineTickSystem as defineTickSystem16 } from "@vibecook/strata-ecs";
13952
- var widgetQ = defineQuery46([Position, Size, WidgetEquipped, Active]);
14038
+ import { defineQuery as defineQuery47, defineTickSystem as defineTickSystem16 } from "@vibecook/strata-ecs";
14039
+ var widgetQ = defineQuery47([Position, Size, WidgetEquipped, Active]);
13953
14040
  function createWidgetRuntime(world) {
13954
14041
  let lastWin = null;
13955
14042
  let lastNavFrame;
@@ -14406,10 +14493,10 @@ function attachPresence(world, opts) {
14406
14493
  }
14407
14494
 
14408
14495
  // ../core/src/presence/publish.ts
14409
- import { defineQuery as defineQuery47 } from "@vibecook/strata-ecs";
14496
+ import { defineQuery as defineQuery48 } from "@vibecook/strata-ecs";
14410
14497
  var SELECTION_KEY_CAP = 32;
14411
14498
  var COUNT_MAX = 65535;
14412
- var localMouseQ = defineQuery47([Pointer, LocalPointer, PointerWorld]);
14499
+ var localMouseQ = defineQuery48([Pointer, LocalPointer, PointerWorld]);
14413
14500
  function presenceCanvasOf(world, peerId, keyOf) {
14414
14501
  const frame2 = currentNavFrame(world);
14415
14502
  if (frame2 === void 0 || frame2 === world.getResource(BoardRoot)?.root) return "";
@@ -14518,9 +14605,9 @@ function summaryEquals(a, b) {
14518
14605
  }
14519
14606
 
14520
14607
  // ../core/src/presence/remote-cursors.ts
14521
- import { Not as Not8, defineQuery as defineQuery48, defineTickSystem as defineTickSystem17 } from "@vibecook/strata-ecs";
14608
+ import { Not as Not8, defineQuery as defineQuery49, defineTickSystem as defineTickSystem17 } from "@vibecook/strata-ecs";
14522
14609
  import { Local as Local2 } from "@vibecook/strata-ecs";
14523
- var remotePeerCursorsQ = defineQuery48([PresenceCursor, PresencePeer, Not8(Local2)]);
14610
+ var remotePeerCursorsQ = defineQuery49([PresenceCursor, PresencePeer, Not8(Local2)]);
14524
14611
  function createRemoteCursorsRig(world, opts = {}) {
14525
14612
  const pool = /* @__PURE__ */ new Map();
14526
14613
  const system = defineTickSystem17(
@@ -14937,12 +15024,12 @@ function webSocketByteChannel(ws) {
14937
15024
  }
14938
15025
 
14939
15026
  // ../core/src/facade/create-canvas-engine.ts
14940
- import { createWorld as createWorld2, defineQuery as defineQuery51 } from "@vibecook/strata-ecs";
15027
+ import { createWorld as createWorld2, defineQuery as defineQuery52 } from "@vibecook/strata-ecs";
14941
15028
 
14942
15029
  // ../core/src/canvas/runtime-extension-host.ts
14943
15030
  import {
14944
15031
  Related as Related3,
14945
- defineQuery as defineQuery49,
15032
+ defineQuery as defineQuery50,
14946
15033
  valueEquals as valueEquals4
14947
15034
  } from "@vibecook/strata-ecs";
14948
15035
  function partition(facets) {
@@ -15028,7 +15115,7 @@ function installCanvasRuntimeExtensions(opts) {
15028
15115
  externalDirty: false
15029
15116
  };
15030
15117
  for (const relation of facets.relations) {
15031
- const query = defineQuery49([Related3(relation)]);
15118
+ const query = defineQuery50([Related3(relation)]);
15032
15119
  activation.unsubs.push(
15033
15120
  world.reactive.observeQuery(query, () => {
15034
15121
  activation.externalDirty = true;
@@ -15209,10 +15296,10 @@ function installCanvasRuntimeExtensions(opts) {
15209
15296
  // ../core/src/canvas/frame-behavior-host.ts
15210
15297
  import {
15211
15298
  Related as Related4,
15212
- defineQuery as defineQuery50,
15299
+ defineQuery as defineQuery51,
15213
15300
  valueEquals as valueEquals5
15214
15301
  } from "@vibecook/strata-ecs";
15215
- var durableQ3 = defineQuery50([PrefabId]);
15302
+ var durableQ3 = defineQuery51([PrefabId]);
15216
15303
  function partition2(facets) {
15217
15304
  const components = /* @__PURE__ */ new Set();
15218
15305
  const tags = /* @__PURE__ */ new Set();
@@ -15279,7 +15366,7 @@ function installFrameBehaviors(opts) {
15279
15366
  };
15280
15367
  for (const relation of facets.relations) {
15281
15368
  state.unsubs.push(
15282
- world.reactive.observeQuery(defineQuery50([Related4(relation)]), () => {
15369
+ world.reactive.observeQuery(defineQuery51([Related4(relation)]), () => {
15283
15370
  state.externalDirty = true;
15284
15371
  })
15285
15372
  );
@@ -15661,14 +15748,15 @@ function createForwardingSink(world, current) {
15661
15748
  }
15662
15749
  };
15663
15750
  }
15664
- var selectableWidgetsQ = defineQuery51([Position, Size, Selectable, Active, WidgetEquipped]);
15665
- var visibleWidgetsQ = defineQuery51([PrefabId, WidgetEquipped, Active, Visible]);
15666
- var tweenQ2 = defineQuery51([Position, TransformTween]);
15667
- var insertGhostQ = defineQuery51([InsertGhost]);
15751
+ var selectableWidgetsQ = defineQuery52([Position, Size, Selectable, Active, WidgetEquipped]);
15752
+ var visibleWidgetsQ = defineQuery52([PrefabId, WidgetEquipped, Active, Visible]);
15753
+ var tweenQ2 = defineQuery52([Position, TransformTween]);
15754
+ var insertGhostQ = defineQuery52([InsertGhost]);
15668
15755
  function createCanvasEngine(opts = {}) {
15669
15756
  registerBuiltinTools();
15670
15757
  const catalog = compileEngineCatalog({
15671
15758
  ...opts.widgets === void 0 ? {} : { widgets: opts.widgets },
15759
+ ...opts.retiredWidgets === void 0 ? {} : { retiredWidgets: opts.retiredWidgets },
15672
15760
  ...opts.tools === void 0 ? {} : { tools: opts.tools },
15673
15761
  ...opts.canvasTypes === void 0 ? {} : { canvasTypes: opts.canvasTypes },
15674
15762
  ...opts.rootCanvas === void 0 ? {} : { rootCanvas: opts.rootCanvas },
@@ -15934,7 +16022,13 @@ function createCanvasEngine(opts = {}) {
15934
16022
  minZoom: st.zoom?.min ?? CAMERA_DEFAULTS.minZoom,
15935
16023
  maxZoom: st.zoom?.max ?? CAMERA_DEFAULTS.maxZoom
15936
16024
  },
15937
- gestures: { ...GESTURE_DEFAULTS, ...st.gestures },
16025
+ gestures: {
16026
+ ...GESTURE_DEFAULTS,
16027
+ ...st.gestures,
16028
+ // Preserve existing scroll-to-zoom consumers at construction. Once
16029
+ // seeded, changing the wheel mode cannot change the pinch response.
16030
+ wheelZoomCurve: st.gestures?.wheelZoomCurve ?? (st.gestures?.wheel === "zoom" ? "exponential" : GESTURE_DEFAULTS.wheelZoomCurve)
16031
+ },
15938
16032
  pointers: { ...POINTER_DEFAULTS, ...st.pointers },
15939
16033
  snap: {
15940
16034
  enabled: st.snap?.enabled ?? SNAP_DEFAULTS.enabled,
@@ -16909,7 +17003,7 @@ import {
16909
17003
  Not as Not9,
16910
17004
  Related as Related5,
16911
17005
  createWorld as createWorld3,
16912
- defineQuery as defineQuery52,
17006
+ defineQuery as defineQuery53,
16913
17007
  defineSystem as defineSystem23,
16914
17008
  defineTickSystem as defineTickSystem18,
16915
17009
  enumOf as enumOf13,
@@ -17015,6 +17109,7 @@ export {
17015
17109
  GestureSuspended,
17016
17110
  HadCapture,
17017
17111
  Simultaneous,
17112
+ MovesSelection,
17018
17113
  RoutedMove,
17019
17114
  RoutedResize,
17020
17115
  RoutedConnect,
@@ -17089,6 +17184,7 @@ export {
17089
17184
  Selected,
17090
17185
  Selectable,
17091
17186
  Movable,
17187
+ SelectionMovable,
17092
17188
  Resizable,
17093
17189
  SnapSource,
17094
17190
  SnapTarget,
@@ -17107,6 +17203,7 @@ export {
17107
17203
  Retained,
17108
17204
  CameraInertia,
17109
17205
  WheelZoomStep,
17206
+ CameraZoomStep,
17110
17207
  createCameraSystems,
17111
17208
  writeRuntimeResource,
17112
17209
  NavTransition,
@@ -17308,7 +17405,7 @@ export {
17308
17405
  Not9 as Not,
17309
17406
  Related5 as Related,
17310
17407
  createWorld3 as createWorld,
17311
- defineQuery52 as defineQuery,
17408
+ defineQuery53 as defineQuery,
17312
17409
  defineSystem23 as defineSystem,
17313
17410
  defineTickSystem18 as defineTickSystem,
17314
17411
  enumOf13 as enumOf,
@@ -17316,4 +17413,4 @@ export {
17316
17413
  Local3 as Local,
17317
17414
  DurableUndoStatus
17318
17415
  };
17319
- //# sourceMappingURL=chunk-Y7K6CHSF.js.map
17416
+ //# sourceMappingURL=chunk-LAZIY3J7.js.map