@vibecook/ice 0.2.0 → 0.3.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.
@@ -396,6 +396,181 @@ function createReflectorRegistry(world, opts) {
396
396
  };
397
397
  }
398
398
 
399
+ // ../core/src/catalog/camera-derived.ts
400
+ import { enumOf, field as field2 } from "@vibecook/strata-ecs";
401
+ var Camera = defineResource("Camera", {
402
+ x: field2("f64", { default: 0 }),
403
+ y: field2("f64", { default: 0 }),
404
+ zoom: field2("f32", { default: 1 }),
405
+ gesturing: field2("bool", { default: false })
406
+ });
407
+ var Viewport = defineResource("Viewport", {
408
+ w: field2("f32", { default: 0 }),
409
+ h: field2("f32", { default: 0 }),
410
+ dpr: field2("f32", { default: 1 })
411
+ });
412
+ var ActiveTool = defineResource("ActiveTool", { id: field2("string", { default: "select" }) });
413
+ var StageMode = defineResource("StageMode", {
414
+ backgroundHolds: field2("u32", { default: 0 })
415
+ });
416
+ var FrameMode = defineResource("FrameMode", {
417
+ freezeHolds: field2("u32", { default: 0 })
418
+ });
419
+ var SnapConfig = defineResource("SnapConfig", {
420
+ enabled: field2("bool", { default: SNAP_DEFAULTS.enabled }),
421
+ thresholdPx: field2("f32", { default: SNAP_DEFAULTS.thresholdPx })
422
+ });
423
+ var ContainerCamera = defineComponent("ContainerCamera", {
424
+ x: field2("f64", { default: 0 }),
425
+ y: field2("f64", { default: 0 }),
426
+ zoom: field2("f32", { default: 1 })
427
+ });
428
+ var Active = defineTag("Active");
429
+ var Visible = defineTag("Visible");
430
+ var Culled = defineTag("Culled");
431
+ var WidgetBreakpoint = defineComponent("WidgetBreakpoint", {
432
+ tier: field2(enumOf(["micro", "compact", "normal", "expanded", "detailed"]), { default: "normal" }),
433
+ w: field2("u16", { default: 0 }),
434
+ h: field2("u16", { default: 0 })
435
+ });
436
+ var MeasuredSize = defineComponent("MeasuredSize", {
437
+ w: field2("f32", { default: 0 }),
438
+ h: field2("f32", { default: 0 })
439
+ });
440
+ var SelectionBox = defineComponent("SelectionBox", {
441
+ x: field2("f64", { default: 0 }),
442
+ y: field2("f64", { default: 0 }),
443
+ w: field2("f32", { default: 0 }),
444
+ h: field2("f32", { default: 0 })
445
+ });
446
+ var HandleSpec = defineComponent("HandleSpec", {
447
+ anchor: enumOf(["nw", "n", "ne", "e", "se", "s", "sw", "w"])
448
+ });
449
+ var GuideLine = defineComponent("GuideLine", {
450
+ axis: enumOf(["x", "y"]),
451
+ at: field2("f64", { default: 0 }),
452
+ from: field2("f64", { default: 0 }),
453
+ to: field2("f64", { default: 0 })
454
+ });
455
+ var SpacingBar = defineComponent("SpacingBar", {
456
+ axis: enumOf(["x", "y"]),
457
+ from: field2("f64", { default: 0 }),
458
+ to: field2("f64", { default: 0 }),
459
+ perp: field2("f64", { default: 0 }),
460
+ gap: field2("f32", { default: 0 })
461
+ });
462
+ var MarqueeBox = defineComponent("MarqueeBox", {
463
+ x: field2("f64", { default: 0 }),
464
+ y: field2("f64", { default: 0 }),
465
+ w: field2("f32", { default: 0 }),
466
+ h: field2("f32", { default: 0 })
467
+ });
468
+ var CursorVisual = defineComponent("CursorVisual", {
469
+ kind: enumOf(["local", "remote"]),
470
+ pressed: field2("bool", { default: false })
471
+ });
472
+ var Follows = defineRelation("Follows", { arity: "one" });
473
+ var VisualOf = defineRelation("VisualOf", { arity: "one" });
474
+ var NavDepth = defineComponent("NavDepth", { d: field2("u8", { default: 0 }) });
475
+ var NavCamera = defineComponent("NavCamera", {
476
+ x: field2("f64", { default: 0 }),
477
+ y: field2("f64", { default: 0 }),
478
+ zoom: field2("f32", { default: 1 })
479
+ });
480
+ var NavFrame = defineRelation("NavFrame", { arity: "one" });
481
+ var CanvasSurface = defineTag("CanvasSurface");
482
+
483
+ // ../core/src/guards/dev.ts
484
+ var enabled = true;
485
+ function setDevGuards(on) {
486
+ enabled = on;
487
+ }
488
+ function devGuardsEnabled() {
489
+ return enabled;
490
+ }
491
+
492
+ // ../core/src/engine/frame-control.ts
493
+ var SETTLE_CAP = 120;
494
+ function createFrameControl(world) {
495
+ const freezes = /* @__PURE__ */ new Map();
496
+ const reporters = /* @__PURE__ */ new Map();
497
+ const listeners = /* @__PURE__ */ new Set();
498
+ let settleLeft = 0;
499
+ let parked = false;
500
+ const sync = () => {
501
+ world.setResource(FrameMode, { freezeHolds: freezes.size });
502
+ };
503
+ const announce = () => {
504
+ for (const fn of [...listeners]) fn();
505
+ };
506
+ const busyNames = () => {
507
+ const names = [];
508
+ for (const r of reporters.values()) if (r.busy()) names.push(r.name);
509
+ return names;
510
+ };
511
+ return {
512
+ freeze(name) {
513
+ const token = Symbol(name);
514
+ const first = freezes.size === 0;
515
+ freezes.set(token, name);
516
+ if (first) {
517
+ settleLeft = SETTLE_CAP;
518
+ parked = false;
519
+ }
520
+ sync();
521
+ announce();
522
+ let released = false;
523
+ return () => {
524
+ if (released) return;
525
+ released = true;
526
+ freezes.delete(token);
527
+ if (freezes.size === 0) {
528
+ settleLeft = 0;
529
+ parked = false;
530
+ }
531
+ sync();
532
+ announce();
533
+ };
534
+ },
535
+ isFrozen: () => freezes.size > 0,
536
+ isParked: () => parked,
537
+ holds: () => [...freezes.values()],
538
+ settleWhile(name, busy) {
539
+ const token = Symbol(name);
540
+ reporters.set(token, { name, busy });
541
+ let released = false;
542
+ return () => {
543
+ if (released) return;
544
+ released = true;
545
+ reporters.delete(token);
546
+ };
547
+ },
548
+ settling: () => busyNames(),
549
+ claimStep() {
550
+ if (freezes.size === 0) return true;
551
+ if (parked) return false;
552
+ if (settleLeft <= 0) {
553
+ parked = true;
554
+ if (devGuardsEnabled()) {
555
+ console.warn(
556
+ `ice: frame.freeze \u2014 settle cap (${SETTLE_CAP} frames) reached with reporters still busy: ${busyNames().join(", ")}. Parking on a possibly unsettled frame.`
557
+ );
558
+ }
559
+ return false;
560
+ }
561
+ settleLeft -= 1;
562
+ if (busyNames().length === 0) parked = true;
563
+ return true;
564
+ },
565
+ onChange(fn) {
566
+ listeners.add(fn);
567
+ return () => {
568
+ listeners.delete(fn);
569
+ };
570
+ }
571
+ };
572
+ }
573
+
399
574
  // ../core/src/engine/engine.ts
