lfocomp 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/types/lfo.d.ts ADDED
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Canvas-based LFO panel with waveform display, shape selector, parameter
3
+ * sliders, and a drag handle for wiring to any modulation target.
4
+ */
5
+ export class LFOWidget {
6
+ /**
7
+ * @param {HTMLElement} container Where the widget is appended.
8
+ * @param {string} lfoId Engine LFO id.
9
+ * @param {object} [opts]
10
+ * @param {string} [opts.color] Accent color hex.
11
+ * @param {string} [opts.label] Display label.
12
+ * @param {function} [opts.onConnect] (lfoId, element, routeId) => void
13
+ * @param {function} [opts.onDisconnect] (routeId) => void
14
+ */
15
+ constructor(container: HTMLElement, lfoId: string, opts?: {
16
+ color?: string;
17
+ label?: string;
18
+ onConnect?: Function;
19
+ onDisconnect?: Function;
20
+ });
21
+ _lfoId: string;
22
+ _color: string;
23
+ _label: string;
24
+ _onConnect: Function;
25
+ _onDisconnect: Function;
26
+ /** @type {Map<string, ModIndicator>} routeId → indicator */
27
+ _indicators: Map<string, ModIndicator>;
28
+ _latestValue: number;
29
+ _unsub: Function;
30
+ _rafHandle: number;
31
+ _destroyed: boolean;
32
+ _build(container: any): void;
33
+ _root: HTMLDivElement;
34
+ _led: HTMLDivElement;
35
+ _canvas: HTMLCanvasElement;
36
+ _ctx: CanvasRenderingContext2D;
37
+ _shapesEl: HTMLDivElement;
38
+ _bipolarBtn: HTMLButtonElement;
39
+ _rateInput: HTMLInputElement;
40
+ _depthInput: HTMLInputElement;
41
+ _phaseInput: HTMLInputElement;
42
+ _offsetInput: HTMLInputElement;
43
+ _jitterInput: HTMLInputElement;
44
+ _skewInput: HTMLInputElement;
45
+ _handle: HTMLDivElement;
46
+ _addParam(container: any, labelText: any, min: any, max: any, defaultVal: any, step: any, param: any, fmt: any, scale?: string): HTMLInputElement;
47
+ _refreshShapeButtons(): void;
48
+ _refreshBipolarBtn(): void;
49
+ /**
50
+ * Reflect effective (post-chain-modulation) rate and depth onto the param
51
+ * sliders so they visually track the modulated position. Only touches the
52
+ * DOM when the effective value actually differs from the displayed value to
53
+ * avoid unnecessary repaints.
54
+ */
55
+ _syncChainedSliders(): void;
56
+ /**
57
+ * Remove any indicators whose routes have been deleted externally — e.g. when
58
+ * the target LFO is destroyed and engine.destroyLFO cleans up incoming routes.
59
+ * Called each tick so stale badges are cleared within one frame.
60
+ */
61
+ _pruneDeadRoutes(): void;
62
+ _recordSample(currentValue: any): void;
63
+ _wfBuf: HTMLCanvasElement;
64
+ _wfBufCtx: CanvasRenderingContext2D;
65
+ _wfHistory: Float32Array<ArrayBuffer>;
66
+ _wfSubpx: any;
67
+ _wfLastTime: number;
68
+ _wfPrevValue: any;
69
+ _wfNeedsFullRedraw: boolean;
70
+ /** Composite _wfBuf → visible canvas + cursor dot. Called from RAF. */
71
+ _rafDraw(): void;
72
+ /** Full repaint of _wfBuf from _wfHistory. */
73
+ _wfPaintFull(bCtx: any, W: any, H: any): void;
74
+ /**
75
+ * Scroll _wfBuf left by intShift, fill background+grid in new strip, then
76
+ * draw only the new right-edge stroke from _wfHistory.
77
+ */
78
+ _wfPaintIncremental(bCtx: any, W: any, H: any, intShift: any): void;
79
+ _wfDrawGrid(bCtx: any, W: any, H: any, x0: any, x1: any): void;
80
+ /** Stroke _wfHistory[xFrom..xTo] onto bCtx. */
81
+ _wfDrawHistoryStroke(bCtx: any, W: any, H: any, xFrom: any, xTo: any): void;
82
+ _updateLed(value: any): void;
83
+ _attachDragHandlers(handle: any): void;
84
+ _connectTo(element: any): void;
85
+ /**
86
+ * Programmatically connect this LFO to an element.
87
+ * @param {HTMLElement} element
88
+ * @param {object} [opts]
89
+ * @param {number} [opts.depth=0.5]
90
+ * @returns {string|null} routeId, or null if rejected (duplicate, self-mod).
91
+ */
92
+ connect(element: HTMLElement, opts?: {
93
+ depth?: number;
94
+ }): string | null;
95
+ /**
96
+ * Remove a specific modulation route.
97
+ * @param {string} routeId
98
+ */
99
+ disconnectRoute(routeId: string): void;
100
+ /** Disconnect all routes from this widget. */
101
+ disconnectAll(): void;
102
+ /** Tear down the widget and all its connections. */
103
+ destroy(): void;
104
+ get element(): HTMLDivElement;
105
+ get lfoId(): string;
106
+ get color(): string;
107
+ get label(): string;
108
+ }
109
+ /**
110
+ * lfo-ui.js — LFO widget, modulation indicators, and drag-to-assign wiring.
111
+ *
112
+ * Provides:
113
+ * LFOWidget — Canvas-based LFO panel with controls and a drag handle.
114
+ * ModIndicator — Floating badge anchored to a connected element showing
115
+ * depth and a remove button. Also draws a range arc on range inputs.
116
+ *
117
+ * No external dependencies. Requires lfo-engine.js.
118
+ */
119
+ export const LFO_COLORS: string[];
120
+ /**
121
+ * Floating badge anchored to a connected input element.
122
+ * Shows depth, allows drag-to-adjust, and a remove button.
123
+ */
124
+ export class ModIndicator {
125
+ /**
126
+ * @param {HTMLElement} element Connected input.
127
+ * @param {string} routeId
128
+ * @param {string} lfoId
129
+ * @param {string} color
130
+ * @param {string} lfoLabel
131
+ * @param {function} onRemove Called when the user removes this connection.
132
+ */
133
+ constructor(element: HTMLElement, routeId: string, lfoId: string, color: string, lfoLabel: string, onRemove: Function);
134
+ _element: HTMLElement;
135
+ _routeId: string;
136
+ _lfoId: string;
137
+ _color: string;
138
+ _onRemove: Function;
139
+ _badge: HTMLDivElement;
140
+ _arcCanvas: HTMLCanvasElement;
141
+ _rafId: number;
142
+ _buildBadge(label: any): void;
143
+ _depthLabel: HTMLSpanElement;
144
+ _buildArcCanvas(): void;
145
+ _arcCtx: CanvasRenderingContext2D;
146
+ _updateDepthLabel(): void;
147
+ _startPositioning(): void;
148
+ _reposition(): void;
149
+ _badgeSize: {
150
+ bw: number;
151
+ bh: number;
152
+ };
153
+ _updateArc(): void;
154
+ destroy(): void;
155
+ get routeId(): string;
156
+ }
157
+ /**
158
+ * lfo-engine.js — Core LFO math engine, no DOM dependencies.
159
+ *
160
+ * Manages LFO instances, a global RAF tick loop, and a modulation routing
161
+ * graph. Routes can target HTML elements (range/number inputs) or other
162
+ * LFO parameters (for chaining).
163
+ *
164
+ * Usage:
165
+ * import { engine, SHAPES } from './lfo-engine.js';
166
+ * const id = engine.createLFO({ shape: 'sine', rate: 2 });
167
+ * const routeId = engine.addRoute(id, 'element', sliderEl, null, { depth: 0.5 });
168
+ */
169
+ export const SHAPES: string[];
170
+ /**
171
+ * Programmatically connect an LFO to an HTML element.
172
+ * Equivalent to calling widget.connect(element, opts).
173
+ *
174
+ * @param {LFOWidget} widget
175
+ * @param {HTMLElement} element
176
+ * @param {object} [opts]
177
+ * @param {number} [opts.depth=0.5]
178
+ * @returns {string|null} routeId, or null if connection was rejected.
179
+ */
180
+ export function connect(widget: LFOWidget, element: HTMLElement, opts?: {
181
+ depth?: number;
182
+ }): string | null;
183
+ /**
184
+ * Create a fully wired LFO widget.
185
+ *
186
+ * @param {HTMLElement|object} containerOrOpts
187
+ * If an HTMLElement, the widget is appended to it and opts is the second arg.
188
+ * If an object, treated as opts — caller is responsible for appending widget.element.
189
+ * @param {object} [opts]
190
+ * @param {string} [opts.shape='sine'] Initial waveform shape.
191
+ * @param {number} [opts.rate=1] Initial rate in Hz.
192
+ * @param {number} [opts.depth=1] Initial depth 0–1.
193
+ * @param {number} [opts.phase=0] Initial phase offset 0–1.
194
+ * @param {number} [opts.offset=0] DC offset -1–1.
195
+ * @param {string} [opts.color] Accent color. Auto-assigned if omitted.
196
+ * @param {string} [opts.label] Widget label. Auto-assigned if omitted.
197
+ * @param {function} [opts.onConnect] Called when a connection is made.
198
+ * @param {function} [opts.onDisconnect] Called when a connection is removed.
199
+ *
200
+ * @returns {{ lfoId: string, widget: LFOWidget }}
201
+ */
202
+ export function createLFO(containerOrOpts?: HTMLElement | object, opts?: {
203
+ shape?: string;
204
+ rate?: number;
205
+ depth?: number;
206
+ phase?: number;
207
+ offset?: number;
208
+ color?: string;
209
+ label?: string;
210
+ onConnect?: Function;
211
+ onDisconnect?: Function;
212
+ }): {
213
+ lfoId: string;
214
+ widget: LFOWidget;
215
+ };
216
+ /**
217
+ * Remove a modulation route and its UI indicator.
218
+ * Prefer calling widget.disconnectRoute(routeId) directly when you have the widget.
219
+ * This function handles programmatic routes created via connect() or drag-to-assign.
220
+ *
221
+ * @param {string} routeId
222
+ */
223
+ export function disconnect(routeId: string): void;
224
+ /** Global engine singleton — import and use directly. */
225
+ export const engine: LFOEngine;
226
+ /**
227
+ * Get all currently active modulation routes.
228
+ * @returns {object[]}
229
+ */
230
+ export function getRoutes(): object[];
231
+ export function injectStyles(): void;
232
+ /** Deterministic pseudo-random in [-1, 1] for a given integer seed. */
233
+ export function seededRand(seed: any): number;
234
+ /** Smoothly interpolated random (cubic Hermite) for non-integer phase. */
235
+ export function smoothRand(seed: any, phase: any): number;
236
+ declare class LFOEngine {
237
+ /** @type {Map<string, LFOState>} */
238
+ _lfos: Map<string, LFOState>;
239
+ /** @type {Map<string, RouteState>} */
240
+ _routes: Map<string, RouteState>;
241
+ /** @type {Map<HTMLElement, ElementState>} */
242
+ _elementStates: Map<HTMLElement, ElementState>;
243
+ /** @type {Set<function>} */
244
+ _subscribers: Set<Function>;
245
+ _lastTs: any;
246
+ _rafId: number;
247
+ _running: boolean;
248
+ _tick(ts: any): void;
249
+ start(): void;
250
+ stop(): void;
251
+ /**
252
+ * Create a new LFO instance.
253
+ * @param {object} opts
254
+ * @param {string} [opts.shape='sine'] Waveform shape. One of SHAPES.
255
+ * @param {number} [opts.rate=1] Frequency in Hz.
256
+ * @param {number} [opts.depth=1] Modulation depth multiplier 0–1.
257
+ * @param {number} [opts.phase=0] Initial phase offset 0–1.
258
+ * @param {number} [opts.offset=0] DC offset added to output, -1–1.
259
+ * @param {boolean} [opts.bipolar=true] If false, output is remapped 0–1.
260
+ * @returns {string} LFO id.
261
+ */
262
+ createLFO(opts?: {
263
+ shape?: string;
264
+ rate?: number;
265
+ depth?: number;
266
+ phase?: number;
267
+ offset?: number;
268
+ bipolar?: boolean;
269
+ }): string;
270
+ /**
271
+ * Remove an LFO and all its routes.
272
+ * @param {string} id
273
+ */
274
+ destroyLFO(id: string): void;
275
+ /**
276
+ * Add a modulation route.
277
+ *
278
+ * For element routes: LFO modulates an HTML input element.
279
+ * engine.addRoute(lfoId, 'element', inputEl, null, { depth: 0.5 });
280
+ *
281
+ * For LFO-chain routes: LFO modulates another LFO's rate or depth.
282
+ * engine.addRoute(lfoId, 'lfo', targetLfoId, 'rate', { depth: 0.3 });
283
+ *
284
+ * @param {string} sourceId
285
+ * @param {'element'|'lfo'} targetType
286
+ * @param {HTMLElement|string} target Element or target LFO id.
287
+ * @param {string|null} targetParam 'rate'|'depth' for lfo, null for element.
288
+ * @param {object} opts
289
+ * @param {number} [opts.depth=0.5] Modulation depth 0–1.
290
+ * @param {number} [opts.min] Override element min.
291
+ * @param {number} [opts.max] Override element max.
292
+ * @param {number} [opts.step] Override element step.
293
+ * @returns {string|null} Route id, or null if the route was rejected (e.g. self-modulation).
294
+ */
295
+ addRoute(sourceId: string, targetType: "element" | "lfo", target: HTMLElement | string, targetParam: string | null, opts?: {
296
+ depth?: number;
297
+ min?: number;
298
+ max?: number;
299
+ step?: number;
300
+ }): string | null;
301
+ /**
302
+ * Remove a modulation route.
303
+ * @param {string} routeId
304
+ */
305
+ removeRoute(routeId: string): void;
306
+ /**
307
+ * Set the depth of an existing route.
308
+ * @param {string} routeId
309
+ * @param {number} depth 0–1
310
+ */
311
+ setRouteDepth(routeId: string, depth: number): void;
312
+ /**
313
+ * Enable or disable a route without removing it.
314
+ * @param {string} routeId
315
+ * @param {boolean} enabled
316
+ */
317
+ setRouteEnabled(routeId: string, enabled: boolean): void;
318
+ /**
319
+ * Set a parameter on an LFO.
320
+ * @param {string} lfoId
321
+ * @param {string} param 'shape'|'rate'|'depth'|'phase'|'offset'|'bipolar'|'baseRate'|'baseDepth'|'jitter'|'skew'
322
+ * @param {*} value
323
+ */
324
+ setParam(lfoId: string, param: string, value: any): void;
325
+ /**
326
+ * Get a parameter from an LFO.
327
+ * @param {string} lfoId
328
+ * @param {string} param
329
+ * @returns {*}
330
+ */
331
+ getParam(lfoId: string, param: string): any;
332
+ /** Get the current output value of an LFO. @param {string} lfoId @returns {number} */
333
+ getValue(lfoId: string): number;
334
+ /**
335
+ * Subscribe to tick notifications. Called each frame for every LFO.
336
+ * @param {function(lfoId: string, value: number): void} fn
337
+ * @returns {function} Unsubscribe callback.
338
+ */
339
+ subscribe(fn: any): Function;
340
+ getLFOs(): LFOState[];
341
+ getLFO(id: any): LFOState;
342
+ getAllRoutes(): RouteState[];
343
+ getRoute(id: any): RouteState;
344
+ getRoutesByElement(element: any): RouteState[];
345
+ getElementMeta(element: any): ElementState;
346
+ _initElementState(element: any, opts: any): void;
347
+ _cleanupElementState(element: any): void;
348
+ _computeValue(lfo: any, dt: any): any;
349
+ }
350
+ export {};