@vibecook/ice 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +37 -2
  2. package/dist/chunk-5SJYHQI4.js +636 -0
  3. package/dist/chunk-5SJYHQI4.js.map +1 -0
  4. package/dist/{chunk-5S7GSXJG.js → chunk-DXU3RZZS.js} +2913 -1180
  5. package/dist/chunk-DXU3RZZS.js.map +1 -0
  6. package/dist/{chunk-FIAXPNNY.js → chunk-IASTQMU5.js} +130 -551
  7. package/dist/chunk-IASTQMU5.js.map +1 -0
  8. package/dist/{chunk-BCJ47SX7.js → chunk-OR5FNVUE.js} +460 -1
  9. package/dist/chunk-OR5FNVUE.js.map +1 -0
  10. package/dist/devtools.js +508 -372
  11. package/dist/devtools.js.map +1 -1
  12. package/dist/dom.js +3 -11
  13. package/dist/ground.js +715 -0
  14. package/dist/ground.js.map +1 -0
  15. package/dist/index.js +70 -2
  16. package/dist/kernel.js +31 -1
  17. package/dist/r3f.js +599 -62
  18. package/dist/r3f.js.map +1 -1
  19. package/dist/react.js +34 -418
  20. package/dist/react.js.map +1 -1
  21. package/dist/types/packages/core/src/catalog/camera-derived.d.ts +41 -3
  22. package/dist/types/packages/core/src/catalog/gesture.d.ts +39 -3
  23. package/dist/types/packages/core/src/catalog/graph.d.ts +7 -6
  24. package/dist/types/packages/core/src/catalog/index.d.ts +1 -0
  25. package/dist/types/packages/core/src/catalog/insert.d.ts +31 -0
  26. package/dist/types/packages/core/src/catalog/pointer.d.ts +11 -0
  27. package/dist/types/packages/core/src/catalog/scene.d.ts +37 -4
  28. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +7 -0
  29. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +21 -0
  30. package/dist/types/packages/core/src/doc/autosave.d.ts +15 -2
  31. package/dist/types/packages/core/src/doc/bootstrap.d.ts +29 -0
  32. package/dist/types/packages/core/src/doc/channels.d.ts +9 -0
  33. package/dist/types/packages/core/src/doc/doc-commit-sink.d.ts +2 -1
  34. package/dist/types/packages/core/src/doc/doc-kit.d.ts +16 -1
  35. package/dist/types/packages/core/src/doc/envelope.d.ts +2 -1
  36. package/dist/types/packages/core/src/doc/migrate.d.ts +8 -6
  37. package/dist/types/packages/core/src/doc/schema-migrate.d.ts +50 -0
  38. package/dist/types/packages/core/src/doc/version-gate.d.ts +3 -0
  39. package/dist/types/packages/core/src/engine/commit-sink.d.ts +24 -2
  40. package/dist/types/packages/core/src/engine/frame-info.d.ts +16 -1
  41. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +70 -6
  42. package/dist/types/packages/core/src/guards/guarded-tx.d.ts +4 -2
  43. package/dist/types/packages/core/src/helpers/churn-guard.d.ts +40 -0
  44. package/dist/types/packages/core/src/index.d.ts +13 -7
  45. package/dist/types/packages/core/src/input/queue.d.ts +11 -0
  46. package/dist/types/packages/core/src/nav/nested-canvas.d.ts +47 -11
  47. package/dist/types/packages/core/src/ops/arrange.d.ts +15 -0
  48. package/dist/types/packages/core/src/ops/insert.d.ts +62 -0
  49. package/dist/types/packages/core/src/ops/point-pick.d.ts +11 -7
  50. package/dist/types/packages/core/src/ops/sibling-order.d.ts +70 -0
  51. package/dist/types/packages/core/src/schema/meta.d.ts +1 -0
  52. package/dist/types/packages/core/src/settings/defaults.d.ts +45 -0
  53. package/dist/types/packages/core/src/settings/ground-config.d.ts +55 -0
  54. package/dist/types/packages/core/src/systems/chrome.d.ts +6 -2
  55. package/dist/types/packages/core/src/systems/insert-ghost.d.ts +25 -0
  56. package/dist/types/packages/core/src/systems/l1-pick.d.ts +25 -11
  57. package/dist/types/packages/core/src/systems/l2-recognize.d.ts +10 -4
  58. package/dist/types/packages/core/src/systems/l3-behave.d.ts +6 -4
  59. package/dist/types/packages/core/src/systems/l3-claim.d.ts +7 -3
  60. package/dist/types/packages/core/src/systems/l3-drop.d.ts +3 -1
  61. package/dist/types/packages/core/src/systems/l3-resize.d.ts +3 -1
  62. package/dist/types/packages/core/src/systems/l3-snap.d.ts +25 -7
  63. package/dist/types/packages/core/src/systems/nav-flight.d.ts +95 -0
  64. package/dist/types/packages/core/src/widget/define-widget.d.ts +39 -0
  65. package/dist/types/packages/core/src/widget/mount-store.d.ts +11 -3
  66. package/dist/types/packages/core/src/widget/set-props.d.ts +16 -0
  67. package/dist/types/packages/core/src/widget/spawn.d.ts +21 -1
  68. package/dist/types/packages/devtools/src/attach.d.ts +77 -0
  69. package/dist/types/packages/devtools/src/dock.d.ts +38 -0
  70. package/dist/types/packages/devtools/src/gl-panel.d.ts +69 -0
  71. package/dist/types/packages/devtools/src/index.d.ts +8 -6
  72. package/dist/types/packages/dom/src/index.d.ts +1 -3
  73. package/dist/types/packages/dom/src/measure-wiring.d.ts +2 -2
  74. package/dist/types/packages/dom/src/pointer-adapter.d.ts +21 -1
  75. package/dist/types/packages/dom/src/reflectors/dom-widgets.d.ts +5 -0
  76. package/dist/types/packages/ground/src/index.d.ts +52 -0
  77. package/dist/types/packages/ground/src/layer.d.ts +40 -0
  78. package/dist/types/packages/ground/src/pass.d.ts +41 -0
  79. package/dist/types/packages/ground/src/passes/grid.d.ts +21 -0
  80. package/dist/types/packages/ground/src/passes/guides-collect.d.ts +14 -0
  81. package/dist/types/packages/ground/src/passes/guides.d.ts +3 -0
  82. package/dist/types/packages/ground/src/passes/soup-collect.d.ts +35 -0
  83. package/dist/types/packages/ground/src/passes/soup-mesh.d.ts +8 -0
  84. package/dist/types/packages/ground/src/passes/wires-collect.d.ts +31 -0
  85. package/dist/types/packages/ground/src/passes/wires.d.ts +10 -0
  86. package/dist/types/packages/ground/src/renderer.d.ts +15 -0
  87. package/dist/types/packages/ice/src/ground.d.ts +1 -0
  88. package/dist/types/packages/kernel/src/bezier.d.ts +15 -0
  89. package/dist/types/packages/kernel/src/coords.d.ts +15 -0
  90. package/dist/types/packages/kernel/src/easing.d.ts +11 -0
  91. package/dist/types/packages/kernel/src/index.d.ts +3 -0
  92. package/dist/types/packages/kernel/src/layout.d.ts +118 -0
  93. package/dist/types/packages/kernel/src/nav-flight.d.ts +93 -0
  94. package/dist/types/packages/r3f/src/bridge.d.ts +73 -12
  95. package/dist/types/packages/r3f/src/composite-material.d.ts +9 -0
  96. package/dist/types/packages/r3f/src/compositor-pass.d.ts +22 -0
  97. package/dist/types/packages/r3f/src/gl-root.d.ts +76 -1
  98. package/dist/types/packages/r3f/src/gl-router.d.ts +10 -0
  99. package/dist/types/packages/r3f/src/index.d.ts +3 -2
  100. package/dist/types/packages/r3f/src/island-state.d.ts +44 -0
  101. package/dist/types/packages/r3f/src/preview-capture.d.ts +19 -0
  102. package/dist/types/packages/r3f/src/self-sustain.d.ts +39 -0
  103. package/dist/types/packages/r3f/src/use-island-frame.d.ts +16 -1
  104. package/dist/types/packages/react/src/engine-context.d.ts +8 -0
  105. package/dist/types/packages/react/src/index.d.ts +4 -2
  106. package/dist/types/packages/react/src/infinite-canvas.d.ts +40 -6
  107. package/dist/types/packages/react/src/preview-snapshots.d.ts +17 -0
  108. package/dist/types/packages/react/src/widget-preview.d.ts +14 -0
  109. package/package.json +13 -8
  110. package/dist/chunk-5S7GSXJG.js.map +0 -1
  111. package/dist/chunk-BCJ47SX7.js.map +0 -1
  112. package/dist/chunk-FIAXPNNY.js.map +0 -1
  113. package/dist/types/packages/devtools/src/panel.d.ts +0 -48
  114. package/dist/types/packages/dom/src/reflectors/grid.d.ts +0 -63
  115. package/dist/types/packages/dom/src/reflectors/wires.d.ts +0 -88
