@vibecook/ice 0.1.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 (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/chunk-5S7GSXJG.js +6003 -0
  4. package/dist/chunk-5S7GSXJG.js.map +1 -0
  5. package/dist/chunk-BCJ47SX7.js +550 -0
  6. package/dist/chunk-BCJ47SX7.js.map +1 -0
  7. package/dist/chunk-FIAXPNNY.js +1446 -0
  8. package/dist/chunk-FIAXPNNY.js.map +1 -0
  9. package/dist/devtools.js +417 -0
  10. package/dist/devtools.js.map +1 -0
  11. package/dist/dom.js +41 -0
  12. package/dist/dom.js.map +1 -0
  13. package/dist/index.js +450 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/kernel.js +63 -0
  16. package/dist/kernel.js.map +1 -0
  17. package/dist/r3f.js +1101 -0
  18. package/dist/r3f.js.map +1 -0
  19. package/dist/react.js +440 -0
  20. package/dist/react.js.map +1 -0
  21. package/dist/types/packages/core/src/boot/hmr.d.ts +12 -0
  22. package/dist/types/packages/core/src/catalog/camera-derived.d.ts +144 -0
  23. package/dist/types/packages/core/src/catalog/gesture.d.ts +254 -0
  24. package/dist/types/packages/core/src/catalog/graph.d.ts +55 -0
  25. package/dist/types/packages/core/src/catalog/index.d.ts +32 -0
  26. package/dist/types/packages/core/src/catalog/pointer.d.ts +111 -0
  27. package/dist/types/packages/core/src/catalog/scene.d.ts +34 -0
  28. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +53 -0
  29. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +46 -0
  30. package/dist/types/packages/core/src/doc/autosave.d.ts +69 -0
  31. package/dist/types/packages/core/src/doc/bootstrap.d.ts +74 -0
  32. package/dist/types/packages/core/src/doc/broadcast-relay.d.ts +52 -0
  33. package/dist/types/packages/core/src/doc/channels.d.ts +49 -0
  34. package/dist/types/packages/core/src/doc/doc-commit-sink.d.ts +22 -0
  35. package/dist/types/packages/core/src/doc/doc-kit.d.ts +50 -0
  36. package/dist/types/packages/core/src/doc/envelope.d.ts +36 -0
  37. package/dist/types/packages/core/src/doc/migrate.d.ts +69 -0
  38. package/dist/types/packages/core/src/doc/version-gate.d.ts +49 -0
  39. package/dist/types/packages/core/src/engine/commit-sink.d.ts +61 -0
  40. package/dist/types/packages/core/src/engine/engine.d.ts +62 -0
  41. package/dist/types/packages/core/src/engine/frame-info.d.ts +16 -0
  42. package/dist/types/packages/core/src/engine/instantiate.d.ts +45 -0
  43. package/dist/types/packages/core/src/engine/pipeline.d.ts +17 -0
  44. package/dist/types/packages/core/src/engine/reflectors.d.ts +56 -0
  45. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +120 -0
  46. package/dist/types/packages/core/src/guards/dev.d.ts +2 -0
  47. package/dist/types/packages/core/src/guards/guarded-tx.d.ts +51 -0
  48. package/dist/types/packages/core/src/guards/live-writer.d.ts +33 -0
  49. package/dist/types/packages/core/src/guards/resource-writer.d.ts +17 -0
  50. package/dist/types/packages/core/src/helpers/phase-set.d.ts +70 -0
  51. package/dist/types/packages/core/src/helpers/version-stamps.d.ts +55 -0
  52. package/dist/types/packages/core/src/index.d.ts +63 -0
  53. package/dist/types/packages/core/src/input/measure-queue.d.ts +30 -0
  54. package/dist/types/packages/core/src/input/queue.d.ts +60 -0
  55. package/dist/types/packages/core/src/interaction/install.d.ts +58 -0
  56. package/dist/types/packages/core/src/nav/nested-canvas.d.ts +62 -0
  57. package/dist/types/packages/core/src/ops/cascade.d.ts +18 -0
  58. package/dist/types/packages/core/src/ops/claims.d.ts +15 -0
  59. package/dist/types/packages/core/src/ops/gestures.d.ts +10 -0
  60. package/dist/types/packages/core/src/ops/point-pick.d.ts +42 -0
  61. package/dist/types/packages/core/src/ops/port-geometry.d.ts +17 -0
  62. package/dist/types/packages/core/src/ops/selection.d.ts +14 -0
  63. package/dist/types/packages/core/src/presence/index.d.ts +7 -0
  64. package/dist/types/packages/core/src/presence/presence-kit.d.ts +39 -0
  65. package/dist/types/packages/core/src/presence/publish.d.ts +14 -0
  66. package/dist/types/packages/core/src/presence/remote-cursors.d.ts +18 -0
  67. package/dist/types/packages/core/src/schema/meta.d.ts +43 -0
  68. package/dist/types/packages/core/src/schema/prefab.d.ts +69 -0
  69. package/dist/types/packages/core/src/settings/defaults.d.ts +56 -0
  70. package/dist/types/packages/core/src/systems/camera-sim.d.ts +19 -0
  71. package/dist/types/packages/core/src/systems/chrome.d.ts +48 -0
  72. package/dist/types/packages/core/src/systems/cleanup.d.ts +19 -0
  73. package/dist/types/packages/core/src/systems/l0-input.d.ts +31 -0
  74. package/dist/types/packages/core/src/systems/l1-pick.d.ts +44 -0
  75. package/dist/types/packages/core/src/systems/l1-wires.d.ts +30 -0
  76. package/dist/types/packages/core/src/systems/l2-arbitrate.d.ts +40 -0
  77. package/dist/types/packages/core/src/systems/l2-recognize.d.ts +45 -0
  78. package/dist/types/packages/core/src/systems/l3-behave.d.ts +24 -0
  79. package/dist/types/packages/core/src/systems/l3-claim.d.ts +26 -0
  80. package/dist/types/packages/core/src/systems/l3-connect.d.ts +57 -0
  81. package/dist/types/packages/core/src/systems/l3-draw.d.ts +21 -0
  82. package/dist/types/packages/core/src/systems/l3-drop.d.ts +21 -0
  83. package/dist/types/packages/core/src/systems/l3-marquee.d.ts +35 -0
  84. package/dist/types/packages/core/src/systems/l3-ports.d.ts +30 -0
  85. package/dist/types/packages/core/src/systems/l3-resize.d.ts +17 -0
  86. package/dist/types/packages/core/src/systems/l3-snap.d.ts +19 -0
  87. package/dist/types/packages/core/src/systems/l4-cursor.d.ts +24 -0
  88. package/dist/types/packages/core/src/systems/measure-ingest.d.ts +26 -0
  89. package/dist/types/packages/core/src/tools/define-tool.d.ts +79 -0
  90. package/dist/types/packages/core/src/widget/define-widget.d.ts +124 -0
  91. package/dist/types/packages/core/src/widget/equip.d.ts +14 -0
  92. package/dist/types/packages/core/src/widget/mount-store.d.ts +47 -0
  93. package/dist/types/packages/core/src/widget/props.d.ts +98 -0
  94. package/dist/types/packages/core/src/widget/spawn.d.ts +30 -0
  95. package/dist/types/packages/devtools/src/index.d.ts +8 -0
  96. package/dist/types/packages/devtools/src/panel.d.ts +48 -0
  97. package/dist/types/packages/dom/src/host.d.ts +24 -0
  98. package/dist/types/packages/dom/src/index.d.ts +19 -0
  99. package/dist/types/packages/dom/src/loop.d.ts +11 -0
  100. package/dist/types/packages/dom/src/measure-adapter.d.ts +31 -0
  101. package/dist/types/packages/dom/src/measure-wiring.d.ts +49 -0
  102. package/dist/types/packages/dom/src/planes.d.ts +33 -0
  103. package/dist/types/packages/dom/src/pointer-adapter.d.ts +48 -0
  104. package/dist/types/packages/dom/src/reflectors/chrome.d.ts +33 -0
  105. package/dist/types/packages/dom/src/reflectors/cursor.d.ts +21 -0
  106. package/dist/types/packages/dom/src/reflectors/dom-widgets.d.ts +54 -0
  107. package/dist/types/packages/dom/src/reflectors/graybox.d.ts +31 -0
  108. package/dist/types/packages/dom/src/reflectors/grid.d.ts +63 -0
  109. package/dist/types/packages/dom/src/reflectors/plane-transform.d.ts +38 -0
  110. package/dist/types/packages/dom/src/reflectors/remote-cursors.d.ts +20 -0
  111. package/dist/types/packages/dom/src/reflectors/wires.d.ts +88 -0
  112. package/dist/types/packages/ice/src/devtools.d.ts +1 -0
  113. package/dist/types/packages/ice/src/dom.d.ts +1 -0
  114. package/dist/types/packages/ice/src/index.d.ts +1 -0
  115. package/dist/types/packages/ice/src/kernel.d.ts +1 -0
  116. package/dist/types/packages/ice/src/r3f.d.ts +1 -0
  117. package/dist/types/packages/ice/src/react.d.ts +1 -0
  118. package/dist/types/packages/kernel/src/anchors.d.ts +18 -0
  119. package/dist/types/packages/kernel/src/bezier.d.ts +38 -0
  120. package/dist/types/packages/kernel/src/coords.d.ts +67 -0
  121. package/dist/types/packages/kernel/src/eviction.d.ts +23 -0
  122. package/dist/types/packages/kernel/src/index.d.ts +13 -0
  123. package/dist/types/packages/kernel/src/shapes.d.ts +22 -0
  124. package/dist/types/packages/kernel/src/snap.d.ts +44 -0
  125. package/dist/types/packages/kernel/src/spatial-index.d.ts +16 -0
  126. package/dist/types/packages/kernel/src/zoom-bands.d.ts +19 -0
  127. package/dist/types/packages/r3f/src/bridge.d.ts +68 -0
  128. package/dist/types/packages/r3f/src/composite-material.d.ts +17 -0
  129. package/dist/types/packages/r3f/src/compositor-pass.d.ts +83 -0
  130. package/dist/types/packages/r3f/src/dev-write-trap.d.ts +30 -0
  131. package/dist/types/packages/r3f/src/gl-root.d.ts +21 -0
  132. package/dist/types/packages/r3f/src/gl-router.d.ts +60 -0
  133. package/dist/types/packages/r3f/src/index.d.ts +16 -0
  134. package/dist/types/packages/r3f/src/island-state.d.ts +68 -0
  135. package/dist/types/packages/r3f/src/island.d.ts +13 -0
  136. package/dist/types/packages/r3f/src/pool.d.ts +56 -0
  137. package/dist/types/packages/r3f/src/resource-registry.d.ts +30 -0
  138. package/dist/types/packages/r3f/src/use-island-frame.d.ts +24 -0
  139. package/dist/types/packages/react/src/engine-context.d.ts +31 -0
  140. package/dist/types/packages/react/src/hooks.d.ts +40 -0
  141. package/dist/types/packages/react/src/index.d.ts +14 -0
  142. package/dist/types/packages/react/src/infinite-canvas.d.ts +71 -0
  143. package/dist/types/packages/react/src/keymap.d.ts +42 -0
  144. package/dist/types/packages/react/src/use-commit.d.ts +35 -0
  145. package/dist/types/packages/react/src/use-presence.d.ts +23 -0
  146. package/dist/types/packages/react/src/use-tool.d.ts +4 -0
  147. package/dist/types/packages/react/src/widget-root.d.ts +33 -0
  148. package/package.json +112 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Chrome derive systems (design-004 §5 chrome plane, §8 LOD; `derive` phase).
3
+ *
4
+ * Two systems, both derive-scheduled, both write change-only:
5
+ *
6
+ * `selectionChrome` — maintains POOLED chrome entities mirroring the current
7
+ * `Selected` set: ONE selection-box entity + 8 resize-handle entities. The box
8
+ * entity carries ONLY the `SelectionBox` value (x,y,w,h = the union bbox); the
9
+ * handles carry Position + Size + `HandleSpec{anchor}` + `VisualOf → box`.
10
+ *
11
+ * HANDLE PICKING (the point of the design): handles carry a world AABB, so the
12
+ * `react`-phase `spatialSync` indexes them automatically and `picking` resolves
13
+ * a corner grab to the handle (HandleSpec has pick priority) → `dragRoute`
14
+ * routes `RoutedResize` → `resizeBehavior` runs. Nothing here touches the index.
15
+ *
16
+ * HANDLES ARE SCREEN-CONSTANT: a handle's world size is `HANDLE_PICK_PX / zoom`
17
+ * so its on-screen hit target stays ~constant across zoom. The tradeoff: the
18
+ * handles must be recomputed whenever the camera zoom changes, so this system
19
+ * runs every frame a selection exists and rewrites the 8 handles' Position/Size
20
+ * change-only (a zoom change restamps 8 entities — small, bounded N; §5's
21
+ * "screen-space, recomputed on camera dirt, small N").
22
+ *
23
+ * THE BOX IS DELIBERATELY NOT PICKABLE. It stores its rect in the `SelectionBox`
24
+ * value, NOT in Position/Size, so `spatialSync` (which indexes [Position,Size])
25
+ * never sees it. design-003 §3's pick priority lists ONLY HandleSpec chrome as
26
+ * pickable; indexing the box would make it a widget-class pick (it has Position)
27
+ * and let a center-of-selection click be grabbed by `moveClaim`. (This diverges
28
+ * from a literal reading of the M6 brief's "Position+Size+SelectionBox" — the
29
+ * box's geometry lives on the `SelectionBox` value instead; the chrome reflector
30
+ * reads it from there.)
31
+ *
32
+ * POOL LIFECYCLE: entities spawn once via `ctx` (runtime prefab class) when a
33
+ * selection appears and are reaped via `ctx.destroy` when it empties. On the
34
+ * spawn frame the handles are still identity-only (placement defers to the
35
+ * phase boundary), so their initial geometry rides the `ctx.spawn` payload and
36
+ * the change-only `edit().set` updates begin the next frame.
37
+ *
38
+ * `breakpoint` — `WidgetBreakpoint{tier,w,h}` from a widget's EFFECTIVE size
39
+ * (`MeasuredSize` where auto-sized and >0, else `Size`), width-thresholded into
40
+ * 5 tiers with ±10% boundary hysteresis. Added lazily (on `WidgetEquipped`
41
+ * widgets, once measured) and thereafter written ONLY when the tier changes —
42
+ * the LOD signal must be stable within a tier so the measure→tier→content→
43
+ * measure loop converges (§2). The stored w,h are the effective size at the
44
+ * tier transition (what the tier "was computed from").
45
+ */
46
+ import type { System, TickSystem, World } from "@vibecook/strata-ecs";
47
+ export declare function createSelectionChromeSystem(world: World): TickSystem;
48
+ export declare function createBreakpointSystem(_world: World): System;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * cleanup phase — nothing transient crosses frames (design-002 §2; design-003
3
+ * §4.1 reap, §8 CancelRequest one-tick rule).
4
+ *
5
+ * `recognizerReap` destroys terminal recognizers at terminal +1 frame: a Just*
6
+ * marker means the transition happened THIS tick (markers clear later this
7
+ * phase, but ctx reads are pre-flush) — no marker means the tag has lingered a
8
+ * full frame and every edge-triggered consumer has run. `ClaimedBy`/`Watches`/
9
+ * `Captures`/`Drags` edges auto-clear with the despawn.
10
+ *
11
+ * `oneTickClear` then clears pointer transition tags, zeroes wheel deltas,
12
+ * clears all Just* markers, and consumes CancelRequest (a latched cancel would
13
+ * kill every future gesture forever).
14
+ */
15
+ import { type System, type World } from "@vibecook/strata-ecs";
16
+ export declare function createCleanupSystems(world: World): {
17
+ recognizerReap: System;
18
+ oneTickClear: System;
19
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * L0 — pointers & ingest (design-003 §2; `input` phase).
3
+ *
4
+ * Order inside the phase is load-bearing:
5
+ *
6
+ * `pointerLifecycle` runs BEFORE `pointerIngest` and reads only immediate
7
+ * values: a touch pointer whose buttons are still 0 at the top of a frame has
8
+ * been idle-up for a full frame (ingest zeroed buttons on the up frame), so its
9
+ * `ctx.destroy` lands at the input flush of frame up+1 — recognizers saw the up
10
+ * frame's `WentUp` in full. Tag-based detection cannot work in-phase (ingest's
11
+ * one-tick tags are deferred to the flush), hence values.
12
+ *
13
+ * `pointerIngest` is scheduled on the CANVAS-SURFACE anchor query (exactly one
14
+ * such entity, guaranteed by install) because a system body only runs when its
15
+ * query matches — and ingest must run on frames where no pointer entity exists
16
+ * yet (the first down CREATES the pointer). It drains the queue once per tick
17
+ * in two passes: fold events into per-pointer samples, then apply — existing
18
+ * pointers get immediate value writes + deferred one-tick tags; NEW pointers
19
+ * spawn once with their folded final state (an identity-only `ctx.spawn` handle
20
+ * cannot take `edit().set`). Facts are always true: `surfaceHandled` events
21
+ * still land, but carry the one-tick `HandledByWidget` tag L1/L2 read (the
22
+ * pinned widget-event contract, design-002 §8).
23
+ */
24
+ import type { System, TickSystem, World } from "@vibecook/strata-ecs";
25
+ import type { InputQueue } from "../input/queue";
26
+ export interface L0Systems {
27
+ pointerLifecycle: System;
28
+ pointerIngest: TickSystem;
29
+ pointerWorldSync: System;
30
+ }
31
+ export declare function createL0Systems(world: World, queue: InputQueue): L0Systems;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * L1 — spatial sync + targeting (design-003 §3; `react` phase).
3
+ *
4
+ * Two systems, run in this order:
5
+ *
6
+ * `spatialSync` maintains the kernel `SpatialIndex` over every Position+Size
7
+ * entity (widgets AND HandleSpec chrome — both carry a world AABB). It is a
8
+ * TICK system (strata 0.5.0) so the body runs EVERY frame — it is the writer
9
+ * that bumps
10
+ * `SpatialVersion`, and its own writes have no version stamp to gate on
11
+ * (design-002 §4), so it must run eagerly and stays cheap via a private
12
+ * last-known cache: an entity is re-`upsert`ed only when its AABB actually
13
+ * changed, and a cache-sweep removes entries no longer matched (despawns, or a
14
+ * lost Position/Size). Materialized ports are M8 — skipped.
15
+ *
16
+ * `picking` runs the dual pick (design-003 §3), gated by a version guard over
17
+ * `PointerVersion ∨ SpatialVersion`. `CameraVersion` does not exist — camera
18
+ * motion alone does not re-pick, an accepted staleness (design-002 §2). Pointer
19
+ * world position is derived from PointerScreen × Camera rather than the
20
+ * PointerWorld cell: PointerWorld lags a frame on the pointer's spawn (the
21
+ * pointerWorldSync writer cannot see a pointer spawned in the same input phase),
22
+ * which would mis-capture on the down frame — screen×camera is exact here.
23
+ * - `Targets` = radiused disc-vs-box pick with a screen-px release
24
+ * dead-band (hover is forgiving; hold the current target
25
+ * while the pointer stays within its expanded bounds).
26
+ * - `TouchesExact` = r=0 point pick (grab is precise; no dead-band).
27
+ * Pick priority is plane priority: HandleSpec chrome first, then widgets by
28
+ * StackZ descending, then the CanvasSurface entity as the guaranteed fallback
29
+ * (design-001 §4). Relations are written change-only (design-002 §4 hygiene).
30
+ * Wires/ports are M8 — skipped.
31
+ */
32
+ import type { Entity, System, TickSystem, World } from "@vibecook/strata-ecs";
33
+ import { SpatialIndex } from "@ice/kernel";
34
+ import { type WirePickSource } from "../ops/point-pick";
35
+ export interface PickingSystems {
36
+ spatialSync: TickSystem;
37
+ picking: System;
38
+ /** The shared spatial index — snap/drop/marquee consume the SAME instance. */
39
+ index: SpatialIndex<Entity>;
40
+ /** Nav-op seam (design-004 §7): forget every last-known AABB so the next
41
+ * spatialSync pass repopulates the cleared index from the new Active set. */
42
+ clearCaches(): void;
43
+ }
44
+ export declare function createPickingSystems(world: World, index?: SpatialIndex<Entity>, wires?: WirePickSource): PickingSystems;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * L1 — wire geometry sync (design-004 §6 ports & wires runtime; `react` phase,
3
+ * AFTER `spatialSync`).
4
+ *
5
+ * A wire is a durable reified edge (Wire tag + WireFrom/WireTo → widgets +
6
+ * WirePorts ids). Its RENDER + PICK geometry is a pure function of the two
7
+ * endpoint widget rects and their port declarations (design-001 §5.3: geometry
8
+ * never reads a port entity — culled endpoints resolve by construction). This
9
+ * TICK system (strata 0.5.0) recomputes each wire's cubic once per frame and
10
+ * keeps a private cache so the shared spatial index only churns on real
11
+ * movement — exactly the `spatialSync` idiom, and the reason it must run every
12
+ * frame: it is a `SpatialVersion` writer and cannot gate on the version it bumps.
13
+ *
14
+ * Per wire: resolve WireFrom/WireTo → endpoint Position+Size + the port slot
15
+ * (PrefabId → widget registry → decl → kernel `portAnchor`) → `wireCubic` →
16
+ * `cubicAABB`. Endpoint or declaration unresolvable (mid-projection, a despawned
17
+ * widget, a removed port id) ⇒ the wire leaves the index (invisible to picking;
18
+ * the renderer draws nothing for it). The cache also feeds the `WirePickSource`
19
+ * the point-pick narrow-phases against (`ops/point-pick`), and exposes the
20
+ * screen-constant pick slop as `slopWorld = wirePickSlopPx / zoom`.
21
+ */
22
+ import type { Entity, TickSystem, World } from "@vibecook/strata-ecs";
23
+ import { type SpatialIndex } from "@ice/kernel";
24
+ import type { WirePickSource } from "../ops/point-pick";
25
+ export interface WireSyncSystem {
26
+ wireSync: TickSystem;
27
+ /** The narrow-phase source `pickTopAt` consults for wire entries. */
28
+ wires: WirePickSource;
29
+ }
30
+ export declare function createWireSync(world: World, index: SpatialIndex<Entity>): WireSyncSystem;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * L2 — arbitration + routing (design-003 §4.3–§4.4; `ctl:arbitrate`).
3
+ *
4
+ * Arbitration rule (v2-proven, generalized): the first recognizer to enter a
5
+ * claiming phase (`Active` for continuous, `Recognized` for discrete) claims
6
+ * every pointer it watches; same-frame ties resolve by priority
7
+ * Pinch > Drag > LongPress > Tap; every other non-terminal, non-`Simultaneous`,
8
+ * non-suspended recognizer watching a claimed pointer → `Failed`. The claim is
9
+ * world state: `ClaimedBy(pointer → recognizer)` (Law 4). DEV asserts at most
10
+ * one ClaimedBy write per pointer per pass (`setRelation` is silent last-wins —
11
+ * a mis-ordered arbitration would otherwise be undetectable).
12
+ *
13
+ * `dragRoute` — the ONE pan/marquee/move decision, latched at Drag activation
14
+ * via route tags; the route never changes mid-gesture (design-003 §4.4).
15
+ */
16
+ import type { System } from "@vibecook/strata-ecs";
17
+ export declare function createArbitrationSystems(): {
18
+ arbitration: System;
19
+ dragRoute: System;
20
+ };
21
+ /** Wheel recognizers never claim; exported so tests can assert the invariant set. */
22
+ export declare const NEVER_CLAIMS: readonly [import("@vibecook/strata-ecs").Component<import("@vibecook/strata-ecs").ValueOf<{
23
+ readonly dx: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
24
+ readonly dy: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
25
+ readonly anchorX: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
26
+ readonly anchorY: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
27
+ }>, {
28
+ readonly dx: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
29
+ readonly dy: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
30
+ readonly anchorX: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
31
+ readonly anchorY: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
32
+ }>, import("@vibecook/strata-ecs").Component<import("@vibecook/strata-ecs").ValueOf<{
33
+ readonly pinch: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
34
+ readonly anchorX: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
35
+ readonly anchorY: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
36
+ }>, {
37
+ readonly pinch: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
38
+ readonly anchorX: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
39
+ readonly anchorY: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
40
+ }>];
@@ -0,0 +1,45 @@
1
+ /**
2
+ * L2 — recognizer lifecycle + per-kind FSMs (design-003 §4.1–§4.2).
3
+ *
4
+ * `ctl:spawn` — cancelSweep (consumes the one-tick CancelRequest) →
5
+ * recognizerSpawn (tool profiles; pinch on 2nd touch suspends
6
+ * singles; wheel recognizers are `Simultaneous`) →
7
+ * recognizerIntegrity (requiredWatches counts, capture death,
8
+ * suspension lift). Newborns are identity-only until the
9
+ * ctl:spawn flush, so integrity naturally skips them until the
10
+ * next frame — by which time their edges are placed.
11
+ * `ctl:recognize` — per-kind systems. Transitions go through the PhaseSet via
12
+ * `ctx` (visible at this phase's flush — arbitration reads them
13
+ * the same frame); field updates are immediate `edit().set`
14
+ * under declared `access.write`.
15
+ *
16
+ * All timing reads FrameInfo.now (the engine clock); all thresholds read
17
+ * the GestureSettings RESOURCE (live-tunable, design-005 §4) with the
18
+ * GESTURE_DEFAULTS constants as the unset fallback. Gesture math is screen-space totals + zoom-at-claim — never
19
+ * live PointerWorld (design-002 §2 staleness rule).
20
+ */
21
+ import type { World } from "@vibecook/strata-ecs";
22
+ import { type System } from "@vibecook/strata-ecs";
23
+ export type SingleKindName = "tap" | "longPress" | "drag";
24
+ /** Tool id → single-pointer recognizer set spawned per down (design-003 §4.1). */
25
+ export type SpawnProfiles = Readonly<Record<string, readonly SingleKindName[]>>;
26
+ export declare const DEFAULT_SPAWN_PROFILES: SpawnProfiles;
27
+ export interface L2Deps {
28
+ readonly world: World;
29
+ readonly profiles?: SpawnProfiles;
30
+ }
31
+ export interface L2Systems {
32
+ cancelSweep: System;
33
+ recognizerSpawn: System;
34
+ /** Same design slot as recognizerSpawn (design-002 §2) over the wheel-source query. */
35
+ wheelSpawn: System;
36
+ recognizerIntegrity: System;
37
+ tapSystem: System;
38
+ longPressSystem: System;
39
+ dragSystem: System;
40
+ pinchSystem: System;
41
+ wheelSystem: System;
42
+ /** Resolves Pending `Sequence`/`RequiresFail` edges; last in `ctl:recognize`. */
43
+ dependencySystem: System;
44
+ }
45
+ export declare function createL2Systems({ world, profiles }: L2Deps): L2Systems;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * L3 — select + move behaviors (design-003 §5 items 1, 3, 5; `ctl:behave`).
3
+ *
4
+ * The behavior contract (design-003 §5): read riders/edges attached at
5
+ * ctl:claim; per frame (persistent `Active`) apply ABSOLUTE live writes from
6
+ * rider origins + gesture totals; on `JustEnded` emit ONE commit (through the
7
+ * CommitSink seam — M5 swaps in the doc transaction); on `JustCancelled`
8
+ * restore from riders — Position AND StackZ (a forgotten StackZ restore leaves
9
+ * the cell diverged forever); remove riders and gesture-scoped edges on every
10
+ * terminal path. Discrete actions edge-trigger on `Just*` markers only.
11
+ *
12
+ * Move outcome tree (design-003 §5.5, three-way via dropSystem's signals):
13
+ * DropTarget + OverlapCandidate on the container → CONSUME (reparent intent);
14
+ * DropTarget without OverlapCandidate → FLY-BACK (no commit; TransformTween
15
+ * rider per widget — the tween HOLDS the claim, design-001 §3 amended);
16
+ * no DropTarget → COMMIT (final Position + StackZ per live Drags edge).
17
+ * Without dropSystem installed no DropTarget ever exists ⇒ plain commits.
18
+ */
19
+ import type { System, World } from "@vibecook/strata-ecs";
20
+ import type { CommitSink } from "../engine/commit-sink";
21
+ export declare function createSelectMoveBehaviors(world: World, sink: CommitSink): {
22
+ selectBehavior: System;
23
+ moveBehavior: System;
24
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ctl:claim — the rider settle point (design-003 §4.5).
3
+ *
4
+ * This sub-phase exists for exactly one reason: riders (`Grab`) and edges
5
+ * (`Drags`) attached via `ctx` must be readable by the behaviors that consume
6
+ * them ON THE CLAIM FRAME — without it, the first mutation lags a frame and a
7
+ * claim-frame `read(w, Grab)` throws (design-003 review C1).
8
+ *
9
+ * `moveClaim` (JustActive × RoutedMove): select-on-grab, `Drags` edges over the
10
+ * dragged set, `Grab` per widget with the CURRENT Position/Size/StackZ embedded
11
+ * in the command payload, and the StackZ elevate (an immediate value write —
12
+ * part of the gesture divergence, restored from `Grab.z` on cancel).
13
+ *
14
+ * `resizeClaim` (JustActive × RoutedResize): `Drags` + `Grab` over the Selected
15
+ * ∧ Resizable set; the anchor lives on the captured handle's `HandleSpec` — no
16
+ * extra state.
17
+ *
18
+ * Same-widget double-grab guard: a widget already in another recognizer's
19
+ * `Drags` set is skipped (first gesture owns it) — two `ctx.addComponent(Grab)`
20
+ * for one widget in one frame would hit strata's flush-time duplicate policy.
21
+ */
22
+ import type { System, World } from "@vibecook/strata-ecs";
23
+ export declare function createClaimSystems(world: World): {
24
+ moveClaim: System;
25
+ resizeClaim: System;
26
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * L3 — connect behavior (design-003 §5 item 8, §4.5 connectClaim; design-004 §6;
3
+ * `ctl:claim` + `ctl:behave`). The node-editor core gesture: drag from a source
4
+ * port to a compatible target port, commit ONE wire.
5
+ *
6
+ * `connectClaim` (JustActive × RoutedConnect): latch the source port — the
7
+ * recognizer's `Captures` target must be a Port entity (dragRoute guarantees it,
8
+ * or the connect tool started the drag). Recognizer field-sets are per-kind
9
+ * (Drag), so per-gesture claim state lives in a closure Map keyed by recognizer
10
+ * (the `tweenStart`/camera-sim precedent), holding the source WIDGET + port id +
11
+ * world anchor + accepts-keys. The preview buffer arms here.
12
+ *
13
+ * `connectBehavior` (a TICK system, like marquee, so it can CLEAR the preview the
14
+ * frame after the gesture ends): per Active frame it writes the out-of-ECS
15
+ * `WirePreviewBuffer` (source anchor → pointer world, snapped to a COMPATIBLE
16
+ * port anchor when the watched pointer `Targets` one; type check via the widgets'
17
+ * port decls; self-wire never compatible). On `JustEnded` over a compatible port
18
+ * it commits `{kind:"connect", wires:[{from,to,fromPort,toPort}]}` (the doc sink
19
+ * spawns the wire); elsewhere it commits nothing.
20
+ *
21
+ * PREVIEW CONTINUITY — SIMPLIFICATION ACCEPTED (design-003 §5.8 / design-002 §8):
22
+ * the preview clears on JustEnded+1 (one linger frame) rather than persisting
23
+ * until the projected wire entity places (the promote-sweep analog). Full
24
+ * continuity — hand the preview off to the freshly-synced wire with no blink —
25
+ * is polish deferred; the one-frame gap is invisible in practice.
26
+ */
27
+ import type { Entity, System, TickSystem, World } from "@vibecook/strata-ecs";
28
+ import { type SpatialIndex } from "@ice/kernel";
29
+ import type { CommitSink } from "../engine/commit-sink";
30
+ import type { WirePickSource } from "../ops/point-pick";
31
+ /**
32
+ * The out-of-ECS connect preview (design-004 §6; the marquee-buffer precedent).
33
+ * `sx,sy` = source port world anchor; `tx,ty` = the projected endpoint (pointer
34
+ * world, or a snapped compatible-port anchor); `compatible` gates the landing.
35
+ */
36
+ export interface WirePreviewBuffer {
37
+ active: boolean;
38
+ compatible: boolean;
39
+ sx: number;
40
+ sy: number;
41
+ tx: number;
42
+ ty: number;
43
+ }
44
+ export interface ConnectSystems {
45
+ connectClaim: System;
46
+ connectBehavior: TickSystem;
47
+ previewBuffer: WirePreviewBuffer;
48
+ }
49
+ /**
50
+ * Signature carries the full graph-slice wiring (design brief) though connect
51
+ * reads only `Targets` today:
52
+ * @param _world reserved (systems reach world state via `ctx`).
53
+ * @param _index reserved (future: a fresh event-time port pick to drop the
54
+ * one-frame `Targets` staleness on snapping — the router's pattern).
55
+ * @param _wires reserved (the wire narrow-phase source; connect reads `Targets`).
56
+ */
57
+ export declare function createConnectSystems(_world: World, sink: CommitSink, _index: SpatialIndex<Entity>, _wires: WirePickSource): ConnectSystems;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * L3 — draw behavior (design-005 §3 `draw(widgetType)` tool; `ctl:behave`,
3
+ * after connect, before camera — design-003 §5 order).
4
+ *
5
+ * A `RoutedDraw` drag creates ONE widget from the release rect: at
6
+ * `JustEnded`, screen start+total → world rect (Camera at release), floored
7
+ * at the widget's `minSize`; a sub-slop release (a click) places the
8
+ * widget's DEFAULT size centered on the point. Commit is one `create`
9
+ * intent through the sink — the doc sink spawns via the same override
10
+ * builder as `ops.spawnWidget`, so the two paths can never diverge.
11
+ * Cancel/fail commit nothing. The widget type comes from the ACTIVE tool's
12
+ * `draw` config (latched per drag at claim would be stricter; tools switch
13
+ * via `ops.setTool` which cancels active gestures first, so the active
14
+ * tool is stable for a live drag by construction).
15
+ *
16
+ * Mid-drag rect preview is recorded polish (design-001 §3's full
17
+ * draft→promote protocol is the vNext shape); v1 draws nothing until release.
18
+ */
19
+ import type { System, World } from "@vibecook/strata-ecs";
20
+ import type { CommitSink } from "../engine/commit-sink";
21
+ export declare function createDrawBehavior(world: World, sink: CommitSink): System;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * L3 — drop candidate detection (design-003 §5 item 4; `ctl:behave`, ordered
3
+ * AFTER moveBehavior so it tests POST-move bounds).
4
+ *
5
+ * For Active `RoutedMove` drags: spatial-query the dragged union bounds for
6
+ * `Container` widgets (∉dragged), pick the topmost by StackZ, and publish two
7
+ * signals the move-outcome tree consumes (l3-behave §5.5):
8
+ * - `DropTarget(recognizer → container)` — set for the container under the
9
+ * bounds REGARDLESS of an accepts-match (so the outcome tree can distinguish
10
+ * a rejected drop from a plain move).
11
+ * - `OverlapCandidate` on the container — ONLY when the container's `Accepts`
12
+ * intersects the dragged set's `Provides` (a widget with no `Provides` never
13
+ * matches; RFC-004 contracts).
14
+ * BOTH are strictly change-only: `setRelation`/`addTag` bump the GLOBAL tag/
15
+ * relation version, and any churn wakes every row-filtered observer world-wide
16
+ * (design-002 §4). Both clear when no container is under the bounds; the move
17
+ * behavior clears them on every terminal path.
18
+ */
19
+ import type { Entity, System, World } from "@vibecook/strata-ecs";
20
+ import type { SpatialIndex } from "@ice/kernel";
21
+ export declare function createDropSystem(world: World, index: SpatialIndex<Entity>): System;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * L3 — marquee behavior (design-003 §5 item 7, §5.7; `ctl:behave`). Rider-free.
3
+ *
4
+ * Two entry paths, one system (anchored on the CanvasSurface entity so the body
5
+ * runs EVERY frame — the preview must clear the frame the gesture ends):
6
+ * - desktop: an Active `RoutedMarquee` Drag — rect from `Drag.start + total`
7
+ * (screen), both corners converted to world via the kernel seam.
8
+ * - touch: a Recognized `LongPress` capturing the canvas, riding its
9
+ * continuous tail — rect from `start → cur` (§4.2, v2's proven path; no
10
+ * `Sequence` machinery).
11
+ * Per frame the hit ENTITY SET goes into an out-of-ECS render buffer
12
+ * (`MarqueeBuffer`, recomputed each frame — preview-as-tags would churn the
13
+ * global tag version, design-003 §5.7). Selection commits ONCE at terminal
14
+ * (`JustEnded`): replace with the hits, or union when the watched pointer holds
15
+ * shift; `SelectionVersion` bumps once (the v1 marquee lesson). No `access.write`
16
+ * — reads + the buffer + ctx selection tags only.
17
+ *
18
+ * Camera staleness: both corners convert with the CURRENT camera, so a mid-
19
+ * marquee camera move re-projects the rect (accepted — design-002 §2).
20
+ */
21
+ import type { Entity, TickSystem, World } from "@vibecook/strata-ecs";
22
+ import { type SpatialIndex } from "@ice/kernel";
23
+ /** The out-of-ECS marquee preview (design-003 §5.7): rect + hit set, recomputed each frame. */
24
+ export interface MarqueeBuffer {
25
+ rect: {
26
+ x: number;
27
+ y: number;
28
+ w: number;
29
+ h: number;
30
+ } | null;
31
+ hits: Entity[];
32
+ }
33
+ export declare function createMarqueeBehavior(world: World, index: SpatialIndex<Entity>): TickSystem & {
34
+ buffer: MarqueeBuffer;
35
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * L3 — port materialization (design-004 §6 ports & wires runtime; `derive`
3
+ * phase, BEFORE `selectionChrome`). The LOCKED gating from design-004 §6 /
4
+ * design-001 §5.3: port ENTITIES are runtime and on-demand, so steady-state
5
+ * pan/zoom with the select tool spawns ZERO ports.
6
+ *
7
+ * Three triggers materialize a widget's declared ports (registry decl → kernel
8
+ * `portAnchor`; a port carries Port + PortAnchor + PortOf → widget, and NO
9
+ * Position/Size — `spatialSync` must never see it; design-004 §6, the
10
+ * SelectionBox precedent). Because ports carry no Position/Size, this system
11
+ * gives them their OWN tiny world AABB in the shared spatial index so they are
12
+ * pickable (design-003 §3 port tier):
13
+ * (a) connect tool → widgets in viewport+overscan (`200/zoom`); materialize at
14
+ * the overscan band, keep across a ×1.5 hysteresis band;
15
+ * (b) any local pointer `Targets` a ported widget → that widget's ports;
16
+ * (c) an Active `RoutedConnect` drag → COMPATIBLE ports (accepts-key
17
+ * intersection with the source port; empty accepts = wildcard) light up
18
+ * STAGED by distance-to-pointer, capped to the nearest 256 within the
19
+ * `portLightUpRadiusPx` screen radius (rev 2: "all visible" at a 10k
20
+ * zoomed-out view meant multi-second fills + sustained pick churn).
21
+ *
22
+ * Spawn budget ≤ `portSpawnPerFrame` (64) per frame — staging spreads a big
23
+ * light-up across frames. A widget's ports reap when every trigger lapsed for
24
+ * `portReapGraceMs`, or immediately if the widget died. Anchors recompute each
25
+ * frame and rewrite Port entities + index entries CHANGE-ONLY (a still widget
26
+ * churns nothing). `SpatialVersion` bumps only on a real index change.
27
+ */
28
+ import type { Entity, TickSystem, World } from "@vibecook/strata-ecs";
29
+ import { type SpatialIndex } from "@ice/kernel";
30
+ export declare function createPortMaterialize(world: World, index: SpatialIndex<Entity>): TickSystem;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * L3 — resize behavior (design-003 §5 item 6; `ctl:behave`).
3
+ *
4
+ * A drag captured on a `HandleSpec` chrome entity (route `RoutedResize`, riders
5
+ * attached by `resizeClaim` §4.5). Per Active frame it writes ABSOLUTE Position+
6
+ * Size for every live `Drags` target from its `Grab` origin + `Drag.total /
7
+ * zoomAtClaim`, resized about the FIXED opposite edge/corner of the grabbed
8
+ * handle (`n`/`s` height-only, `e`/`w` width-only, corners both). Modifiers ride
9
+ * the watched pointer's `PointerMods`: `alt` = resize about center, `shift` =
10
+ * preserve aspect (corner handles). Min size clamps to 1×1. `JustEnded` emits ONE
11
+ * `resize` commit (Position+Size per live target); `JustCancelled`/`JustFailed`
12
+ * restore from `Grab`. Every terminal path removes `Grab` and the `Drags` edges
13
+ * (mirrors l3-behave's clearGestureState; resize has no DropTarget).
14
+ */
15
+ import type { System, World } from "@vibecook/strata-ecs";
16
+ import type { CommitSink } from "../engine/commit-sink";
17
+ export declare function createResizeBehavior(world: World, sink: CommitSink): System;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * L3 — snap (design-003 §5 item 2, §6; `ctl:behave`, ordered BEFORE moveBehavior).
3
+ *
4
+ * For Active `RoutedMove` drags whose dragged set is a `SnapSource`: compute the
5
+ * intended PRE-SNAP rect as `Grab.origin + Drag.total / zoomAtClaim`, unioned
6
+ * over the dragged widgets — NEVER last-applied `Position` (one frame stale ⇒
7
+ * guide-chasing oscillation, design-003 §5.2 red-team; `Grab` is readable here
8
+ * thanks to the ctl:claim settle point, §4.5). Candidates come from the SHARED
9
+ * spatial index (rect query = intended bounds expanded by threshold, filtered to
10
+ * `SnapTarget ∧ ∉dragged`; Visible filtering waits for cull). Threshold is
11
+ * `thresholdPx / zoomAtClaim` (screen-constant). The kernel `computeSnapGuides`
12
+ * does the Figma math; we write `SnapState{dx,dy}` on the recognizer (moveBehavior
13
+ * adds it to the absolute write). Guide CHROME entities (`GuideLine`) are deferred
14
+ * to the chrome-reflector milestone — SnapState only here. SnapState clears to 0,0
15
+ * when snap is off / no source / no candidate.
16
+ */
17
+ import type { Entity, System, World } from "@vibecook/strata-ecs";
18
+ import { type SpatialIndex } from "@ice/kernel";
19
+ export declare function createSnapSystem(world: World, index: SpatialIndex<Entity>): System;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * L4 — cursor projection (design-003 §7; `derive` phase).
3
+ *
4
+ * Memoryless: resolved fresh every run from live world state, priority order
5
+ * (1) any LOCAL pointer with a live `ClaimedBy` — Drag+RoutedMove or a
6
+ * LongPress in Recognized → "grabbing"; RoutedResize → directional resize by
7
+ * the captured handle's `HandleSpec.anchor`; RoutedPan → "grabbing";
8
+ * (2) `ActiveTool` override — pan tool → "grab"; (3) else the mouse pointer's
9
+ * `Targets` kind — a `HandleSpec` → directional resize, an entity with
10
+ * `Position` (widget) → "default", `CanvasSurface`/none → "default".
11
+ *
12
+ * Scheduled on the `CanvasSurface` anchor query (exactly one such entity,
13
+ * guaranteed by install — the same idiom `pointerIngest` uses in l0-input.ts)
14
+ * so the body runs every frame even on tool switches with no pointer motion;
15
+ * `world.query(...)` inside then does the actual local-pointer scan (mirrors
16
+ * `oneTickClear`'s marker sweep in cleanup.ts).
17
+ *
18
+ * The resolved string is closure state; `readCursor()` exposes it — the DOM
19
+ * cursor reflector is the only consumer (core never touches DOM).
20
+ */
21
+ import type { System, World } from "@vibecook/strata-ecs";
22
+ export declare function createCursorSync(world: World): System & {
23
+ readCursor(): string;
24
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Measurement ingest (design-004 §2; `input` phase).
3
+ *
4
+ * Drains the {@link MeasureQueue} once per tick and folds each auto-sized
5
+ * widget's latest content-box measurement into the `MeasuredSize` session rider
6
+ * — the effective-size source cull/hit/breakpoint consume where a widget is
7
+ * auto-sized (`MeasuredSize` where present and >0, else `Size`). Auto-sized
8
+ * widgets never commit `Size`; the doc stores authorial intent only.
9
+ *
10
+ * Scheduled on the CANVAS-SURFACE anchor query (exactly one such entity,
11
+ * guaranteed by install) — like `pointerIngest` — because the body must run on
12
+ * frames where no measured widget exists yet, and a tag-only query matches every
13
+ * archetype-independent (a tick system, strata 0.5.0): the drain runs exactly
14
+ * once per frame BY CONSTRUCTION.
15
+ *
16
+ * Two guards keep a hidden widget's `display:none` collapse out of the rider
17
+ * (the §2 double wall): the adapter never enqueues a `0×0` sample, and ingest
18
+ * skips `w===0 && h===0` again here. Real changes clear a **±1 px dead-band**
19
+ * against the current rider so sub-pixel RO jitter never restamps (which would
20
+ * churn breakpoint/cull downstream). Within one drain, samples fold last-wins
21
+ * per entity so a same-tick pair never double-`addComponent`s (strata's
22
+ * flush-time duplicate policy).
23
+ */
24
+ import type { TickSystem, World } from "@vibecook/strata-ecs";
25
+ import type { MeasureQueue } from "../input/measure-queue";
26
+ export declare function createMeasureIngest(world: World, queue: MeasureQueue): TickSystem;