@vibecook/ice 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +10 -5
  2. package/dist/{chunk-ZTY2VRIS.js → chunk-6W2FPXR7.js} +13 -7
  3. package/dist/chunk-6W2FPXR7.js.map +1 -0
  4. package/dist/{chunk-Y7K6CHSF.js → chunk-LAZIY3J7.js} +286 -189
  5. package/dist/chunk-LAZIY3J7.js.map +1 -0
  6. package/dist/{chunk-REJTEK3V.js → chunk-M2HUDENL.js} +288 -318
  7. package/dist/chunk-M2HUDENL.js.map +1 -0
  8. package/dist/{chunk-BH5AFWJX.js → chunk-VZEZ7CYW.js} +9 -13
  9. package/dist/chunk-VZEZ7CYW.js.map +1 -0
  10. package/dist/desk-kit.js +2 -2
  11. package/dist/desk-objects.js +45 -14
  12. package/dist/desk-objects.js.map +1 -1
  13. package/dist/desk.js +3 -3
  14. package/dist/devtools.js +1 -1
  15. package/dist/dom.js +2 -2
  16. package/dist/index.js +7 -1
  17. package/dist/react.js +2 -2
  18. package/dist/types/packages/core/src/canvas/engine-catalog.d.ts +6 -0
  19. package/dist/types/packages/core/src/catalog/desk.d.ts +6 -6
  20. package/dist/types/packages/core/src/catalog/gesture.d.ts +2 -0
  21. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +2 -0
  22. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +8 -4
  23. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +11 -5
  24. package/dist/types/packages/core/src/index.d.ts +1 -1
  25. package/dist/types/packages/core/src/ops/selection-drag.d.ts +8 -0
  26. package/dist/types/packages/core/src/settings/defaults.d.ts +2 -0
  27. package/dist/types/packages/core/src/systems/camera-sim.d.ts +13 -0
  28. package/dist/types/packages/core/src/systems/tray.d.ts +5 -4
  29. package/dist/types/packages/core/src/tools/define-tool.d.ts +2 -2
  30. package/dist/types/packages/core/src/widget/define-widget.d.ts +2 -1
  31. package/dist/types/packages/desk/src/ground.d.ts +4 -3
  32. package/dist/types/packages/desk/src/host/layer.d.ts +1 -3
  33. package/dist/types/packages/desk/src/mat/layout.d.ts +45 -5
  34. package/dist/types/packages/desk/src/mat/mat-pass.d.ts +7 -0
  35. package/dist/types/packages/desk/src/mat/ruler-regions.d.ts +17 -0
  36. package/dist/types/packages/desk/src/shaders.gen.d.ts +4 -4
  37. package/dist/types/packages/desk/src/theme.d.ts +0 -15
  38. package/dist/types/packages/desk/src/tray/drawer.d.ts +10 -8
  39. package/dist/types/packages/desk/src/tray/flux.d.ts +2 -3
  40. package/dist/types/packages/desk/src/tray/layout.d.ts +1 -6
  41. package/dist/types/packages/desk/src/tray/look.d.ts +0 -9
  42. package/dist/types/packages/desk/src/tray/pass.d.ts +7 -18
  43. package/dist/types/packages/desk/src/tray/specimens.d.ts +2 -19
  44. package/dist/types/packages/dom/src/pointer-adapter.d.ts +1 -1
  45. package/dist/types/packages/objects/src/minimat/layout.d.ts +1 -1
  46. package/dist/types/packages/objects/src/photo/photo.d.ts +2 -2
  47. package/dist/types/packages/objects/src/preset.d.ts +5 -3
  48. package/package.json +15 -16
  49. package/dist/chunk-BH5AFWJX.js.map +0 -1
  50. package/dist/chunk-REJTEK3V.js.map +0 -1
  51. package/dist/chunk-Y7K6CHSF.js.map +0 -1
  52. package/dist/chunk-ZTY2VRIS.js.map +0 -1
package/dist/desk.js CHANGED
@@ -101,7 +101,7 @@ import {
101
101
  withKindActs,
102
102
  withoutKind,
103
103
  writable
104
- } from "./chunk-REJTEK3V.js";
104
+ } from "./chunk-M2HUDENL.js";
105
105
  import "./chunk-ENIFIUEP.js";
106
106
  import {
107
107
  BLOB_STORE,
@@ -255,9 +255,9 @@ import {
255
255
  visibleRect,
256
256
  worldBounds,
257
257
  writeChanged
258
- } from "./chunk-BH5AFWJX.js";
258
+ } from "./chunk-VZEZ7CYW.js";
259
259
  import "./chunk-RTBW5AIZ.js";
260
- import "./chunk-Y7K6CHSF.js";
260
+ import "./chunk-LAZIY3J7.js";
261
261
  import "./chunk-RE4GDHFJ.js";