@@ -21,7 +21,9 @@
21
21
  import type { Entity, World } from "@vibecook/strata-ecs";
22
22
  import { type Engine } from "../engine/engine";
23
23
  import { type InteractionStack } from "../interaction/install";
24
- import { type NestedCanvas } from "../nav/nested-canvas";
24
+ import { type NavOpts, type NestedCanvas } from "../nav/nested-canvas";
25
+ import { type ArrangeOpts } from "../ops/arrange";
26
+ import { type InsertByDragOpts } from "../ops/insert";
25
27
  import { type WidgetRuntime } from "../widget/mount-store";
26
28
  import { type SpawnWidgetOpts } from "../widget/spawn";
27
29
  import { type Tool } from "../tools/define-tool";
@@ -29,6 +31,7 @@ import { type DocSession, type DocSessionOpts, type OpenDocResult } from "../doc
29
31
  import { type JoinDocOpts, type JoinResult } from "../doc/bootstrap";
30
32
  import type { ByteChannel } from "../doc/channels";
31
33
  import { type Autosave, type AutosaveOpts, type AutosaveStorageWrite } from "../doc/autosave";
34
+ import { type PresenceSession } from "../presence/presence-kit";
32
35
  import type { MeasureQueue } from "../input/measure-queue";
33
36
  import { GESTURE_DEFAULTS, POINTER_DEFAULTS } from "../settings/defaults";
34
37
  export interface CanvasEngineOpts {
@@ -53,6 +56,10 @@ export interface CanvasEngineOpts {
53
56
  readonly enabled?: boolean;
54
57
  readonly thresholdPx?: number;
55
58
  };
59
+ /** Selection-chrome knobs: liftScale = the app's visual drag-lift scale (union box wraps it). */
60
+ readonly chrome?: {
61
+ readonly liftScale?: number;
62
+ };
56
63
  };
