@kitlangton/knobs 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1270 -2
- package/dist/dev/chunk-e13znr7c.js +155 -0
- package/dist/dev/chunk-kdewv0mt.js +1334 -0
- package/dist/dev/chunk-ktsn42p7.js +15668 -0
- package/dist/dev/chunk-qtt698hp.js +1118 -0
- package/dist/dev/index.js +1389 -0
- package/dist/index.js +2367 -0
- package/dist/panel.js +23635 -0
- package/dist/react.js +326 -0
- package/dist/solid.js +336 -0
- package/dist/themes.js +235 -0
- package/dist/types/core/adapter.d.ts +21 -0
- package/dist/types/core/code.d.ts +3 -0
- package/dist/types/core/color.d.ts +27 -0
- package/dist/types/core/easing.d.ts +21 -0
- package/dist/types/core/internal.d.ts +18 -0
- package/dist/types/core/keys.d.ts +21 -0
- package/dist/types/core/mutate.d.ts +21 -0
- package/dist/types/core/ramp.d.ts +150 -0
- package/dist/types/core/random.d.ts +2 -0
- package/dist/types/core/readout.d.ts +73 -0
- package/dist/types/core/remote.d.ts +258 -0
- package/dist/types/core/schema.d.ts +526 -0
- package/dist/types/core/spring.d.ts +38 -0
- package/dist/types/core/storage.d.ts +8 -0
- package/dist/types/core/store.d.ts +474 -0
- package/dist/types/core/theme.d.ts +27 -0
- package/dist/types/core/variants.d.ts +17 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/panel/attach.d.ts +5 -0
- package/dist/types/panel/choice.d.ts +56 -0
- package/dist/types/panel/die.d.ts +121 -0
- package/dist/types/panel/editors.d.ts +159 -0
- package/dist/types/panel/folds.d.ts +14 -0
- package/dist/types/panel/give.d.ts +73 -0
- package/dist/types/panel/gpu/atlas.d.ts +40 -0
- package/dist/types/panel/gpu/color.d.ts +128 -0
- package/dist/types/panel/gpu/die.wgsl.d.ts +1 -0
- package/dist/types/panel/gpu/renderer.d.ts +712 -0
- package/dist/types/panel/gpu/shader.wgsl.d.ts +2 -0
- package/dist/types/panel/haptics.d.ts +8 -0
- package/dist/types/panel/has.d.ts +14 -0
- package/dist/types/panel/hints.d.ts +45 -0
- package/dist/types/panel/icons.d.ts +30 -0
- package/dist/types/panel/index.d.ts +10 -0
- package/dist/types/panel/inspector.d.ts +20 -0
- package/dist/types/panel/measure.d.ts +6 -0
- package/dist/types/panel/menu.d.ts +38 -0
- package/dist/types/panel/morph.d.ts +38 -0
- package/dist/types/panel/motion.d.ts +77 -0
- package/dist/types/panel/page-hints.d.ts +82 -0
- package/dist/types/panel/page.d.ts +423 -0
- package/dist/types/panel/panel.d.ts +43 -0
- package/dist/types/panel/position.d.ts +5 -0
- package/dist/types/panel/prefs.d.ts +28 -0
- package/dist/types/panel/presets.d.ts +48 -0
- package/dist/types/panel/ramps.d.ts +14 -0
- package/dist/types/panel/readout-row.d.ts +21 -0
- package/dist/types/panel/reveal.d.ts +15 -0
- package/dist/types/panel/rolling-css.d.ts +2 -0
- package/dist/types/panel/search.d.ts +36 -0
- package/dist/types/panel/seg.d.ts +15 -0
- package/dist/types/panel/session.d.ts +21 -0
- package/dist/types/panel/slider.d.ts +92 -0
- package/dist/types/panel/smear.d.ts +7 -0
- package/dist/types/panel/spin.d.ts +13 -0
- package/dist/types/panel/styles.d.ts +11 -0
- package/dist/types/panel/swipe.d.ts +114 -0
- package/dist/types/panel/switcher.d.ts +20 -0
- package/dist/types/panel/tabs.d.ts +31 -0
- package/dist/types/panel/thumb.d.ts +36 -0
- package/dist/types/react/Knobs.d.ts +15 -0
- package/dist/types/react/VariantSwitcher.d.ts +10 -0
- package/dist/types/react/index.d.ts +3 -0
- package/dist/types/react/useControls.d.ts +11 -0
- package/dist/types/solid/index.d.ts +50 -0
- package/dist/types/themes/index.d.ts +1 -0
- package/dist/types/ui/bento-css.d.ts +1 -0
- package/dist/types/ui/bento-model.d.ts +96 -0
- package/dist/types/ui/bento.d.ts +77 -0
- package/dist/types/ui/commands.d.ts +11 -0
- package/dist/types/ui/confirm.d.ts +13 -0
- package/dist/types/ui/index.d.ts +20 -0
- package/dist/types/ui/layer.d.ts +70 -0
- package/dist/types/ui/look.d.ts +53 -0
- package/dist/types/ui/menu.d.ts +63 -0
- package/dist/types/ui/overlay-css.d.ts +1 -0
- package/dist/types/ui/overlay-model.d.ts +87 -0
- package/dist/types/ui/palette.d.ts +38 -0
- package/dist/types/ui/popover.d.ts +35 -0
- package/dist/types/ui/react.d.ts +45 -0
- package/dist/types/ui/readout-css.d.ts +1 -0
- package/dist/types/ui/readout-model.d.ts +137 -0
- package/dist/types/ui/readouts.d.ts +85 -0
- package/dist/types/ui/rgba.d.ts +6 -0
- package/dist/types/ui/solid.d.ts +40 -0
- package/dist/types/ui/split-model.d.ts +81 -0
- package/dist/types/ui/split.d.ts +75 -0
- package/dist/types/ui/timeline-model.d.ts +83 -0
- package/dist/types/ui/timeline.d.ts +76 -0
- package/dist/types/ui/toast.d.ts +19 -0
- package/dist/types/ui/tooltip.d.ts +19 -0
- package/dist/types/ui/tree-model.d.ts +125 -0
- package/dist/types/ui/tree.d.ts +95 -0
- package/dist/ui-react.js +6558 -0
- package/dist/ui-solid.js +6511 -0
- package/dist/ui.js +9238 -0
- package/package.json +99 -4
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
import { type Oklch } from "./color.js";
|
|
2
|
+
import { type Bezier, type EasingName } from "./easing.js";
|
|
3
|
+
import type { LogEntry, TableRows } from "./readout.js";
|
|
4
|
+
import { CURVE_SHAPES, type CurveInterp, type CurvePoint, type GradientSpace, type GradientStop } from "./ramp.js";
|
|
5
|
+
import type { SpringValue } from "./spring.js";
|
|
6
|
+
export interface FieldMeta {
|
|
7
|
+
readonly label?: string;
|
|
8
|
+
readonly group?: string;
|
|
9
|
+
/**
|
|
10
|
+
* What the group's header shows when it isn't the `group` id itself (the first field that
|
|
11
|
+
* gives one wins). The id stays the group's identity: presets, resets, highlights and code.
|
|
12
|
+
*/
|
|
13
|
+
readonly groupLabel?: string;
|
|
14
|
+
/** A page region the field's group sits in (see `mountPage`); panels ignore it. */
|
|
15
|
+
readonly section?: string;
|
|
16
|
+
/** What the section's heading shows (the first field that gives one wins); `section` by default. */
|
|
17
|
+
readonly sectionLabel?: string;
|
|
18
|
+
/** One muted line under the group's card title on a page (the first field that gives one wins). */
|
|
19
|
+
readonly groupDescription?: string;
|
|
20
|
+
/** One muted line under the section's heading on a page (the first field that gives one wins). */
|
|
21
|
+
readonly sectionDescription?: string;
|
|
22
|
+
readonly shortcut?: string;
|
|
23
|
+
/** `false` keeps the field out of Random and Mutate, as a lock does, but by declaration. */
|
|
24
|
+
readonly random?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* The row dims and takes no edits from the pointer or keys (focus can still reach it, to read
|
|
27
|
+
* it); Random, Mutate and Reset skip it. A function decides from the current values, e.g.
|
|
28
|
+
* `(v) => v.light !== "spot"`.
|
|
29
|
+
*/
|
|
30
|
+
readonly disabled?: boolean | ((values: State) => boolean);
|
|
31
|
+
/** Shows the value at full strength but takes no edits; Random, Mutate and Reset skip it. */
|
|
32
|
+
readonly readOnly?: boolean | ((values: State) => boolean);
|
|
33
|
+
/**
|
|
34
|
+
* The group's card starts folded (the first field of a group that says wins), and its header
|
|
35
|
+
* folds and opens it, in a panel or a page. `groupFolded` (on the mount, then the store)
|
|
36
|
+
* overrides it, and on a page what the user last chose wins over both.
|
|
37
|
+
*/
|
|
38
|
+
readonly folded?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* On a page, the field's section starts folded to its heading (the first field of a section
|
|
41
|
+
* that says wins), and the heading folds and opens it. `sectionFolded` (on the mount, then the
|
|
42
|
+
* store) overrides it, and what the user last chose wins over both.
|
|
43
|
+
*/
|
|
44
|
+
readonly sectionFolded?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The panel tab the field sits on (`mountPanel` draws a tab strip once any field names one).
|
|
47
|
+
* Fields without a tab show on every tab.
|
|
48
|
+
*/
|
|
49
|
+
readonly tab?: string;
|
|
50
|
+
/**
|
|
51
|
+
* A collapsible sub-heading inside the field's group: a flat heading with a hairline, never a
|
|
52
|
+
* card inside the card. Consecutive fields that share it sit under one heading.
|
|
53
|
+
*/
|
|
54
|
+
readonly subsection?: string;
|
|
55
|
+
}
|
|
56
|
+
/** Meta keys copied from a field's options or a descriptor onto the field. */
|
|
57
|
+
export declare const META_KEYS: readonly ["label", "group", "groupLabel", "section", "sectionLabel", "groupDescription", "sectionDescription", "shortcut", "random", "disabled", "readOnly", "folded", "sectionFolded", "tab", "subsection"];
|
|
58
|
+
/** The meta `source` gives, without undefined keys. */
|
|
59
|
+
export declare function pickMeta(source: FieldMeta | undefined, skip?: readonly string[]): FieldMeta;
|
|
60
|
+
/** Marks a knob as half of a flat spring: two number keys drawn as one spring card. */
|
|
61
|
+
export interface SpringPart {
|
|
62
|
+
/** Shared by both halves; the card sits where the first of them is. */
|
|
63
|
+
readonly id: string;
|
|
64
|
+
readonly part: "duration" | "bounce";
|
|
65
|
+
/** The card's title (taken from the duration half). */
|
|
66
|
+
readonly label?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface Knob extends FieldMeta {
|
|
69
|
+
readonly kind: "knob";
|
|
70
|
+
readonly value: number;
|
|
71
|
+
readonly min: number;
|
|
72
|
+
readonly max: number;
|
|
73
|
+
readonly step: number;
|
|
74
|
+
readonly unit?: string;
|
|
75
|
+
/** Digits after the point in the readout; the step's own by default. */
|
|
76
|
+
readonly decimals?: number;
|
|
77
|
+
readonly spring?: SpringPart;
|
|
78
|
+
}
|
|
79
|
+
export interface Choice<T extends string = string> extends FieldMeta {
|
|
80
|
+
readonly kind: "choice";
|
|
81
|
+
readonly value: T;
|
|
82
|
+
readonly options: readonly T[];
|
|
83
|
+
/** What each option reads as, when it isn't the option itself (`{ md: "Medium" }`). */
|
|
84
|
+
readonly labels?: Readonly<Record<string, string>>;
|
|
85
|
+
/**
|
|
86
|
+
* Segments or a drop-down menu. By default it's segmented while the labels fit with room to
|
|
87
|
+
* spare and there are at most four options, and a menu otherwise, switching as the width changes.
|
|
88
|
+
*/
|
|
89
|
+
readonly display?: "menu" | "segmented";
|
|
90
|
+
}
|
|
91
|
+
export interface Toggle extends FieldMeta {
|
|
92
|
+
readonly kind: "toggle";
|
|
93
|
+
readonly value: boolean;
|
|
94
|
+
}
|
|
95
|
+
export interface SpringField extends FieldMeta {
|
|
96
|
+
readonly kind: "spring";
|
|
97
|
+
readonly value: SpringValue;
|
|
98
|
+
}
|
|
99
|
+
/** The value is an `oklch(L C H)` string, usable as-is in CSS and always inside sRGB. */
|
|
100
|
+
export interface ColorField extends FieldMeta {
|
|
101
|
+
readonly kind: "color";
|
|
102
|
+
readonly value: string;
|
|
103
|
+
}
|
|
104
|
+
export interface Point {
|
|
105
|
+
readonly x: number;
|
|
106
|
+
readonly y: number;
|
|
107
|
+
}
|
|
108
|
+
export interface PointField extends FieldMeta {
|
|
109
|
+
readonly kind: "point";
|
|
110
|
+
readonly value: Point;
|
|
111
|
+
readonly min: Point;
|
|
112
|
+
readonly max: Point;
|
|
113
|
+
readonly step: Point;
|
|
114
|
+
}
|
|
115
|
+
export interface EasingField extends FieldMeta {
|
|
116
|
+
readonly kind: "easing";
|
|
117
|
+
readonly value: Bezier;
|
|
118
|
+
}
|
|
119
|
+
/** Colour over a 0…1 parameter (over life, over the day): stops sorted by position. */
|
|
120
|
+
export interface GradientField extends FieldMeta {
|
|
121
|
+
readonly kind: "gradient";
|
|
122
|
+
readonly value: readonly GradientStop[];
|
|
123
|
+
/** How the stops blend: `oklab` (perceptual, the default) or `srgb` (as CSS does). */
|
|
124
|
+
readonly space: GradientSpace;
|
|
125
|
+
/** Named ramps offered as chips in the editor. */
|
|
126
|
+
readonly presets?: Readonly<Record<string, readonly GradientStop[]>>;
|
|
127
|
+
}
|
|
128
|
+
/** A number over 0…1 (a falloff, a response): points sorted by x, the ends pinned at 0 and 1. */
|
|
129
|
+
export interface CurveField extends FieldMeta {
|
|
130
|
+
readonly kind: "curve";
|
|
131
|
+
readonly value: readonly CurvePoint[];
|
|
132
|
+
/** The y range, 0…1 by default. */
|
|
133
|
+
readonly range: readonly [number, number];
|
|
134
|
+
readonly interp: CurveInterp;
|
|
135
|
+
/** Named shapes offered as chips (y in `range`), after the built-in ones unless `shapes: false`. */
|
|
136
|
+
readonly presets?: Readonly<Record<string, readonly CurvePoint[]>>;
|
|
137
|
+
/** The built-in shapes (linear, ease-out, inverse², smoothstep, bell) as chips; on by default. */
|
|
138
|
+
readonly shapes: boolean;
|
|
139
|
+
}
|
|
140
|
+
/** A button row. It holds no value: pressing it calls `run` and the store's `onAction(key)`. */
|
|
141
|
+
export interface ActionField extends FieldMeta {
|
|
142
|
+
readonly kind: "action";
|
|
143
|
+
readonly run?: () => void;
|
|
144
|
+
}
|
|
145
|
+
export interface Vec3 {
|
|
146
|
+
readonly x: number;
|
|
147
|
+
readonly y: number;
|
|
148
|
+
readonly z: number;
|
|
149
|
+
}
|
|
150
|
+
/** `vec2` / `vec3`: inline x, y (and z) number cells, each scrubbed or typed. */
|
|
151
|
+
export interface VecField<N extends 2 | 3 = 2 | 3> extends FieldMeta {
|
|
152
|
+
readonly kind: "vec";
|
|
153
|
+
readonly axes: N;
|
|
154
|
+
readonly value: N extends 3 ? Vec3 : Point;
|
|
155
|
+
readonly min: number;
|
|
156
|
+
readonly max: number;
|
|
157
|
+
readonly step: number;
|
|
158
|
+
readonly unit?: string;
|
|
159
|
+
readonly decimals?: number;
|
|
160
|
+
/** Shows a link toggle: while linked, changing one cell scales the others with it. */
|
|
161
|
+
readonly link?: boolean;
|
|
162
|
+
/** Starts linked (implies `link`). */
|
|
163
|
+
readonly linked?: boolean;
|
|
164
|
+
/** The cells' names, in order (`["x", "z"]` for a ground-plane pair): their letters and labels. */
|
|
165
|
+
readonly axisLabels?: readonly string[];
|
|
166
|
+
}
|
|
167
|
+
/** A `[low, high]` pair on one slider with two thumbs that can't cross. */
|
|
168
|
+
export interface RangeField extends FieldMeta {
|
|
169
|
+
readonly kind: "range";
|
|
170
|
+
readonly value: readonly [number, number];
|
|
171
|
+
readonly min: number;
|
|
172
|
+
readonly max: number;
|
|
173
|
+
readonly step: number;
|
|
174
|
+
readonly unit?: string;
|
|
175
|
+
readonly decimals?: number;
|
|
176
|
+
}
|
|
177
|
+
/** Degrees on a dial; `wrap` (a full turn by default) carries 359° on to 0°. */
|
|
178
|
+
export interface AngleField extends FieldMeta {
|
|
179
|
+
readonly kind: "angle";
|
|
180
|
+
readonly value: number;
|
|
181
|
+
readonly min: number;
|
|
182
|
+
readonly max: number;
|
|
183
|
+
readonly step: number;
|
|
184
|
+
readonly wrap: boolean;
|
|
185
|
+
}
|
|
186
|
+
/** A whole number with a die that rolls a new one; out of Random and Mutate unless `random: true`. */
|
|
187
|
+
export interface SeedField extends FieldMeta {
|
|
188
|
+
readonly kind: "seed";
|
|
189
|
+
readonly value: number;
|
|
190
|
+
readonly min: number;
|
|
191
|
+
readonly max: number;
|
|
192
|
+
}
|
|
193
|
+
/** A key combination such as `"Meta+Shift+K"` (`""` for none), captured by pressing it. */
|
|
194
|
+
export interface KeybindField extends FieldMeta {
|
|
195
|
+
readonly kind: "keybind";
|
|
196
|
+
readonly value: string;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* A toolbar button's key and where it presses the button: while the panel has focus (`"panel"`),
|
|
200
|
+
* anywhere on the page but a text field (`"page"`), or nowhere (`"none"`: the chip only, for a
|
|
201
|
+
* key the host binds itself).
|
|
202
|
+
*/
|
|
203
|
+
export interface ToolbarShortcut {
|
|
204
|
+
readonly key: string;
|
|
205
|
+
readonly scope?: "page" | "panel" | "none";
|
|
206
|
+
}
|
|
207
|
+
/** A toolbar button: an optional icon, a label and a shortcut chip. */
|
|
208
|
+
export interface ToolbarItem {
|
|
209
|
+
/** Reported to `onAction`; the label by default. */
|
|
210
|
+
readonly id?: string;
|
|
211
|
+
readonly label: string;
|
|
212
|
+
/** A built-in icon name (`play`, `frame`, `retrigger`, …) or SVG path data on a 256 grid. */
|
|
213
|
+
readonly icon?: string;
|
|
214
|
+
/**
|
|
215
|
+
* A key or combination (`"Space"`, `"f"`, `"Shift+P"`) that presses the button while the panel
|
|
216
|
+
* has focus, or `{ key, scope }` to say where it works (see `ToolbarShortcut`).
|
|
217
|
+
*/
|
|
218
|
+
readonly shortcut?: string | ToolbarShortcut;
|
|
219
|
+
/** A plain-string shortcut works anywhere on the page (as `scope: "page"`). */
|
|
220
|
+
readonly global?: boolean;
|
|
221
|
+
readonly disabled?: boolean;
|
|
222
|
+
readonly run?: () => void;
|
|
223
|
+
}
|
|
224
|
+
/** A row of buttons that wrap; holds no value. Each press calls its `run` and `onAction(id)`. */
|
|
225
|
+
export interface ToolbarField extends FieldMeta {
|
|
226
|
+
readonly kind: "toolbar";
|
|
227
|
+
readonly items: readonly ToolbarItem[];
|
|
228
|
+
}
|
|
229
|
+
export type ValueField = Knob | Choice | Toggle | SpringField | ColorField | PointField | EasingField | VecField | RangeField | AngleField | SeedField | KeybindField | GradientField | CurveField;
|
|
230
|
+
/** A readout's own: polled while its row shows, instead of pushed with `controls.watch`. */
|
|
231
|
+
interface ReadoutMeta extends FieldMeta {
|
|
232
|
+
/** Read each frame while the row is on screen (pushing with `controls.watch` is the other way). */
|
|
233
|
+
readonly get?: () => unknown;
|
|
234
|
+
readonly unit?: string;
|
|
235
|
+
/** Digits after the point; by default fewer as the number grows (2 under 10, 1 under 100). */
|
|
236
|
+
readonly decimals?: number;
|
|
237
|
+
/** Text for a value, in place of the number and unit. */
|
|
238
|
+
readonly format?: (value: number) => string;
|
|
239
|
+
/** How often the text may change, per second (4 by default): readable, never a blur. */
|
|
240
|
+
readonly hz?: number;
|
|
241
|
+
}
|
|
242
|
+
/** A live number or text, with an optional unit; holds nothing in the store's values. */
|
|
243
|
+
export interface WatchField extends ReadoutMeta {
|
|
244
|
+
readonly kind: "watch";
|
|
245
|
+
}
|
|
246
|
+
/** A watch with a small history graph in its row, auto-scaled. */
|
|
247
|
+
export interface SparklineField extends ReadoutMeta {
|
|
248
|
+
readonly kind: "sparkline";
|
|
249
|
+
/** Samples kept (60 by default). */
|
|
250
|
+
readonly history: number;
|
|
251
|
+
/** A fixed floor or ceiling for the scale; it fits the samples otherwise. */
|
|
252
|
+
readonly min?: number;
|
|
253
|
+
readonly max?: number;
|
|
254
|
+
/** The line's colour (any CSS colour), the accent by default. */
|
|
255
|
+
readonly color?: string;
|
|
256
|
+
}
|
|
257
|
+
export interface GraphSeries {
|
|
258
|
+
readonly id: string;
|
|
259
|
+
readonly label?: string;
|
|
260
|
+
/** Any CSS colour; the accent, then a palette, by default. */
|
|
261
|
+
readonly color?: string;
|
|
262
|
+
/** Fills the area under the line. */
|
|
263
|
+
readonly area?: boolean;
|
|
264
|
+
}
|
|
265
|
+
export interface GraphThreshold {
|
|
266
|
+
readonly value: number;
|
|
267
|
+
readonly label?: string;
|
|
268
|
+
readonly color?: string;
|
|
269
|
+
}
|
|
270
|
+
/** A taller row: a multi-series line or area graph with thresholds and a hover crosshair. */
|
|
271
|
+
export interface GraphField extends ReadoutMeta {
|
|
272
|
+
readonly kind: "graph";
|
|
273
|
+
readonly series: readonly GraphSeries[];
|
|
274
|
+
/** Samples kept per series (120 by default). */
|
|
275
|
+
readonly history: number;
|
|
276
|
+
/** The plot's height in px (64 by default). */
|
|
277
|
+
readonly height: number;
|
|
278
|
+
/** A fixed range; each bound left out fits the samples (with thresholds kept in view). */
|
|
279
|
+
readonly min?: number;
|
|
280
|
+
readonly max?: number;
|
|
281
|
+
readonly thresholds: readonly GraphThreshold[];
|
|
282
|
+
}
|
|
283
|
+
/** A bar for a value out of a maximum; `null` makes it indeterminate. */
|
|
284
|
+
export interface MeterField extends ReadoutMeta {
|
|
285
|
+
readonly kind: "meter";
|
|
286
|
+
readonly min: number;
|
|
287
|
+
readonly max: number;
|
|
288
|
+
/** Splits the bar into this many cells. */
|
|
289
|
+
readonly segments?: number;
|
|
290
|
+
/** From this value on, the bar turns the warning colour (`--k-warn`). */
|
|
291
|
+
readonly warn?: number;
|
|
292
|
+
/** From this value on, the critical colour (`--k-critical`). */
|
|
293
|
+
readonly critical?: number;
|
|
294
|
+
}
|
|
295
|
+
/** A compact table of 2–4 columns: rows of cells, or a key-value record. */
|
|
296
|
+
export interface TableField extends ReadoutMeta {
|
|
297
|
+
readonly kind: "table";
|
|
298
|
+
/** Column headings; the first sits under the row's label. */
|
|
299
|
+
readonly columns?: readonly string[];
|
|
300
|
+
}
|
|
301
|
+
/** A scrolling log with levels, a filter, follow-tail and copy. */
|
|
302
|
+
export interface LogField extends ReadoutMeta {
|
|
303
|
+
readonly kind: "log";
|
|
304
|
+
/** Lines shown (8 by default). */
|
|
305
|
+
readonly lines: number;
|
|
306
|
+
/** Entries kept (1000 by default). */
|
|
307
|
+
readonly max: number;
|
|
308
|
+
}
|
|
309
|
+
export type ReadoutField = WatchField | SparklineField | GraphField | MeterField | TableField | LogField;
|
|
310
|
+
export type Field = ValueField | ActionField | ToolbarField | ReadoutField;
|
|
311
|
+
/** Whether a field is a readout (it shows pushed values and holds none). */
|
|
312
|
+
export declare const isReadout: (field: {
|
|
313
|
+
readonly kind: string;
|
|
314
|
+
}) => field is ReadoutField;
|
|
315
|
+
/** Whether a field holds a value (actions, toolbars and readouts don't). */
|
|
316
|
+
export declare const hasValue: (field: Field) => field is ValueField;
|
|
317
|
+
export type Schema = Readonly<Record<string, Field>>;
|
|
318
|
+
export type FieldValue<F extends Field> = F extends Knob ? number : F extends Choice<infer T> ? T : F extends Toggle ? boolean : F extends SpringField ? SpringValue : F extends ColorField ? string : F extends PointField ? Point : F extends EasingField ? Bezier : F extends VecField<3> ? Vec3 : F extends VecField<2> ? Point : F extends RangeField ? readonly [number, number] : F extends AngleField | SeedField ? number : F extends KeybindField ? string : F extends GradientField ? readonly GradientStop[] : F extends CurveField ? readonly CurvePoint[] : never;
|
|
319
|
+
/** The keys of a schema's readouts (what `controls.watch` takes). */
|
|
320
|
+
export type ReadoutKeys<S extends Schema> = {
|
|
321
|
+
[K in keyof S]: [S[K] & ReadoutField] extends [never] ? never : K;
|
|
322
|
+
}[keyof S] & string;
|
|
323
|
+
/** What a readout takes from `controls.watch` (`null` clears it). */
|
|
324
|
+
export type ReadoutInput<F> = F extends WatchField ? number | string | null : F extends SparklineField ? number | readonly number[] | null : F extends GraphField ? number | Readonly<Record<string, number>> | null : F extends MeterField ? number | null : F extends TableField ? TableRows | null : F extends LogField ? string | LogEntry | readonly (string | LogEntry)[] | null : never;
|
|
325
|
+
/** Action keys map to `never`: they hold no value and are absent at runtime. */
|
|
326
|
+
export type Values<S extends Schema> = {
|
|
327
|
+
readonly [K in keyof S]: FieldValue<S[K]>;
|
|
328
|
+
};
|
|
329
|
+
export type Value = number | string | boolean | SpringValue | Point | Vec3 | Bezier | readonly [number, number] | readonly GradientStop[] | readonly CurvePoint[];
|
|
330
|
+
export type State = Readonly<Record<string, Value>>;
|
|
331
|
+
/** Ranges for spring fields: duration in seconds, and SwiftUI's bounce (below 0 is overdamped). */
|
|
332
|
+
export declare const SPRING: {
|
|
333
|
+
readonly duration: {
|
|
334
|
+
readonly min: 0.05;
|
|
335
|
+
readonly max: 2;
|
|
336
|
+
readonly step: 0.01;
|
|
337
|
+
};
|
|
338
|
+
readonly bounce: {
|
|
339
|
+
readonly min: -0.5;
|
|
340
|
+
readonly max: 1;
|
|
341
|
+
readonly step: 0.01;
|
|
342
|
+
};
|
|
343
|
+
};
|
|
344
|
+
/** The keys that hold values (every field but actions). */
|
|
345
|
+
export declare function valueKeys(schema: Schema): string[];
|
|
346
|
+
export declare function knob(value: number, options: Omit<Knob, "kind" | "value" | "step"> & {
|
|
347
|
+
step?: number;
|
|
348
|
+
}): Knob;
|
|
349
|
+
export declare function choice<const T extends readonly [string, ...string[]]>(value: T[number], options: T, meta?: FieldMeta & {
|
|
350
|
+
readonly labels?: Readonly<Partial<Record<T[number], string>>>;
|
|
351
|
+
readonly display?: "menu" | "segmented";
|
|
352
|
+
}): Choice<T[number]>;
|
|
353
|
+
/** `action("Replay", { run })`: a button row. Its key also reaches the store's `onAction`. */
|
|
354
|
+
export declare function action(label?: string, meta?: Omit<FieldMeta, "label"> & {
|
|
355
|
+
run?: () => void;
|
|
356
|
+
}): ActionField;
|
|
357
|
+
type SpringHalf = number | Knob;
|
|
358
|
+
/**
|
|
359
|
+
* A flat spring: two plain number fields (`{ duration, bounce }` as separate keys) drawn as one
|
|
360
|
+
* spring card with a curve and two sliders. Spread the result into a schema, or rename its halves:
|
|
361
|
+
* `defineControls("m", { ...flatSpring({ duration: 0.45, bounce: 0.3 }, { label: "Spring" }) })`.
|
|
362
|
+
*/
|
|
363
|
+
export declare function flatSpring(parts?: {
|
|
364
|
+
duration?: SpringHalf;
|
|
365
|
+
bounce?: SpringHalf;
|
|
366
|
+
}, meta?: Omit<FieldMeta, "shortcut"> & {
|
|
367
|
+
id?: string;
|
|
368
|
+
}): {
|
|
369
|
+
readonly duration: Knob;
|
|
370
|
+
readonly bounce: Knob;
|
|
371
|
+
};
|
|
372
|
+
export declare function toggle(value: boolean, meta?: FieldMeta): Toggle;
|
|
373
|
+
/** `spring({ duration: 0.4, bounce: 0.2 })`, like SwiftUI's `.spring(duration:bounce:)`. */
|
|
374
|
+
export declare function spring(value?: Partial<SpringValue>, meta?: FieldMeta): SpringField;
|
|
375
|
+
/** `color("#4f8cff")`, `color("oklch(0.7 0.15 250)")` or `color({ l, c, h })`. */
|
|
376
|
+
export declare function color(value: string | Oklch, meta?: FieldMeta): ColorField;
|
|
377
|
+
type Axis = number | Point;
|
|
378
|
+
/** A 2D pad: `point({ x: 0, y: 0 }, { min: -1, max: 1 })`; bounds and step take a number or `{ x, y }`. */
|
|
379
|
+
export declare function point(value: Point, options: FieldMeta & {
|
|
380
|
+
min: Axis;
|
|
381
|
+
max: Axis;
|
|
382
|
+
step?: Axis;
|
|
383
|
+
}): PointField;
|
|
384
|
+
/** A cubic bezier `[x1, y1, x2, y2]` or a name: ease, ease-in, ease-out, ease-in-out, linear, smooth, snappy, back. */
|
|
385
|
+
export declare function easing(value: Bezier | EasingName, meta?: FieldMeta): EasingField;
|
|
386
|
+
interface NumberOptions {
|
|
387
|
+
readonly min: number;
|
|
388
|
+
readonly max: number;
|
|
389
|
+
readonly step?: number;
|
|
390
|
+
readonly unit?: string;
|
|
391
|
+
readonly decimals?: number;
|
|
392
|
+
}
|
|
393
|
+
type VecOptions = FieldMeta & NumberOptions & {
|
|
394
|
+
readonly link?: boolean;
|
|
395
|
+
readonly linked?: boolean;
|
|
396
|
+
/** What the cells are called (`["x", "z"]`): their letters and accessible names. */
|
|
397
|
+
readonly axes?: readonly string[];
|
|
398
|
+
};
|
|
399
|
+
/** Inline x and y cells: `vec2({ x: 0, y: 1 }, { min: -10, max: 10, step: 0.1 })`. */
|
|
400
|
+
export declare function vec2(value: Point, options: VecOptions): VecField<2>;
|
|
401
|
+
/** Inline x, y and z cells, with an optional link for uniform scaling (`link: true`). */
|
|
402
|
+
export declare function vec3(value: Vec3, options: VecOptions): VecField<3>;
|
|
403
|
+
/** A low–high pair on one slider: `range([0.2, 0.8], { min: 0, max: 1 })`. */
|
|
404
|
+
export declare function range(value: readonly [number, number], options: FieldMeta & NumberOptions): {
|
|
405
|
+
value: readonly [number, number];
|
|
406
|
+
kind: "range";
|
|
407
|
+
min: number;
|
|
408
|
+
max: number;
|
|
409
|
+
step: number;
|
|
410
|
+
unit?: string;
|
|
411
|
+
decimals?: number;
|
|
412
|
+
label?: string;
|
|
413
|
+
group?: string;
|
|
414
|
+
groupLabel?: string;
|
|
415
|
+
section?: string;
|
|
416
|
+
sectionLabel?: string;
|
|
417
|
+
groupDescription?: string;
|
|
418
|
+
sectionDescription?: string;
|
|
419
|
+
shortcut?: string;
|
|
420
|
+
random?: boolean;
|
|
421
|
+
disabled?: boolean | ((values: State) => boolean);
|
|
422
|
+
readOnly?: boolean | ((values: State) => boolean);
|
|
423
|
+
folded?: boolean;
|
|
424
|
+
sectionFolded?: boolean;
|
|
425
|
+
tab?: string;
|
|
426
|
+
subsection?: string;
|
|
427
|
+
};
|
|
428
|
+
/** Degrees on a dial (0–360 and wrapping by default): `angle(45)`, `angle(30, { min: -90, max: 90 })`. */
|
|
429
|
+
export declare function angle(value: number, options?: FieldMeta & {
|
|
430
|
+
min?: number;
|
|
431
|
+
max?: number;
|
|
432
|
+
step?: number;
|
|
433
|
+
wrap?: boolean;
|
|
434
|
+
}): AngleField;
|
|
435
|
+
/** A seed with a die that rolls a new one; Random and Mutate leave it alone unless `random: true`. */
|
|
436
|
+
export declare function seed(value: number, options?: FieldMeta & {
|
|
437
|
+
min?: number;
|
|
438
|
+
max?: number;
|
|
439
|
+
}): SeedField;
|
|
440
|
+
/** A key combination captured by pressing it (`"Meta+Shift+K"`, `""` for none). */
|
|
441
|
+
export declare function keybind(value?: string, meta?: FieldMeta): KeybindField;
|
|
442
|
+
/**
|
|
443
|
+
* Colour over a 0…1 parameter: `gradient([{ at: 0, color: "#fff4d6" }, { at: 1, color: "#20242c" }])`.
|
|
444
|
+
* Colours take what `color` takes and are kept as `oklch()` strings. `space` blends in `oklab`
|
|
445
|
+
* (default) or `srgb`; `presets` are named ramps offered as chips. Sample it with `sampleGradient`.
|
|
446
|
+
*/
|
|
447
|
+
export declare function gradient(stops: readonly {
|
|
448
|
+
readonly at: number;
|
|
449
|
+
readonly color: string | {
|
|
450
|
+
l: number;
|
|
451
|
+
c: number;
|
|
452
|
+
h: number;
|
|
453
|
+
};
|
|
454
|
+
}[], options?: FieldMeta & {
|
|
455
|
+
readonly space?: GradientSpace;
|
|
456
|
+
readonly presets?: Readonly<Record<string, readonly {
|
|
457
|
+
at: number;
|
|
458
|
+
color: string;
|
|
459
|
+
}[]>>;
|
|
460
|
+
}): GradientField;
|
|
461
|
+
/**
|
|
462
|
+
* A number over 0…1: `curve([{ x: 0, y: 1 }, { x: 1, y: 0 }], { range: [0, 1], interp: "smooth" })`.
|
|
463
|
+
* The ends are pinned at x 0 and 1. `smooth` is a monotone cubic (no overshoot); `linear` and
|
|
464
|
+
* `step` join the points as they say. Sample it with `sampleCurve`.
|
|
465
|
+
*/
|
|
466
|
+
export declare function curve(points: readonly CurvePoint[] | keyof typeof CURVE_SHAPES, options?: FieldMeta & {
|
|
467
|
+
readonly range?: readonly [number, number];
|
|
468
|
+
readonly interp?: CurveInterp;
|
|
469
|
+
readonly presets?: Readonly<Record<string, readonly CurvePoint[]>>;
|
|
470
|
+
readonly shapes?: boolean;
|
|
471
|
+
}): CurveField;
|
|
472
|
+
/** A toolbar item's shortcut as `{ key, scope }`, or undefined without one. */
|
|
473
|
+
export declare function toolbarShortcut(item: ToolbarItem): {
|
|
474
|
+
readonly key: string;
|
|
475
|
+
readonly scope: "page" | "panel" | "none";
|
|
476
|
+
} | undefined;
|
|
477
|
+
/** A wrapping row of buttons with icons and shortcut chips; holds no value. */
|
|
478
|
+
export declare function toolbar(items: readonly ToolbarItem[], meta?: FieldMeta): ToolbarField;
|
|
479
|
+
type ReadoutOptions = Omit<ReadoutMeta, "shortcut" | "random" | "readOnly">;
|
|
480
|
+
/** A live value: `watch({ label: "FPS", decimals: 0 })`, then `controls.watch("fps", 59.9)`. */
|
|
481
|
+
export declare function watch(options?: ReadoutOptions): WatchField;
|
|
482
|
+
/** A watch with a small history graph: `sparkline({ label: "Frame", unit: "ms", min: 0 })`. */
|
|
483
|
+
export declare function sparkline(options?: ReadoutOptions & {
|
|
484
|
+
history?: number;
|
|
485
|
+
min?: number;
|
|
486
|
+
max?: number;
|
|
487
|
+
color?: string;
|
|
488
|
+
}): SparklineField;
|
|
489
|
+
/**
|
|
490
|
+
* A multi-series graph: `graph({ series: [{ id: "cpu" }, { id: "gpu" }], unit: "ms",
|
|
491
|
+
* thresholds: [{ value: 16.7, label: "60 fps" }] })`; push `{ cpu, gpu }` each frame.
|
|
492
|
+
*/
|
|
493
|
+
export declare function graph(options?: ReadoutOptions & {
|
|
494
|
+
series?: readonly (GraphSeries | string)[];
|
|
495
|
+
history?: number;
|
|
496
|
+
height?: number;
|
|
497
|
+
min?: number;
|
|
498
|
+
max?: number;
|
|
499
|
+
thresholds?: readonly (GraphThreshold | number)[];
|
|
500
|
+
}): GraphField;
|
|
501
|
+
/** A bar: `meter({ label: "Memory", max: 512, unit: "MB", warn: 384, critical: 480 })`. */
|
|
502
|
+
export declare function meter(options?: ReadoutOptions & {
|
|
503
|
+
min?: number;
|
|
504
|
+
max?: number;
|
|
505
|
+
segments?: number;
|
|
506
|
+
warn?: number;
|
|
507
|
+
critical?: number;
|
|
508
|
+
}): MeterField;
|
|
509
|
+
/** A small table: `table({ label: "Passes", columns: ["Pass", "ms", "Draws"] })`. */
|
|
510
|
+
export declare function table(options?: ReadoutOptions & {
|
|
511
|
+
columns?: readonly string[];
|
|
512
|
+
}): TableField;
|
|
513
|
+
/** A log: `log({ label: "Events", lines: 8 })`, then `controls.watch("events", { level, text })`. */
|
|
514
|
+
export declare function log(options?: ReadoutOptions & {
|
|
515
|
+
lines?: number;
|
|
516
|
+
max?: number;
|
|
517
|
+
}): LogField;
|
|
518
|
+
/** An angle carried into `[min, max)` a whole turn at a time. */
|
|
519
|
+
export declare const wrapAngle: (v: number, min: number, max: number) => number;
|
|
520
|
+
export declare function normalizeField(field: ValueField, input: unknown): Value;
|
|
521
|
+
export declare function normalize<S extends Schema>(schema: S, input: unknown): Values<S>;
|
|
522
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
523
|
+
/** Value equality: springs, points, beziers, gradients and curves compare by their numbers. */
|
|
524
|
+
export declare function same(a: unknown, b: unknown): boolean;
|
|
525
|
+
export declare function equal(a: State, b: State): boolean;
|
|
526
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare class Spring {
|
|
2
|
+
x: number;
|
|
3
|
+
omega: number;
|
|
4
|
+
zeta: number;
|
|
5
|
+
eps: number;
|
|
6
|
+
v: number;
|
|
7
|
+
target: number;
|
|
8
|
+
/** A retarget waiting for its turn in a cascade (performance.now() ms). */
|
|
9
|
+
private next;
|
|
10
|
+
constructor(x: number, omega?: number, zeta?: number, eps?: number);
|
|
11
|
+
/** With a `delay` (ms) the new target applies later; repeating the same target is a no-op. */
|
|
12
|
+
set(target: number, delay?: number): this;
|
|
13
|
+
snap(x: number): this;
|
|
14
|
+
step(dt: number): number;
|
|
15
|
+
get resting(): boolean;
|
|
16
|
+
}
|
|
17
|
+
/** A SwiftUI-style `.spring(duration:bounce:)`: perceptual duration in seconds, bounce -1…1. */
|
|
18
|
+
export interface SpringValue {
|
|
19
|
+
readonly duration: number;
|
|
20
|
+
readonly bounce: number;
|
|
21
|
+
}
|
|
22
|
+
/** SwiftUI's mapping: ω = 2π / duration; ζ = 1 − bounce, or 1 / (1 + bounce) below zero. */
|
|
23
|
+
export declare function springMotion({ duration, bounce }: SpringValue): {
|
|
24
|
+
omega: number;
|
|
25
|
+
zeta: number;
|
|
26
|
+
};
|
|
27
|
+
/** The step response (0 → 1) sampled every `dt` seconds for `seconds`. */
|
|
28
|
+
export declare function springResponse(omega: number, zeta: number, seconds: number, dt?: number): number[];
|
|
29
|
+
/** The step response as a CSS `linear()` easing plus its settle time (ms). */
|
|
30
|
+
export declare function springEasing(omega: number, zeta: number): {
|
|
31
|
+
easing: string;
|
|
32
|
+
ms: number;
|
|
33
|
+
};
|
|
34
|
+
/** A spring field's value as CSS: `transition: transform ${duration}ms ${easing}`. */
|
|
35
|
+
export declare function springCss(value: SpringValue): {
|
|
36
|
+
easing: string;
|
|
37
|
+
duration: number;
|
|
38
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface StoragePort {
|
|
2
|
+
getItem(key: string): string | null;
|
|
3
|
+
setItem(key: string, value: string): void;
|
|
4
|
+
}
|
|
5
|
+
export declare function memoryStorage(): StoragePort;
|
|
6
|
+
export declare function browserStorage(): StoragePort | null;
|
|
7
|
+
export declare function urlFlag(name: string): () => boolean;
|
|
8
|
+
export declare const storageKey: (id: string, part: string) => string;
|