400
575
  function createEngine(world, opts) {
401
576
  const pipeline = createPipelineRegistry();
@@ -404,11 +579,13 @@ function createEngine(world, opts) {
404
579
  opts?.onReflectorFault ? { onFault: opts.onReflectorFault } : void 0
405
580
  );
406
581
  const publishHooks = [];
582
+ const frame2 = createFrameControl(world);
407
583
  let telemetryArmed = false;
408
584
  let last;
409
585
  let building = null;
410
586
  return {
411
587
  world,
588
+ frame: frame2,
412
589
  addSystems(group, ...systems) {
413
590
  return pipeline.add(group, ...systems);
414
591
  },
@@ -467,15 +644,6 @@ function createEngine(world, opts) {
467
644
  };
468
645
  }
469
646
 
470
- // ../core/src/guards/dev.ts
471
- var enabled = true;
472
- function setDevGuards(on) {
473
- enabled = on;
474
- }
475
- function devGuardsEnabled() {
476
- return enabled;
477
- }
478
-
479
647
  // ../core/src/guards/live-writer.ts
480
648
  function createLiveWriter(world, opts) {
481
649
  return {
@@ -599,34 +767,34 @@ function writeRuntimeResource(world, res, v) {
599
767
  }
600
768
 
601
769
  // ../core/src/catalog/scene.ts
602
- import { field as field2 } from "@vibecook/strata-ecs";
770
+ import { field as field3 } from "@vibecook/strata-ecs";
603
771
  var Position = defineComponent("Position", { x: "f64", y: "f64" });
604
772
  var Size = defineComponent("Size", { w: "f32", h: "f32" });
605
- var Rotation = defineComponent("Rotation", { r: field2("f32", { default: 0 }) });
606
- var Opacity = defineComponent("Opacity", { a: field2("f32", { default: 1 }) });
773
+ var Rotation = defineComponent("Rotation", { r: field3("f32", { default: 0 }) });
774
+ var Opacity = defineComponent("Opacity", { a: field3("f32", { default: 1 }) });
607
775
  var StackZ = defineComponent("StackZ", { z: "f64" });
608
776
  var ChildOf = defineRelation("ChildOf", { arity: "one", ordered: true });
609
777
  var BoardRoot = defineResource("BoardRoot", { root: "eid" });
610
778
 
611
779
  // ../core/src/catalog/graph.ts
612
- import { enumOf, field as field3 } from "@vibecook/strata-ecs";
780
+ import { enumOf as enumOf2, field as field4 } from "@vibecook/strata-ecs";
613
781
  var Wire = defineTag("Wire");
614
782
  var WireFrom = defineRelation("WireFrom", { arity: "one" });
615
783
  var WireTo = defineRelation("WireTo", { arity: "one" });
616
784
  var WirePorts = defineComponent("WirePorts", { from: "string", to: "string" });
617
785
  var Port = defineComponent("Port", {
618
786
  id: "string",
619
- side: enumOf(["n", "e", "s", "w"]),
620
- index: field3("u8", { default: 0 })
787
+ side: enumOf2(["n", "e", "s", "w"]),
788
+ index: field4("u8", { default: 0 })
621
789
  });
622
790
  var PortOf = defineRelation("PortOf", { arity: "one" });
623
791
  var PortAnchor = defineComponent("PortAnchor", {
624
- x: field3("f64", { default: 0 }),
625
- y: field3("f64", { default: 0 })
792
+ x: field4("f64", { default: 0 }),
793
+ y: field4("f64", { default: 0 })
626
794
  });
627
795
  var Container = defineTag("Container");
628
- var Accepts = defineComponent("Accepts", { list: field3("string", { default: "[]" }) });
629
- var Provides = defineComponent("Provides", { list: field3("string", { default: "[]" }) });
796
+ var Accepts = defineComponent("Accepts", { list: field4("string", { default: "[]" }) });
797
+ var Provides = defineComponent("Provides", { list: field4("string", { default: "[]" }) });
630
798
  var WirePrefab = definePrefab("wire", {
631
799
  store: "durable",
632
800
  version: 1,
@@ -636,35 +804,35 @@ var WirePrefab = definePrefab("wire", {
636
804
  });
637
805
 
638
806
  // ../core/src/catalog/pointer.ts
639
- import { enumOf as enumOf2, field as field4 } from "@vibecook/strata-ecs";
807
+ import { enumOf as enumOf3, field as field5 } from "@vibecook/strata-ecs";
640
808
  var Pointer = defineComponent("Pointer", {
641
809
  id: "string",
642
- device: enumOf2(["mouse", "touch", "pen"]),
643
- owner: field4("string", { default: "" })
810
+ device: enumOf3(["mouse", "touch", "pen"]),
811
+ owner: field5("string", { default: "" })
644
812
  });
645
813
  var PointerScreen = defineComponent("PointerScreen", {
646
- x: field4("f32", { default: 0 }),
647
- y: field4("f32", { default: 0 })
814
+ x: field5("f32", { default: 0 }),
815
+ y: field5("f32", { default: 0 })
648
816
  });
649
817
  var PointerButtons = defineComponent("PointerButtons", {
650
- buttons: field4("u8", { default: 0 }),
651
- downX: field4("f32", { default: 0 }),
652
- downY: field4("f32", { default: 0 }),
818
+ buttons: field5("u8", { default: 0 }),
819
+ downX: field5("f32", { default: 0 }),
820
+ downY: field5("f32", { default: 0 }),
653
821
  /** The down EVENT's timestamp (0 = unknown ⇒ consumers fall back to frame now). */
654
- downMs: field4("f64", { default: 0 })
822
+ downMs: field5("f64", { default: 0 })
655
823
  });
656
824
  var PointerMods = defineComponent("PointerMods", {
657
- shift: field4("bool", { default: false }),
658
- ctrl: field4("bool", { default: false }),
659
- alt: field4("bool", { default: false }),
660
- meta: field4("bool", { default: false })
825
+ shift: field5("bool", { default: false }),
826
+ ctrl: field5("bool", { default: false }),
827
+ alt: field5("bool", { default: false }),
828
+ meta: field5("bool", { default: false })
661
829
  });
662
830
  var PointerWheel = defineComponent("PointerWheel", {
663
- dx: field4("f32", { default: 0 }),
664
- dy: field4("f32", { default: 0 }),
665
- pinch: field4("f32", { default: 0 })
831
+ dx: field5("f32", { default: 0 }),
832
+ dy: field5("f32", { default: 0 }),
833
+ pinch: field5("f32", { default: 0 })
666
834
  });
667
- var PointerRadius = defineComponent("PointerRadius", { r: field4("f32", { default: 0 }) });
835
+ var PointerRadius = defineComponent("PointerRadius", { r: field5("f32", { default: 0 }) });
668
836
  var WentDown = defineTag("WentDown");
669
837
  var WentUp = defineTag("WentUp");
670
838
  var WentCancelled = defineTag("WentCancelled");
@@ -672,18 +840,18 @@ var HandledByWidget = defineTag("HandledByWidget");
672
840
  var OverInteractive = defineTag("OverInteractive");
673
841
  var LocalPointer = defineTag("LocalPointer");
674
842
  var PointerWorld = defineComponent("PointerWorld", {
675
- x: field4("f64", { default: 0 }),
676
- y: field4("f64", { default: 0 })
843
+ x: field5("f64", { default: 0 }),
844
+ y: field5("f64", { default: 0 })
677
845
  });
678
846
  var Keyboard = defineResource("Keyboard", {
679
- shift: field4("bool", { default: false }),
680
- ctrl: field4("bool", { default: false }),
681
- alt: field4("bool", { default: false }),
682
- meta: field4("bool", { default: false }),
683
- space: field4("bool", { default: false })
847
+ shift: field5("bool", { default: false }),
848
+ ctrl: field5("bool", { default: false }),
849
+ alt: field5("bool", { default: false }),
850
+ meta: field5("bool", { default: false }),
851
+ space: field5("bool", { default: false })
684
852
  });
685
853
  var CancelRequest = defineResource("CancelRequest", {
686
- active: field4("bool", { default: false })
854
+ active: field5("bool", { default: false })
687
855
  });
688
856
  var Targets = defineRelation("Targets", { arity: "one" });
689
857
  var TouchesExact = defineRelation("TouchesExact", { arity: "one" });
@@ -733,44 +901,44 @@ function definePhaseSet(name, phases) {
733
901
  }
734
902
 
735
903
  // ../core/src/catalog/gesture.ts
736
- import { field as field5 } from "@vibecook/strata-ecs";
904
+ import { field as field6 } from "@vibecook/strata-ecs";
737
905
  var Drag = defineComponent("Drag", {
738
- startX: field5("f64", { default: 0 }),
739
- startY: field5("f64", { default: 0 }),
740
- totalX: field5("f32", { default: 0 }),
741
- totalY: field5("f32", { default: 0 }),
742
- velX: field5("f32", { default: 0 }),
743
- velY: field5("f32", { default: 0 }),
744
- zoomAtClaim: field5("f32", { default: 1 })
906
+ startX: field6("f64", { default: 0 }),
907
+ startY: field6("f64", { default: 0 }),
908
+ totalX: field6("f32", { default: 0 }),
909
+ totalY: field6("f32", { default: 0 }),
910
+ velX: field6("f32", { default: 0 }),
911
+ velY: field6("f32", { default: 0 }),
912
+ zoomAtClaim: field6("f32", { default: 1 })
745
913
  });
746
914
  var Tap = defineComponent("Tap", {
747
- downAt: field5("f64", { default: 0 }),
748
- count: field5("u32", { default: 0 })
915
+ downAt: field6("f64", { default: 0 }),
916
+ count: field6("u32", { default: 0 })
749
917
  });
750
918
  var LongPress = defineComponent("LongPress", {
751
- downAt: field5("f64", { default: 0 }),
752
- startX: field5("f64", { default: 0 }),
753
- startY: field5("f64", { default: 0 }),
754
- curX: field5("f64", { default: 0 }),
755
- curY: field5("f64", { default: 0 })
919
+ downAt: field6("f64", { default: 0 }),
920
+ startX: field6("f64", { default: 0 }),
921
+ startY: field6("f64", { default: 0 }),
922
+ curX: field6("f64", { default: 0 }),
923
+ curY: field6("f64", { default: 0 })
756
924
  });
757
925
  var Pinch = defineComponent("Pinch", {
758
- startDist: field5("f32", { default: 0 }),
759
- startZoom: field5("f32", { default: 1 }),
760
- cx: field5("f64", { default: 0 }),
761
- cy: field5("f64", { default: 0 }),
762
- zoomAtClaim: field5("f32", { default: 1 })
926
+ startDist: field6("f32", { default: 0 }),
927
+ startZoom: field6("f32", { default: 1 }),
928
+ cx: field6("f64", { default: 0 }),
929
+ cy: field6("f64", { default: 0 }),
930
+ zoomAtClaim: field6("f32", { default: 1 })
763
931
  });
764
932
  var WheelPan = defineComponent("WheelPan", {
765
- dx: field5("f32", { default: 0 }),
766
- dy: field5("f32", { default: 0 }),
767
- anchorX: field5("f32", { default: 0 }),
768
- anchorY: field5("f32", { default: 0 })
933
+ dx: field6("f32", { default: 0 }),
934
+ dy: field6("f32", { default: 0 }),
935
+ anchorX: field6("f32", { default: 0 }),
936
+ anchorY: field6("f32", { default: 0 })
769
937
  });
770
938
  var WheelZoom = defineComponent("WheelZoom", {
771
- pinch: field5("f32", { default: 0 }),
772
- anchorX: field5("f32", { default: 0 }),
773
- anchorY: field5("f32", { default: 0 })
939
+ pinch: field6("f32", { default: 0 }),
940
+ anchorX: field6("f32", { default: 0 }),
941
+ anchorY: field6("f32", { default: 0 })
774
942
  });
775
943
  var GesturePhases = definePhaseSet("Gesture", [
776
944
  "Possible",
@@ -798,9 +966,9 @@ var RoutedMarquee = defineTag("RoutedMarquee");
798
966
  var RoutedPan = defineTag("RoutedPan");
799
967
  var RoutedDraw = defineTag("RoutedDraw");
800
968
  var MultiTap = defineComponent("MultiTap", {
801
- max: field5("u32", { default: 2 }),
802
- windowMs: field5("f32", { default: GESTURE_DEFAULTS.multiTapWindowMs }),
803
- slopPx: field5("f32", { default: GESTURE_DEFAULTS.multiTapSlopPx })
969
+ max: field6("u32", { default: 2 }),
970
+ windowMs: field6("f32", { default: GESTURE_DEFAULTS.multiTapWindowMs }),
971
+ slopPx: field6("f32", { default: GESTURE_DEFAULTS.multiTapSlopPx })
804
972
  });
805
973
  var Watches = defineRelation("Watches", { arity: "many" });
806
974
  var Sequence = defineRelation("Sequence", { arity: "one" });
@@ -822,8 +990,8 @@ var Grab = defineComponent("Grab", {
822
990
  ord: "f64"
823
991
  });
824
992
  var SnapState = defineComponent("SnapState", {
825
- dx: field5("f32", { default: 0 }),
826
- dy: field5("f32", { default: 0 })
993
+ dx: field6("f32", { default: 0 }),
994
+ dy: field6("f32", { default: 0 })
827
995
  });
828
996
  var Down = defineComponent("Down", { x: "f64", y: "f64", ms: "f64" });
829
997
  var OverlapCandidate = defineTag("OverlapCandidate");
@@ -834,14 +1002,14 @@ var TransformTween = defineComponent("TransformTween", {
834
1002
  toX: "f64",
835
1003
  toY: "f64",
836
1004
  durationMs: "f32",
837
- elapsedMs: field5("f32", { default: 0 })
1005
+ elapsedMs: field6("f32", { default: 0 })
838
1006
  });
839
1007
 
840
1008
  // ../core/src/catalog/insert.ts
841
- import { field as field6 } from "@vibecook/strata-ecs";
1009
+ import { field as field7 } from "@vibecook/strata-ecs";
842
1010
  var InsertGhost = defineComponent("InsertGhost", {
843
1011
  type: "string",
844
- props: field6("string", { default: "{}" }),
1012
+ props: field7("string", { default: "{}" }),
845
1013
  screenX: "f32",
846
1014
  screenY: "f32"
847
1015
  });
@@ -849,7 +1017,7 @@ var GhostCommitted = defineTag("GhostCommitted");
849
1017
  var GhostRetiring = defineTag("GhostRetiring");
850
1018
 
851
1019
  // ../core/src/catalog/selection-presence.ts
852
- import { enumOf as enumOf4, field as field7 } from "@vibecook/strata-ecs";
1020
+ import { enumOf as enumOf5, field as field8 } from "@vibecook/strata-ecs";
853
1021
  var Selected = defineTag("Selected");
854
1022
  var Selectable = defineTag("Selectable");
855
1023
  var Movable = defineTag("Movable");
@@ -860,99 +1028,18 @@ var SweepsContained = defineTag("SweepsContained");
860
1028
  var PresencePeer = defineTag("PresencePeer");
861
1029
  var PresenceInfo = defineComponent("PresenceInfo", { name: "string", color: "string" });
862
1030
  var PresenceCursor = defineComponent("PresenceCursor", {
863
- x: field7("f64", { default: 0 }),
864
- y: field7("f64", { default: 0 }),
865
- device: enumOf4(["mouse", "touch", "pen"])
866
- });
867
- var SelectionSummary = defineComponent("SelectionSummary", {
868
- count: field7("u16", { default: 0 }),
869
- x: field7("f64", { default: 0 }),
870
- y: field7("f64", { default: 0 }),
871
- w: field7("f32", { default: 0 }),
872
- h: field7("f32", { default: 0 }),
873
- keys: field7("string", { default: "[]" })
874
- });
875
-
876
- // ../core/src/catalog/camera-derived.ts
877
- import { enumOf as enumOf5, field as field8 } from "@vibecook/strata-ecs";
878
- var Camera = defineResource("Camera", {
879
- x: field8("f64", { default: 0 }),
880
- y: field8("f64", { default: 0 }),
881
- zoom: field8("f32", { default: 1 }),
882
- gesturing: field8("bool", { default: false })
883
- });
884
- var Viewport = defineResource("Viewport", {
885
- w: field8("f32", { default: 0 }),
886
- h: field8("f32", { default: 0 }),
887
- dpr: field8("f32", { default: 1 })
888
- });
889
- var ActiveTool = defineResource("ActiveTool", { id: field8("string", { default: "select" }) });
890
- var StageMode = defineResource("StageMode", {
891
- backgroundHolds: field8("u32", { default: 0 })
892
- });
893
- var SnapConfig = defineResource("SnapConfig", {
894
- enabled: field8("bool", { default: SNAP_DEFAULTS.enabled }),
895
- thresholdPx: field8("f32", { default: SNAP_DEFAULTS.thresholdPx })
896
- });
897
- var ContainerCamera = defineComponent("ContainerCamera", {
898
- x: field8("f64", { default: 0 }),
899
- y: field8("f64", { default: 0 }),
900
- zoom: field8("f32", { default: 1 })
901
- });
902
- var Active = defineTag("Active");
903
- var Visible = defineTag("Visible");
904
- var Culled = defineTag("Culled");
905
- var WidgetBreakpoint = defineComponent("WidgetBreakpoint", {
906
- tier: field8(enumOf5(["micro", "compact", "normal", "expanded", "detailed"]), { default: "normal" }),
907
- w: field8("u16", { default: 0 }),
908
- h: field8("u16", { default: 0 })
909
- });
910
- var MeasuredSize = defineComponent("MeasuredSize", {
911
- w: field8("f32", { default: 0 }),
912
- h: field8("f32", { default: 0 })
913
- });
914
- var SelectionBox = defineComponent("SelectionBox", {
915
1031
  x: field8("f64", { default: 0 }),
916
1032
  y: field8("f64", { default: 0 }),
917
- w: field8("f32", { default: 0 }),
918
- h: field8("f32", { default: 0 })
1033
+ device: enumOf5(["mouse", "touch", "pen"])
919
1034
  });
920
- var HandleSpec = defineComponent("HandleSpec", {
921
- anchor: enumOf5(["nw", "n", "ne", "e", "se", "s", "sw", "w"])
922
- });
923
- var GuideLine = defineComponent("GuideLine", {
924
- axis: enumOf5(["x", "y"]),
925
- at: field8("f64", { default: 0 }),
926
- from: field8("f64", { default: 0 }),
927
- to: field8("f64", { default: 0 })
928
- });
929
- var SpacingBar = defineComponent("SpacingBar", {
930
- axis: enumOf5(["x", "y"]),
931
- from: field8("f64", { default: 0 }),
932
- to: field8("f64", { default: 0 }),
933
- perp: field8("f64", { default: 0 }),
934
- gap: field8("f32", { default: 0 })
935
- });
936
- var MarqueeBox = defineComponent("MarqueeBox", {
1035
+ var SelectionSummary = defineComponent("SelectionSummary", {
1036
+ count: field8("u16", { default: 0 }),
937
1037
  x: field8("f64", { default: 0 }),
938
1038
  y: field8("f64", { default: 0 }),
939
1039
  w: field8("f32", { default: 0 }),
940
- h: field8("f32", { default: 0 })
941
- });
942
- var CursorVisual = defineComponent("CursorVisual", {
943
- kind: enumOf5(["local", "remote"]),
944
- pressed: field8("bool", { default: false })
945
- });
946
- var Follows = defineRelation("Follows", { arity: "one" });
947
- var VisualOf = defineRelation("VisualOf", { arity: "one" });
948
- var NavDepth = defineComponent("NavDepth", { d: field8("u8", { default: 0 }) });
949
- var NavCamera = defineComponent("NavCamera", {
950
- x: field8("f64", { default: 0 }),
951
- y: field8("f64", { default: 0 }),
952
- zoom: field8("f32", { default: 1 })
1040
+ h: field8("f32", { default: 0 }),
1041
+ keys: field8("string", { default: "[]" })
953
1042
  });
954
- var NavFrame = defineRelation("NavFrame", { arity: "one" });
955
- var CanvasSurface = defineTag("CanvasSurface");
956
1043
 
957
1044
  // ../core/src/catalog/settings-resources.ts
958
1045
  import { field as field9 } from "@vibecook/strata-ecs";
@@ -5300,6 +5387,28 @@ function installInteractionStack(engine, opts = {}) {
5300
5387
  };
5301
5388
  }
5302
5389
 
5390
+ // ../core/src/interaction/gesture-status.ts
5391
+ import { Any as Any4, defineQuery as defineQuery25 } from "@vibecook/strata-ecs";
5392
+ var gestureQ = defineQuery25([Any4(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
5393
+ var P13 = GesturePhases;
5394
+ function anyGestureNonTerminal(world) {
5395
+ let active = false;
5396
+ world.query(gestureQ).each((b) => {
5397
+ for (const r of b) {
5398
+ const e = b.entity(r);
5399
+ const terminal = world.hasTag(e, P13.tags.Failed) || world.hasTag(e, P13.tags.Cancelled) || world.hasTag(e, P13.tags.Ended) || world.hasTag(e, P13.tags.Recognized) && world.has(e, Tap);
5400
+ if (!terminal) {
5401
+ active = true;
5402
+ return;
5403
+ }
5404
+ }
5405
+ });
5406
+ return active;
5407
+ }
5408
+ function isMidGesture(world) {
5409
+ return world.getResource(Camera)?.gesturing === true || anyGestureNonTerminal(world);
5410
+ }
5411
+
5303
5412
  // ../core/src/doc/envelope.ts
5304
5413
  var ENVELOPE_MAGIC = "ICE1";
5305
5414
  var ENVELOPE_VERSION = 1;
@@ -5432,9 +5541,9 @@ function gateVerdict(report) {
5432
5541
  }
5433
5542
 
5434
5543
  // ../core/src/doc/migrate.ts
5435
- import { defineQuery as defineQuery25 } from "@vibecook/strata-ecs";
5544
+ import { defineQuery as defineQuery26 } from "@vibecook/strata-ecs";
5436
5545
  var PACK_PREFIX2 = "engine.pack.";
5437
- var allDurableQ = defineQuery25([PrefabId]);
5546
+ var allDurableQ = defineQuery26([PrefabId]);
5438
5547
  function runMigrations(ctx, report) {
5439
5548
  const { store, world } = ctx;
5440
5549
  const migrated = [];
@@ -5512,10 +5621,10 @@ import { LoroDoc } from "loro-crdt";
5512
5621
  import { attachDurable, createDurableStore } from "@vibecook/strata-ecs/durable";
5513
5622
 
5514
5623
  // ../core/src/doc/schema-migrate.ts
5515
- import { defineQuery as defineQuery26 } from "@vibecook/strata-ecs";
5624
+ import { defineQuery as defineQuery27 } from "@vibecook/strata-ecs";
5516
5625
  var SCHEMA_PREFIX2 = "engine.schema.";
5517
5626
  var BOARD_ROOT_META = "engine.boardRoot";
5518
- var allDurableQ2 = defineQuery26([PrefabId]);
5627
+ var allDurableQ2 = defineQuery27([PrefabId]);
5519
5628
  function ensureBoardRoot(world, store) {
5520
5629
  let recorded;
5521
5630
  store.metaTransaction((meta) => {
@@ -5880,8 +5989,8 @@ var p = {
5880
5989
  };
5881
5990
 
5882
5991
  // ../core/src/widget/equip.ts
5883
- import { Not as Not4, defineQuery as defineQuery27, defineSystem as defineSystem17 } from "@vibecook/strata-ecs";
5884
- var unequippedQ = defineQuery27([PrefabId, Not4(WidgetEquipped)]);
5992
+ import { Not as Not4, defineQuery as defineQuery28, defineSystem as defineSystem17 } from "@vibecook/strata-ecs";
5993
+ var unequippedQ = defineQuery28([PrefabId, Not4(WidgetEquipped)]);
5885
5994
  function createWidgetEquipSystem() {
5886
5995
  return defineSystem17(
5887
5996
  unequippedQ,
@@ -5975,8 +6084,8 @@ function createMeasureIngest(world, queue) {
5975
6084
  }
5976
6085
 
5977
6086
  // ../core/src/widget/mount-store.ts
5978
- import { Not as Not5, defineQuery as defineQuery29, defineTickSystem as defineTickSystem13 } from "@vibecook/strata-ecs";
5979
- var widgetQ = defineQuery29([Position, Size, WidgetEquipped, Active]);
6087
+ import { Not as Not5, defineQuery as defineQuery30, defineTickSystem as defineTickSystem13 } from "@vibecook/strata-ecs";
6088
+ var widgetQ = defineQuery30([Position, Size, WidgetEquipped, Active]);
5980
6089
  function createWidgetRuntime(world, opts = {}) {
5981
6090
  const budget = opts.keepMounted ?? RUNTIME_BUDGETS.keepMountedWidgets;
5982
6091
  let lastWin = null;
@@ -6059,8 +6168,8 @@ function createWidgetRuntime(world, opts = {}) {
6059
6168
  let snapshot = [];
6060
6169
  let dirty = false;
6061
6170
  const listeners = /* @__PURE__ */ new Set();
6062
- const visibleWidgetsQ = defineQuery29([Position, Size, WidgetEquipped, Active, Visible]);
6063
- const culledWidgetsQ = defineQuery29([Position, Size, WidgetEquipped, Not5(Visible)]);
6171
+ const visibleWidgetsQ = defineQuery30([Position, Size, WidgetEquipped, Active, Visible]);
6172
+ const culledWidgetsQ = defineQuery30([Position, Size, WidgetEquipped, Not5(Visible)]);
6064
6173
  const mountGuard = makeChurnGuard(world, { tags: [Visible, Culled], coarse: false });
6065
6174
  const mountSystem = defineTickSystem13(
6066
6175
  (ctx) => {
@@ -6204,23 +6313,6 @@ var DEFAULT_SNAP_GUIDES_CONFIG = {
6204
6313
  };
6205
6314
 
6206
6315
  // ../core/src/doc/autosave.ts
6207
- import { Any as Any4, defineQuery as defineQuery30 } from "@vibecook/strata-ecs";
6208
- var gestureQ = defineQuery30([Any4(Tap, LongPress, Drag, Pinch, WheelPan, WheelZoom)]);
6209
- var P13 = GesturePhases;
6210
- function anyGestureNonTerminal(world) {
6211
- let active = false;
6212
- world.query(gestureQ).each((b) => {
6213
- for (const r of b) {
6214
- const e = b.entity(r);
6215
- const terminal = world.hasTag(e, P13.tags.Failed) || world.hasTag(e, P13.tags.Cancelled) || world.hasTag(e, P13.tags.Ended) || world.hasTag(e, P13.tags.Recognized) && world.has(e, Tap);
6216
- if (!terminal) {
6217
- active = true;
6218
- return;
6219
- }
6220
- }
6221
- });
6222
- return active;
6223
- }
6224
6316
  function defaultSchedule(fn, ms) {
6225
6317
  const id = setTimeout(fn, ms);
6226
6318
  return () => clearTimeout(id);
@@ -6251,7 +6343,7 @@ function startAutosave(session, opts) {
6251
6343
  let pendingUpdates = [];
6252
6344
  let writing = false;
6253
6345
  let writeInFlight = Promise.resolve();
6254
- const deferred = () => world.getResource(Camera)?.gesturing === true || anyGestureNonTerminal(world);
6346
+ const deferred = () => isMidGesture(world);
6255
6347
  const clearTimer = () => {
6256
6348
  if (cancelTimer !== void 0) {
6257
6349
  cancelTimer();
@@ -7439,6 +7531,14 @@ function createCanvasEngine(opts = {}) {
7439
7531
  isBackgrounded: () => stageHolds.size > 0,
7440
7532
  holds: () => [...stageHolds.values()]
7441
7533
  };
7534
+ engine.frame.settleWhile("gestures", () => isMidGesture(world));
7535
+ engine.frame.onChange(() => {
7536
+ if (engine.frame.isFrozen()) {
7537
+ cancelActiveGestures(world);
7538
+ return;
7539
+ }
7540
+ stack.queue.drain();
7541
+ });
7442
7542
  return {
7443
7543
  world,
7444
7544
  engine,
@@ -7448,6 +7548,7 @@ function createCanvasEngine(opts = {}) {
7448
7548
  ops,
7449
7549
  docs,
7450
7550
  stage,
7551
+ frame: engine.frame,
7451
7552
  budgets,
7452
7553
  step: (now) => engine.step(now),
7453
7554
  dispose() {
@@ -7502,9 +7603,35 @@ export {
7502
7603
  PHASE_GROUPS,
7503
7604
  createPipelineRegistry,
7504
7605
  createReflectorRegistry,
7505
- createEngine,
7606
+ Camera,
7607
+ Viewport,
7608
+ ActiveTool,
7609
+ StageMode,
7610
+ FrameMode,
7611
+ SnapConfig,
7612
+ ContainerCamera,
7613
+ Active,
7614
+ Visible,
7615
+ Culled,
7616
+ WidgetBreakpoint,
7617
+ MeasuredSize,
7618
+ SelectionBox,
7619
+ HandleSpec,
7620
+ GuideLine,
7621
+ SpacingBar,
7622
+ MarqueeBox,
7623
+ CursorVisual,
7624
+ Follows,
7625
+ VisualOf,
7626
+ NavDepth,
7627
+ NavCamera,
7628
+ NavFrame,
7629
+ CanvasSurface,
7506
7630
  setDevGuards,
7507
7631
  devGuardsEnabled,
7632
+ SETTLE_CAP,
7633
+ createFrameControl,
7634
+ createEngine,
7508
7635
  createLiveWriter,
7509
7636
  guardedTransaction,
7510
7637
  writeRuntimeResource,
@@ -7600,29 +7727,6 @@ export {
7600
7727
  PresenceInfo,
7601
7728
  PresenceCursor,
7602
7729
  SelectionSummary,
7603
- Camera,
7604
- Viewport,
7605
- ActiveTool,
7606
- StageMode,
7607
- SnapConfig,
7608
- ContainerCamera,
7609
- Active,
7610
- Visible,
7611
- Culled,
7612
- WidgetBreakpoint,
7613
- MeasuredSize,
7614
- SelectionBox,
7615
- HandleSpec,
7616
- GuideLine,
7617
- SpacingBar,
7618
- MarqueeBox,
7619
- CursorVisual,
7620
- Follows,
7621
- VisualOf,
7622
- NavDepth,
7623
- NavCamera,
7624
- NavFrame,
7625
- CanvasSurface,
7626
7730
  ChromeSettings,
7627
7731
  GestureSettings,
7628
7732
  PointerSettings,
@@ -7684,6 +7788,8 @@ export {
7684
7788
  ensureCanvasSurface,
7685
7789
  installInteractionCore,
7686
7790
  installInteractionStack,
7791
+ anyGestureNonTerminal,
7792
+ isMidGesture,
7687
7793
  ENVELOPE_MAGIC,
7688
7794
  ENVELOPE_VERSION,
7689
7795
  ENGINE_SCHEMA_VERSION,
@@ -7733,4 +7839,4 @@ export {
7733
7839
  Local2 as Local,
7734
7840
  DurableUndoStatus
7735
7841
  };
7736
- //# sourceMappingURL=chunk-DXU3RZZS.js.map
7842
+ //# sourceMappingURL=chunk-5QY7HK6G.js.map