57
64
  readonly policy?: {
58
65
  /** The gate verdict a "migrate"-classified doc downgrades to when migration is off/fails. */
@@ -65,40 +72,96 @@ export interface CanvasOps {
65
72
  /** cancel active gestures → switch (design-003 §8; the strata-example lesson). */
66
73
  setTool(id: string): void;
67
74
  spawnWidget(type: string, opts: SpawnWidgetOpts): Entity;
75
+ /**
76
+ * Tray adoption (2026-07-19): DRAFT-spawn a runtime ghost of `type` centered
77
+ * under the pressing pointer and enqueue one synthetic down — the ordinary
78
+ * drag stack takes over (lift, snap, drop targets, folder consume). Release
79
+ * promotes it through ONE `create` tx (selected, one undo step); cancel or a
80
+ * rejected drop flies it back to the tray press point and despawns it with
81
+ * zero undo footprint. Call from the tray tile's `pointerdown` AFTER
82
+ * `stopPropagation()` (the down must not double-land via the adapter).
83
+ */
84
+ insertByDrag(type: string, opts: InsertByDragOpts): Entity;
85
+ /** Validated prop update: Standard-Schema-checked, json serialized, ONE tx (2026-07-13 review). */
86
+ setWidgetProps(entity: Entity, props: Readonly<Record<string, unknown>>): void;
68
87
  deleteSelection(): void;
69
88
  /** Twin spawns offset +16/+16; the clones become the selection. */
70
89
  duplicateSelection(): Entity[];
71
90
  setSelection(ids: readonly Entity[], mode?: "replace" | "add" | "toggle"): void;
72
91
  clearSelection(): void;
73
92
  selectAll(): void;
74
- /** StackZ sweep, one tx: selection (or ids) to top/bottom. */
93
+ /** Sibling-sequence sweep, one tx: the ids to the frame top/bottom (petition 8). */
75
94
  reorder(ids: readonly Entity[], mode: "top" | "bottom"): void;
95
+ /**
96
+ * Desktop-style Clean Up (kernel packLayout): tidy reading-order rows, one
97
+ * undo step, 240ms glide (durationMs: 0 snaps). Scope: ids > selection ≥2 >
98
+ * current nav frame. Returns the movers (empty = already tidy).
99
+ */
100
+ arrange(opts?: ArrangeOpts): Entity[];
76
101
  zoomToFit(ids?: readonly Entity[]): void;
102
+ /**
103
+ * The natural DEFAULT framing (2026-07-18): zoom-to-fit the current
104
+ * frame's widgets inside the FIT_DEFAULTS band (never past 100%, never
105
+ * below 50%, ∩ settings.zoom) — same band as the folder arrival camera.
106
+ * Returns false (camera untouched) until a real viewport AND content
107
+ * exist, so boot code can retry. zoomToFit stays the uncapped explicit
108
+ * "show me everything".
109
+ */
110
+ frameContent(): boolean;
77
111
  zoomTo(zoom: number, anchor?: {
78
112
  x: number;
79
113
  y: number;
80
114
  }): void;
81
115
  panTo(x: number, y: number): void;
82
- enterContainer(container: Entity): void;
83
- exitContainer(): void;
116
+ enterContainer(container: Entity, opts?: NavOpts): void;
117
+ exitContainer(opts?: NavOpts): void;
118
+ /** Pop several levels in ONE transition (breadcrumb jumps; design-006 §5). */
119
+ exitTo(targetDepth: number, opts?: NavOpts): void;
84
120
  cancelActiveGestures(): void;
85
121
  }
86
122
  export interface CanvasDocs {
87
123
  create(opts?: DocSessionOpts): DocSession;
88
124
  open(bytes: Uint8Array, opts?: DocSessionOpts): OpenDocResult;
89
- /** §6.5 bootstrap + optional presence sugar over the same channel. */
90
- join(channel: ByteChannel, opts?: Omit<JoinDocOpts, "presence"> & {
125
+ /**
126
+ * §6.5 bootstrap + optional presence sugar over the same channel. `signal`/
127
+ * `onSession` are facade-owned (supersede + re-bootstrap wiring) — track the
128
+ * live session through `docs.current()`. Rejects if another document is
129
+ * opened while the join is in flight.
130
+ */
131
+ join(channel: ByteChannel, opts?: Omit<JoinDocOpts, "presence" | "signal" | "onSession"> & {
91
132
  readonly presence?: {
92
133
  name: string;
93
134
  color: string;
94
135
  };
95
136
  }): Promise<JoinResult>;
96
137
  current(): DocSession | undefined;
138
+ /**
139
+ * The live presence session (the `join({presence})` sugar's attachment), or
140
+ * undefined when doc-less / presence-less. An INSPECTION seam — the devtools
141
+ * dock's ephemeral tab reads `presence().eph` (DevtoolsOpts.presence) —
142
+ * never a sync path; same contract as `DocSession.attachment`. Swaps with
143
+ * the doc lifecycle exactly like `current()`: set by join, cleared by close.
144
+ */
145
+ presence(): PresenceSession | undefined;
97
146
  close(): void;
98
147
  undo(): boolean;
99
148
  redo(): boolean;
100
149
  autosave(storage: AutosaveStorageWrite, opts?: Omit<AutosaveOpts, "storage" | "world">): Autosave;
101
150
  }
151
+ /**
152
+ * Stage presentation control (StageMode resource, 2026-07-19): app chrome
153
+ * that covers/recedes the canvas takes a refcounted, NAMED background hold —
154
+ * the disposer pattern makes overlay lifecycles leak-proof (release on
155
+ * unmount), the name makes "why isn't the canvas animating?" answerable.
156
+ * Rendering policy only — input/interactability stays the overlay's concern.
157
+ */
158
+ export interface StageControl {
159
+ /** Take a named background hold. Returns an IDEMPOTENT release. */
160
+ background(name: string): () => void;
161
+ isBackgrounded(): boolean;
162
+ /** Live hold names, in take order (debug/devtools). */
163
+ holds(): readonly string[];
164
+ }
102
165
  export interface CanvasEngine {
103
166
  readonly world: World;
104
167
  readonly engine: Engine;
@@ -109,6 +172,7 @@ export interface CanvasEngine {
109
172
  readonly nav: NestedCanvas;
110
173
  readonly ops: CanvasOps;
111
174
  readonly docs: CanvasDocs;
175
+ readonly stage: StageControl;
112
176
  readonly budgets: {
113
177
  readonly keepMounted: number;
114
178
  readonly fboBytes: number;
@@ -11,7 +11,7 @@
11
11
  * Tags are not eligibility-checked in M2 (essential tags spawn with the
12
12
  * prefab; optional-tag modeling is future work — documented).
13
13
  */
14
- import type { Component, Entity, Relation, Resource, Tag, World } from "@vibecook/strata-ecs";
14
+ import type { Component, Entity, OrderPlace, Relation, Resource, Tag, World } from "@vibecook/strata-ecs";
15
15
  import type { Mutator } from "@vibecook/strata-ecs/durable";
16
16
  import { type ComponentInit, type Prefab } from "../schema/prefab";
17
17
  export interface GuardedTx {
@@ -26,9 +26,11 @@ export interface GuardedTx {
26
26
  };
27
27
  addTag(e: Entity, t: Tag): void;
28
28
  removeTag(e: Entity, t: Tag): void;
29
- setRelation(e: Entity, r: Relation, target: Entity): void;
29
+ setRelation(e: Entity, r: Relation, target: Entity, place?: OrderPlace): void;
30
30
  addRelation(e: Entity, r: Relation, target: Entity): void;
31
31
  removeRelation(e: Entity, r: Relation, target?: Entity): void;
32
+ /** Reorder within the current parent's sibling sequence — ordered relations only (petition 8). */
33
+ moveRelation(e: Entity, r: Relation, place: OrderPlace): void;
32
34
  setResource<S>(res: Resource<S>, v: S): void;
33
35
  }
34
36
  interface GuardedEditor {
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Churn guard — the `runIf` half of the petition-7 gating pattern
3
+ * (design-002 §4 "guards live in runIf, never the body" × strata 0.7.0
4
+ * `world.changes`).
5
+ *
6
+ * `activeMembership` gates by draining a collector INSIDE its tick body
7
+ * (legal there: it declares no writes, so an early-out stamps nothing).
8
+ * Systems that DECLARE `access.write` cannot use that shape — strata
9
+ * blanket-stamps declared writes for any system that RUNS, even one that
10
+ * early-outs (see helpers/version-stamps.ts) — so their gate must be a real
11
+ * `runIf`. But a naive collector-in-runIf would LOSE the drained delta when
12
+ * the body runs: this guard drains in `runIf`, stashes the delta, and hands
13
+ * it to the body via `take()` in the same frame.
14
+ *
15
+ * Contract:
16
+ * - `runIf` drains the collector every frame (collector creation is lazy —
17
+ * a guard whose system is never installed never journals) and evaluates
18
+ * the optional `extra` trigger (a value-compare closure, e.g. "camera
19
+ * zoom changed"; it is called every frame so it can keep its own cache
20
+ * current). Returns true iff there is work.
21
+ * - `take()` (body, same frame) returns the work: `full` means rebuild
22
+ * everything (first run, `world.reset`, coarse writes, or `extra` fired);
23
+ * otherwise `changed`/`removed` are the journaled entities. The arrays
24
+ * alias the collector's internal buffers — valid until the next drain,
25
+ * i.e. for the body that runs this frame; do not retain them.
26
+ */
27
+ import type { CollectOptions, Entity, World } from "@vibecook/strata-ecs";
28
+ export interface ChurnWork {
29
+ /** Rebuild everything: first run, reset, coarse writes, or `extra` fired. */
30
+ readonly full: boolean;
31
+ readonly changed: readonly Entity[];
32
+ readonly removed: readonly Entity[];
33
+ }
34
+ export interface ChurnGuard {
35
+ /** Drop into a system's `runIf`. */
36
+ readonly runIf: () => boolean;
37
+ /** The work stashed by this frame's `runIf` (undefined if it returned false). */
38
+ take(): ChurnWork | undefined;
39
+ }
40
+ export declare function makeChurnGuard(world: World, collect: CollectOptions, extra?: () => boolean): ChurnGuard;
@@ -3,10 +3,10 @@
3
3
  * scene systems · doc kit · publish step · engine facade · reflector registry.
4
4
  * Import wall: strata-ecs + @ice/kernel ONLY — never react/dom/three (enforced).
5
5
  */
6
- export declare const CORE_VERSION = "0.0.0";
6
+ export declare const CORE_VERSION = "0.1.0";
7
7
  export { defineSchemaOnce, hmrInvalidateOnSchemaChange } from "./boot/hmr";
8
8
  export { All, Any, Not, Related, createWorld, defineQuery, defineSystem, defineTickSystem, enumOf, field, Local, } from "@vibecook/strata-ecs";
9
- export type { Batch, Component, Condition, Entity, Pipeline, Query, Relation, Resource, System, SystemCtx, Tag, TickSystem, World, } from "@vibecook/strata-ecs";
9
+ export type { Batch, Component, Condition, Entity, OrderPlace, Pipeline, Query, Relation, Resource, System, SystemCtx, Tag, TickSystem, World, } from "@vibecook/strata-ecs";
10
10
  export { defineComponent, defineRelation, defineResource, defineTag, schemaMeta, type ComponentMeta, type RawSchema, type RelationMeta, type ResourceMeta, } from "./schema/meta";
11
11
  export { definePrefab, init, PrefabId, prefabs, type ComponentInit, type FieldWrite, type Prefab, type PrefabClass, type PrefabDef, } from "./schema/prefab";
12
12
  export { instantiate, type EphSpawner, type SpawnTarget } from "./engine/instantiate";
@@ -21,13 +21,16 @@ export { writeRuntimeResource } from "./guards/resource-writer";
21
21
  export * from "./catalog";
22
22
  export * from "./helpers/phase-set";
23
23
  export * from "./helpers/version-stamps";
24
+ export * from "./ops/arrange";
24
25
  export * from "./ops/selection";
25
26
  export * from "./ops/cascade";
26
27
  export * from "./ops/claims";
27
28
  export * from "./ops/gestures";
28
29
  export * from "./ops/point-pick";
30
+ export * from "./ops/sibling-order";
31
+ export { portSlots, portSlotOf } from "./ops/port-geometry";
29
32
  export { createInputQueue, NO_MODS, type InputEvent, type InputEventKind, type InputMods, type InputQueue } from "./input/queue";
30
- export { createRecordingCommitSink, type CommitIntent, type CommitCreate, type CommitReparent, type CommitSink, type CommitWrite, } from "./engine/commit-sink";
33
+ export { createRecordingCommitSink, type CommitIntent, type CommitCreate, type CommitOrder, type CommitReparent, type CommitSink, type CommitWrite, } from "./engine/commit-sink";
31
34
  export { ensureCanvasSurface, installInteractionCore, installInteractionStack, type InteractionCore, type InteractionCoreOpts, type InteractionStack, } from "./interaction/install";
32
35
  export type { MarqueeBuffer } from "./systems/l3-marquee";
33
36
  export { DEFAULT_SPAWN_PROFILES, type SingleKindName, type SpawnProfiles } from "./systems/l2-recognize";
@@ -45,19 +48,22 @@ export { runMigrations, type MigrationCtx, type MigrationOutcome } from "./doc/m
45
48
  export { p, type JsonShape, type PropSpec, type PropsDecl, type StandardSchemaV1 } from "./widget/props";
46
49
  export { WidgetEquipped, defineWidget, widgets, type SizeMode, type WidgetDef, type WidgetGroup, type WidgetInteraction, type WidgetPortDecl, type WidgetSurface, type WidgetType, } from "./widget/define-widget";
47
50
  export { createWidgetEquipSystem } from "./widget/equip";
48
- export { spawnWidget, widgetSpawnInits, type SpawnWidgetOpts } from "./widget/spawn";
51
+ export { attachSpawnParent, spawnWidget, widgetSpawnInits, type SpawnWidgetOpts } from "./widget/spawn";
52
+ export { setWidgetProps } from "./widget/set-props";
49
53
  export { createWidgetRuntime, installWidgetRuntime, type MountEntry, type WidgetMountStore, type WidgetRuntime, } from "./widget/mount-store";
50
54
  export * from "./settings/defaults";
55
+ export * from "./settings/ground-config";
51
56
  export { CameraInertia, createCameraSystems, type CameraSystems } from "./systems/camera-sim";
52
57
  export { restoreAutosave, startAutosave, type Autosave, type AutosaveOpts, type AutosaveState, type AutosaveStatus, type AutosaveStorageRead, type AutosaveStorageWrite, type CancelScheduled, type RestoreResult, } from "./doc/autosave";
53
58
  export { attachBroadcastRelay, type BroadcastRelay, type BroadcastRelayOpts, type RelayChannel, } from "./doc/broadcast-relay";
54
59
  export { createMeasureQueue, type MeasureEvent, type MeasureQueue } from "./input/measure-queue";
55
60
  export { createMeasureIngest } from "./systems/measure-ingest";
56
61
  export { createBreakpointSystem, createSelectionChromeSystem } from "./systems/chrome";
57
- export { createNestedCanvas, currentNavEntry, currentNavFrame, type NestedCanvas, type NestedCanvasOpts, } from "./nav/nested-canvas";
62
+ export { createActiveMembership, createNestedCanvas, currentNavEntry, currentNavFrame, type NavOpts, type NestedCanvas, type NestedCanvasOpts, } from "./nav/nested-canvas";
63
+ export { abortNavFlight, createNavFlight, navFlightActive, NavTransition, startNavFlight, } from "./systems/nav-flight";
58
64
  export { attachPresence, createPresencePublish, createRemoteCursorsSystem, DEFAULT_PRESENCE_TTL_MS, installPresence, type InstallPresenceOpts, type PresenceOpts, type PresencePublishOpts, type PresenceSession, } from "./presence";
59
- export { joinDoc, type BootstrapClock, type JoinDocOpts, type JoinResult, } from "./doc/bootstrap";
65
+ export { joinDoc, offerBase, type BootstrapClock, type JoinDocOpts, type JoinResult, } from "./doc/bootstrap";
60
66
  export { broadcastChannelByteChannel, webSocketByteChannel, type ByteChannel, type OwnedByteChannel, type WebSocketLike, } from "./doc/channels";
61
67
  export { createDrawTool, defineTool, tools, type CanvasDragRoute, type Tool, type ToolDef, type ToolGates, type ToolRoute, type WidgetDragRoute, } from "./tools/define-tool";
62
- export { createCanvasEngine, type CanvasDocs, type CanvasEngine, type CanvasEngineOpts, type CanvasOps, } from "./facade/create-canvas-engine";
68
+ export { createCanvasEngine, type CanvasDocs, type CanvasEngine, type CanvasEngineOpts, type StageControl, type CanvasOps, } from "./facade/create-canvas-engine";
63
69
  export { createDrawBehavior } from "./systems/l3-draw";
@@ -40,6 +40,17 @@ export interface InputEvent {
40
40
  };
41
41
  /** GL-island opt-out (pinned widget-event contract, design-002 §8): fact still lands, recognizers skip. */
42
42
  readonly surfaceHandled?: boolean;
43
+ /**
44
+ * Hover-time widget-boundary fact (design-002 §8 amendment, 2026-07-18): the
45
+ * pointer is currently over content that would opt a down out — a native
46
+ * interactive / `[data-canvas-interactive]` (DOM) or claim-capable island
47
+ * content (GL). Stamped on down/move by adapters that track it; ABSENT means
48
+ * "no hover information this event" (wheel, key, blur-cancel) — ingest keeps
49
+ * the pointer's `OverInteractive` tag unchanged, it never treats absent as
50
+ * false. Presentation-grade truth (cursor affordances), never a gesture gate:
51
+ * recognizers keep reading `surfaceHandled`/`HandledByWidget` only.
52
+ */
53
+ readonly overInteractive?: boolean;
43
54
  /**
44
55
  * Event timestamp (DOMHighResTimeStamp — the same clock rAF hands
45
56
  * `engine.step`). Gesture timing anchors on THIS, not the processing frame:
@@ -7,10 +7,25 @@
7
7
  * (at root: no container ancestor at all). Children of a deeper container
8
8
  * are that container's content — not Active until you enter it.
9
9
  * - `activeMembership` (derive tick, before cull): recomputes membership and
10
- * flips Active/Visible/Culled CHANGE-ONLY. A nav switch is O(frame
11
- * content) tag flips — bounded, rare, migration-free. Boards without
12
- * containers converge to "everything Active" on the first pass and never
13
- * write again (M3–M7 demos unaffected).
10
+ * flips Active/Visible/Culled CHANGE-ONLY, gated per design-004 §7
11
+ * (`runIf: nav-change ∨ ChildOf churn`) as a drain-and-early-return tick
12
+ * body — the spatialSync shape (petition 7 ChangeCollector; a `runIf`
13
+ * cannot drain, and this system declares no writes so an early-out
14
+ * blanket-stamps nothing). Idle frames cost one drain + one nav compare.
15
+ * Full resweeps run on seed / reset / coarse / NAV CHANGE / container
16
+ * despawn; everything else is delta-driven: a journaled entity whose
17
+ * membership INPUTS (ChildOf edge, Container-ness) are unchanged is
18
+ * skipped (drag frames journal Position every tick — O(1) each), a real
19
+ * reparent/container-flip reclassifies its re-anchored subtree.
20
+ * MEMBERSHIP-CHURN SIGNAL (why Position is the reparent proxy): relations
21
+ * are not collector-journalable (strata CollectOptions = components +
22
+ * tags), but coordinates are FRAME-LOCAL (design-001 §5.1) — a reparent
23
+ * that does not rewrite Position into the new frame's space is already a
24
+ * bug, and every real path co-writes: the doc sink commits reparent +
25
+ * Position in ONE tx (doc-commit-sink.ts), and undo/redo/remote imports
26
+ * project both rows of that tx. A bare runtime `world.setRelation(e,
27
+ * ChildOf, …)` with no Position write on a pre-existing entity is OUTSIDE
28
+ * the contract and goes stale until the next resweep.
14
29
  * - Nav stack = SESSION entities: `NavEntry` rows carry NavDepth + NavCamera
15
30
  * (the camera to restore on exit) + NavFrame(entry→container). Root =
16
31
  * empty stack. Current frame = deepest live entry's NavFrame target.
@@ -23,11 +38,20 @@
23
38
  * container died (undo/remote — NavFrame edge auto-cleared), pop to the
24
39
  * nearest LIVE ancestor entry (skipping dead ones) or root, restore that
25
40
  * camera, rebuild. The recognizer-integrity pattern applied to nav.
26
- * - Camera memory: enter saves the live camera on the pushed entry
27
- * (NavCamera) and applies the container's `ContainerCamera` rider (else
28
- * zoom-to-fit over the frame's content, else identity); exit writes the
29
- * rider back (per-user view memory; lost on undo-despawn — accepted) and
30
- * restores the entry's NavCamera.
41
+ * - Camera policy (design-006, amending design-004 §7; James 2026-07-15):
42
+ * enter saves the live camera on the pushed entry (NavCamera) and ALWAYS
43
+ * lands on the DEFAULT framing — zoom-to-fit over the frame's content, else
44
+ * identity. The `ContainerCamera` rider is neither read nor written by the
45
+ * engine anymore (per-canvas view memory made re-entry unpredictable); the
46
+ * component stays in the catalog for userland. Exit restores the entry's
47
+ * NavCamera — "back where you came from" is the nav stack, not view memory.
48
+ * - Transitions (design-006 T1): with a live Viewport and `transition` not
49
+ * "none", enter/exit CUT exactly as before and then FLY — the camera snaps
50
+ * to the continuity-solved start and `navFlight` springs it to the arrival
51
+ * (systems/nav-flight.ts). `exitTo(depth)` pops multi-level in ONE flight
52
+ * through the composed portals (rebuilt from CURRENT container rects — a
53
+ * collaborator may have moved a card). Headless (no Viewport) or opted-out
54
+ * calls snap, preserving the pre-T1 behavior exactly.
31
55
  */
32
56
  import type { Entity, TickSystem, World } from "@vibecook/strata-ecs";
33
57
  import type { SpatialIndex } from "@ice/kernel";
@@ -35,11 +59,17 @@ import type { SpatialIndex } from "@ice/kernel";
35
59
  export declare function currentNavEntry(world: World): Entity | undefined;
36
60
  /** The container the user is inside, or undefined at root. */
37
61
  export declare function currentNavFrame(world: World): Entity | undefined;
62
+ /** Per-op transition choice (design-006 §3.1); default is the portal zoom. */
63
+ export interface NavOpts {
64
+ readonly transition?: "zoom" | "none";
65
+ }
38
66
  export interface NestedCanvas {
39
67
  readonly activeMembership: TickSystem;
40
68
  readonly navIntegrity: TickSystem;
41
- enterContainer(container: Entity): void;
42
- exitContainer(): void;
69
+ enterContainer(container: Entity, opts?: NavOpts): void;
70
+ exitContainer(opts?: NavOpts): void;
71
+ /** Pop to `targetDepth` in ONE transition (breadcrumb jumps; design-006 §5). */
72
+ exitTo(targetDepth: number, opts?: NavOpts): void;
43
73
  /** Depth of the nav stack (0 = root). */
44
74
  depth(): number;
45
75
  }
@@ -57,6 +87,12 @@ export interface NestedCanvasOpts {
57
87
  * The membership stamper alone — installed by `installWidgetRuntime` (before
58
88
  * cull) so EVERY app partitions correctly, containers or not: a board with no
59
89
  * containers converges to all-Active on the first pass and never writes again.
90
+ *
91
+ * Gated per design-004 §7 (see the file header): the tick body drains a
92
+ * petition-7 collector and early-returns on idle frames; membership work runs
93
+ * only on nav change or membership-input churn. Baseline before this gate
94
+ * (bench/membership-scale.test.ts, 2026-07-15): the full scan cost 19.0 ms
95
+ * PER IDLE FRAME at 100k widgets nested 8 deep.
60
96
  */
61
97
  export declare function createActiveMembership(world: World): TickSystem;
62
98
  export declare function createNestedCanvas(world: World, opts: NestedCanvasOpts): NestedCanvas;
@@ -0,0 +1,15 @@
1
+ import type { Entity, World } from "@vibecook/strata-ecs";
2
+ import type { DurableStore } from "@vibecook/strata-ecs/durable";
3
+ import type { LiveWriter } from "../guards/live-writer";
4
+ export interface ArrangeOpts {
5
+ /** Explicit scope; wins over selection/frame resolution. */
6
+ readonly ids?: readonly Entity[];
7
+ /** Min separation between packed widgets (default 24). */
8
+ readonly gutter?: number;
9
+ /** Row wrap width; default = packLayout's near-square derivation. */
10
+ readonly maxWidth?: number;
11
+ /** Glide duration; 0 snaps instantly (tests/headless). Default 240ms. */
12
+ readonly durationMs?: number;
13
+ }
14
+ /** Returns the entities that actually moved (empty = already tidy). */
15
+ export declare function arrangeWidgets(store: DurableStore, liveWriter: LiveWriter, world: World, opts?: ArrangeOpts): Entity[];
@@ -0,0 +1,62 @@
1
+ /**
2
+ * insertByDrag — the tray-adoption op (2026-07-19, James: the widget tray).
3
+ *
4
+ * Called from the app's tray-tile `pointerdown` (which `stopPropagation`s the
5
+ * native down — the sanctioned widget-content boundary, design-002 §8). Two
6
+ * event-time moves, then the ENGINE owns everything:
7
+ *
8
+ * 1. DRAFT-spawn the ghost (design-001 §3; instantiate `{ draft: true }`) —
9
+ * a runtime instance of the widget prefab centered under the pointer,
10
+ * equipped + Active + top-of-frame IMMEDIATELY (the equip system runs in
11
+ * `derive`, AFTER this tick's pick — the down below must find the ghost
12
+ * indexed and topmost in the SAME tick, so the op stamps what equip
13
+ * would). Two capability tags are deliberately withheld:
14
+ * - `LongPressDrag`: a tray insert is always instant-drag — nobody holds
15
+ * 500ms over a palette;
16
+ * - `SweepsContained`: a comment ghost at the tray's world point must not
17
+ * sweep the widgets resting under the tray into the insert.
18
+ * The projected twin gets the FULL tag set from the equip system.
19
+ *
20
+ * 2. Enqueue ONE synthetic un-flagged `down` (Law 2 — this op is an adapter
21
+ * here, it only enqueues; the GL router precedent). Next tick: spatialSync
22
+ * indexes the ghost, targeting resolves it topmost, the Drag recognizer
23
+ * captures it — and the ordinary L0–L4 stack runs the whole drag: lift,
24
+ * snap, drop targets, folder consume. moveBehavior's ghost terminals
25
+ * promote (one `create` tx) or fly the ghost home and reap it.
26
+ */
27
+ import type { Entity, World } from "@vibecook/strata-ecs";
28
+ import { type InputQueue } from "../input/queue";
29
+ export interface InsertByDragOpts {
30
+ /** The press point in canvas-container CSS px (the kernel screen space). */
31
+ readonly screenX: number;
32
+ readonly screenY: number;
33
+ /** Prop overrides for the eventual create (validated by widgetSpawnInits). */
34
+ readonly props?: Readonly<Record<string, unknown>>;
35
+ /** Adapter pointer id of the pressing pointer (default "mouse"). */
36
+ readonly pointerId?: string;
37
+ readonly device?: "mouse" | "touch" | "pen";
38
+ /** PointerEvent.buttons at the press (default 1 = primary). */
39
+ readonly buttons?: number;
40
+ /**
41
+ * Fly-back HOME in screen px (default: the press point). Apps that adopt
42
+ * the drag AWAY from the tray (the deferred-spawn proxy pattern — the ghost
43
+ * spawns at the tray-EXIT point) aim the cancel/reject return at the
44
+ * persistent chrome (the toolbar) instead of a spot in open canvas.
45
+ */
46
+ readonly home?: {
47
+ readonly x: number;
48
+ readonly y: number;
49
+ };
50
+ /**
51
+ * Proportional GRAB POINT (0–1 within the widget rect; default center).
52
+ * The grab point is the drag's INVARIANT (2026-07-19 polish): the spot
53
+ * under the finger in the tray tile stays the same spot of the spawned
54
+ * widget — the proxy→widget morph then composes as a pure scale about the
55
+ * cursor, with no re-anchoring snap.
56
+ */
57
+ readonly anchor?: {
58
+ readonly u: number;
59
+ readonly v: number;
60
+ };
61
+ }
62
+ export declare function insertByDrag(world: World, queue: InputQueue, type: string, opts: InsertByDragOpts): Entity;
@@ -6,11 +6,13 @@
6
6
  * the tick are verified-unrestricted). One implementation so the two can
7
7
  * never disagree on ordering.
8
8
  *
9
- * Priority: HandleSpec chrome first (nearest edge), then widgets by StackZ
10
- * descending. Deliberately NOT plane-stratified: cross-plane z is stratified
11
- * visually (P2 GL composites above P1 DOM), but pick order is StackZ across
12
- * all surfaces — design-004 §1 names the mixed-overlap consequence and
13
- * accepts it; do not "fix" it here.
9
+ * Priority: HandleSpec chrome first (nearest edge), then widgets topmost by
10
+ * SIBLING ORDER (petition 8: the frame parent's ChildOf sequence, legacy
11
+ * (StackZ, entity) fallback for edge-less entities — compareStackOrder is the
12
+ * ONE comparator paint and pick share). Deliberately NOT plane-stratified:
13
+ * cross-plane z is stratified visually (P2 GL composites above P1 DOM), but
14
+ * pick order is sibling order across all surfaces — design-004 §1 names the
15
+ * mixed-overlap consequence and accepts it; do not "fix" it here.
14
16
  */
15
17
  import type { Component, Entity } from "@vibecook/strata-ecs";
16
18
  import type { Cubic, SpatialIndex } from "@ice/kernel";
@@ -33,10 +35,12 @@ export declare function distPointToBox(px: number, py: number, minX: number, min
33
35
  * Top pick under a world point within `rWorld` (point-in-box when 0).
34
36
  * Tier order (design-003 §3, amended for M8): HandleSpec chrome → PORT
35
37
  * entities (interaction affordances sit atop their widget edge) → widgets by
36
- * StackZ → WIRES (render in P0 under content; pick below widgets, above
38
+ * sibling order (topmost = compareStackOrder max; `ordinals` is the caller's
39
+ * frame ordinal map — SiblingOrderIndex — so paint and pick share one order)
40
+ * → WIRES (render in P0 under content; pick below widgets, above
37
41
  * canvas — render order and pick order agree). The canvas fallback stays the
38
42
  * caller's. Wires narrow-phase against their cached cubic (`wires` source;
39
43
  * without one, wire entries are skipped — coarse AABB hits would make fat
40
44
  * bounding boxes steal canvas taps).
41
45
  */
42
- export declare function pickTopAt(reader: PickReader, index: SpatialIndex<Entity>, wx: number, wy: number, rWorld: number, wires?: WirePickSource): Entity | undefined;
46
+ export declare function pickTopAt(reader: PickReader, index: SpatialIndex<Entity>, wx: number, wy: number, rWorld: number, wires?: WirePickSource, ordinals?: ReadonlyMap<Entity, number>): Entity | undefined;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Sibling order — THE per-frame stacking source (petition 8; design-004 §1
3
+ * amendment). Within a frame, paint/pick/drop order IS the frame parent's
4
+ * ordered `ChildOf` sibling sequence: index 0 paints first (bottom), the tail
5
+ * paints last (top). The frame parent is `currentNavFrame(world) ?? BoardRoot`
6
+ * — every renderer/pick consumer shares this module so the orders can never
7
+ * diverge (the point-pick lesson, extended to the comparator).
8
+ *
9
+ * LEGACY FALLBACK (must keep working): when the `BoardRoot` resource is absent
10
+ * (a pre-schema-2 doc opened read-only, or a doc-less runtime world) OR an
11
+ * entity carries no `ChildOf` edge (bare runtime spawns), stacking falls back
12
+ * to the legacy `(StackZ.z asc, entity asc)` comparator. This module is the
13
+ * ONLY sanctioned StackZ reader outside the schema migration.
14
+ *
15
+ * Mixed frames — some entities ordinal-mapped, some fallback — are nominally
16
+ * impossible (the 1→2 migration hangs an edge on every durable widget, and a
17
+ * pre-schema-2 read-only doc has no BoardRoot at all, so it is all-fallback).
18
+ * The comparator still totals them: ordinal-mapped entities sort BELOW the
19
+ * fallback set (ordinals first in paint order), each group internally ordered
20
+ * by its own rule — documented so a stray bare spawn lands somewhere stable
21
+ * rather than somewhere random.
22
+ *
23
+ * Invalidation is PULL-ONLY, the strata 0.8.0 contract: `world.orderStamp
24
+ * (parent, ChildOf)` is a monotonic per-parent version consumers poll after a
25
+ * reactive wake; the wake itself is an `observeQuery` whose grammar names the
26
+ * relation (`Related(ChildOf)` — pure reorders turn it over).
27
+ */
28
+ import type { Component, Entity, World } from "@vibecook/strata-ecs";
29
+ /** Structural read both `World` and `SystemCtx` provide — all the comparator needs. */
30
+ export interface StackOrderReader {
31
+ get<S>(e: Entity, c: Component<S>): S | undefined;
32
+ }
33
+ /**
34
+ * The frame parent — the entity whose `ChildOf` sibling sequence is the
35
+ * current frame's stacking order: the nav frame when inside a container, else
36
+ * the document's board root. `undefined` = a legacy world (pre-schema-2
37
+ * read-only doc / doc-less runtime) — everything is fallback-ordered.
38
+ */
39
+ export declare function frameParent(world: World): Entity | undefined;
40
+ /** `parent`'s sibling sequence as entity → position (the renderers' sort key). */
41
+ export declare function buildOrdinals(world: World, parent: Entity): Map<Entity, number>;
42
+ /**
43
+ * THE stacking comparator (ascending = paint order; the pick tier takes the
44
+ * max). Ordinal-mapped entities order by sibling position; entities missing
45
+ * from the map use the legacy `(StackZ asc, entity asc)` fallback among
46
+ * themselves and sort ABOVE the ordinal-mapped set (see the header note on
47
+ * nominally-impossible mixed frames).
48
+ */
49
+ export declare function compareStackOrder(reader: StackOrderReader, ordinals: ReadonlyMap<Entity, number>, a: Entity, b: Entity): number;
50
+ export interface SiblingOrderIndex {
51
+ /** The frame parent backing the current ordinal map (undefined = legacy world). */
52
+ parent(): Entity | undefined;
53
+ /** The stamp-checked ordinal map — rebuilt only when the frame parent or its `orderStamp` moved. */
54
+ ordinals(): ReadonlyMap<Entity, number>;
55
+ /** True when the next `ordinals()` would rebuild (cheap pull; no rebuild). */
56
+ stale(): boolean;
57
+ /**
58
+ * Arm the reorder wake: an `observeQuery` naming `ChildOf` (`Related`
59
+ * grammar — pure reorders and edge turnover both fire it). Callers pair it
60
+ * with `stale()`/`ordinals()` so other-frame churn stays a no-op.
61
+ */
62
+ observe(cb: () => void): () => void;
63
+ }
64
+ /**
65
+ * A pull-based ordinal cache over the CURRENT frame parent's sibling sequence.
66
+ * Consumers each hold their own instance (the cache is a cheap `getReverse`
67
+ * walk); correctness is shared through {@link compareStackOrder} and the
68
+ * stamp, never through instance identity.
69
+ */
70
+ export declare function createSiblingOrderIndex(world: World): SiblingOrderIndex;
@@ -31,6 +31,7 @@ export declare function defineComponent<const Sch extends RawSchema>(name: strin
31
31
  export declare function defineTag(name: string): Tag;
32
32
  export declare function defineRelation(name: string, opts?: {
33
33
  arity?: "one" | "many";
34
+ ordered?: boolean;
34
35
  }): Relation;
35
36
  export declare function defineResource<const Sch extends RawSchema>(name: string, schema: Sch, opts?: {
36
37
  durable?: boolean;
@@ -15,6 +15,8 @@ export declare const GESTURE_DEFAULTS: {
15
15
  readonly inertiaDecayMs: 325;
16
16
  readonly multiTapWindowMs: 280;
17
17
  readonly multiTapSlopPx: 20;
18
+ readonly wheelZoomSensitivity: 0.01;
19
+ readonly wheelZoomMaxStep: 10;
18
20
  };
19
21
  /** Pick radii + retarget dead-band (design-003 §3 L1 targeting). */
20
22
  export declare const POINTER_DEFAULTS: {
@@ -39,12 +41,55 @@ export declare const SNAP_DEFAULTS: {
39
41
  readonly enabled: true;
40
42
  readonly thresholdPx: 5;
41
43
  };
44
+ /**
45
+ * Selection-chrome knobs (2026-07-17). `liftScale` mirrors the app's visual
46
+ * drag-lift scale (widgetlab CardShell: 1.05) so the union box can inflate a
47
+ * grabbed member's rect and keep WRAPPING the card it sees; 1 = no lift
48
+ * visual, no inflation.
49
+ */
50
+ export declare const CHROME_DEFAULTS: {
51
+ readonly liftScale: 1;
52
+ };
42
53
  /** Zoom clamp (design-003 §5 item 9 cameraControl) and frame dt clamp (design-002 §1). */
43
54
  export declare const CAMERA_DEFAULTS: {
44
55
  readonly minZoom: 0.1;
45
56
  readonly maxZoom: 5;
46
57
  readonly dtClampMs: 64;
47
58
  };
59
+ /**
60
+ * The natural auto-framing band (2026-07-18, James: "not super zoomed in
61
+ * nor super zoomed out, should feel natural"): every DEFAULT framing —
62
+ * `ops.frameContent` at boot, the folder arrival camera, and the folder
63
+ * minis' portal affine (widgetlab keeps its preview in lockstep) — fits
64
+ * content via kernel `fitCamera` but never lands outside
65
+ * [fitMinZoom, fitMaxZoom], intersected with the session's hard
66
+ * CameraLimits. `ops.zoomToFit` stays UNCAPPED: an explicit "show me
67
+ * everything" beats natural.
68
+ */
69
+ export declare const FIT_DEFAULTS: {
70
+ readonly pad: 80;
71
+ readonly minZoom: 0.5;
72
+ readonly maxZoom: 1;
73
+ };
74
+ /**
75
+ * Nav-transition motion constants (design-006 §4/§5, tuned in the approved
76
+ * 2026-07-15 mock). `responseMs` is the critically-damped spring response for
77
+ * ENTER; exit runs at `exitResponseFactor ×` (returning is lighter). Response
78
+ * scales `durationPerOctave` per zoom-octave beyond `baseOctaves` (Apple's
79
+ * duration-with-distance). Beyond `freezeOctaves` a flight cannot be presented
80
+ * geometrically (Chromium raster-scale swing — design-006 §5): the start depth
81
+ * caps at `capFactor ×` arrival and the transition presents as a crossfade.
82
+ */
83
+ export declare const NAV_TRANSITION_DEFAULTS: {
84
+ readonly responseMs: 420;
85
+ readonly exitResponseFactor: 0.8;
86
+ readonly durationPerOctave: 0.12;
87
+ readonly baseOctaves: 3.5;
88
+ readonly freezeOctaves: 4.2;
89
+ readonly capFactor: 10;
90
+ readonly settleP: 0.999;
91
+ readonly settleV: 0.02;
92
+ };
48
93
  /** Widget/FBO/port budgets (design-004 §2 host pipeline, §3 FBO pool, §6 port materialization; ported into design-005 §4 engine facade). */
49
94
  export declare const RUNTIME_BUDGETS: {
50
95
  readonly keepMountedWidgets: 256;