@kitlangton/knobs 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +303 -41
  2. package/dist/dev/{chunk-qtt698hp.js → chunk-7xgkerd2.js} +34 -11
  3. package/dist/dev/{chunk-ktsn42p7.js → chunk-jx1ktap3.js} +13762 -11794
  4. package/dist/dev/{chunk-kdewv0mt.js → chunk-pmkvb9ep.js} +1692 -207
  5. package/dist/dev/{chunk-e13znr7c.js → chunk-v8ssbcbk.js} +18 -7
  6. package/dist/dev/index.js +557 -130
  7. package/dist/index.js +589 -141
  8. package/dist/panel.js +21615 -17048
  9. package/dist/types/core/keys.d.ts +2 -0
  10. package/dist/types/core/random.d.ts +61 -1
  11. package/dist/types/core/remote.d.ts +5 -1
  12. package/dist/types/core/schema.d.ts +35 -6
  13. package/dist/types/core/store.d.ts +97 -8
  14. package/dist/types/core/unlock.d.ts +77 -0
  15. package/dist/types/core/variants.d.ts +10 -2
  16. package/dist/types/index.d.ts +4 -2
  17. package/dist/types/panel/attach.d.ts +2 -0
  18. package/dist/types/panel/crumbs.d.ts +19 -0
  19. package/dist/types/panel/editors.d.ts +20 -0
  20. package/dist/types/panel/feel.d.ts +103 -0
  21. package/dist/types/panel/flash.d.ts +13 -0
  22. package/dist/types/panel/give.d.ts +34 -1
  23. package/dist/types/panel/gpu/color.d.ts +4 -4
  24. package/dist/types/panel/gpu/renderer.d.ts +110 -6
  25. package/dist/types/panel/gpu/shader.wgsl.d.ts +1 -1
  26. package/dist/types/panel/haptics.d.ts +6 -2
  27. package/dist/types/panel/has.d.ts +0 -1
  28. package/dist/types/panel/index.d.ts +3 -1
  29. package/dist/types/panel/inspector.d.ts +33 -3
  30. package/dist/types/panel/lens.d.ts +113 -0
  31. package/dist/types/panel/motion.d.ts +2 -0
  32. package/dist/types/panel/optkeys.d.ts +7 -0
  33. package/dist/types/panel/page-hints.d.ts +2 -1
  34. package/dist/types/panel/prefs.d.ts +2 -2
  35. package/dist/types/panel/presence.d.ts +20 -0
  36. package/dist/types/panel/presets.d.ts +17 -5
  37. package/dist/types/panel/ramp-morph.d.ts +117 -0
  38. package/dist/types/panel/ramps.d.ts +1 -1
  39. package/dist/types/panel/reel.d.ts +43 -0
  40. package/dist/types/panel/scope.d.ts +48 -0
  41. package/dist/types/panel/slider.d.ts +22 -5
  42. package/dist/types/panel/sound.d.ts +137 -0
  43. package/dist/types/panel/styles.d.ts +1 -1
  44. package/dist/types/panel/tab-transition.d.ts +15 -0
  45. package/dist/types/panel/tabs.d.ts +1 -1
  46. package/dist/types/panel/toggle.d.ts +27 -0
  47. package/dist/types/panel/toolbar-grid.d.ts +6 -0
  48. package/dist/types/ui/activity-css.d.ts +1 -0
  49. package/dist/types/ui/activity-model.d.ts +122 -0
  50. package/dist/types/ui/activity.d.ts +67 -0
  51. package/dist/types/ui/follow.d.ts +17 -0
  52. package/dist/types/ui/index.d.ts +5 -1
  53. package/dist/types/ui/look.d.ts +9 -0
  54. package/dist/types/ui/picker-css.d.ts +1 -0
  55. package/dist/types/ui/picker-model.d.ts +53 -0
  56. package/dist/types/ui/picker.d.ts +67 -0
  57. package/dist/types/ui/react.d.ts +27 -0
  58. package/dist/types/ui/scrollbar.d.ts +12 -0
  59. package/dist/types/ui/solid.d.ts +23 -0
  60. package/dist/types/ui/split-model.d.ts +55 -0
  61. package/dist/types/ui/split.d.ts +22 -3
  62. package/dist/ui-react.js +3462 -690
  63. package/dist/ui-solid.js +3440 -689
  64. package/dist/ui.js +2963 -264
  65. package/package.json +1 -1
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Where each halving of the rate happens (px off the row: from, to). ×1 within 24 px, ×½ around
3
+ * 60, ×¼ around 110, ×⅛ beyond 146.
4
+ */
5
+ export declare const PRECISION: readonly (readonly [number, number])[];
6
+ /** How far (px) a pointer at `y` is off a row spanning `top`..`bottom` (0 on it). */
7
+ export declare const offRow: (y: number, top: number, bottom: number) => number;
8
+ /** How many halvings a drag `off` px from its row moves at: 0 near it, up to 3, smoothly. */
9
+ export declare const precisionDepth: (off: number) => number;
10
+ /** The rate (value per px of the hand, relative to 1:1) a drag `off` px from its row moves at. */
11
+ export declare const precisionRate: (off: number) => number;
12
+ /** The ruler's levels: intervals across the track, tick height (px) and the accent's alpha. */
13
+ export declare const RULER: readonly (readonly [number, number, number])[];
14
+ /** The ruler shows in full within `RULER_NEAR` px of the handle, fading out by `RULER_FADE`. */
15
+ export declare const RULER_NEAR = 36;
16
+ export declare const RULER_FADE = 120;
17
+ /** The ruler's finest level a slider of `steps` steps shows (each halves the last, from tenths). */
18
+ export declare const rulerLevels: (steps: number) => number;
19
+ /** How much of ruler level `level` (1–3) shows at `depth` halvings. */
20
+ export declare const rulerAlpha: (depth: number, level: number) => number;
21
+ /** The depth a ruler shows for a drag at `rate` (with ⌥'s tenth folded in), at most `levels`. */
22
+ export declare const rulerDepth: (rate: number, levels: number) => number;
23
+ /** How much a stretched control thins per unit of strain (a row ~300 px long, 14 px over: ~.92). */
24
+ export declare const THIN = 1.7;
25
+ /** The thinnest a stretched control gets. */
26
+ export declare const THINNEST = 0.85;
27
+ /** How thin a control stretched to `scale` times its length draws, across it. */
28
+ export declare const thinOf: (scale: number) => number;
29
+ /** Over how many px of give a control's stretching corners round off fully. */
30
+ export declare const ROUND_IN = 4;
31
+ /** How far (0–1) the corners at a stretching end have rounded off. */
32
+ export declare const roundOf: (give: number) => number;
33
+ /**
34
+ * A box `length` px long, stretched `give` px past one end (positive: past its far end, negative:
35
+ * past its start): its scale along it, about the end that stays put (0 its start, 1 its far end).
36
+ */
37
+ export declare const stretchOf: (give: number, length: number) => {
38
+ scale: number;
39
+ anchor: number;
40
+ };
41
+ /**
42
+ * Where a point `at` px along a box `length` long draws while it's stretched `give` px: points near
43
+ * the anchored end barely move, the stretching end moves by the whole give.
44
+ */
45
+ export declare const stretchAt: (at: number, give: number, length: number) => number;
46
+ /**
47
+ * The most a control gives where it has `room` px before something clips it: `most`, or less so
48
+ * it never draws cut off (and a hair at least, so meeting the limit still ticks).
49
+ */
50
+ export declare const giveRoom: (room: number, most: number) => number;
51
+ export type DetentKind = "default" | "base" | "round";
52
+ /** A detent's hold (px either side where the value sticks) and the ramp past it (px). */
53
+ export declare const DETENTS: Readonly<Record<DetentKind, {
54
+ readonly hold: number;
55
+ readonly ramp: number;
56
+ }>>;
57
+ /** How strong detents are at a drag's rate: full at 1:1, weaker faster than the rate slows. */
58
+ export declare const detentScale: (rate: number) => number;
59
+ export interface Detent {
60
+ /** Where it sits along the track (px). */
61
+ readonly at: number;
62
+ /** The value it holds. */
63
+ readonly value: number;
64
+ readonly kind: DetentKind;
65
+ }
66
+ /**
67
+ * The detents of a track `width` px wide: its default first, then the active preset's value,
68
+ * then the round values given, each dropped where it would crowd one before it.
69
+ */
70
+ export declare function detentsOf(width: number, min: number, max: number, o: {
71
+ readonly value: number;
72
+ readonly base?: number;
73
+ readonly round?: readonly number[];
74
+ }): Detent[];
75
+ /** A range's round values worth a detent: its middle, and zero when it lies inside. */
76
+ export declare const roundValues: (min: number, max: number) => number[];
77
+ /**
78
+ * Where the value shows for a hand at `x` (px): on a detent within its hold, catching up a little
79
+ * faster than the hand just past it, and the hand's own position beyond. `k` scales the detents.
80
+ */
81
+ export declare function warp(x: number, list: readonly Detent[], k?: number): number;
82
+ /**
83
+ * The hand position that shows `shown` with detents at strength `k` (`warp`'s inverse); on a
84
+ * detent, the one nearest `x`. Re-anchoring here when the strength changes keeps the value still.
85
+ */
86
+ export declare function unwarp(shown: number, x: number, list: readonly Detent[], k?: number): number;
87
+ /**
88
+ * A drag's detents: where the value shows, which detent holds it, and the moment one catches (to
89
+ * tick once). Once caught, a detent catches again only after the hand has left its reach, so a
90
+ * hand resting on its edge doesn't chatter.
91
+ */
92
+ export declare class Notches {
93
+ readonly list: readonly Detent[];
94
+ /** The detent holding the value, or -1. */
95
+ held: number;
96
+ private readonly armed;
97
+ constructor(list: readonly Detent[], x: number);
98
+ /** The shown position for a hand at `x` with detents at strength `k`, and any detent caught now. */
99
+ move(x: number, k?: number): {
100
+ shown: number;
101
+ caught?: Detent;
102
+ };
103
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * A button's press flash: its wash brightens at once and eases out, so a command fired from a key
3
+ * shows on the button it belongs to (Undo, Redo, Reset, Copy, Random, a group's die and reset).
4
+ * The DOM runs it as a CSS animation (`data-k-flash`, see the styles); the GPU renderer draws the
5
+ * same curve from `flashOf`.
6
+ */
7
+ export declare const FLASH_MS = 320;
8
+ export declare function flash(button: HTMLElement | undefined, wake?: () => void): void;
9
+ /**
10
+ * How much of `button`'s flash is left at `now` (1 to 0): ease-out cubic, as the DOM's
11
+ * `cubic-bezier(.33,1,.68,1)` from the flash back to the button's own wash.
12
+ */
13
+ export declare function flashOf(button: Element, now: number): number;
@@ -1,5 +1,10 @@
1
1
  /** The most a control gives past an end (px). */
2
2
  export declare const GIVE = 6;
3
+ /** The most a slider's row stretches past an end (px), dragged or panned alike. */
4
+ export declare const STRETCH = 14;
5
+ /** How long (s) a give takes to spring home, with no bounce: a readout's, and a stretch's. */
6
+ export declare const HOME_S = 0.25;
7
+ export declare const STRETCH_HOME_S = 0.35;
3
8
  /** The give `over` px of push past an end makes: 1:1 at first, never reaching `max`. */
4
9
  export declare const rubber: (over: number, max?: number) => number;
5
10
  /** The push (px) that makes `give` (`rubber`'s inverse). */
@@ -62,7 +67,12 @@ export declare const giveOf: (el: Element) => number;
62
67
  * pan puts it; let go, it springs home on one loop that both renderers read: the DOM as a
63
68
  * `translate`, the GPU through `giveOf`.
64
69
  */
65
- export declare function textGive(el: HTMLElement | SVGElement, wake: () => void): {
70
+ export declare function textGive(el: HTMLElement | SVGElement, wake: () => void, o?: {
71
+ /** Seconds to spring home (`HOME_S` by default). */
72
+ readonly home?: number;
73
+ /** Draws the give in the DOM (a `translate` by default; not called while the GPU draws). */
74
+ readonly draw?: (px: number) => void;
75
+ }): {
66
76
  /** The give as last held (0 once let go). */
67
77
  readonly give: number;
68
78
  /** Holds the give at `px` (signed), ticking as it starts. */
@@ -71,3 +81,26 @@ export declare function textGive(el: HTMLElement | SVGElement, wake: () => void)
71
81
  release(): void;
72
82
  };
73
83
  export type TextGive = ReturnType<typeof textGive>;
84
+ /**
85
+ * Draws `el` stretched like rubber, `x` px past an end along it (and `y` px down or up, for a pad):
86
+ * scaled about the end that stays put, thinner across it as it lengthens (`thin`), its stretching
87
+ * corners rounding off. CSS reads the vars (.knobs-stretching); `unclip` is a parent whose clip it
88
+ * may draw past meanwhile (its card).
89
+ */
90
+ export declare function drawStretch(el: HTMLElement, x: number, y: number, size: {
91
+ readonly w: number;
92
+ readonly h: number;
93
+ }, o?: {
94
+ readonly thin?: boolean;
95
+ readonly unclip?: Element | null;
96
+ }): void;
97
+ /**
98
+ * How far (px) `el` can stretch each way before an ancestor clips it (its overflow isn't
99
+ * visible), passing over `skip` (a card it unclips while it stretches).
100
+ */
101
+ export declare function roomOf(el: Element, skip?: Element | null): {
102
+ left: number;
103
+ right: number;
104
+ top: number;
105
+ bottom: number;
106
+ };
@@ -1,7 +1,5 @@
1
- export type Rgba = readonly [number, number, number, number];
2
- export declare function parseCssColor(raw: string, fallback?: Rgba): Rgba;
3
- export declare function withAlpha(c: Rgba, alphaFactor: number): Rgba;
4
- export declare function mixColor(a: Rgba, b: Rgba, t: number): Rgba;
1
+ import { mixRgba as mixColor, parseCssColor, type Rgba, withAlpha } from "../../ui/rgba.js";
2
+ export { mixColor, parseCssColor, type Rgba, withAlpha };
5
3
  /** CSS `color-mix(in srgb, a p, b)`, interpolated with premultiplied alpha like the browser. */
6
4
  export declare function cssMix(a: Rgba, b: Rgba, p: number): Rgba;
7
5
  export interface PanelThemeTokens {
@@ -124,5 +122,7 @@ export interface PanelThemeTokens {
124
122
  readonly thumb: Rgba;
125
123
  /** How strongly small drop shadows show under thumbs and pills (--k-lift). */
126
124
  readonly lift: number;
125
+ /** How dark the panel's drop shadow is (--k-shadow-strength): .48 on dark panels, .16 on light. */
126
+ readonly shadowStrength: number;
127
127
  }
128
128
  export declare function readPanelTokens(panel: HTMLElement, version?: number): PanelThemeTokens;
@@ -3,7 +3,8 @@ import { type HeaderDie } from "../die.js";
3
3
  import { type IconName } from "../icons.js";
4
4
  import { Edges } from "../motion.js";
5
5
  import type { MorphFrame } from "../morph.js";
6
- import type { PresetStrip } from "../presets.js";
6
+ import type { LensShape } from "../lens.js";
7
+ import { type PresetStrip } from "../presets.js";
7
8
  import type { DigitPlace, Slider } from "../slider.js";
8
9
  import type { TabStrip } from "../tabs.js";
9
10
  import type { ReadoutView } from "../../ui/readouts.js";
@@ -111,8 +112,11 @@ export interface GpuPointRow {
111
112
  readonly x: GpuExpander;
112
113
  readonly read: HTMLElement;
113
114
  readonly pad: HTMLElement;
115
+ /** Where the puck and the default sit at rest (px in the pad); a stretch moves them with it. */
114
116
  puck(): readonly [number, number];
115
117
  home(): readonly [number, number];
118
+ /** How far (px) the pad stretches past an edge across and down (see drawStretch). */
119
+ stretch(): readonly [number, number];
116
120
  dragging(): boolean;
117
121
  readonly wave: RowWave;
118
122
  isModified(): boolean;
@@ -130,6 +134,11 @@ export interface GpuEasingRow {
130
134
  curve(): readonly number[];
131
135
  /** P0, P1, P3, P2: the two arms from the ends to their handles. */
132
136
  arms(): readonly number[];
137
+ /** Steps the row's morph (curve, arms, handles) to this frame; whether it still moves. */
138
+ advance(now: number): boolean;
139
+ /** The line's motion blur (px), and each handle's (px across, px down): 0 at rest. */
140
+ blur(): number;
141
+ smear(i: number): readonly [number, number];
133
142
  /** (0,0) and (1,1) in the box. */
134
143
  guides(): readonly number[];
135
144
  readonly handles: readonly HTMLElement[];
@@ -148,6 +157,13 @@ export interface GpuRampHandle {
148
157
  readonly selected: boolean;
149
158
  /** Dragged off the strip or graph: it goes when let go. */
150
159
  readonly leaving: boolean;
160
+ /**
161
+ * How grown it is (0…1), when its row's morph sizes it: budding out of the line or merging
162
+ * into a neighbour. Its position is then already the morph's, so it isn't eased again.
163
+ */
164
+ readonly grow?: number;
165
+ /** Its motion blur (px along its travel, across and down), 0, 0 at rest. */
166
+ readonly smear?: readonly [number, number];
151
167
  }
152
168
  export interface GpuGradientRow {
153
169
  readonly kind: "gradient";
@@ -156,12 +172,15 @@ export interface GpuGradientRow {
156
172
  readonly row: HTMLElement;
157
173
  readonly x: GpuExpander;
158
174
  readonly read: HTMLElement;
159
- /** The head's swatch strip, and its stop ticks (x in the strip). */
175
+ /** The head's swatch strip, and its stop ticks (x in the strip; grown 0…1 as its stop is). */
160
176
  readonly mini: HTMLElement;
161
177
  ticks(): readonly {
162
178
  readonly el: HTMLElement;
163
179
  readonly x: number;
180
+ readonly grow?: number;
164
181
  }[];
182
+ /** Steps the row's morph to this frame (samples, stops and ticks); whether it still moves. */
183
+ advance(now: number): boolean;
165
184
  /** Evenly spaced samples as gamma sRGB triples, flat (see `gradientSamples`). */
166
185
  samples(): readonly number[];
167
186
  /** The editor's strip and how far in from each end its ramp starts (the handles' radius). */
@@ -192,7 +211,12 @@ export interface GpuCurveRow {
192
211
  readonly graph: HTMLElement;
193
212
  /** Grid lines as x0, y0, x1, y1 quadruples in the graph. */
194
213
  grid(): readonly number[];
214
+ /** The line and mini curve as the row's morph shows them now (stepped to `now`, ms). */
195
215
  curve(): readonly number[];
216
+ /** Steps the row's morph to this frame; whether it still moves. */
217
+ advance(now: number): boolean;
218
+ /** The line's motion blur (px), 0 at rest. */
219
+ blur(): number;
196
220
  handles(): readonly GpuRampHandle[];
197
221
  /** The hover crosshair: its x, the curve's y there, and the readout's element. */
198
222
  hover(): {
@@ -212,9 +236,17 @@ export interface GpuActionRow {
212
236
  readonly display: string;
213
237
  readonly row: HTMLElement;
214
238
  readonly button: HTMLButtonElement;
239
+ /** Its shortcut's key cap, at the row's end: a rebindable one listens while `capturing`. */
240
+ readonly keys?: GpuKeyCap;
215
241
  readonly wave: RowWave;
216
242
  isModified(): boolean;
217
243
  }
244
+ /** A key cap (a keybind's, an action's shortcut): its text, and whether it's listening for keys. */
245
+ export interface GpuKeyCap {
246
+ readonly chip: HTMLElement;
247
+ readonly text: HTMLElement;
248
+ capturing(): boolean;
249
+ }
218
250
  /** A vector's number cell: its axis letter and readout (DOM-placed text). */
219
251
  export interface GpuCell {
220
252
  readonly el: HTMLElement;
@@ -397,6 +429,13 @@ export interface GpuPanelBinding {
397
429
  readonly rows: readonly GpuRowBinding[];
398
430
  readonly actionButtons: readonly HTMLButtonElement[];
399
431
  isPopoverOpen(): boolean;
432
+ /** The focus lens (lens.ts): its shapes each frame, drawn as the DOM's `.knobs-lens`. */
433
+ readonly lens?: {
434
+ frame(now: number): readonly LensShape[];
435
+ moving(now: number): boolean;
436
+ };
437
+ /** The scope line beside the title (crumbs.ts): its spans are drawn where they sit. */
438
+ readonly crumbs?: HTMLElement;
400
439
  /** While the panel grows out of (or into) its chip: the shape at a frame time. */
401
440
  readonly morph?: (now: number) => MorphFrame | undefined;
402
441
  /** True while rows, cards or group heads arrive or leave (a descriptor swap). */
@@ -517,7 +556,10 @@ declare class GpuOverlayManager {
517
556
  private curSubHovered;
518
557
  /** Whether the pointer has one of the panel's rows (and keys haven't taken over since). */
519
558
  private curPointerRow;
520
- private readonly hotRows;
559
+ /** The panel being drawn marks focus with its lens: the per-level washes step aside. */
560
+ private curLens;
561
+ /** Each panel's armed look (--k-armed-*, --k-title-rest), read again when styles change. */
562
+ private readonly armedLooks;
521
563
  private curPanelRect;
522
564
  private curPanelScrollTop;
523
565
  private curLayoutKey;
@@ -601,11 +643,21 @@ declare class GpuOverlayManager {
601
643
  * their hover twins, at --k-button-radius.
602
644
  */
603
645
  private drawButtonBox;
604
- private isHot;
605
646
  /** Square inside its card, except the card's own rounded corners on the first and last rows. */
606
647
  private rowCorners;
607
648
  /** A row's hover wash, drawn beneath its control like the DOM row background. */
608
649
  private drawRowHover;
650
+ /**
651
+ * A row stretched `give` px past an end, as drawStretch scales it in the DOM: its rect (about
652
+ * the end that stays put, thinner across), its scale along, its corners rounding off at the
653
+ * stretching end, and its clip let out to the panel's on that side (past its card).
654
+ */
655
+ /**
656
+ * A box stretched `x` px past an end across and `y` px down or up, about the far ends, and
657
+ * (`thin`, stretched along x) thinner down, as drawStretch scales it in the DOM.
658
+ */
659
+ private stretchRect;
660
+ private stretch;
609
661
  /** The hairline above every row but a card's first, and the focus wash. */
610
662
  private drawRowOverlay;
611
663
  /** Whether `el` shows its focus wash: one wash at a time, the pointer's row's while it has one. */
@@ -613,6 +665,11 @@ declare class GpuOverlayManager {
613
665
  private drawSeparator;
614
666
  /** The focus wash, matching the row's corners inside its card. */
615
667
  private drawFocus;
668
+ /**
669
+ * A header or group button that blooms in and out of its slot (`data-shown`): its opacity, scale
670
+ * and blur (σ, px) from the DOM's transition while one runs, else simply there or not.
671
+ */
672
+ private bloomOf;
616
673
  private drawIcon;
617
674
  /**
618
675
  * Copy, and the check it turns into once copied, from the DOM's transitions while they run
@@ -621,6 +678,18 @@ declare class GpuOverlayManager {
621
678
  private drawCopy;
622
679
  /** The die is always traced, at rest too, exactly as the DOM canvas does: nothing swaps. */
623
680
  private drawDie;
681
+ /** Panels whose DOM overlays `cutUnderHead` has cut, to restore once nothing is under. */
682
+ private readonly headCuts;
683
+ /**
684
+ * The DOM pieces the GPU leaves above its canvas (a row's accessory, the number being typed,
685
+ * the search field) are cut at a pinned header's foot (`foot`, viewport y), as the rows are.
686
+ */
687
+ private cutUnderHead;
688
+ /**
689
+ * A button's press flash (flash.ts) over its wash: the wash brightened toward the text colour,
690
+ * easing out. Returns `ink` brightened toward the text colour while the flash lasts.
691
+ */
692
+ private drawFlash;
624
693
  /** A circular icon button's hover/focus wash. */
625
694
  private drawRoundWash;
626
695
  /**
@@ -648,6 +717,7 @@ declare class GpuOverlayManager {
648
717
  /** The current row's selection wash (0…1), which its hover wash gives way to. */
649
718
  private curSelected;
650
719
  /** A stroke through `pts` (x,y pairs in viewport px), round-capped like SVG's. */
720
+ /** `blur` (px) softens it across, as a moving line's smear (the DOM's Gaussian over √12). */
651
721
  private pushLine;
652
722
  /**
653
723
  * Eases a list of numbers toward `target` on the fill spring, the way the DOM transitions the
@@ -660,6 +730,32 @@ declare class GpuOverlayManager {
660
730
  private shape;
661
731
  /** An outline like CSS `outline: 1.5px` at `offset`, following `radius`; drawn while focus-visible. */
662
732
  private readout;
733
+ /** Each name-like readout's text and the one before it, for their crossfade (see `fadeText`). */
734
+ private readonly fades;
735
+ /** Text that crossfades from what it said before when its element says `data-fade`, as the DOM's. */
736
+ private fadeText;
737
+ /**
738
+ * A rolling readout (reel.ts), right-aligned where its element ends: each number a wheel per
739
+ * place, as the slider's readout draws its digits, and the text between them still. Laid out
740
+ * here from the glyphs' advances (tabular digits), not from the DOM's spans, which may not
741
+ * have caught up yet.
742
+ */
743
+ private drawRolling;
744
+ private advanceOf;
745
+ /**
746
+ * A number's places, right-aligned at `right`: each digit a wheel seen through a feathered
747
+ * slot (faces 2.1em apart, as the DOM's reel), blurring with speed; punctuation keeps its own
748
+ * advance, and a place on its way out keeps its last spot. True while any place moves.
749
+ */
750
+ private drawPlaces;
751
+ /** The armed look's tokens for a panel (see the styles' --k-armed-*). */
752
+ private armedLook;
753
+ /** The focus lens's shapes (lens.ts), as the DOM's `.knobs-lens`: a wash and a hairline. */
754
+ private drawLens;
755
+ /** The scope line's spans (crumbs.ts) where the DOM placed them, at their opacity. */
756
+ private drawCrumbs;
757
+ /** The soft wash on the card focus is on (`data-k-scope`), as the DOM's ::after. */
758
+ private drawScope;
663
759
  /** A disclosure head (hover, label and changed dot, caret, focus); returns the body's clip, if open. */
664
760
  private drawHead;
665
761
  /** A disclosure chevron, turning a quarter on the lead spring as it opens. */
@@ -674,8 +770,6 @@ declare class GpuOverlayManager {
674
770
  private drawEasing;
675
771
  /** A gradient strip from its samples (see shader kind 13), `inset` in from each end. */
676
772
  private pushRamp;
677
- /** How far a handle that arrived mid-life has grown in (`data-born`), like the DOM's keyframes. */
678
- private appear;
679
773
  private drawGradient;
680
774
  private drawCurve;
681
775
  private readonly lastHover;
@@ -694,6 +788,16 @@ declare class GpuOverlayManager {
694
788
  private drawRange;
695
789
  private drawAngle;
696
790
  private drawKeybind;
791
+ /** When each listening key cap started, so its breathing starts from full strength. */
792
+ private readonly capSince;
793
+ /** Each key cap's text and the one before it, for their crossfade. */
794
+ private readonly capTexts;
795
+ /**
796
+ * A key cap, as the DOM's: its tray's width glides to fit new text (snappy, no bounce) with its
797
+ * right edge still, while the old text fades out and the new in. Listening, it takes a soft
798
+ * accent wash and its text breathes; no ring.
799
+ */
800
+ private drawKeyCap;
697
801
  /** A readout's clip: the card's, narrowed to `el` when given. */
698
802
  private clipTo;
699
803
  /** Paints a readout's ops (local px from `r`'s corner), clipped to it, as its canvas does. */
@@ -1,2 +1,2 @@
1
- export declare const FLOATS_PER_PRIM = 40;
1
+ export declare const FLOATS_PER_PRIM = 44;
2
2
  export declare const panelWgsl: string;
@@ -1,5 +1,9 @@
1
- /** One light tick for a change made by `from`'s control, unless ticks are off or too close. */
2
- export declare function tick(from: Element): void;
1
+ import { type SoundCue } from "./sound.js";
2
+ /**
3
+ * One light tick for a change made by `from`'s control, unless ticks are off or too close. With
4
+ * `sound`, a panel that plays sounds plays that cue at the same moment (see sound.ts).
5
+ */
6
+ export declare function tick(from: Element, sound?: SoundCue): void;
3
7
  /**
4
8
  * Lays a label for the hidden switch over `target` (a positioned button), so a tap on it is the
5
9
  * user's own tap on a switch: the only tick iOS 26.5+ plays. Only where Safari's switch exists and
@@ -7,7 +7,6 @@
7
7
  * - `data-k-fv` on each ancestor of the focused element while it's `:focus-visible`
8
8
  * (`:has(:focus-visible)`); `"track"` when that's a slider track, `"head"` an editor's header.
9
9
  * - `data-k-active` on each ancestor of a `.knobs-active` element (`:has(.knobs-active)`).
10
- * - `data-k-head-hover` on an editor row whose header is hovered (`:has(>.knobs-x-head:hover)`).
11
10
  * - `data-k-row-hover` on the root while the pointer is on one of its rows
12
11
  * (`:has(.knobs-card>:hover)`).
13
12
  */
@@ -1,4 +1,5 @@
1
- export { attach } from "./attach.js";
1
+ export { attach, status } from "./attach.js";
2
+ export { toggleLayer, type ToggleLayer, type ToggleSurface } from "./toggle.js";
2
3
  export { getGpuOverlayManager, resolveRendererMode, type KnobsGpuDiagnostics, } from "./gpu/renderer.js";
3
4
  export { computeHintPrefixes, type HintBadgeState, type HintCandidate, type HintResolution, } from "./hints.js";
4
5
  export { assignPageCodes, hints, pageHints, type HintPainter, type HintSourceOptions, type PageHints, type PageHintTarget, } from "./page-hints.js";
@@ -6,5 +7,6 @@ export { Spring, VelocityTracker } from "./motion.js";
6
7
  export { createPanel, mountPage, mountPanel, type Panel, type PanelSearch } from "./panel.js";
7
8
  export { balancedRuns, type FoldSummaryInfo, type MountPageOptions, type Page, type PageAction, type PageCard, type PageCardOptions, type PageControl, type PageFoldOptions, type PageFoldSource, type PageGroupInfo, type PageHighlight, type PageSectionInfo, } from "./page.js";
8
9
  export { createPresetStrip, nextPresetIndex, resolveActivePresetEntry, type ActivePresetState, type PresetEntry, type PresetStrip, } from "./presets.js";
10
+ export { sound, type CueDetail, type Sound, type SoundCue, type SoundLayer, type SoundOptions, type SoundTheme, } from "./sound.js";
9
11
  export { injectStyles } from "./styles.js";
10
12
  export { attachVariantSwitcher, getSwitcherOptions, type ChoiceKey, type SwitcherOptions, } from "./switcher.js";
@@ -1,5 +1,5 @@
1
- import { type AngleField, type KeybindField, type Point, type RangeField, type SeedField, type ToolbarField, type ToolbarItem, type Vec3, type VecField } from "../core/schema.js";
2
- import type { EditorRow, RowContext } from "./editors.js";
1
+ import { toolbarShortcut, type AngleField, type KeybindField, type Point, type RangeField, type SeedField, type ToolbarField, type ToolbarItem, type Vec3, type VecField } from "../core/schema.js";
2
+ import { type EditorRow, type RowContext } from "./editors.js";
3
3
  type Vec = Point & {
4
4
  readonly z?: number;
5
5
  };
@@ -7,6 +7,28 @@ export declare function vecRow(c: RowContext<VecField>): EditorRow;
7
7
  export declare function rangeRow(c: RowContext<RangeField>): EditorRow;
8
8
  export declare function angleRow(c: RowContext<AngleField>): EditorRow;
9
9
  export declare function seedRow(c: RowContext<SeedField>): EditorRow;
10
+ export interface KeyCap {
11
+ readonly chip: HTMLButtonElement;
12
+ readonly text: HTMLElement;
13
+ capturing(): boolean;
14
+ /** The combination it shows: `""` for none, undefined for mixed ("—"). */
15
+ show(combo: string | undefined): void;
16
+ }
17
+ /**
18
+ * A key cap that records a combination: a click, Enter or Space listens, the next combination is
19
+ * the value, Esc cancels and ⌫ clears. While it listens its row takes the active wash and the cap
20
+ * breathes, "Type keys…" (or the modifiers held so far) in its place; its width follows its text
21
+ * on a spring, its right edge still. Keybind rows and rebindable action rows use it.
22
+ */
23
+ export declare function keyCap(o: {
24
+ readonly doc: Document;
25
+ readonly row: HTMLElement;
26
+ /** What the cap reads with no combination. */
27
+ readonly empty: string;
28
+ name(): string;
29
+ set(combo: string): void;
30
+ wake(): void;
31
+ }): KeyCap;
10
32
  export declare function keybindRow(c: RowContext<KeybindField>): EditorRow;
11
33
  export interface ToolbarRow extends EditorRow {
12
34
  readonly field: ToolbarField;
@@ -14,7 +36,15 @@ export interface ToolbarRow extends EditorRow {
14
36
  match(event: KeyboardEvent, global: boolean): ToolbarItem | undefined;
15
37
  press(item: ToolbarItem): void;
16
38
  swap(field: ToolbarField): void;
39
+ /** Shows the shortcuts as they are now (after a rebinding). */
40
+ refresh(): void;
17
41
  }
18
- export declare function toolbarRow(c: RowContext<ToolbarField>, press: (item: ToolbarItem) => void): ToolbarRow;
42
+ type Shortcut = ReturnType<typeof toolbarShortcut>;
43
+ /**
44
+ * A toolbar: its buttons in equal columns, as many as fit and balanced across the rows (see
45
+ * `toolbarColumns`), each with its icon and label at the start and its shortcut at the end.
46
+ * `keyOf` is each item's shortcut as it is now (the store's rebinding, else its own).
47
+ */
48
+ export declare function toolbarRow(c: RowContext<ToolbarField>, press: (item: ToolbarItem) => void, keyOf?: (item: ToolbarItem) => Shortcut): ToolbarRow;
19
49
  /** The value a vector shows, as `{ x, y }` or `{ x, y, z }`. */
20
50
  export type { Vec, Vec3 };
@@ -0,0 +1,113 @@
1
+ /** Corner radii: top left, top right, bottom right, bottom left. */
2
+ export type LensCorners = [number, number, number, number];
3
+ /** A box with its corners, in viewport px. */
4
+ export interface LensBox {
5
+ x: number;
6
+ y: number;
7
+ w: number;
8
+ h: number;
9
+ r: LensCorners;
10
+ }
11
+ export type LensLevel = "editor" | "row" | "card" | "panel";
12
+ /**
13
+ * One shape to draw: its box, how present it is (0–1), and its wash and edge (shares of
14
+ * --k-surface-hi and --k-line-hi).
15
+ */
16
+ export interface LensShape extends LensBox {
17
+ alpha: number;
18
+ wash: number;
19
+ line: number;
20
+ }
21
+ /** The look, from the panel's `--k-lens-*` tokens (see the README). */
22
+ export interface LensTune {
23
+ /** The morph's duration (ms), a spring with no bounce. */
24
+ ms: number;
25
+ /** How much quicker the size settles than the position (1: together). */
26
+ lead: number;
27
+ /** The wash: a share of --k-surface-hi. */
28
+ wash: number;
29
+ /** The hairline edge: a share of --k-line-hi. */
30
+ line: number;
31
+ /** The wash at the panel's level, where the shape covers everything (a share of `wash`). */
32
+ panelWash: number;
33
+ /** A row's (or an editor part's) shape sits this far inside it (px). */
34
+ inset: number;
35
+ /** The panel's shape sits this far inside its edge (px). */
36
+ panelInset: number;
37
+ }
38
+ export declare const LENS_DEFAULTS: LensTune;
39
+ export declare function readLensTune(style: CSSStyleDeclaration): LensTune;
40
+ /**
41
+ * Offsets that decay to zero on a critically damped spring (ω = 2π / duration), sampled by time:
42
+ * x(t) = (x₀ + (v₀ + ωx₀)t)·e^(−ωt). Each channel has its own ω.
43
+ */
44
+ export declare class Glide {
45
+ omegas: readonly number[];
46
+ private readonly eps;
47
+ private x0;
48
+ private v0;
49
+ private t0;
50
+ constructor(omegas: readonly number[], eps?: number);
51
+ sample(now: number): {
52
+ x: number[];
53
+ v: number[];
54
+ };
55
+ /** From `now`, the offsets are `x` moving at `v` (px/s). */
56
+ set(x: readonly number[], v: readonly number[], now: number, omegas?: readonly number[]): void;
57
+ zero(): void;
58
+ resting(now: number): boolean;
59
+ }
60
+ /** The ω for a spring that settles in `ms` with no bounce (knobs' mapping: ω = 2π / duration). */
61
+ export declare const omegaOf: (ms: number) => number;
62
+ /** A box as glide channels (x, y, w, h, then the four radii), and back. */
63
+ export declare const boxChannels: (b: LensBox) => number[];
64
+ export declare const boxPlus: (b: LensBox, d: readonly number[]) => LensBox;
65
+ /**
66
+ * The corners a box inside a rounded container shows: where one of its corners sits on the
67
+ * container's (within half a pixel), the container's radius there, else its own. A row in a card
68
+ * is square but for the card's corners it reaches; so is an editor's part.
69
+ */
70
+ export declare function cornersWithin(box: {
71
+ left: number;
72
+ top: number;
73
+ right: number;
74
+ bottom: number;
75
+ }, own: LensCorners, outer?: {
76
+ left: number;
77
+ top: number;
78
+ right: number;
79
+ bottom: number;
80
+ r: LensCorners;
81
+ }): LensCorners;
82
+ export interface LensTarget {
83
+ readonly el: HTMLElement;
84
+ readonly level: LensLevel;
85
+ }
86
+ export interface LensOptions {
87
+ readonly root: HTMLElement;
88
+ /** A page: the panel's level is what shows of it under its header. */
89
+ readonly header?: HTMLElement;
90
+ readonly page?: boolean;
91
+ /** Whether a target shows now (a row's only while keys are in use, say). */
92
+ readonly shown: (target: LensTarget) => boolean;
93
+ readonly reduced: () => boolean;
94
+ /** Asks the GPU overlay for a frame. */
95
+ readonly wake: () => void;
96
+ /** While the layout glides (a page's cards): the DOM shape is re-placed every frame. */
97
+ readonly follow?: () => boolean;
98
+ }
99
+ export interface Lens {
100
+ /** The element the DOM draws it with. */
101
+ readonly element: HTMLElement;
102
+ /** Where focus is: a target, `null` to fade where it is, or "out" to grow out and fade. */
103
+ set(target: LensTarget | null | "out"): void;
104
+ readonly target: LensTarget | null;
105
+ /** The shapes to draw at `now` (viewport px). */
106
+ frame(now: number): LensShape[];
107
+ moving(now: number): boolean;
108
+ tune(): LensTune;
109
+ /** Re-place it (a scroll, a resize, a change in what shows). */
110
+ poke(followMs?: number): void;
111
+ dispose(): void;
112
+ }
113
+ export declare function createLens(o: LensOptions): Lens;
@@ -40,6 +40,8 @@ export declare class Edges {
40
40
  export declare const POP_MS = 360;
41
41
  /** Decile pop: a critically damped kick that swells to `peak` at 55 ms and settles (t in ms). */
42
42
  export declare function popScale(t: number, peak?: number): number;
43
+ /** A slider's handle settling on a detent: its height swells like the pop, a little more (t in ms). */
44
+ export declare const settleScale: (t: number) => number;
43
45
  export declare class VelocityTracker {
44
46
  private samples;
45
47
  add(x: number, y: number, t?: number): void;
@@ -0,0 +1,7 @@
1
+ import type { RowOptions } from "./editors.js";
2
+ export declare function createOptionKeys(doc: Document, root: HTMLElement, wake: () => void): {
3
+ /** Shows `options`' digits (undefined hides them); the same ones again just re-place. */
4
+ show(options: RowOptions | undefined): void;
5
+ dispose(): void;
6
+ };
7
+ export type OptionKeys = ReturnType<typeof createOptionKeys>;