262
262
  export {
263
263
  AMBIENT_DEFAULTS,
package/dist/devtools.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  WheelPan,
15
15
  WheelZoom,
16
16
  Wire
17
- } from "./chunk-Y7K6CHSF.js";
17
+ } from "./chunk-LAZIY3J7.js";
18
18
  import "./chunk-RE4GDHFJ.js";
19
19
 
20
20
  // ../devtools/src/attach.ts
package/dist/dom.js CHANGED
@@ -13,8 +13,8 @@ import {
13
13
  keyboardClaimOf,
14
14
  startRafLoop,
15
15
  wheelCede
16
- } from "./chunk-ZTY2VRIS.js";
17
- import "./chunk-Y7K6CHSF.js";
16
+ } from "./chunk-6W2FPXR7.js";
17
+ import "./chunk-LAZIY3J7.js";
18
18
  import "./chunk-RE4GDHFJ.js";
19
19
  export {
20
20
  CLAIM_OWNS_ESCAPE,
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  Camera,
15
15
  CameraInertia,
16
16
  CameraLimits,
17
+ CameraZoomStep,
17
18
  CancelRequest,
18
19
  CanvasIntentScope,
19
20
  CanvasSession,
@@ -95,6 +96,7 @@ import {
95
96
  LongPressDrag,
96
97
  MarqueeBox,
97
98
  Movable,
99
+ MovesSelection,
98
100
  MultiTap,
99
101
  NAV_TRANSITION_DEFAULTS,
100
102
  NO_ENTITY,
@@ -157,6 +159,7 @@ import {
157
159
  STRATUM_BANDS,
158
160
  Selectable,
159
161
  Selected,
162
+ SelectionMovable,
160
163
  SelectionSummary,
161
164
  SelectionVersion,
162
165
  Sequence,
@@ -394,7 +397,7 @@ import {
394
397
  widgetTypeFor,
395
398
  widgets,
396
399
  writeRuntimeResource
397
- } from "./chunk-Y7K6CHSF.js";
400
+ } from "./chunk-LAZIY3J7.js";
398
401
  import "./chunk-RE4GDHFJ.js";
399
402
  export {
400
403
  Accepts,
@@ -412,6 +415,7 @@ export {
412
415
  Camera,
413
416
  CameraInertia,
414
417
  CameraLimits,
418
+ CameraZoomStep,
415
419
  CancelRequest,
416
420
  CanvasIntentScope,
417
421
  CanvasSession,
@@ -493,6 +497,7 @@ export {
493
497
  LongPressDrag,
494
498
  MarqueeBox,
495
499
  Movable,
500
+ MovesSelection,
496
501
  MultiTap,
497
502
  NAV_TRANSITION_DEFAULTS,
498
503
  NO_ENTITY,
@@ -555,6 +560,7 @@ export {
555
560
  STRATUM_BANDS,
556
561
  Selectable,
557
562
  Selected,
563
+ SelectionMovable,
558
564
  SelectionSummary,
559
565
  SelectionVersion,
560
566
  Sequence,
package/dist/react.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  createDeskHost,
3
3
  isEditableTarget,
4
4
  keyboardClaimOf
5
- } from "./chunk-ZTY2VRIS.js";
5
+ } from "./chunk-6W2FPXR7.js";
6
6
  import {
7
7
  ActiveTool,
8
8
  Container,
@@ -28,7 +28,7 @@ import {
28
28
  tools,
29
29
  trayOpen,
30
30
  widgets
31
- } from "./chunk-Y7K6CHSF.js";
31
+ } from "./chunk-LAZIY3J7.js";
32
32
  import "./chunk-RE4GDHFJ.js";
33
33
 
34
34
  // ../react/src/hooks.ts
@@ -16,6 +16,10 @@ export interface EngineCatalogCompileOpts {
16
16
  readonly widgets?: readonly {
17
17
  readonly type: string;
18
18
  }[];
19
+ /** Schema compatibility only: no placement, runtime, tray, or canvas presentation. */
20
+ readonly retiredWidgets?: readonly {
21
+ readonly type: string;
22
+ }[];
19
23
  readonly tools?: readonly Tool[];
20
24
  readonly canvasTypes?: readonly CanvasType[];
21
25
  readonly rootCanvas?: CanvasType;
@@ -30,6 +34,8 @@ export interface EngineCatalog {
30
34
  readonly rootCanvas: CanvasType;
31
35
  readonly presentationFallback: CanvasType;
32
36
  widget(id: string): WidgetType | undefined;
37
+ /** A dormant schema retained for saved documents, outside the active widget catalog. */
38
+ retiredWidget(id: string): WidgetType | undefined;
33
39
  widgetTypes(): readonly WidgetType[];
34
40
  tool(id: string): Tool | undefined;
35
41
  toolTypes(): readonly Tool[];
@@ -206,11 +206,11 @@ export declare const Tray: import("@vibecook/strata-ecs").Component<import("@vib
206
206
  readonly stretch: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
207
207
  readonly wheelAt: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
208
208
  /**
209
- * K9 (S11, D-K9-c.3): the last wheel `dy` the drawer scrolled by, and how many deltas in a row have SHRUNK while pushing the band
210
- * further — a fading tail (the OS's momentum decays; a push does not, steadily). At `TRAY_INPUT.fadeDeltas` the band lets go and
211
- * the rest of that tail is spent — swallowed, scroll and band untouched — until a reversal, a growing delta or quiet.
209
+ * @deprecated Legacy wheel-tail bookkeeping, retained for component compatibility. Wheel scrolling now stays within its
210
+ * bounds and consumes the OS's momentum directly; trayInput no longer reads or writes these fields.
212
211
  */
213
212
  readonly wheelDy: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
213
+ /** @deprecated See wheelDy. */
214
214
  readonly fade: import("@vibecook/strata-ecs").FieldSpec<"u32", true>;
215
215
  /** K5a: the type of the specimen under the mouse while the drawer is out ("" — none): the hover that lifts it (flux). */
216
216
  readonly hover: import("@vibecook/strata-ecs").FieldSpec<"string", true>;
@@ -247,11 +247,11 @@ export declare const Tray: import("@vibecook/strata-ecs").Component<import("@vib
247
247
  readonly stretch: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
248
248
  readonly wheelAt: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
249
249
  /**
250
- * K9 (S11, D-K9-c.3): the last wheel `dy` the drawer scrolled by, and how many deltas in a row have SHRUNK while pushing the band
251
- * further — a fading tail (the OS's momentum decays; a push does not, steadily). At `TRAY_INPUT.fadeDeltas` the band lets go and
252
- * the rest of that tail is spent — swallowed, scroll and band untouched — until a reversal, a growing delta or quiet.
250
+ * @deprecated Legacy wheel-tail bookkeeping, retained for component compatibility. Wheel scrolling now stays within its
251
+ * bounds and consumes the OS's momentum directly; trayInput no longer reads or writes these fields.
253
252
  */
254
253
  readonly wheelDy: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
254
+ /** @deprecated See wheelDy. */
255
255
  readonly fade: import("@vibecook/strata-ecs").FieldSpec<"u32", true>;
256
256
  /** K5a: the type of the specimen under the mouse while the drawer is out ("" — none): the hover that lifts it (flux). */
257
257
  readonly hover: import("@vibecook/strata-ecs").FieldSpec<"string", true>;
@@ -140,6 +140,8 @@ export declare const GestureSuspended: import("@vibecook/strata-ecs").Tag;
140
140
  export declare const HadCapture: import("@vibecook/strata-ecs").Tag;
141
141
  /** Runs alongside claims without competing (wheel pan/zoom) — keeps zoom-while-dragging legal. */
142
142
  export declare const Simultaneous: import("@vibecook/strata-ecs").Tag;
143
+ /** A group-move intent, latched at pointer-down so custom carries can yield before lifting. */
144
+ export declare const MovesSelection: import("@vibecook/strata-ecs").Tag;
143
145
  export declare const RoutedMove: import("@vibecook/strata-ecs").Tag;
144
146
  export declare const RoutedResize: import("@vibecook/strata-ecs").Tag;
145
147
  export declare const RoutedConnect: import("@vibecook/strata-ecs").Tag;
@@ -2,6 +2,8 @@
2
2
  export declare const Selected: import("@vibecook/strata-ecs").Tag;
3
3
  export declare const Selectable: import("@vibecook/strata-ecs").Tag;
4
4
  export declare const Movable: import("@vibecook/strata-ecs").Tag;
5
+ /** Core moves this widget with a selection; its own driver handles a solo drag. */
6
+ export declare const SelectionMovable: import("@vibecook/strata-ecs").Tag;
5
7
  export declare const Resizable: import("@vibecook/strata-ecs").Tag;
6
8
  export declare const SnapSource: import("@vibecook/strata-ecs").Tag;
7
9
  export declare const SnapTarget: import("@vibecook/strata-ecs").Tag;
@@ -24,9 +24,11 @@ export declare const GestureSettings: import("@vibecook/strata-ecs").Resource<im
24
24
  readonly multiTapSlopPx: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
25
25
  readonly wheelZoomSensitivity: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
26
26
  readonly wheelZoomMaxStep: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
27
- /** A plain wheel's job (design-015 §9, D-D11): "pan" (default, today) or the desk's "zoom" about the pointer. */
27
+ /** Ordinary scrolling pans by default; apps can opt into cursor-anchored wheel zoom. */
28
28
  readonly wheel: import("@vibecook/strata-ecs").FieldSpec<import("@vibecook/strata-ecs").EnumType<"pan" | "zoom">, true>;
29
- /** "zoom" mode's law: `zoom · exp(−Δ · wheelZoomRate)` for a plain wheel and a pinch. f64: the prototype's 0.0016, exactly. */
29
+ /** Pinch/modifier zoom response, independent of the plain wheel's job. */
30
+ readonly wheelZoomCurve: import("@vibecook/strata-ecs").FieldSpec<import("@vibecook/strata-ecs").EnumType<"clamped" | "exponential">, true>;
31
+ /** Continuous zoom: `zoom · exp(−Δ · wheelZoomRate)`. f64 keeps the configured rate exact. */
30
32
  readonly wheelZoomRate: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
31
33
  }>, {
32
34
  readonly tapMaxMs: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
@@ -42,9 +44,11 @@ export declare const GestureSettings: import("@vibecook/strata-ecs").Resource<im
42
44
  readonly multiTapSlopPx: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
43
45
  readonly wheelZoomSensitivity: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
44
46
  readonly wheelZoomMaxStep: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
45
- /** A plain wheel's job (design-015 §9, D-D11): "pan" (default, today) or the desk's "zoom" about the pointer. */
47
+ /** Ordinary scrolling pans by default; apps can opt into cursor-anchored wheel zoom. */
46
48
  readonly wheel: import("@vibecook/strata-ecs").FieldSpec<import("@vibecook/strata-ecs").EnumType<"pan" | "zoom">, true>;
47
- /** "zoom" mode's law: `zoom · exp(−Δ · wheelZoomRate)` for a plain wheel and a pinch. f64: the prototype's 0.0016, exactly. */
49
+ /** Pinch/modifier zoom response, independent of the plain wheel's job. */
50
+ readonly wheelZoomCurve: import("@vibecook/strata-ecs").FieldSpec<import("@vibecook/strata-ecs").EnumType<"clamped" | "exponential">, true>;
51
+ /** Continuous zoom: `zoom · exp(−Δ · wheelZoomRate)`. f64 keeps the configured rate exact. */
48
52
  readonly wheelZoomRate: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
49
53
  }>;
50
54
  /** Pick radii + retarget dead-band live mirror (design-003 §3 L1 targeting). */
@@ -47,12 +47,16 @@ import type { ByteChannel } from "../doc/channels";
47
47
  import { type Autosave, type AutosaveOpts, type AutosaveStorageWrite } from "../doc/autosave";
48
48
  import { type PresenceOpts, type PresenceSession } from "../presence/presence-kit";
49
49
  import type { EngineGpu } from "../surface/gpu-device";
50
- import { GESTURE_DEFAULTS, POINTER_DEFAULTS, type WheelMode } from "../settings/defaults";
50
+ import { GESTURE_DEFAULTS, POINTER_DEFAULTS, type WheelMode, type WheelZoomCurve } from "../settings/defaults";
51
51
  export interface CanvasEngineOpts {
52
52
  /** Registered widget types (definition happens at defineWidget; this list is validated). */
53
53
  readonly widgets?: readonly {
54
54
  readonly type: string;
55
55
  }[];
56
+ /** Preserve these schemas in old documents without loading their runtime or showing their objects. */
57
+ readonly retiredWidgets?: readonly {
58
+ readonly type: string;
59
+ }[];
56
60
  /** Registered tools (definition happens at defineTool; validated). */
57
61
  readonly tools?: readonly Tool[];
58
62
  /** Explicit Canvas SDK definitions. Supplying any typed field enables typed mode. */
@@ -106,12 +110,14 @@ export interface CanvasEngineOpts {
106
110
  readonly max?: number;
107
111
  };
108
112
  /**
109
- * GestureSettings seeds. `wheel` is a plain wheel's job (design-015 §9,
110
- * D-D11): "pan" (default) or the desk's "zoom" about the pointer by
111
- * `zoom · exp(−Δ · wheelZoomRate)` (default rate 0.0016, the prototype's).
113
+ * GestureSettings seeds. `wheel` selects ordinary scroll pan (default)
114
+ * or zoom. `wheelZoomCurve` selects pinch/modifier zoom independently.
115
+ * Omitted curves preserve the initial wheel mode's legacy response.
112
116
  */
113
- readonly gestures?: Partial<Record<Exclude<keyof typeof GESTURE_DEFAULTS, "wheel">, number>> & {
117
+ readonly gestures?: Partial<Record<Exclude<keyof typeof GESTURE_DEFAULTS, "wheel" | "wheelZoomCurve">, number>> & {
114
118
  readonly wheel?: WheelMode;
119
+ /** Pinch and modifier-wheel response; changing `wheel` never changes this curve. */
120
+ readonly wheelZoomCurve?: WheelZoomCurve;
115
121
  };
116
122
  readonly pointers?: Partial<Record<keyof typeof POINTER_DEFAULTS, number>>;
117
123
  readonly snap?: {
@@ -78,7 +78,7 @@ export type { FramePickSlot, FramePickSource, PointPick } from "./systems/l1-pic
78
78
  export { setWidgetProps } from "./widget/set-props";
79
79
  export { createWidgetRuntime, installWidgetRuntime, type WidgetRuntime } from "./widget/mount-store";
80
80
  export * from "./settings/defaults";
81
- export { CameraInertia, WheelZoomStep, createCameraSystems, type CameraSystems } from "./systems/camera-sim";
81
+ export { CameraInertia, CameraZoomStep, WheelZoomStep, createCameraSystems, type CameraSystems } from "./systems/camera-sim";
82
82
  export { restoreAutosave, startAutosave, type Autosave, type AutosaveOpts, type AutosaveState, type AutosaveStatus, type AutosaveStorageRead, type AutosaveStorageWrite, type CancelScheduled, type RestoreResult, } from "./doc/autosave";
83
83
  export { attachBroadcastRelay, type BroadcastRelay, type BroadcastRelayOpts, type RelayChannel, } from "./doc/broadcast-relay";
84
84
  export { createBreakpointSystem, createSelectionChromeSystem } from "./systems/chrome";
@@ -0,0 +1,8 @@
1
+ import { type Entity, type SystemCtx } from "@vibecook/strata-ecs";
2
+ import type { Tool } from "../tools/define-tool";
3
+ /**
4
+ * Decide ONCE at pointer-down, never during hover or rendering. Empty space in
5
+ * a multi-selection can carry the group; real objects, controls and handles
6
+ * keep their pick priority. Shift on the canvas starts an additive marquee.
7
+ */
8
+ export declare function selectionDragAt(ctx: SystemCtx, target: Entity | undefined, sx: number, sy: number, tool: Tool, shift: boolean): boolean;
@@ -18,10 +18,12 @@ export declare const GESTURE_DEFAULTS: {
18
18
  readonly wheelZoomSensitivity: 0.01;
19
19
  readonly wheelZoomMaxStep: 10;
20
20
  readonly wheel: "pan";
21
+ readonly wheelZoomCurve: "clamped";
21
22
  readonly wheelZoomRate: 0.0016;
22
23
  };
23
24
  /** What a plain wheel does to the camera (`GestureSettings.wheel`, design-015 §9). */
24
25
  export type WheelMode = "pan" | "zoom";
26
+ export type WheelZoomCurve = "clamped" | "exponential";
25
27
  /** Pick radii + retarget dead-band (design-003 §3 L1 targeting). */
26
28
  export declare const POINTER_DEFAULTS: {
27
29
  readonly radiusMousePx: 0;
@@ -40,6 +40,19 @@ export declare const WheelZoomStep: import("@vibecook/strata-ecs").Resource<impo
40
40
  readonly anchorY: import("@vibecook/strata-ecs").FieldSpec<"f32", true>;
41
41
  readonly tick: import("@vibecook/strata-ecs").FieldSpec<"u32", true>;
42
42
  }>;
43
+ /** Latest user-driven camera zoom, including touch pinch. Presentation hosts
44
+ * can acknowledge scale crossings without mistaking a fit, flight, document
45
+ * restore or zoom-through rebase for a gesture. Values describe cameraControl's
46
+ * zoom before later navigation systems run. Idle frames never write it. */
47
+ export declare const CameraZoomStep: import("@vibecook/strata-ecs").Resource<import("@vibecook/strata-ecs").ValueOf<{
48
+ readonly from: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
49
+ readonly to: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
50
+ readonly tick: import("@vibecook/strata-ecs").FieldSpec<"u32", true>;
51
+ }>, {
52
+ readonly from: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
53
+ readonly to: import("@vibecook/strata-ecs").FieldSpec<"f64", true>;
54
+ readonly tick: import("@vibecook/strata-ecs").FieldSpec<"u32", true>;
55
+ }>;
43
56
  export interface CameraSystems {
44
57
  cameraControl: TickSystem;
45
58
  cameraInertia: TickSystem;
@@ -13,9 +13,9 @@
13
13
  * - OPEN, the desk is INERT: every local pointer gets the one-tick `HandledByWidget` and `WheelHandled`, each tick, as the hand's
14
14
  * do — so "the wheel never moves the camera" is not a rule the camera keeps; it is a fact the camera never hears about. Over the
15
15
  * drawer the wheel scrolls it (`dy`; the OS's momentum arrives as deltas and is applied as it comes — no inertia of ours; ⌘/ctrl
16
- * and a pinch are swallowed) and a press-drag scrolls it; past an end the rest is the band's `stretch` (a reversal unwinds it
17
- * first), which lets go once the scroll input has been quiet `letGoMs` — or (K9) once a FADING tail has pushed it `fadeDeltas`
18
- * shrinking deltas, the rest of that tail spent (the OS's momentum no longer holds it for its second). A click on the dimmed desk — pressed and released there,
16
+ * and a pinch are swallowed). Wheel scrolling stays within the content: excess deltas are discarded, so a reversal responds
17
+ * immediately and an uneven momentum tail cannot restart an edge bounce. Only an intentional press-drag can pull the band's
18
+ * `stretch`; its spring returns on release. A click on the dimmed desk — pressed and released there,
19
19
  * unmoved — closes it. Shut, the wheel stays the tray's until it has been quiet `letGoMs` (K9): a flick's momentum still
20
20
  * arriving as the drawer shuts never zooms the desk.
21
21
  * - K5b, TAKING ONE (design-017 §9): a press on a SPECIMEN is `TrayPress specimen` — its type, the grab point across the object as the
@@ -74,10 +74,11 @@ export interface TrayPoseSource {
74
74
  export interface TrayPoseSlot {
75
75
  current: TrayPoseSource | null;
76
76
  }
77
- /** The tray's input numbers (design-017 §7): a click's slop, how long the scroll input must be quiet before the band lets go — and (K9, D-K9-c.3) how many shrinking deltas in a row a fading tail pushes the band before it lets go. (design-018 §5: the lip's drag, handle and pad retired with it.) */
77
+ /** The tray's input numbers: a click's slop and the quiet period for a drag's band and the wheel latch after closing. */
78
78
  export declare const TRAY_INPUT: {
79
79
  readonly slopPx: 4;
80
80
  readonly letGoMs: 120;
81
+ /** @deprecated Wheel input no longer estimates momentum from shrinking deltas. Kept for source compatibility. */
81
82
  readonly fadeDeltas: 3;
82
83
  };
83
84
  /** The tray's specimens (K5a): the tray entity's children tagged `Specimen`, in sibling order. */
@@ -27,8 +27,8 @@ export interface ToolRoute {
27
27
  /** Drag starting on empty canvas (after device overrides: touch/space/middle → pan). */
28
28
  readonly canvasDrag?: CanvasDragRoute;
29
29
  /**
30
- * The same drag with SHIFT held (design-015 §9, D-D11 — D2a-core): the desk's
31
- * select tool pans the bare mat and draws its marquee on shift —
30
+ * The same drag with SHIFT held. For example, a custom tool can pan normally
31
+ * and draw its marquee on shift —
32
32
  * `{ canvasDrag: "pan", canvasDragShift: "marquee" }`. Omitted: the tool's
33
33
  * own `canvasDrag`, so shift changes nothing (every tool before this field).
34
34
  * The device conventions (touch / space / middle → pan) still sit above it.
@@ -87,7 +87,8 @@ export interface WidgetBehaviorEntry {
87
87
  }
88
88
  export interface WidgetInteraction {
89
89
  readonly selectable?: boolean;
90
- readonly movable?: boolean;
90
+ /** "selection": core moves it with a group; a custom driver owns its solo drag. */
91
+ readonly movable?: boolean | "selection";
91
92
  /**
92
93
  * May this widget be dropped INTO an accepting container (design-015 §9, D-D6 — D2b)?
93
94
  * `"into"` (default): yes — for a GPU object, when its centre is let go over the container's
@@ -325,7 +325,8 @@ export declare class SlotPool {
325
325
  * it, then the objects stratum by stratum: within a stratum in paint order, one
326
326
  * `drawRange` per RUN of one kind (each kind counting its own records), the run
327
327
  * cut after an object with a live inside — the inside over its face (restoring
328
- * this slot's scissor), then that object's marks over the inside. Returns
328
+ * this slot's scissor), then that object's marks over the inside. The edge
329
+ * rulers finish the slot above its objects. Returns
329
330
  * whether it drew.
330
331
  */
331
332
  export declare function drawSlot(pass: GPURenderPassEncoder, size: {
@@ -381,7 +382,7 @@ export interface TraySlotSource {
381
382
  export declare function prepareFrame(encoder: GPUCommandEncoder, root: SlotSet, pool: SlotPool, inputs: GroundFrameInputs, grid?: GridConfig, target?: RenderTarget, traySlots?: TraySlotSource): PreparedFrame;
382
383
  /**
383
384
  * THE TRAY, drawn (design-017 §5, §8; K5a) — shared by `Ground.render` and the Node oracle: the drawer UNDER its specimens (the dim, its
384
- * shadows, the board to its edge, the accessories), each specimen by its own kind through the drawer's face (inside the edge — the rim
385
+ * shadows, the board to its edge), each specimen by its own kind through the drawer's face (inside the edge — the rim
385
386
  * laid over them all retired, design-018 §2), their name tags (the marks' pills), then the VEIL over them all at the top (design-018
386
387
  * rev 5: the plain board, whole in the header and fading out over its ramp — what hangs there fades into the board, never see-through
387
388
  * over a hole); then what the tray carries, whole. Shut (p 0) the drawer draws nothing (its pass laid no quad) and only a carried copy
@@ -502,7 +503,7 @@ export declare class Ground {
502
503
  /** When `idleTray` next lets a tray layer go (K7a — a time the host registers; ∞ — nothing to let go). */
503
504
  trayIdleAt(): number;
504
505
  }
505
- /** The specimens' name tags this frame (K5a): each label centred under its specimen — below a shelf's plank — in screen px. */
506
+ /** The specimens' name tags this frame (K5a): each label centred under its specimen, in screen px. */
506
507
  export declare function tagsOf(tray: TrayFrameInputs | undefined): {
507
508
  readonly label: string;
508
509
  readonly x: number;
@@ -256,19 +256,17 @@ export interface DeskLayerBoot {
256
256
  * The pegboard tray's door (design-017; K3) — the app's `a` and a rig's hand: the facts through core's tray ops (the one writer beside
257
257
  * the tray's input), the flux's pins and its state.
258
258
  */
259
- /** A specimen as the last frame drew it (K5a — the tray door's witness): its type, kind, tag and accessory, its rect and pegs on screen (CSS px), the scale its kind drew it at. */
259
+ /** A specimen as the last frame drew it (K5a — the tray door's witness): its type, kind, tag and rect on screen (CSS px), the scale its kind drew it at. */
260
260
  export interface TraySpecimenSeen {
261
261
  readonly type: string;
262
262
  readonly kind: string;
263
263
  readonly label: string;
264
- readonly accessory: string;
265
264
  readonly screen: {
266
265
  readonly x0: number;
267
266
  readonly y0: number;
268
267
  readonly x1: number;
269
268
  readonly y1: number;
270
269
  };
271
- readonly pegs: readonly (readonly [number, number])[];
272
270
  readonly zoom: number;
273
271
  /** K5b: its object as drawn on screen (the fit inside the hang). */
274
272
  readonly object: {
@@ -16,9 +16,9 @@ import { type MatLight } from "./night";
16
16
  * attachment's texels, `CSS px · dpr` (a fragment's `@builtin(position).xy`); colours sRGB-encoded 0..1 unless marked LINEAR.
17
17
  * The fields, x · y · z · w:
18
18
  *
19
- * - `cam` — the camera: the world point at the attachment's top-left (x, y — UNWRAPPED world units: the projector is fixed in
20
- * world), the zoom (z — CSS px per world unit, `mat_zoom`), the attachment's device px per CSS px (w — `mat_dpr`; below 1
21
- * for a capture's thumbnail or the held desk copy, petition I29);
19
+ * - `cam` — the camera: the world point at the attachment's top-left (x, y — UNWRAPPED world units), the zoom (z — CSS px
20
+ * per world unit, `mat_zoom`), the attachment's device px per CSS px (w — `mat_dpr`; below 1 for a capture's thumbnail or
21
+ * the held desk copy, petition I29);
22
22
  * - `view` — the attachment's size (x, y — CSS px), the grain's clock (z — seconds), the OBJECTS' presentation opacity (w —
23
23
  * 0..1, the slot's × their own presence: what every kind multiplies its output by);
24
24
  * - `phase` — the camera wrapped to the lattice's coarse period (x, y — world units: the lattice's phase, which the lines are
@@ -39,7 +39,9 @@ import { type MatLight } from "./night";
39
39
  * 0..1) and its dark floor (w — 0..1): `sample_gobo`, `shade_mat`;
40
40
  * - `grade` — the saturation bump in shade (x); y, z, w unused;
41
41
  * - `noise` — the blue noise's offset (x, y — uv, re-rolled while the wind blows), one tile texel in uv (z — 1 / 128); w unused;
42
- * - `wind` — the gobo's clock (x — seconds) and the plate's wind strength (y); z, w unused;
42
+ * - `wind` — the gobo's clock (x — seconds), the plate's wind strength (y), and projection space (z — 0 = world,
43
+ * 1 = viewport); w unused. Viewport shadows use CSS px at the original origin and scale, independent of the camera
44
+ * and slot light handovers. The mode uses an existing spare lane so the shared view block does not grow;
43
45
  * - `night` — the NIGHT (mat/night.ts): its amount (x — 0..1, 0 = the day's chain exactly), the Moon's illuminance (y — lux),
44
46
  * the exposure (z — scene → display), the snow (w — display units, peak to peak): `night_mat`, `mat_colour`;
45
47
  * - `moon` — the Moon's colour as the adapted eye takes it (xyz — LINEAR sRGB, Y = 1) and the sky's share in the shadow (w —
@@ -63,7 +65,8 @@ import { type MatLight } from "./night";
63
65
  * spacing (z); w unused;
64
66
  * - `box` — the slot's box on the attachment (x, y, w, h — CSS px): what is culled; the mat is fullscreen under the scissor;
65
67
  * - `light` — the camera the lamp's gobo is sampled under (`SlotLight`: x, y — world units at its top-left, z — its zoom) and
66
- * the cross-fade toward `light2` (w — 0..1): `lit_desk`, `lit_gobo`;
68
+ * the cross-fade toward `light2` (w — 0..1): `lit_desk`, `lit_gobo`. Viewport mode fixes this camera at (0, 0, 1)
69
+ * with no handover, so the mat uses the same shader path as a world-space lamp;
67
70
  * - `light2` — the second light a flight hands the slot to (x, y, z as `light`'s); w unused;
68
71
  * - `presence` — the SLOT's presentation opacity (x — 0..1: what the mat itself is drawn at; `view.w` is its objects'); y, z,
69
72
  * w unused.
@@ -112,6 +115,8 @@ export interface MatConfig {
112
115
  readonly ground: RGB;
113
116
  readonly ink: RGB;
114
117
  readonly gobo: {
118
+ /** World by default. Viewport keeps the projection at its original origin and 100% scale in CSS px while the canvas moves. */
119
+ readonly space?: "world" | "viewport";
115
120
  readonly opacity: number;
116
121
  readonly blurTexels: number;
117
122
  readonly shadeMix: number;
@@ -162,6 +167,41 @@ export declare const PLATE_SIZE = 512;
162
167
  export declare function matUniformValues(view: View & {
163
168
  readonly dpr: number;
164
169
  }, fadeIn: FadeIn, cfg: MatConfig, f: MatFrame, plateStrength: number, present?: Presentation, light?: MatLight, glyphs?: GlyphAtlasMeta, lit?: SlotLight): {
170
+ presence: number[];
171
+ light: readonly [0, 0, 1, 0];
172
+ light2: readonly [0, 0, 1, 0];
173
+ ruler: number[];
174
+ rulerText: number[];
175
+ rulerAlpha: number[];
176
+ rulerOrigin: number[];
177
+ rulerGlyph: number[];
178
+ rulerAtlas: number[];
179
+ rulerSites: number[];
180
+ rulerFormat: number[];
181
+ box: number[];
182
+ portals: number[];
183
+ clips: number[];
184
+ night: number[];
185
+ moon: number[];
186
+ rod: number[];
187
+ eigengrau: number[];
188
+ cam: number[];
189
+ view: number[];
190
+ phase: number[];
191
+ rungs: number[];
192
+ lod: number[];
193
+ line: number[];
194
+ grain: number[];
195
+ ground: number[];
196
+ ink: number[];
197
+ plane: number[];
198
+ goboMatrix: Mat4;
199
+ goboParams: number[];
200
+ gobo: number[];
201
+ grade: number[];
202
+ noise: number[];
203
+ wind: number[];
204
+ } | {
165
205
  presence: number[];
166
206
  light: number[];
167
207
  light2: number[];
@@ -4,6 +4,7 @@ import { type GlyphAtlasMeta, type MatConfig, type MatFrame, type PlateName, typ
4
4
  import { type MatLight } from "./night";
5
5
  import type { MatPass } from "../kit/view";
6
6
  import type { MatShaders } from "./shaders";
7
+ import { type MatRegion } from "./ruler-regions";
7
8
  export declare class CuttingMat implements MatPass {
8
9
  readonly name = "mat/mat";
9
10
  private readonly uniforms;
@@ -22,6 +23,7 @@ export declare class CuttingMat implements MatPass {
22
23
  /** The view block as last uploaded (K7a: uploaded only when its bytes moved; a layered kind compares a layer's view by it). */
23
24
  private readonly sentView;
24
25
  private viewSent;
26
+ private ruler;
25
27
  private readonly device;
26
28
  private readonly shared;
27
29
  private constructor();
@@ -78,6 +80,11 @@ export declare class CuttingMat implements MatPass {
78
80
  readonly dpr: number;
79
81
  }, fadeIn: FadeIn, cfg: MatConfig, frame: MatFrame, present?: Presentation, light?: MatLight, lit?: SlotLight): boolean;
80
82
  draw(pass: GPURenderPassEncoder): void;
83
+ /** The mat beneath objects; enabled ruler strips are reserved for the foreground. */
84
+ drawSurface(pass: GPURenderPassEncoder, clip: MatRegion): void;
85
+ /** The edge bands and frame above every object in this slot, within its portal. */
86
+ drawRulers(pass: GPURenderPassEncoder, clip: MatRegion): void;
87
+ private drawRegions;
81
88
  /** This slot's buffers; the shared plates go with the last slot standing. */
82
89
  dispose(): void;
83
90
  }
@@ -0,0 +1,17 @@
1
+ import type { View } from "../lattice/lod";
2
+ import type { RulerConfig } from "./layout";
3
+ export type MatRegion = readonly [number, number, number, number];
4
+ export interface RulerRegions {
5
+ readonly width: number;
6
+ readonly height: number;
7
+ readonly dpr: number;
8
+ readonly margin: number;
9
+ readonly band: number;
10
+ readonly line: number;
11
+ readonly surface: readonly MatRegion[];
12
+ readonly edges: readonly MatRegion[];
13
+ }
14
+ /** Geometry changes only on resize, DPR or ruler styling; camera motion reuses it. */
15
+ export declare function rulerRegions(view: View & {
16
+ readonly dpr: number;
17
+ }, ruler: RulerConfig, previous: RulerRegions | null): RulerRegions;