@digitalmeadow/control-panel 1.0.1 → 1.0.3

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 (44) hide show
  1. package/dist/ControlPanel.d.ts +56 -0
  2. package/dist/ControlPanel.d.ts.map +1 -0
  3. package/dist/controllers/ArrayController.d.ts +24 -0
  4. package/dist/controllers/ArrayController.d.ts.map +1 -0
  5. package/dist/controllers/BooleanController.d.ts +9 -0
  6. package/dist/controllers/BooleanController.d.ts.map +1 -0
  7. package/dist/controllers/ButtonController.d.ts +9 -0
  8. package/dist/controllers/ButtonController.d.ts.map +1 -0
  9. package/dist/controllers/ColorController.d.ts +9 -0
  10. package/dist/controllers/ColorController.d.ts.map +1 -0
  11. package/dist/controllers/Controller.d.ts +27 -0
  12. package/dist/controllers/Controller.d.ts.map +1 -0
  13. package/dist/controllers/GradientController.d.ts +37 -0
  14. package/dist/controllers/GradientController.d.ts.map +1 -0
  15. package/dist/controllers/NumberController.d.ts +42 -0
  16. package/dist/controllers/NumberController.d.ts.map +1 -0
  17. package/dist/controllers/RadioController.d.ts +12 -0
  18. package/dist/controllers/RadioController.d.ts.map +1 -0
  19. package/dist/controllers/SelectController.d.ts +12 -0
  20. package/dist/controllers/SelectController.d.ts.map +1 -0
  21. package/dist/index.d.ts +13 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/{control-panel.js → index.js} +2 -0
  24. package/dist/{control-panel.umd.cjs → index.umd.cjs} +1 -1
  25. package/dist/signals/AudioSignals.d.ts +35 -0
  26. package/dist/signals/AudioSignals.d.ts.map +1 -0
  27. package/dist/signals/MidiSignals.d.ts +18 -0
  28. package/dist/signals/MidiSignals.d.ts.map +1 -0
  29. package/dist/signals/SignalHandler.d.ts +41 -0
  30. package/dist/signals/SignalHandler.d.ts.map +1 -0
  31. package/dist/stats.d.ts +11 -0
  32. package/dist/stats.d.ts.map +1 -0
  33. package/dist/utils/color.d.ts +2 -0
  34. package/dist/utils/color.d.ts.map +1 -0
  35. package/dist/utils/dom.d.ts +3 -0
  36. package/dist/utils/dom.d.ts.map +1 -0
  37. package/dist/utils/easings.d.ts +3 -0
  38. package/dist/utils/easings.d.ts.map +1 -0
  39. package/dist/utils/math.d.ts +3 -0
  40. package/dist/utils/math.d.ts.map +1 -0
  41. package/dist/utils/strings.d.ts +2 -0
  42. package/dist/utils/strings.d.ts.map +1 -0
  43. package/package.json +6 -6
  44. /package/dist/{control-panel.css → index.css} +0 -0
@@ -0,0 +1,56 @@
1
+ import "./styles.css";
2
+ import { Controller } from "./controllers/Controller";
3
+ import { NumberController, type NumberControllerOptions } from "./controllers/NumberController";
4
+ import { SelectController, type SelectControllerOptions } from "./controllers/SelectController";
5
+ import { ButtonController, type ButtonControllerOptions } from "./controllers/ButtonController";
6
+ import { BooleanController, type BooleanControllerOptions } from "./controllers/BooleanController";
7
+ import { RadioController, type RadioControllerOptions } from "./controllers/RadioController";
8
+ import { ColorController, type ColorControllerOptions } from "./controllers/ColorController";
9
+ import { GradientController, type GradientControllerOptions } from "./controllers/GradientController";
10
+ import { ArrayController, type ArrayControllerOptions } from "./controllers/ArrayController";
11
+ import { Stats } from "./stats";
12
+ export interface ControlPanelOptions {
13
+ title?: string;
14
+ presetsPrefix?: string;
15
+ }
16
+ export interface ControlPanelSectionState {
17
+ controllers: Record<string, any>;
18
+ folders: Record<string, ControlPanelSectionState>;
19
+ }
20
+ export declare abstract class ControlPanelContainer {
21
+ abstract contentElement: HTMLElement;
22
+ controllers: Controller<any>[];
23
+ folders: Folder[];
24
+ addNumber(object: any, property: string, options?: NumberControllerOptions): NumberController;
25
+ addSelect<T>(object: any, property: string, options?: SelectControllerOptions<T>): SelectController<T>;
26
+ addBoolean(object: any, property: string, options?: BooleanControllerOptions): BooleanController;
27
+ addButton(label: string, fn: () => void, options?: ButtonControllerOptions): ButtonController;
28
+ addRadio<T>(object: any, property: string, options?: RadioControllerOptions<T>): RadioController<T>;
29
+ addColor(object: any, property: string, options?: ColorControllerOptions): ColorController;
30
+ addGradient(object: any, property: string, options?: GradientControllerOptions): GradientController;
31
+ addArray(object: any, property: string, options?: ArrayControllerOptions): ArrayController;
32
+ addFolder(title: string): Folder;
33
+ save(): ControlPanelSectionState;
34
+ load(state: ControlPanelSectionState): void;
35
+ reset(): void;
36
+ }
37
+ export declare class Folder extends ControlPanelContainer {
38
+ domElement: HTMLDetailsElement;
39
+ contentElement: HTMLElement;
40
+ summaryElement: HTMLElement;
41
+ title: string;
42
+ constructor(title: string);
43
+ }
44
+ export declare class ControlPanel extends ControlPanelContainer {
45
+ domElement: HTMLDetailsElement;
46
+ summaryElement: HTMLElement;
47
+ contentElement: HTMLElement;
48
+ stats: Stats;
49
+ private presetStoragePrefix;
50
+ constructor(container?: HTMLElement, options?: ControlPanelOptions);
51
+ saveToLocalStorage(key: string): void;
52
+ loadFromLocalStorage(key: string): void;
53
+ saveDefaultPreset(): void;
54
+ destroy(): void;
55
+ }
56
+ //# sourceMappingURL=ControlPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ControlPanel.d.ts","sourceRoot":"","sources":["../src/ControlPanel.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC7B,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,EAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,EAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC5B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;CACnD;AAED,8BAAsB,qBAAqB;IACzC,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC;IACrC,WAAW,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAM;IACpC,OAAO,EAAE,MAAM,EAAE,CAAM;IAEvB,SAAS,CACP,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B;IAQvC,SAAS,CAAC,CAAC,EACT,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAAuB,CAAC,CAAC,CAAM;IAQ1C,UAAU,CACR,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B;IAQxC,SAAS,CACP,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,IAAI,EACd,OAAO,GAAE,uBAA4B;IAQvC,QAAQ,CAAC,CAAC,EACR,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAAsB,CAAC,CAAC,CAAmC;IAQtE,QAAQ,CACN,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B;IAQtC,WAAW,CACT,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B;IAQzC,QAAQ,CACN,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B;IAQtC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAOhC,IAAI,IAAI,wBAAwB;IAoBhC,IAAI,CAAC,KAAK,EAAE,wBAAwB;IAqCpC,KAAK;CAYN;AAED,qBAAa,MAAO,SAAQ,qBAAqB;IAC/C,UAAU,EAAE,kBAAkB,CAAC;IAC/B,cAAc,EAAE,WAAW,CAAC;IAC5B,cAAc,EAAE,WAAW,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;gBAEF,KAAK,EAAE,MAAM;CA2B1B;AAED,qBAAa,YAAa,SAAQ,qBAAqB;IACrD,UAAU,EAAE,kBAAkB,CAAC;IAC/B,cAAc,EAAE,WAAW,CAAC;IAC5B,cAAc,EAAE,WAAW,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,CAAC,mBAAmB,CAAS;gBAExB,SAAS,CAAC,EAAE,WAAW,EAAE,OAAO,GAAE,mBAAwB;IA+RtE,kBAAkB,CAAC,GAAG,EAAE,MAAM;IAS9B,oBAAoB,CAAC,GAAG,EAAE,MAAM;IAYhC,iBAAiB;IAQjB,OAAO;CAMR"}
@@ -0,0 +1,24 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ export type ArrayItemType = "color" | "number" | "string";
3
+ export interface ArrayControllerOptions extends ControllerOptions {
4
+ itemType?: ArrayItemType;
5
+ }
6
+ export declare class ArrayController extends Controller<string> {
7
+ items: string[];
8
+ itemType: ArrayItemType;
9
+ itemsContainer: HTMLElement;
10
+ private initialOptions;
11
+ constructor(object: any, property: string, options?: ArrayControllerOptions);
12
+ private parseValue;
13
+ private serializeValue;
14
+ private getDefaultItemValue;
15
+ private addItem;
16
+ private updateValue;
17
+ private updateSummary;
18
+ renderItems(): void;
19
+ updateDisplay(): void;
20
+ save(): string[];
21
+ load(data: any): void;
22
+ reset(): void;
23
+ }
24
+ //# sourceMappingURL=ArrayController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArrayController.d.ts","sourceRoot":"","sources":["../../src/controllers/ArrayController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1D,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAC/D,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED,qBAAa,eAAgB,SAAQ,UAAU,CAAC,MAAM,CAAC;IACrD,KAAK,EAAE,MAAM,EAAE,CAAM;IACrB,QAAQ,EAAE,aAAa,CAAC;IACxB,cAAc,EAAE,WAAW,CAAC;IAC5B,OAAO,CAAC,cAAc,CAAyB;gBAG7C,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B;IAyDtC,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IAOrB,WAAW;IAgDX,aAAa;IAIb,IAAI,IAAI,MAAM,EAAE;IAIhB,IAAI,CAAC,IAAI,EAAE,GAAG;IAUd,KAAK;CAMN"}
@@ -0,0 +1,9 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ export interface BooleanControllerOptions extends ControllerOptions {
3
+ }
4
+ export declare class BooleanController extends Controller<boolean> {
5
+ input: HTMLInputElement;
6
+ constructor(object: any, property: string, options?: BooleanControllerOptions);
7
+ updateDisplay(): void;
8
+ }
9
+ //# sourceMappingURL=BooleanController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BooleanController.d.ts","sourceRoot":"","sources":["../../src/controllers/BooleanController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;CAAG;AAEtE,qBAAa,iBAAkB,SAAQ,UAAU,CAAC,OAAO,CAAC;IACxD,KAAK,EAAE,gBAAgB,CAAC;gBAGtB,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B;IAkBxC,aAAa;CAGd"}
@@ -0,0 +1,9 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ export interface ButtonControllerOptions extends ControllerOptions {
3
+ }
4
+ export declare class ButtonController extends Controller<() => void> {
5
+ button: HTMLButtonElement;
6
+ constructor(label: string, fn: () => void, options?: ButtonControllerOptions);
7
+ updateDisplay(): void;
8
+ }
9
+ //# sourceMappingURL=ButtonController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ButtonController.d.ts","sourceRoot":"","sources":["../../src/controllers/ButtonController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;CAAG;AAErE,qBAAa,gBAAiB,SAAQ,UAAU,CAAC,MAAM,IAAI,CAAC;IAC1D,MAAM,EAAE,iBAAiB,CAAC;gBAGxB,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,IAAI,EACd,OAAO,GAAE,uBAA4B;IAsBvC,aAAa;CACd"}
@@ -0,0 +1,9 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ export interface ColorControllerOptions extends ControllerOptions {
3
+ }
4
+ export declare class ColorController extends Controller<string> {
5
+ input: HTMLInputElement;
6
+ constructor(object: any, property: string, options?: ColorControllerOptions);
7
+ updateDisplay(): void;
8
+ }
9
+ //# sourceMappingURL=ColorController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColorController.d.ts","sourceRoot":"","sources":["../../src/controllers/ColorController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;CAAG;AAEpE,qBAAa,eAAgB,SAAQ,UAAU,CAAC,MAAM,CAAC;IACrD,KAAK,EAAE,gBAAgB,CAAC;gBAGtB,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B;IAoBtC,aAAa;CAGd"}
@@ -0,0 +1,27 @@
1
+ export type ChangeCallback<T> = (value: T) => void;
2
+ export interface ControllerOptions {
3
+ label?: string;
4
+ disabled?: boolean;
5
+ id?: string;
6
+ }
7
+ export declare abstract class Controller<T> {
8
+ static audio: import("..").AudioSignals;
9
+ static midi: import("..").MidiSignals;
10
+ readonly key: string;
11
+ readonly initialValue: T;
12
+ domElement: HTMLElement;
13
+ protected object: any;
14
+ protected property: string;
15
+ protected changeFns: Set<ChangeCallback<T>>;
16
+ constructor(object: any, property: string, options?: ControllerOptions);
17
+ get value(): T;
18
+ setValue(value: T, shouldEmit?: boolean): void;
19
+ save(): any;
20
+ load(data: any): void;
21
+ reset(): void;
22
+ abstract updateDisplay(): void;
23
+ onChange(fn: ChangeCallback<T>): this;
24
+ protected emitChange(value: T): void;
25
+ protected appendWidget(widget: HTMLElement): void;
26
+ }
27
+ //# sourceMappingURL=Controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Controller.d.ts","sourceRoot":"","sources":["../../src/controllers/Controller.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,8BAAsB,UAAU,CAAC,CAAC;IAChC,MAAM,CAAC,KAAK,4BAAgB;IAC5B,MAAM,CAAC,IAAI,2BAAe;IAE1B,SAAgB,GAAG,EAAE,MAAM,CAAC;IAC5B,SAAgB,YAAY,EAAE,CAAC,CAAC;IAChC,UAAU,EAAE,WAAW,CAAC;IACxB,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC;IACtB,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAa;gBAE5C,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB;IAoB1E,IAAI,KAAK,IAAI,CAAC,CAEb;IAED,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,UAAU,UAAO;IAQpC,IAAI,IAAI,GAAG;IAIX,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI;IAIrB,KAAK,IAAI,IAAI;IAIb,QAAQ,CAAC,aAAa,IAAI,IAAI;IAE9B,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAK9B,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAM7B,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW;CAG3C"}
@@ -0,0 +1,37 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ import { type SignalHandlerState } from "../signals/SignalHandler";
3
+ export interface ColorStop {
4
+ color: string;
5
+ position: number;
6
+ }
7
+ export interface GradientControllerOptions extends ControllerOptions {
8
+ stops?: ColorStop[];
9
+ }
10
+ interface GradientControllerState {
11
+ stops: ColorStop[];
12
+ settings: {
13
+ signal: SignalHandlerState;
14
+ };
15
+ }
16
+ export declare class GradientController extends Controller<string> {
17
+ stops: ColorStop[];
18
+ private signalHandler?;
19
+ private pingPongDirection;
20
+ private animationT;
21
+ private manualPosition;
22
+ displayColor: HTMLElement;
23
+ displayText: HTMLElement;
24
+ stopsContainer: HTMLElement;
25
+ private initialOptions;
26
+ constructor(object: any, property: string, options?: GradientControllerOptions);
27
+ sortStops(): void;
28
+ renderStops(): void;
29
+ updateOutput(t?: number): void;
30
+ updateDisplay(): void;
31
+ private applySignal;
32
+ save(): GradientControllerState;
33
+ load(data: any): void;
34
+ reset(): void;
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=GradientController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GradientController.d.ts","sourceRoot":"","sources":["../../src/controllers/GradientController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,yBAA0B,SAAQ,iBAAiB;IAClE,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,UAAU,uBAAuB;IAC/B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,QAAQ,EAAE;QACR,MAAM,EAAE,kBAAkB,CAAC;KAC5B,CAAC;CACH;AAED,qBAAa,kBAAmB,SAAQ,UAAU,CAAC,MAAM,CAAC;IAExD,KAAK,EAAE,SAAS,EAAE,CAAM;IAGxB,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,cAAc,CAAa;IAGnC,YAAY,EAAE,WAAW,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,WAAW,CAAC;IAE5B,OAAO,CAAC,cAAc,CAA4B;gBAGhD,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B;IAiFzC,SAAS;IAIT,WAAW;IAkDX,YAAY,CAAC,CAAC,GAAE,MAA4B;IAoC5C,aAAa;IASb,OAAO,CAAC,WAAW;IAmCnB,IAAI,IAAI,uBAAuB;IAS/B,IAAI,CAAC,IAAI,EAAE,GAAG;IAWd,KAAK;CAUN"}
@@ -0,0 +1,42 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ import { type SignalHandlerState } from "../signals/SignalHandler";
3
+ export interface NumberControllerOptions extends ControllerOptions {
4
+ min?: number;
5
+ max?: number;
6
+ step?: number;
7
+ }
8
+ interface NumberControllerState {
9
+ value: number;
10
+ settings: {
11
+ min: number;
12
+ max: number;
13
+ step: string;
14
+ signal: SignalHandlerState;
15
+ };
16
+ }
17
+ export declare class NumberController extends Controller<number> {
18
+ input: HTMLInputElement;
19
+ display: HTMLElement;
20
+ private signalHandler?;
21
+ private pingPongDirection;
22
+ private min;
23
+ private max;
24
+ private initialOptions;
25
+ private minInput;
26
+ private maxInput;
27
+ private stepInput;
28
+ constructor(object: any, property: string, options?: NumberControllerOptions);
29
+ setMin(val: string | number): void;
30
+ setMax(val: string | number): void;
31
+ setStep(val: string | number | undefined): void;
32
+ private applySignal;
33
+ private roundToStep;
34
+ private createSetting;
35
+ updateDisplay(): void;
36
+ save(): NumberControllerState;
37
+ load(data: any): void;
38
+ reset(): void;
39
+ private resetSettings;
40
+ }
41
+ export {};
42
+ //# sourceMappingURL=NumberController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NumberController.d.ts","sourceRoot":"","sources":["../../src/controllers/NumberController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,qBAAqB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,kBAAkB,CAAC;KAC5B,CAAC;CACH;AAED,qBAAa,gBAAiB,SAAQ,UAAU,CAAC,MAAM,CAAC;IACtD,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,GAAG,CAAe;IAE1B,OAAO,CAAC,cAAc,CAA0B;IAGhD,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,SAAS,CAAoB;gBAGnC,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B;IA6FvC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAa3B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAa3B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAkBxC,OAAO,CAAC,WAAW;IA6CnB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IA0BrB,aAAa;IAOb,IAAI,IAAI,qBAAqB;IAY7B,IAAI,CAAC,IAAI,EAAE,GAAG;IA6Cd,KAAK;IAKL,OAAO,CAAC,aAAa;CAWtB"}
@@ -0,0 +1,12 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ export interface RadioControllerOptions<T> extends ControllerOptions {
3
+ options?: T[];
4
+ }
5
+ export declare class RadioController<T> extends Controller<T> {
6
+ container: HTMLElement;
7
+ buttons: HTMLButtonElement[];
8
+ optionValues: T[];
9
+ constructor(object: any, property: string, options: RadioControllerOptions<T>);
10
+ updateDisplay(): void;
11
+ }
12
+ //# sourceMappingURL=RadioController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioController.d.ts","sourceRoot":"","sources":["../../src/controllers/RadioController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,MAAM,WAAW,sBAAsB,CAAC,CAAC,CAAE,SAAQ,iBAAiB;IAClE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;CACf;AAED,qBAAa,eAAe,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IACnD,SAAS,EAAE,WAAW,CAAC;IACvB,OAAO,EAAE,iBAAiB,EAAE,CAAM;IAClC,YAAY,EAAE,CAAC,EAAE,CAAM;gBAGrB,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAyBpC,aAAa;CAWd"}
@@ -0,0 +1,12 @@
1
+ import { Controller, type ControllerOptions } from "./Controller";
2
+ export interface SelectControllerOptions<T> extends ControllerOptions {
3
+ options?: T[];
4
+ }
5
+ export declare class SelectController<T> extends Controller<T> {
6
+ select: HTMLSelectElement;
7
+ optionValues: T[];
8
+ constructor(object: any, property: string, options: SelectControllerOptions<T>);
9
+ setOptions(options: T[]): void;
10
+ updateDisplay(): void;
11
+ }
12
+ //# sourceMappingURL=SelectController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectController.d.ts","sourceRoot":"","sources":["../../src/controllers/SelectController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGlE,MAAM,WAAW,uBAAuB,CAAC,CAAC,CAAE,SAAQ,iBAAiB;IACnE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;CACf;AAED,qBAAa,gBAAgB,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IACpD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,YAAY,EAAE,CAAC,EAAE,CAAM;gBAGrB,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC;IA0BrC,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE;IAevB,aAAa;CAMd"}
@@ -0,0 +1,13 @@
1
+ export * from "./ControlPanel";
2
+ export * from "./controllers/Controller";
3
+ export * from "./controllers/NumberController";
4
+ export * from "./controllers/SelectController";
5
+ export * from "./controllers/BooleanController";
6
+ export * from "./controllers/ButtonController";
7
+ export * from "./controllers/RadioController";
8
+ export * from "./controllers/ColorController";
9
+ export * from "./controllers/GradientController";
10
+ export * from "./controllers/ArrayController";
11
+ export * from "./signals/AudioSignals";
12
+ export * from "./signals/MidiSignals";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
@@ -1061,7 +1061,9 @@ export {
1061
1061
  _ as ButtonController,
1062
1062
  G as ColorController,
1063
1063
  et as ControlPanel,
1064
+ k as ControlPanelContainer,
1064
1065
  m as Controller,
1066
+ tt as Folder,
1065
1067
  Q as GradientController,
1066
1068
  $ as MidiSignals,
1067
1069
  H as NumberController,
@@ -1 +1 @@
1
- (function(d,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(d=typeof globalThis<"u"?globalThis:d||self,o(d.ControlPanel={}))})(this,(function(d){"use strict";function o(n,t={},e=[]){const i=document.createElement(n);for(const[s,a]of Object.entries(t))s==="className"?i.className=String(a):s==="style"&&typeof a=="object"?Object.assign(i.style,a):s==="open"&&typeof a=="boolean"?a?i.setAttribute("open",""):i.removeAttribute("open"):typeof a!="object"&&i.setAttribute(s,String(a));for(const s of e)typeof s=="string"?i.appendChild(document.createTextNode(s)):i.appendChild(s);return i}function D(n){const t=o("button",{className:"cp-button cp-button-delete"},["×"]);return t.addEventListener("click",n),t}function K(n){return n.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}function O(n,t,e){return Math.min(Math.max(n,t),e)}function Q(n,t,e){if(t.length!==e.length)throw new Error("Input and output ranges must have the same length");if(t.length<2)throw new Error("Input and output ranges must have at least two values");let i=0;for(;i<t.length-1&&n>t[i+1];)i++;if(i===t.length-1)return e[e.length-1];if(i===0&&n<t[0])return e[0];const s=t[i],a=t[i+1],r=e[i],h=e[i+1];return(n-s)/(a-s)*(h-r)+r}class B{constructor(){this.source=null,this.stream=null,this.fftSize=2048,this.smoothingTimeConstant=.92,this.spectrumBoost=2,this.levels={bass:0,mids:0,highs:0,volume:0},this.peaks={bass:0,mids:0,highs:0,volume:0},this._isAnalyzing=!1,this.loop=()=>{this._isAnalyzing&&(requestAnimationFrame(this.loop),this.update())};const t=window.AudioContext||window.webkitAudioContext;this.ctx=new t,this.analyser=this.ctx.createAnalyser(),this.analyser.fftSize=this.fftSize,this.analyser.smoothingTimeConstant=this.smoothingTimeConstant,this.dataArray=new Uint8Array(this.analyser.frequencyBinCount),this.waveformArray=new Uint8Array(this.analyser.frequencyBinCount)}setFFTSize(t){this.fftSize=t,this.analyser.fftSize=t,this.dataArray=new Uint8Array(this.analyser.frequencyBinCount),this.waveformArray=new Uint8Array(this.analyser.frequencyBinCount)}async setInput(t){try{let e;t==="browser"?e=navigator.mediaDevices.getDisplayMedia({audio:!0,video:!0}):e=navigator.mediaDevices.getUserMedia({audio:!0});const i=await e;this.ctx.state==="suspended"&&this.ctx.resume(),this.source&&this.source.disconnect(),this.stream&&this.stream.getTracks().forEach(s=>s.stop()),this.stream=i,this.source=this.ctx.createMediaStreamSource(this.stream),this.source.connect(this.analyser),this._isAnalyzing=!0,this.loop()}catch(e){console.error("Error accessing audio input:",e),this._isAnalyzing=!1}}update(){if(this.analyser.getByteFrequencyData(this.dataArray),this.analyser.getByteTimeDomainData(this.waveformArray),this.spectrumBoost!==1){const p=this.dataArray.length;for(let c=0;c<p;c++){const f=1+c/p*(this.spectrumBoost-1);this.dataArray[c]=Math.min(255,this.dataArray[c]*f)}}const t=[2,10],e=[10,150],i=[150,600],s=this.getAverage(t[0],t[1]),a=this.getAverage(e[0],e[1]),r=this.getAverage(i[0],i[1]),h=this.getAverage(0,i[1]);this.processLevel("bass",s),this.processLevel("mids",a),this.processLevel("highs",r),this.processLevel("volume",h)}processLevel(t,e){this.peaks[t]-=5e-4,this.peaks[t]=O(this.peaks[t],.1,1),e>this.peaks[t]&&(this.peaks[t]=e),this.levels[t]=O(Q(e,[0,this.peaks[t]],[0,1]),0,1)}getAverage(t,e){let i=0;const s=e-t;if(s<=0)return 0;for(let a=t;a<e;a++)i+=this.dataArray[a];return i/s/255}getSignal(t){return()=>this.levels[t]}}const x=new B;class F{constructor(){this.midiAccess=null,this.values=new Map,this.isListening=!1,this.resolveListen=null,this.listeningCallback=null,this.init()}async init(){if(typeof navigator<"u"&&navigator.requestMIDIAccess)try{this.midiAccess=await navigator.requestMIDIAccess(),this.setupInputs(),this.midiAccess.onstatechange=t=>{t.port.type==="input"&&t.port.state==="connected"&&this.setupInputs()}}catch(t){console.warn("MIDI Access failed",t)}}setupInputs(){if(!this.midiAccess)return;const t=this.midiAccess.inputs.values();for(const e of t)e.onmidimessage=this.handleMessage.bind(this)}handleMessage(t){const e=t.data,[i]=e;if((i&240)>=240)return;const a=this.getIdFromMessage(t),r=this.normalizeValue(e);this.values.set(a,r),this.isListening&&this.resolveListen&&r>0&&(this.resolveListen(a),this.isListening=!1,this.resolveListen=null,this.listeningCallback&&this.listeningCallback())}getIdFromMessage(t){const e=t.data,[i,s]=e,a=i&240,r=t.currentTarget.name||"unknown",h=a===144||a===128?"note":"ctrl",p=r.replace(/[^a-zA-Z0-9]/g,"");return`${s}_${h}_${p}`}normalizeValue(t){const[e,i,s]=t,a=e&240;return a===144?s>0?1:0:a===128?0:a===176?s/127:0}listen(){return this.isListening=!0,new Promise(t=>{this.resolveListen=t})}cancelListen(){this.isListening=!1,this.resolveListen=null}getSignal(t){return()=>this.values.get(t)??0}}const P=new F,M=class M{constructor(t,e,i={}){this.changeFns=new Set,this.object=t,this.property=e,this.key=i.id??e,this.initialValue=this.object[this.property],this.domElement=o("div",{className:"cp-controller"});const s=i.label??K(e),a=o("label",{className:"cp-label"},[String(s)]);a.setAttribute("title",String(s)),this.domElement.appendChild(a),i.disabled&&this.domElement.setAttribute("data-disabled","true")}get value(){return this.object[this.property]}setValue(t,e=!0){this.object[this.property]=t,e&&this.emitChange(t),this.updateDisplay()}save(){return this.value}load(t){this.setValue(t)}reset(){this.setValue(this.initialValue)}onChange(t){return this.changeFns.add(t),this}emitChange(t){for(const e of this.changeFns)e(t)}appendWidget(t){this.domElement.appendChild(t)}};M.audio=x,M.midi=P;let m=M;const k={linear:n=>n,quadIn:n=>n*n,quadOut:n=>n*(2-n),quadInOut:n=>n<.5?2*n*n:-1+(4-2*n)*n,cubicIn:n=>n*n*n,cubicOut:n=>--n*n*n+1,cubicInOut:n=>n<.5?4*n*n*n:(n-1)*(2*n-2)*(2*n-2)+1,expoIn:n=>n===0?0:Math.pow(2,10*(n-1)),expoOut:n=>n===1?1:-Math.pow(2,-10*n)+1,expoInOut:n=>n===0||n===1?n:(n*=2)<1?.5*Math.pow(2,10*(n-1)):.5*(-Math.pow(2,-10*--n)+2),sineIn:n=>1-Math.cos(n*Math.PI/2),sineOut:n=>Math.sin(n*Math.PI/2),sineInOut:n=>-(Math.cos(Math.PI*n)-1)/2};class R{constructor(t){this.rafId=null,this.currentSignalType=null,this.currentMidiId=null,this.currentEase="linear",this.currentBehaviour="forward",this.loop=()=>{if(this.currentSignalType){let e=0;this.currentSignalType==="midi"?this.currentMidiId&&(e=m.midi.getSignal(this.currentMidiId)()):e=m.audio.getSignal(this.currentSignalType)();const i=k[this.currentEase](e);this.onChange(i,this.currentBehaviour),this.rafId=requestAnimationFrame(this.loop)}},this.onChange=t.onChange,this.setupControllers(t.container)}setupControllers(t){const e=this.createSettingSelect("signal",["none","bass","mids","highs","volume","midi"],r=>this.setSignalType(r));this.signalSelect=e.select,t.appendChild(e.row),this.midiRow=o("div",{className:"cp-setting-row",style:"display: none;"});const i=o("label",{className:"cp-setting-label"},["Midi"]);this.midiBtn=o("button",{className:"cp-button cp-input-small"},["Learn"]),this.midiBtn.addEventListener("click",async()=>{if(this.midiBtn.textContent==="Listening..."){m.midi.cancelListen(),this.setMidiId(null);return}this.midiBtn.textContent="Listening...";const r=await m.midi.listen();this.setMidiId(r)}),this.midiRow.appendChild(i),this.midiRow.appendChild(this.midiBtn),t.appendChild(this.midiRow);const s=this.createSettingSelect("behaviour",["forward","backward","loopForward","loopBackward","pingpong"],r=>this.setBehaviour(r));this.behaviourRow=s.row,this.behaviourSelect=s.select,this.behaviourRow.style.display="none",this.behaviourSelect.value=this.currentBehaviour,t.appendChild(this.behaviourRow);const a=this.createSettingSelect("ease",Object.keys(k),r=>this.setEase(r));this.easeRow=a.row,this.easeSelect=a.select,this.easeRow.style.display="none",this.easeSelect.value=this.currentEase,t.appendChild(this.easeRow)}createSettingSelect(t,e,i){const s=o("div",{className:"cp-setting-row"}),a=o("label",{className:"cp-setting-label"},[t]),r=o("select",{className:"cp-select cp-input-small"});return e.forEach(h=>{const p=o("option",{value:h},[h]);r.appendChild(p)}),r.addEventListener("change",()=>i(r.value)),s.appendChild(a),s.appendChild(r),{row:s,select:r}}setSignalType(t){if(!t||t==="none")this.currentSignalType=null,this.currentMidiId=null,this.midiRow.style.display="none",this.easeRow.style.display="none",this.behaviourRow.style.display="none",this.stop(),this.signalSelect.value!=="none"&&(this.signalSelect.value="none");else{this.currentSignalType=t;const e=t==="midi";this.midiRow.style.display=e?"flex":"none",this.easeRow.style.display="flex",this.behaviourRow.style.display="flex",e||(this.currentMidiId=null,m.audio.ctx.state==="suspended"&&m.audio.setInput("microphone")),this.start(),this.signalSelect.value!==t&&(this.signalSelect.value=t)}}setMidiId(t){this.currentMidiId=t,this.midiBtn.textContent=t??"Learn"}setEase(t){this.currentEase=t,this.easeSelect.value!==t&&(this.easeSelect.value=t)}setBehaviour(t){this.currentBehaviour=t,this.behaviourSelect.value!==t&&(this.behaviourSelect.value=t)}start(){!this.rafId&&this.currentSignalType&&this.loop()}stop(){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null)}save(){return{type:this.currentSignalType,midiId:this.currentMidiId,ease:this.currentEase,behaviour:this.currentBehaviour}}load(t){t&&(this.setSignalType(t.type),this.setMidiId(t.midiId||null),this.setEase(t.ease||"linear"),this.setBehaviour(t.behaviour||"forward"))}reset(){this.setSignalType("none"),this.setEase("linear"),this.setBehaviour("forward"),this.setMidiId(null)}}class j extends m{constructor(t,e,i={}){super(t,e,i),this.pingPongDirection=1,this.min=0,this.max=100,this.initialOptions=i,this.min=i.min??0,this.max=i.max??100;const s=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"});this.input=o("input",{type:"range",className:"cp-input-range",step:i.step??"any"}),i.min!==void 0&&(this.input.min=String(i.min)),i.max!==void 0&&(this.input.max=String(i.max)),this.input.value=String(this.value),this.display=o("span",{className:"cp-value-display"},[String(this.value.toFixed(1))]),this.input.addEventListener("input",()=>{const l=parseFloat(this.input.value);isNaN(l)||(this.setValue(l),this.display.textContent=String(l.toFixed(1)))}),this.input.addEventListener("click",l=>{l.stopPropagation()});const r=o("div",{className:"cp-controller-summary-content"});r.appendChild(this.input),r.appendChild(this.display),a.appendChild(r),s.appendChild(a);const h=o("div",{className:"cp-number-settings"}),p=this.createSetting("min",i.min,l=>this.setMin(l));this.minInput=p.input,h.appendChild(p.row);const c=this.createSetting("max",i.max,l=>this.setMax(l));this.maxInput=c.input,h.appendChild(c.row);const v=this.createSetting("step",i.step,l=>this.setStep(l));this.stepInput=v.input,h.appendChild(v.row);const f=o("hr",{className:"cp-separator"});h.appendChild(f),this.signalHandler=new R({container:h,onChange:(l,u)=>this.applySignal(l,u)}),s.appendChild(h),this.appendWidget(s)}setMin(t){typeof t=="number"&&(t=String(t)),t===""||isNaN(parseFloat(t))?this.input.removeAttribute("min"):(this.input.min=t,this.min=parseFloat(t)),this.minInput&&this.minInput.value!==t&&(this.minInput.value=t)}setMax(t){typeof t=="number"&&(t=String(t)),t===""||isNaN(parseFloat(t))?this.input.removeAttribute("max"):(this.input.max=t,this.max=parseFloat(t)),this.maxInput&&this.maxInput.value!==t&&(this.maxInput.value=t)}setStep(t){t===void 0&&(t=""),typeof t=="number"&&(t=String(t)),t===""||t==="any"||isNaN(parseFloat(t))?this.input.step="any":this.input.step=t,this.stepInput&&(t==="any"||t===""?this.stepInput.value="":this.stepInput.value!==t&&(this.stepInput.value=t))}applySignal(t,e){const i=this.max-this.min;let s;if(e==="forward")s=this.min+t*i;else if(e==="backward")s=this.max-t*i;else{const a=t*(i*.01);s=this.value,e==="loopForward"?(s+=a,s>this.max&&(s=this.min+(s-this.min)%i)):e==="loopBackward"?(s-=a,s<this.min&&(s=this.max-(this.max-s)%i)):e==="pingpong"&&(s+=a*this.pingPongDirection,s>=this.max?(s=this.max,this.pingPongDirection=-1):s<=this.min&&(s=this.min,this.pingPongDirection=1))}s=this.roundToStep(s),this.setValue(s),this.input.value=String(s),this.display.textContent=String(s.toFixed(1))}roundToStep(t){const e=this.input.step;if(e==="any"||e===""||isNaN(parseFloat(e)))return t;const i=parseFloat(e),s=this.min;return s+Math.round((t-s)/i)*i}createSetting(t,e,i){const s=o("div",{className:"cp-setting-row"}),a=o("label",{className:"cp-setting-label"},[t]),r=o("input",{type:"number",className:"cp-input-number cp-input-small",step:"any"});return e!==void 0&&(r.value=String(e)),r.addEventListener("input",()=>i(r.value)),s.appendChild(a),s.appendChild(r),{row:s,input:r}}updateDisplay(){this.input.value=String(this.value),this.display.textContent=String(this.value.toFixed(1))}save(){return{value:this.value,settings:{min:this.min,max:this.max,step:this.input.step,signal:this.signalHandler.save()}}}load(t){if(typeof t=="number")this.setValue(t),this.resetSettings();else if(typeof t=="object"&&t!==null&&"value"in t){const e=t.settings||{};e.min!==void 0?this.setMin(e.min):this.setMin(this.initialOptions.min!==void 0?this.initialOptions.min:""),e.max!==void 0?this.setMax(e.max):this.setMax(this.initialOptions.max!==void 0?this.initialOptions.max:""),e.step!==void 0?this.setStep(e.step):this.setStep(this.initialOptions.step);let i=t.value;!isNaN(this.min)&&i<this.min&&(i=this.min),!isNaN(this.max)&&i>this.max&&(i=this.max),this.setValue(i),this.signalHandler?.load(e.signal)}}reset(){this.setValue(this.initialValue),this.resetSettings()}resetSettings(){this.setMin(this.initialOptions.min!==void 0?this.initialOptions.min:""),this.setMax(this.initialOptions.max!==void 0?this.initialOptions.max:""),this.setStep(this.initialOptions.step),this.signalHandler?.reset()}}class z extends m{constructor(t,e,i){super(t,e,i),this.optionValues=[],this.select=o("select",{className:"cp-select"}),this.optionValues=i.options||[],this.optionValues.forEach((s,a)=>{const r=o("option",{value:String(a)},[String(s)]);this.select.appendChild(r)}),this.updateDisplay(),this.select.addEventListener("change",()=>{const s=parseInt(this.select.value),a=this.optionValues[s];this.setValue(a)}),this.appendWidget(this.select)}setOptions(t){this.select.innerHTML="",this.optionValues=t,this.optionValues.forEach((e,i)=>{const s=o("option",{value:String(i)},[String(e)]);this.select.appendChild(s)}),this.updateDisplay(),this.select.value===""&&this.optionValues.length>0&&this.setValue(this.optionValues[0])}updateDisplay(){const t=this.optionValues.indexOf(this.value);t!==-1&&(this.select.value=String(t))}}class $ extends m{constructor(t,e,i={}){const s={action:e};super(s,"action",i);const a=i.label??t;this.button=o("button",{className:"cp-button"},[String(a)]),this.button.addEventListener("click",()=>{const r=this.value;typeof r=="function"&&r(),this.emitChange(r)}),this.appendWidget(this.button)}updateDisplay(){}}class q extends m{constructor(t,e,i={}){super(t,e,i),this.input=o("input",{type:"checkbox",className:"cp-checkbox"}),this.input.checked=this.value,this.input.addEventListener("change",()=>{this.setValue(this.input.checked)}),this.appendWidget(this.input)}updateDisplay(){this.input.checked=this.value}}class H extends m{constructor(t,e,i){super(t,e,i),this.buttons=[],this.optionValues=[],this.container=o("div",{className:"cp-radios"}),this.optionValues=i.options||[],this.optionValues.forEach(s=>{const a=o("button",{className:"cp-button cp-radio"},[String(s)]);a.addEventListener("click",()=>{this.setValue(s)}),this.container.appendChild(a),this.buttons.push(a)}),this.updateDisplay(),this.appendWidget(this.container)}updateDisplay(){const t=this.value;this.buttons.forEach((e,i)=>{this.optionValues[i]===t?e.setAttribute("data-active","true"):e.removeAttribute("data-active")})}}class U extends m{constructor(t,e,i={}){super(t,e,i),this.input=o("input",{type:"color",className:"cp-input-color",value:this.value||"#000000"}),this.appendWidget(this.input),this.input.addEventListener("input",s=>{const a=s.target;this.setValue(a.value)}),this.updateDisplay()}updateDisplay(){this.input.value=this.value}}function _(n){const t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;n=n.replace(t,(i,s,a,r)=>s+s+a+a+r+r);const e=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(n);return e?[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]:[0,0,0]}function X(n,t,e){return"#"+((1<<24)+(Math.round(n)<<16)+(Math.round(t)<<8)+Math.round(e)).toString(16).slice(1)}function I(n){const t=n/255;return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function A(n){return n<=.0031308?n*12.92*255:(1.055*Math.pow(n,1/2.4)-.055)*255}function Y(n,t,e){const[i,s,a]=_(n),[r,h,p]=_(t),c=I(i),v=I(s),f=I(a),l=I(r),u=I(h),g=I(p),S=c+e*(l-c),N=v+e*(u-v),C=f+e*(g-f),b=A(S),y=A(N),w=A(C);return X(b,y,w)}class W extends m{constructor(t,e,i={}){super(t,e,i),this.stops=[],this.pingPongDirection=1,this.animationT=0,this.manualPosition=0,this.initialOptions=i,this.stops=i.stops||[{color:"#000000",position:0},{color:"#ffffff",position:1}],this.sortStops();const s=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"});this.displayColor=o("div",{className:"cp-color-swatch",style:`background-color: ${this.value}`}),this.displayText=o("span",{className:"cp-value-display"},[String(this.value)]),r.appendChild(this.displayColor),r.appendChild(this.displayText),a.appendChild(r),s.appendChild(a);const h=o("div",{className:"cp-number-settings"});this.stopsContainer=o("div",{className:"cp-stops-container"}),this.renderStops(),h.appendChild(this.stopsContainer);const p=o("button",{className:"cp-button"},["+ Add Stop"]);p.addEventListener("click",()=>{this.stops.push({color:"#ffffff",position:.5}),this.sortStops(),this.renderStops(),this.updateOutput()}),h.appendChild(p);const c=o("hr",{className:"cp-separator"});h.appendChild(c),this.signalHandler=new R({container:h,onChange:(v,f)=>this.applySignal(v,f)}),s.appendChild(h),this.appendWidget(s),this.updateOutput(0)}sortStops(){this.stops.sort((t,e)=>t.position-e.position)}renderStops(){this.stopsContainer.innerHTML="",this.stops.forEach((t,e)=>{const i=o("div",{className:"cp-setting-row"}),s=o("input",{type:"color",className:"cp-input-color",value:t.color});s.addEventListener("input",h=>{t.color=h.target.value,this.updateOutput()});const a=o("input",{type:"number",className:"cp-input-number cp-input-small",min:"0",max:"1",step:"0.01",value:String(t.position)});a.addEventListener("change",h=>{let p=parseFloat(h.target.value);isNaN(p)&&(p=0),t.position=Math.max(0,Math.min(1,p)),this.sortStops(),this.renderStops(),this.updateOutput()});const r=D(()=>{this.stops.splice(e,1),this.renderStops(),this.updateOutput()});i.appendChild(s),i.appendChild(a),i.appendChild(r),this.stopsContainer.appendChild(i)})}updateOutput(t=this.manualPosition){if(this.stops.length===0)return;if(this.stops.length===1){this.setValue(this.stops[0].color),this.updateDisplay();return}let e="#000000";if(t=Math.max(0,Math.min(1,t)),t<=this.stops[0].position)e=this.stops[0].color;else if(t>=this.stops[this.stops.length-1].position)e=this.stops[this.stops.length-1].color;else for(let i=0;i<this.stops.length-1;i++){const s=this.stops[i],a=this.stops[i+1];if(t>=s.position&&t<=a.position){const r=a.position-s.position,h=r===0?0:(t-s.position)/r;e=Y(s.color,a.color,h);break}}this.setValue(e),this.updateDisplay()}updateDisplay(){this.displayColor&&(this.displayColor.style.backgroundColor=this.value),this.displayText&&(this.displayText.textContent=this.value)}applySignal(t,e){let i=t;if(e==="forward")i=t;else if(e==="backward")i=1-t;else{const s=t*.05;e==="loopForward"?(this.animationT=(this.animationT+s)%1,i=this.animationT):e==="loopBackward"?(this.animationT=(this.animationT-s+1)%1,i=this.animationT):e==="pingpong"&&(this.animationT+=s*this.pingPongDirection,this.animationT>=1?(this.animationT=1,this.pingPongDirection=-1):this.animationT<=0&&(this.animationT=0,this.pingPongDirection=1),i=this.animationT)}this.updateOutput(i),this.manualPosition=i}save(){return{stops:this.stops,settings:{signal:this.signalHandler.save()}}}load(t){t&&t.stops&&(this.stops=t.stops,this.sortStops(),this.renderStops()),t&&t.settings&&this.signalHandler?.load(t.settings.signal)}reset(){this.stops=this.initialOptions.stops||[{color:"#000000",position:0},{color:"#ffffff",position:1}],this.sortStops(),this.renderStops(),this.signalHandler?.reset(),this.updateOutput(0)}}class J extends m{constructor(t,e,i={}){super(t,e,i),this.items=[],this.initialOptions=i,this.itemType=i.itemType||"string",this.items=this.parseValue(this.value);const s=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"}),h=o("span",{className:"cp-value-display"},[`${this.items.length} items`]);r.appendChild(h),a.appendChild(r),s.appendChild(a);const p=o("div",{className:"cp-number-settings"});this.itemsContainer=o("div",{className:"cp-stops-container"}),this.renderItems(),p.appendChild(this.itemsContainer);const c=o("button",{className:"cp-button cp-input-small",style:"margin-top: 8px; width: 100%;"},["+ Add Item"]);c.addEventListener("click",()=>{this.addItem()}),p.appendChild(c),s.appendChild(p),this.appendWidget(s)}parseValue(t){return!t||t.trim()===""?[]:t.split(",").map(e=>e.trim())}serializeValue(){return this.items.join(",")}getDefaultItemValue(){switch(this.itemType){case"color":return"#ffffff";case"number":return"0";default:return""}}addItem(t){const e=t!==void 0?t:this.getDefaultItemValue();this.items.push(e),this.renderItems(),this.updateValue()}updateValue(){const t=this.serializeValue();this.setValue(t),this.updateSummary()}updateSummary(){const t=this.domElement.querySelector(".cp-value-display");t&&(t.textContent=`${this.items.length} items`)}renderItems(){this.itemsContainer.innerHTML="",this.items.forEach((t,e)=>{const i=o("div",{className:"cp-setting-row"});let s;this.itemType==="color"?s=o("input",{type:"color",className:"cp-input-color",value:t}):this.itemType==="number"?s=o("input",{type:"number",className:"cp-input-number cp-input-small",step:"any",value:t}):s=o("input",{type:"text",className:"cp-input-number cp-input-small",value:t}),s.addEventListener("input",r=>{this.items[e]=r.target.value,this.updateValue()});const a=D(()=>{this.items.splice(e,1),this.renderItems(),this.updateValue()});i.appendChild(s),i.appendChild(a),this.itemsContainer.appendChild(i)})}updateDisplay(){}save(){return[...this.items]}load(t){Array.isArray(t)?this.items=[...t]:typeof t=="string"&&(this.items=this.parseValue(t)),this.renderItems(),this.updateValue()}reset(){const t=this.initialValue||"";this.items=this.parseValue(t),this.renderItems(),this.updateValue()}}class tt{constructor(){this.frames=0,this.pollingInterval=1e3,this.prevTime=performance.now(),this.render=()=>{this.frames++;const t=performance.now();if(t>=this.prevTime+this.pollingInterval){const e=Math.round(this.frames*1e3/(t-this.prevTime));let i="";const s=performance.memory;s&&(i=` / ${Math.round(s.usedJSHeapSize/1048576)}MB`),this.domElement.textContent=`${e} FPS${i}`,this.prevTime=t,this.frames=0}this.rafId=requestAnimationFrame(this.render)},this.domElement=o("span",{className:"cp-stats"}),this.rafId=requestAnimationFrame(this.render)}destroy(){cancelAnimationFrame(this.rafId)}}class G{constructor(){this.controllers=[],this.folders=[]}addNumber(t,e,i={}){const s=new j(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addSelect(t,e,i={}){const s=new z(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addBoolean(t,e,i={}){const s=new q(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addButton(t,e,i={}){const s=new $(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addRadio(t,e,i={}){const s=new H(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addColor(t,e,i={}){const s=new U(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addGradient(t,e,i={}){const s=new W(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addArray(t,e,i={}){const s=new J(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addFolder(t){const e=new et(t);return this.contentElement.appendChild(e.domElement),this.folders.push(e),e}save(){const t={controllers:{},folders:{}};for(const e of this.controllers)typeof e.value!="function"&&(t.controllers[e.key]=e.save());for(const e of this.folders)t.folders[e.title]=e.save();return t}load(t){if(!t){this.reset();return}for(const e of this.controllers)if(typeof e.value!="function")if(t.controllers&&e.key in t.controllers){const i=t.controllers[e.key];i!==void 0&&e.load(i)}else e.reset();for(const e of this.folders){const i=t.folders?t.folders[e.title]:void 0;e.load(i)}}reset(){for(const t of this.controllers)typeof t.value!="function"&&t.reset();for(const t of this.folders)t.reset()}}class et extends G{constructor(t){super(),this.title=t,this.domElement=o("details",{className:"cp-folder",open:!0}),this.summaryElement=o("summary",{className:"cp-summary"},[t]),this.domElement.appendChild(this.summaryElement),this.contentElement=o("div",{className:"cp-content cp-folder-content"}),this.domElement.appendChild(this.contentElement),this.domElement.appendChild(o("hr",{className:"cp-separator"}))}}class st extends G{constructor(t,e={}){super(),this.domElement=o("details",{className:"cp-root",open:!0}),this.summaryElement=o("summary",{className:"cp-summary cp-summary-root"}),this.domElement.appendChild(this.summaryElement);const i=o("span",{},[e.title||"ControlPanel"]);this.summaryElement.appendChild(i),this.stats=new tt,this.summaryElement.appendChild(this.stats.domElement),this.contentElement=o("div",{className:"cp-content"}),this.domElement.appendChild(this.contentElement);const s=this.addFolder("_Signals"),a={audioInput:null,fftSize:2048};s.addRadio(a,"audioInput",{label:"Audio Signal",options:["microphone","browser"]}).onChange(l=>{x.setInput(l)}),s.addSelect(a,"fftSize",{label:"FFT Size",options:[256,512,1024,2048]}).onChange(l=>{x.setFFTSize(l)}),s.addNumber(x,"smoothingTimeConstant",{min:0,max:.99,step:.01,label:"Smoothing"}).onChange(l=>{x.analyser.smoothingTimeConstant=l}),s.addNumber(x,"spectrumBoost",{min:1,max:5,step:.1,label:"Compression"}),t?t.appendChild(this.domElement):document.body.appendChild(this.domElement);const r=e.title||"ControlPanel";this.presetStoragePrefix=`cp-presets-${r}-`;const h=this.addFolder("_User Presets"),p=()=>{const l=["Default"];if(typeof localStorage>"u")return l;for(let u=0;u<localStorage.length;u++){const g=localStorage.key(u);if(g&&g.startsWith(this.presetStoragePrefix)){const S=g.substring(this.presetStoragePrefix.length);S!=="Default"&&!l.includes(S)&&l.push(S)}}return l.sort()},c={selected:"Default",save:()=>{const l=prompt("Preset Name:",c.selected);if(l){if(l==="Default"){alert("Cannot overwrite Default preset");return}const u=this.presetStoragePrefix+l;this.saveToLocalStorage(u);const g=p();f.setOptions(g),c.selected=l,f.setValue(l)}},load:()=>{const l=c.selected,u=this.presetStoragePrefix+l;this.loadFromLocalStorage(u),c.selected=l,f.setValue(l)},delete:()=>{if(c.selected==="Default"){alert("Cannot delete Default preset");return}if(confirm(`Delete preset "${c.selected}"?`)){const l=this.presetStoragePrefix+c.selected;localStorage.removeItem(l);const u=p();f.setOptions(u),c.selected="Default",f.setValue("Default"),this.reset()}},export:()=>{const l=this.save(),u=L=>{const E={controllers:{},folders:{}};for(const[T,V]of Object.entries(L.controllers))T.startsWith("_")||(E.controllers[T]=V);for(const[T,V]of Object.entries(L.folders))T.startsWith("_")||(E.folders[T]=u(V));return E},g=u(l),S={_presetName:c.selected||"CustomPreset",_exportDate:new Date().toISOString(),_instructions:"To add as factory preset: Copy 'controllers' and 'folders' fields into the presets.json file",...g},N=JSON.stringify(S,null,2),C=new Blob([N],{type:"application/json"}),b=URL.createObjectURL(C),y=document.createElement("a");y.href=b;const w=new Date().toISOString().split("T")[0],Z=c.selected.replace(/[^a-z0-9]/gi,"-").toLowerCase();y.download=`${r.toLowerCase()}-preset-${Z}-${w}.json`,document.body.appendChild(y),y.click(),document.body.removeChild(y),URL.revokeObjectURL(b)},import:()=>{const l=document.createElement("input");l.type="file",l.accept=".json",l.onchange=u=>{const g=u.target.files?.[0];if(!g)return;const S=new FileReader;S.onload=N=>{try{const C=N.target?.result,b=JSON.parse(C),y={controllers:b.controllers||{},folders:b.folders||{}};if(!y.controllers||!y.folders){alert("Invalid preset file: missing 'controllers' or 'folders'");return}this.load(y);const w=b._presetName||"ImportedPreset";if(confirm(`Preset loaded! Save as "${w}" to User Presets?`)){const L=this.presetStoragePrefix+w;this.saveToLocalStorage(L);const E=p();f.setOptions(E),c.selected=w,f.setValue(w)}}catch(C){alert(`Failed to import preset: ${C instanceof Error?C.message:"Invalid JSON"}`),console.error("Import error:",C)}},S.readAsText(g)},l.click()}},v=p(),f=h.addSelect(c,"selected",{label:"Preset",options:v});h.addButton("Load",()=>c.load()),h.addButton("Save / New",()=>c.save()),h.addButton("Delete",()=>c.delete()),h.addButton("Export JSON",()=>c.export()),h.addButton("Import JSON",()=>c.import())}saveToLocalStorage(t){const e=this.save();try{localStorage.setItem(t,JSON.stringify(e))}catch(i){console.warn("ControlPanel: Failed to save to localStorage",i)}}loadFromLocalStorage(t){try{const e=localStorage.getItem(t);if(e){const i=JSON.parse(e);this.load(i)}}catch(e){console.warn("ControlPanel: Failed to load from localStorage",e)}}saveDefaultPreset(){const t=this.presetStoragePrefix+"Default";this.save(),this.saveToLocalStorage(t)}destroy(){this.stats.destroy(),this.domElement.remove(),this.controllers=[],this.folders=[]}}d.ArrayController=J,d.AudioSignals=B,d.BooleanController=q,d.ButtonController=$,d.ColorController=U,d.ControlPanel=st,d.Controller=m,d.GradientController=W,d.MidiSignals=F,d.NumberController=j,d.RadioController=H,d.SelectController=z,d.audioSignals=x,d.midiSignals=P,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(d,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(d=typeof globalThis<"u"?globalThis:d||self,o(d.ControlPanel={}))})(this,(function(d){"use strict";function o(n,t={},e=[]){const i=document.createElement(n);for(const[s,a]of Object.entries(t))s==="className"?i.className=String(a):s==="style"&&typeof a=="object"?Object.assign(i.style,a):s==="open"&&typeof a=="boolean"?a?i.setAttribute("open",""):i.removeAttribute("open"):typeof a!="object"&&i.setAttribute(s,String(a));for(const s of e)typeof s=="string"?i.appendChild(document.createTextNode(s)):i.appendChild(s);return i}function O(n){const t=o("button",{className:"cp-button cp-button-delete"},["×"]);return t.addEventListener("click",n),t}function Q(n){return n.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}function F(n,t,e){return Math.min(Math.max(n,t),e)}function X(n,t,e){if(t.length!==e.length)throw new Error("Input and output ranges must have the same length");if(t.length<2)throw new Error("Input and output ranges must have at least two values");let i=0;for(;i<t.length-1&&n>t[i+1];)i++;if(i===t.length-1)return e[e.length-1];if(i===0&&n<t[0])return e[0];const s=t[i],a=t[i+1],r=e[i],h=e[i+1];return(n-s)/(a-s)*(h-r)+r}class B{constructor(){this.source=null,this.stream=null,this.fftSize=2048,this.smoothingTimeConstant=.92,this.spectrumBoost=2,this.levels={bass:0,mids:0,highs:0,volume:0},this.peaks={bass:0,mids:0,highs:0,volume:0},this._isAnalyzing=!1,this.loop=()=>{this._isAnalyzing&&(requestAnimationFrame(this.loop),this.update())};const t=window.AudioContext||window.webkitAudioContext;this.ctx=new t,this.analyser=this.ctx.createAnalyser(),this.analyser.fftSize=this.fftSize,this.analyser.smoothingTimeConstant=this.smoothingTimeConstant,this.dataArray=new Uint8Array(this.analyser.frequencyBinCount),this.waveformArray=new Uint8Array(this.analyser.frequencyBinCount)}setFFTSize(t){this.fftSize=t,this.analyser.fftSize=t,this.dataArray=new Uint8Array(this.analyser.frequencyBinCount),this.waveformArray=new Uint8Array(this.analyser.frequencyBinCount)}async setInput(t){try{let e;t==="browser"?e=navigator.mediaDevices.getDisplayMedia({audio:!0,video:!0}):e=navigator.mediaDevices.getUserMedia({audio:!0});const i=await e;this.ctx.state==="suspended"&&this.ctx.resume(),this.source&&this.source.disconnect(),this.stream&&this.stream.getTracks().forEach(s=>s.stop()),this.stream=i,this.source=this.ctx.createMediaStreamSource(this.stream),this.source.connect(this.analyser),this._isAnalyzing=!0,this.loop()}catch(e){console.error("Error accessing audio input:",e),this._isAnalyzing=!1}}update(){if(this.analyser.getByteFrequencyData(this.dataArray),this.analyser.getByteTimeDomainData(this.waveformArray),this.spectrumBoost!==1){const p=this.dataArray.length;for(let c=0;c<p;c++){const f=1+c/p*(this.spectrumBoost-1);this.dataArray[c]=Math.min(255,this.dataArray[c]*f)}}const t=[2,10],e=[10,150],i=[150,600],s=this.getAverage(t[0],t[1]),a=this.getAverage(e[0],e[1]),r=this.getAverage(i[0],i[1]),h=this.getAverage(0,i[1]);this.processLevel("bass",s),this.processLevel("mids",a),this.processLevel("highs",r),this.processLevel("volume",h)}processLevel(t,e){this.peaks[t]-=5e-4,this.peaks[t]=F(this.peaks[t],.1,1),e>this.peaks[t]&&(this.peaks[t]=e),this.levels[t]=F(X(e,[0,this.peaks[t]],[0,1]),0,1)}getAverage(t,e){let i=0;const s=e-t;if(s<=0)return 0;for(let a=t;a<e;a++)i+=this.dataArray[a];return i/s/255}getSignal(t){return()=>this.levels[t]}}const x=new B;class P{constructor(){this.midiAccess=null,this.values=new Map,this.isListening=!1,this.resolveListen=null,this.listeningCallback=null,this.init()}async init(){if(typeof navigator<"u"&&navigator.requestMIDIAccess)try{this.midiAccess=await navigator.requestMIDIAccess(),this.setupInputs(),this.midiAccess.onstatechange=t=>{t.port.type==="input"&&t.port.state==="connected"&&this.setupInputs()}}catch(t){console.warn("MIDI Access failed",t)}}setupInputs(){if(!this.midiAccess)return;const t=this.midiAccess.inputs.values();for(const e of t)e.onmidimessage=this.handleMessage.bind(this)}handleMessage(t){const e=t.data,[i]=e;if((i&240)>=240)return;const a=this.getIdFromMessage(t),r=this.normalizeValue(e);this.values.set(a,r),this.isListening&&this.resolveListen&&r>0&&(this.resolveListen(a),this.isListening=!1,this.resolveListen=null,this.listeningCallback&&this.listeningCallback())}getIdFromMessage(t){const e=t.data,[i,s]=e,a=i&240,r=t.currentTarget.name||"unknown",h=a===144||a===128?"note":"ctrl",p=r.replace(/[^a-zA-Z0-9]/g,"");return`${s}_${h}_${p}`}normalizeValue(t){const[e,i,s]=t,a=e&240;return a===144?s>0?1:0:a===128?0:a===176?s/127:0}listen(){return this.isListening=!0,new Promise(t=>{this.resolveListen=t})}cancelListen(){this.isListening=!1,this.resolveListen=null}getSignal(t){return()=>this.values.get(t)??0}}const k=new P,M=class M{constructor(t,e,i={}){this.changeFns=new Set,this.object=t,this.property=e,this.key=i.id??e,this.initialValue=this.object[this.property],this.domElement=o("div",{className:"cp-controller"});const s=i.label??Q(e),a=o("label",{className:"cp-label"},[String(s)]);a.setAttribute("title",String(s)),this.domElement.appendChild(a),i.disabled&&this.domElement.setAttribute("data-disabled","true")}get value(){return this.object[this.property]}setValue(t,e=!0){this.object[this.property]=t,e&&this.emitChange(t),this.updateDisplay()}save(){return this.value}load(t){this.setValue(t)}reset(){this.setValue(this.initialValue)}onChange(t){return this.changeFns.add(t),this}emitChange(t){for(const e of this.changeFns)e(t)}appendWidget(t){this.domElement.appendChild(t)}};M.audio=x,M.midi=k;let m=M;const R={linear:n=>n,quadIn:n=>n*n,quadOut:n=>n*(2-n),quadInOut:n=>n<.5?2*n*n:-1+(4-2*n)*n,cubicIn:n=>n*n*n,cubicOut:n=>--n*n*n+1,cubicInOut:n=>n<.5?4*n*n*n:(n-1)*(2*n-2)*(2*n-2)+1,expoIn:n=>n===0?0:Math.pow(2,10*(n-1)),expoOut:n=>n===1?1:-Math.pow(2,-10*n)+1,expoInOut:n=>n===0||n===1?n:(n*=2)<1?.5*Math.pow(2,10*(n-1)):.5*(-Math.pow(2,-10*--n)+2),sineIn:n=>1-Math.cos(n*Math.PI/2),sineOut:n=>Math.sin(n*Math.PI/2),sineInOut:n=>-(Math.cos(Math.PI*n)-1)/2};class j{constructor(t){this.rafId=null,this.currentSignalType=null,this.currentMidiId=null,this.currentEase="linear",this.currentBehaviour="forward",this.loop=()=>{if(this.currentSignalType){let e=0;this.currentSignalType==="midi"?this.currentMidiId&&(e=m.midi.getSignal(this.currentMidiId)()):e=m.audio.getSignal(this.currentSignalType)();const i=R[this.currentEase](e);this.onChange(i,this.currentBehaviour),this.rafId=requestAnimationFrame(this.loop)}},this.onChange=t.onChange,this.setupControllers(t.container)}setupControllers(t){const e=this.createSettingSelect("signal",["none","bass","mids","highs","volume","midi"],r=>this.setSignalType(r));this.signalSelect=e.select,t.appendChild(e.row),this.midiRow=o("div",{className:"cp-setting-row",style:"display: none;"});const i=o("label",{className:"cp-setting-label"},["Midi"]);this.midiBtn=o("button",{className:"cp-button cp-input-small"},["Learn"]),this.midiBtn.addEventListener("click",async()=>{if(this.midiBtn.textContent==="Listening..."){m.midi.cancelListen(),this.setMidiId(null);return}this.midiBtn.textContent="Listening...";const r=await m.midi.listen();this.setMidiId(r)}),this.midiRow.appendChild(i),this.midiRow.appendChild(this.midiBtn),t.appendChild(this.midiRow);const s=this.createSettingSelect("behaviour",["forward","backward","loopForward","loopBackward","pingpong"],r=>this.setBehaviour(r));this.behaviourRow=s.row,this.behaviourSelect=s.select,this.behaviourRow.style.display="none",this.behaviourSelect.value=this.currentBehaviour,t.appendChild(this.behaviourRow);const a=this.createSettingSelect("ease",Object.keys(R),r=>this.setEase(r));this.easeRow=a.row,this.easeSelect=a.select,this.easeRow.style.display="none",this.easeSelect.value=this.currentEase,t.appendChild(this.easeRow)}createSettingSelect(t,e,i){const s=o("div",{className:"cp-setting-row"}),a=o("label",{className:"cp-setting-label"},[t]),r=o("select",{className:"cp-select cp-input-small"});return e.forEach(h=>{const p=o("option",{value:h},[h]);r.appendChild(p)}),r.addEventListener("change",()=>i(r.value)),s.appendChild(a),s.appendChild(r),{row:s,select:r}}setSignalType(t){if(!t||t==="none")this.currentSignalType=null,this.currentMidiId=null,this.midiRow.style.display="none",this.easeRow.style.display="none",this.behaviourRow.style.display="none",this.stop(),this.signalSelect.value!=="none"&&(this.signalSelect.value="none");else{this.currentSignalType=t;const e=t==="midi";this.midiRow.style.display=e?"flex":"none",this.easeRow.style.display="flex",this.behaviourRow.style.display="flex",e||(this.currentMidiId=null,m.audio.ctx.state==="suspended"&&m.audio.setInput("microphone")),this.start(),this.signalSelect.value!==t&&(this.signalSelect.value=t)}}setMidiId(t){this.currentMidiId=t,this.midiBtn.textContent=t??"Learn"}setEase(t){this.currentEase=t,this.easeSelect.value!==t&&(this.easeSelect.value=t)}setBehaviour(t){this.currentBehaviour=t,this.behaviourSelect.value!==t&&(this.behaviourSelect.value=t)}start(){!this.rafId&&this.currentSignalType&&this.loop()}stop(){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=null)}save(){return{type:this.currentSignalType,midiId:this.currentMidiId,ease:this.currentEase,behaviour:this.currentBehaviour}}load(t){t&&(this.setSignalType(t.type),this.setMidiId(t.midiId||null),this.setEase(t.ease||"linear"),this.setBehaviour(t.behaviour||"forward"))}reset(){this.setSignalType("none"),this.setEase("linear"),this.setBehaviour("forward"),this.setMidiId(null)}}class z extends m{constructor(t,e,i={}){super(t,e,i),this.pingPongDirection=1,this.min=0,this.max=100,this.initialOptions=i,this.min=i.min??0,this.max=i.max??100;const s=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"});this.input=o("input",{type:"range",className:"cp-input-range",step:i.step??"any"}),i.min!==void 0&&(this.input.min=String(i.min)),i.max!==void 0&&(this.input.max=String(i.max)),this.input.value=String(this.value),this.display=o("span",{className:"cp-value-display"},[String(this.value.toFixed(1))]),this.input.addEventListener("input",()=>{const l=parseFloat(this.input.value);isNaN(l)||(this.setValue(l),this.display.textContent=String(l.toFixed(1)))}),this.input.addEventListener("click",l=>{l.stopPropagation()});const r=o("div",{className:"cp-controller-summary-content"});r.appendChild(this.input),r.appendChild(this.display),a.appendChild(r),s.appendChild(a);const h=o("div",{className:"cp-number-settings"}),p=this.createSetting("min",i.min,l=>this.setMin(l));this.minInput=p.input,h.appendChild(p.row);const c=this.createSetting("max",i.max,l=>this.setMax(l));this.maxInput=c.input,h.appendChild(c.row);const v=this.createSetting("step",i.step,l=>this.setStep(l));this.stepInput=v.input,h.appendChild(v.row);const f=o("hr",{className:"cp-separator"});h.appendChild(f),this.signalHandler=new j({container:h,onChange:(l,u)=>this.applySignal(l,u)}),s.appendChild(h),this.appendWidget(s)}setMin(t){typeof t=="number"&&(t=String(t)),t===""||isNaN(parseFloat(t))?this.input.removeAttribute("min"):(this.input.min=t,this.min=parseFloat(t)),this.minInput&&this.minInput.value!==t&&(this.minInput.value=t)}setMax(t){typeof t=="number"&&(t=String(t)),t===""||isNaN(parseFloat(t))?this.input.removeAttribute("max"):(this.input.max=t,this.max=parseFloat(t)),this.maxInput&&this.maxInput.value!==t&&(this.maxInput.value=t)}setStep(t){t===void 0&&(t=""),typeof t=="number"&&(t=String(t)),t===""||t==="any"||isNaN(parseFloat(t))?this.input.step="any":this.input.step=t,this.stepInput&&(t==="any"||t===""?this.stepInput.value="":this.stepInput.value!==t&&(this.stepInput.value=t))}applySignal(t,e){const i=this.max-this.min;let s;if(e==="forward")s=this.min+t*i;else if(e==="backward")s=this.max-t*i;else{const a=t*(i*.01);s=this.value,e==="loopForward"?(s+=a,s>this.max&&(s=this.min+(s-this.min)%i)):e==="loopBackward"?(s-=a,s<this.min&&(s=this.max-(this.max-s)%i)):e==="pingpong"&&(s+=a*this.pingPongDirection,s>=this.max?(s=this.max,this.pingPongDirection=-1):s<=this.min&&(s=this.min,this.pingPongDirection=1))}s=this.roundToStep(s),this.setValue(s),this.input.value=String(s),this.display.textContent=String(s.toFixed(1))}roundToStep(t){const e=this.input.step;if(e==="any"||e===""||isNaN(parseFloat(e)))return t;const i=parseFloat(e),s=this.min;return s+Math.round((t-s)/i)*i}createSetting(t,e,i){const s=o("div",{className:"cp-setting-row"}),a=o("label",{className:"cp-setting-label"},[t]),r=o("input",{type:"number",className:"cp-input-number cp-input-small",step:"any"});return e!==void 0&&(r.value=String(e)),r.addEventListener("input",()=>i(r.value)),s.appendChild(a),s.appendChild(r),{row:s,input:r}}updateDisplay(){this.input.value=String(this.value),this.display.textContent=String(this.value.toFixed(1))}save(){return{value:this.value,settings:{min:this.min,max:this.max,step:this.input.step,signal:this.signalHandler.save()}}}load(t){if(typeof t=="number")this.setValue(t),this.resetSettings();else if(typeof t=="object"&&t!==null&&"value"in t){const e=t.settings||{};e.min!==void 0?this.setMin(e.min):this.setMin(this.initialOptions.min!==void 0?this.initialOptions.min:""),e.max!==void 0?this.setMax(e.max):this.setMax(this.initialOptions.max!==void 0?this.initialOptions.max:""),e.step!==void 0?this.setStep(e.step):this.setStep(this.initialOptions.step);let i=t.value;!isNaN(this.min)&&i<this.min&&(i=this.min),!isNaN(this.max)&&i>this.max&&(i=this.max),this.setValue(i),this.signalHandler?.load(e.signal)}}reset(){this.setValue(this.initialValue),this.resetSettings()}resetSettings(){this.setMin(this.initialOptions.min!==void 0?this.initialOptions.min:""),this.setMax(this.initialOptions.max!==void 0?this.initialOptions.max:""),this.setStep(this.initialOptions.step),this.signalHandler?.reset()}}class $ extends m{constructor(t,e,i){super(t,e,i),this.optionValues=[],this.select=o("select",{className:"cp-select"}),this.optionValues=i.options||[],this.optionValues.forEach((s,a)=>{const r=o("option",{value:String(a)},[String(s)]);this.select.appendChild(r)}),this.updateDisplay(),this.select.addEventListener("change",()=>{const s=parseInt(this.select.value),a=this.optionValues[s];this.setValue(a)}),this.appendWidget(this.select)}setOptions(t){this.select.innerHTML="",this.optionValues=t,this.optionValues.forEach((e,i)=>{const s=o("option",{value:String(i)},[String(e)]);this.select.appendChild(s)}),this.updateDisplay(),this.select.value===""&&this.optionValues.length>0&&this.setValue(this.optionValues[0])}updateDisplay(){const t=this.optionValues.indexOf(this.value);t!==-1&&(this.select.value=String(t))}}class q extends m{constructor(t,e,i={}){const s={action:e};super(s,"action",i);const a=i.label??t;this.button=o("button",{className:"cp-button"},[String(a)]),this.button.addEventListener("click",()=>{const r=this.value;typeof r=="function"&&r(),this.emitChange(r)}),this.appendWidget(this.button)}updateDisplay(){}}class H extends m{constructor(t,e,i={}){super(t,e,i),this.input=o("input",{type:"checkbox",className:"cp-checkbox"}),this.input.checked=this.value,this.input.addEventListener("change",()=>{this.setValue(this.input.checked)}),this.appendWidget(this.input)}updateDisplay(){this.input.checked=this.value}}class U extends m{constructor(t,e,i){super(t,e,i),this.buttons=[],this.optionValues=[],this.container=o("div",{className:"cp-radios"}),this.optionValues=i.options||[],this.optionValues.forEach(s=>{const a=o("button",{className:"cp-button cp-radio"},[String(s)]);a.addEventListener("click",()=>{this.setValue(s)}),this.container.appendChild(a),this.buttons.push(a)}),this.updateDisplay(),this.appendWidget(this.container)}updateDisplay(){const t=this.value;this.buttons.forEach((e,i)=>{this.optionValues[i]===t?e.setAttribute("data-active","true"):e.removeAttribute("data-active")})}}class _ extends m{constructor(t,e,i={}){super(t,e,i),this.input=o("input",{type:"color",className:"cp-input-color",value:this.value||"#000000"}),this.appendWidget(this.input),this.input.addEventListener("input",s=>{const a=s.target;this.setValue(a.value)}),this.updateDisplay()}updateDisplay(){this.input.value=this.value}}function W(n){const t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;n=n.replace(t,(i,s,a,r)=>s+s+a+a+r+r);const e=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(n);return e?[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]:[0,0,0]}function Y(n,t,e){return"#"+((1<<24)+(Math.round(n)<<16)+(Math.round(t)<<8)+Math.round(e)).toString(16).slice(1)}function I(n){const t=n/255;return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function A(n){return n<=.0031308?n*12.92*255:(1.055*Math.pow(n,1/2.4)-.055)*255}function tt(n,t,e){const[i,s,a]=W(n),[r,h,p]=W(t),c=I(i),v=I(s),f=I(a),l=I(r),u=I(h),g=I(p),S=c+e*(l-c),N=v+e*(u-v),C=f+e*(g-f),b=A(S),y=A(N),w=A(C);return Y(b,y,w)}class J extends m{constructor(t,e,i={}){super(t,e,i),this.stops=[],this.pingPongDirection=1,this.animationT=0,this.manualPosition=0,this.initialOptions=i,this.stops=i.stops||[{color:"#000000",position:0},{color:"#ffffff",position:1}],this.sortStops();const s=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"});this.displayColor=o("div",{className:"cp-color-swatch",style:`background-color: ${this.value}`}),this.displayText=o("span",{className:"cp-value-display"},[String(this.value)]),r.appendChild(this.displayColor),r.appendChild(this.displayText),a.appendChild(r),s.appendChild(a);const h=o("div",{className:"cp-number-settings"});this.stopsContainer=o("div",{className:"cp-stops-container"}),this.renderStops(),h.appendChild(this.stopsContainer);const p=o("button",{className:"cp-button"},["+ Add Stop"]);p.addEventListener("click",()=>{this.stops.push({color:"#ffffff",position:.5}),this.sortStops(),this.renderStops(),this.updateOutput()}),h.appendChild(p);const c=o("hr",{className:"cp-separator"});h.appendChild(c),this.signalHandler=new j({container:h,onChange:(v,f)=>this.applySignal(v,f)}),s.appendChild(h),this.appendWidget(s),this.updateOutput(0)}sortStops(){this.stops.sort((t,e)=>t.position-e.position)}renderStops(){this.stopsContainer.innerHTML="",this.stops.forEach((t,e)=>{const i=o("div",{className:"cp-setting-row"}),s=o("input",{type:"color",className:"cp-input-color",value:t.color});s.addEventListener("input",h=>{t.color=h.target.value,this.updateOutput()});const a=o("input",{type:"number",className:"cp-input-number cp-input-small",min:"0",max:"1",step:"0.01",value:String(t.position)});a.addEventListener("change",h=>{let p=parseFloat(h.target.value);isNaN(p)&&(p=0),t.position=Math.max(0,Math.min(1,p)),this.sortStops(),this.renderStops(),this.updateOutput()});const r=O(()=>{this.stops.splice(e,1),this.renderStops(),this.updateOutput()});i.appendChild(s),i.appendChild(a),i.appendChild(r),this.stopsContainer.appendChild(i)})}updateOutput(t=this.manualPosition){if(this.stops.length===0)return;if(this.stops.length===1){this.setValue(this.stops[0].color),this.updateDisplay();return}let e="#000000";if(t=Math.max(0,Math.min(1,t)),t<=this.stops[0].position)e=this.stops[0].color;else if(t>=this.stops[this.stops.length-1].position)e=this.stops[this.stops.length-1].color;else for(let i=0;i<this.stops.length-1;i++){const s=this.stops[i],a=this.stops[i+1];if(t>=s.position&&t<=a.position){const r=a.position-s.position,h=r===0?0:(t-s.position)/r;e=tt(s.color,a.color,h);break}}this.setValue(e),this.updateDisplay()}updateDisplay(){this.displayColor&&(this.displayColor.style.backgroundColor=this.value),this.displayText&&(this.displayText.textContent=this.value)}applySignal(t,e){let i=t;if(e==="forward")i=t;else if(e==="backward")i=1-t;else{const s=t*.05;e==="loopForward"?(this.animationT=(this.animationT+s)%1,i=this.animationT):e==="loopBackward"?(this.animationT=(this.animationT-s+1)%1,i=this.animationT):e==="pingpong"&&(this.animationT+=s*this.pingPongDirection,this.animationT>=1?(this.animationT=1,this.pingPongDirection=-1):this.animationT<=0&&(this.animationT=0,this.pingPongDirection=1),i=this.animationT)}this.updateOutput(i),this.manualPosition=i}save(){return{stops:this.stops,settings:{signal:this.signalHandler.save()}}}load(t){t&&t.stops&&(this.stops=t.stops,this.sortStops(),this.renderStops()),t&&t.settings&&this.signalHandler?.load(t.settings.signal)}reset(){this.stops=this.initialOptions.stops||[{color:"#000000",position:0},{color:"#ffffff",position:1}],this.sortStops(),this.renderStops(),this.signalHandler?.reset(),this.updateOutput(0)}}class G extends m{constructor(t,e,i={}){super(t,e,i),this.items=[],this.initialOptions=i,this.itemType=i.itemType||"string",this.items=this.parseValue(this.value);const s=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"}),h=o("span",{className:"cp-value-display"},[`${this.items.length} items`]);r.appendChild(h),a.appendChild(r),s.appendChild(a);const p=o("div",{className:"cp-number-settings"});this.itemsContainer=o("div",{className:"cp-stops-container"}),this.renderItems(),p.appendChild(this.itemsContainer);const c=o("button",{className:"cp-button cp-input-small",style:"margin-top: 8px; width: 100%;"},["+ Add Item"]);c.addEventListener("click",()=>{this.addItem()}),p.appendChild(c),s.appendChild(p),this.appendWidget(s)}parseValue(t){return!t||t.trim()===""?[]:t.split(",").map(e=>e.trim())}serializeValue(){return this.items.join(",")}getDefaultItemValue(){switch(this.itemType){case"color":return"#ffffff";case"number":return"0";default:return""}}addItem(t){const e=t!==void 0?t:this.getDefaultItemValue();this.items.push(e),this.renderItems(),this.updateValue()}updateValue(){const t=this.serializeValue();this.setValue(t),this.updateSummary()}updateSummary(){const t=this.domElement.querySelector(".cp-value-display");t&&(t.textContent=`${this.items.length} items`)}renderItems(){this.itemsContainer.innerHTML="",this.items.forEach((t,e)=>{const i=o("div",{className:"cp-setting-row"});let s;this.itemType==="color"?s=o("input",{type:"color",className:"cp-input-color",value:t}):this.itemType==="number"?s=o("input",{type:"number",className:"cp-input-number cp-input-small",step:"any",value:t}):s=o("input",{type:"text",className:"cp-input-number cp-input-small",value:t}),s.addEventListener("input",r=>{this.items[e]=r.target.value,this.updateValue()});const a=O(()=>{this.items.splice(e,1),this.renderItems(),this.updateValue()});i.appendChild(s),i.appendChild(a),this.itemsContainer.appendChild(i)})}updateDisplay(){}save(){return[...this.items]}load(t){Array.isArray(t)?this.items=[...t]:typeof t=="string"&&(this.items=this.parseValue(t)),this.renderItems(),this.updateValue()}reset(){const t=this.initialValue||"";this.items=this.parseValue(t),this.renderItems(),this.updateValue()}}class et{constructor(){this.frames=0,this.pollingInterval=1e3,this.prevTime=performance.now(),this.render=()=>{this.frames++;const t=performance.now();if(t>=this.prevTime+this.pollingInterval){const e=Math.round(this.frames*1e3/(t-this.prevTime));let i="";const s=performance.memory;s&&(i=` / ${Math.round(s.usedJSHeapSize/1048576)}MB`),this.domElement.textContent=`${e} FPS${i}`,this.prevTime=t,this.frames=0}this.rafId=requestAnimationFrame(this.render)},this.domElement=o("span",{className:"cp-stats"}),this.rafId=requestAnimationFrame(this.render)}destroy(){cancelAnimationFrame(this.rafId)}}class V{constructor(){this.controllers=[],this.folders=[]}addNumber(t,e,i={}){const s=new z(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addSelect(t,e,i={}){const s=new $(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addBoolean(t,e,i={}){const s=new H(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addButton(t,e,i={}){const s=new q(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addRadio(t,e,i={}){const s=new U(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addColor(t,e,i={}){const s=new _(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addGradient(t,e,i={}){const s=new J(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addArray(t,e,i={}){const s=new G(t,e,i);return this.contentElement.appendChild(s.domElement),this.controllers.push(s),s}addFolder(t){const e=new Z(t);return this.contentElement.appendChild(e.domElement),this.folders.push(e),e}save(){const t={controllers:{},folders:{}};for(const e of this.controllers)typeof e.value!="function"&&(t.controllers[e.key]=e.save());for(const e of this.folders)t.folders[e.title]=e.save();return t}load(t){if(!t){this.reset();return}for(const e of this.controllers)if(typeof e.value!="function")if(t.controllers&&e.key in t.controllers){const i=t.controllers[e.key];i!==void 0&&e.load(i)}else e.reset();for(const e of this.folders){const i=t.folders?t.folders[e.title]:void 0;e.load(i)}}reset(){for(const t of this.controllers)typeof t.value!="function"&&t.reset();for(const t of this.folders)t.reset()}}class Z extends V{constructor(t){super(),this.title=t,this.domElement=o("details",{className:"cp-folder",open:!0}),this.summaryElement=o("summary",{className:"cp-summary"},[t]),this.domElement.appendChild(this.summaryElement),this.contentElement=o("div",{className:"cp-content cp-folder-content"}),this.domElement.appendChild(this.contentElement),this.domElement.appendChild(o("hr",{className:"cp-separator"}))}}class st extends V{constructor(t,e={}){super(),this.domElement=o("details",{className:"cp-root",open:!0}),this.summaryElement=o("summary",{className:"cp-summary cp-summary-root"}),this.domElement.appendChild(this.summaryElement);const i=o("span",{},[e.title||"ControlPanel"]);this.summaryElement.appendChild(i),this.stats=new et,this.summaryElement.appendChild(this.stats.domElement),this.contentElement=o("div",{className:"cp-content"}),this.domElement.appendChild(this.contentElement);const s=this.addFolder("_Signals"),a={audioInput:null,fftSize:2048};s.addRadio(a,"audioInput",{label:"Audio Signal",options:["microphone","browser"]}).onChange(l=>{x.setInput(l)}),s.addSelect(a,"fftSize",{label:"FFT Size",options:[256,512,1024,2048]}).onChange(l=>{x.setFFTSize(l)}),s.addNumber(x,"smoothingTimeConstant",{min:0,max:.99,step:.01,label:"Smoothing"}).onChange(l=>{x.analyser.smoothingTimeConstant=l}),s.addNumber(x,"spectrumBoost",{min:1,max:5,step:.1,label:"Compression"}),t?t.appendChild(this.domElement):document.body.appendChild(this.domElement);const r=e.title||"ControlPanel";this.presetStoragePrefix=`cp-presets-${r}-`;const h=this.addFolder("_User Presets"),p=()=>{const l=["Default"];if(typeof localStorage>"u")return l;for(let u=0;u<localStorage.length;u++){const g=localStorage.key(u);if(g&&g.startsWith(this.presetStoragePrefix)){const S=g.substring(this.presetStoragePrefix.length);S!=="Default"&&!l.includes(S)&&l.push(S)}}return l.sort()},c={selected:"Default",save:()=>{const l=prompt("Preset Name:",c.selected);if(l){if(l==="Default"){alert("Cannot overwrite Default preset");return}const u=this.presetStoragePrefix+l;this.saveToLocalStorage(u);const g=p();f.setOptions(g),c.selected=l,f.setValue(l)}},load:()=>{const l=c.selected,u=this.presetStoragePrefix+l;this.loadFromLocalStorage(u),c.selected=l,f.setValue(l)},delete:()=>{if(c.selected==="Default"){alert("Cannot delete Default preset");return}if(confirm(`Delete preset "${c.selected}"?`)){const l=this.presetStoragePrefix+c.selected;localStorage.removeItem(l);const u=p();f.setOptions(u),c.selected="Default",f.setValue("Default"),this.reset()}},export:()=>{const l=this.save(),u=L=>{const E={controllers:{},folders:{}};for(const[T,D]of Object.entries(L.controllers))T.startsWith("_")||(E.controllers[T]=D);for(const[T,D]of Object.entries(L.folders))T.startsWith("_")||(E.folders[T]=u(D));return E},g=u(l),S={_presetName:c.selected||"CustomPreset",_exportDate:new Date().toISOString(),_instructions:"To add as factory preset: Copy 'controllers' and 'folders' fields into the presets.json file",...g},N=JSON.stringify(S,null,2),C=new Blob([N],{type:"application/json"}),b=URL.createObjectURL(C),y=document.createElement("a");y.href=b;const w=new Date().toISOString().split("T")[0],K=c.selected.replace(/[^a-z0-9]/gi,"-").toLowerCase();y.download=`${r.toLowerCase()}-preset-${K}-${w}.json`,document.body.appendChild(y),y.click(),document.body.removeChild(y),URL.revokeObjectURL(b)},import:()=>{const l=document.createElement("input");l.type="file",l.accept=".json",l.onchange=u=>{const g=u.target.files?.[0];if(!g)return;const S=new FileReader;S.onload=N=>{try{const C=N.target?.result,b=JSON.parse(C),y={controllers:b.controllers||{},folders:b.folders||{}};if(!y.controllers||!y.folders){alert("Invalid preset file: missing 'controllers' or 'folders'");return}this.load(y);const w=b._presetName||"ImportedPreset";if(confirm(`Preset loaded! Save as "${w}" to User Presets?`)){const L=this.presetStoragePrefix+w;this.saveToLocalStorage(L);const E=p();f.setOptions(E),c.selected=w,f.setValue(w)}}catch(C){alert(`Failed to import preset: ${C instanceof Error?C.message:"Invalid JSON"}`),console.error("Import error:",C)}},S.readAsText(g)},l.click()}},v=p(),f=h.addSelect(c,"selected",{label:"Preset",options:v});h.addButton("Load",()=>c.load()),h.addButton("Save / New",()=>c.save()),h.addButton("Delete",()=>c.delete()),h.addButton("Export JSON",()=>c.export()),h.addButton("Import JSON",()=>c.import())}saveToLocalStorage(t){const e=this.save();try{localStorage.setItem(t,JSON.stringify(e))}catch(i){console.warn("ControlPanel: Failed to save to localStorage",i)}}loadFromLocalStorage(t){try{const e=localStorage.getItem(t);if(e){const i=JSON.parse(e);this.load(i)}}catch(e){console.warn("ControlPanel: Failed to load from localStorage",e)}}saveDefaultPreset(){const t=this.presetStoragePrefix+"Default";this.save(),this.saveToLocalStorage(t)}destroy(){this.stats.destroy(),this.domElement.remove(),this.controllers=[],this.folders=[]}}d.ArrayController=G,d.AudioSignals=B,d.BooleanController=H,d.ButtonController=q,d.ColorController=_,d.ControlPanel=st,d.ControlPanelContainer=V,d.Controller=m,d.Folder=Z,d.GradientController=J,d.MidiSignals=P,d.NumberController=z,d.RadioController=U,d.SelectController=$,d.audioSignals=x,d.midiSignals=k,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
@@ -0,0 +1,35 @@
1
+ export type AudioInputType = "microphone" | "browser";
2
+ export declare class AudioSignals {
3
+ ctx: AudioContext;
4
+ analyser: AnalyserNode;
5
+ source: MediaStreamAudioSourceNode | null;
6
+ stream: MediaStream | null;
7
+ fftSize: number;
8
+ dataArray: Uint8Array<ArrayBuffer>;
9
+ waveformArray: Uint8Array<ArrayBuffer>;
10
+ smoothingTimeConstant: number;
11
+ spectrumBoost: number;
12
+ levels: {
13
+ bass: number;
14
+ mids: number;
15
+ highs: number;
16
+ volume: number;
17
+ };
18
+ peaks: {
19
+ bass: number;
20
+ mids: number;
21
+ highs: number;
22
+ volume: number;
23
+ };
24
+ private _isAnalyzing;
25
+ constructor();
26
+ setFFTSize(size: 256 | 512 | 1024 | 2048): void;
27
+ setInput(type: AudioInputType): Promise<void>;
28
+ loop: () => void;
29
+ update(): void;
30
+ private processLevel;
31
+ private getAverage;
32
+ getSignal(type: "bass" | "mids" | "highs" | "volume"): () => number;
33
+ }
34
+ export declare const audioSignals: AudioSignals;
35
+ //# sourceMappingURL=AudioSignals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioSignals.d.ts","sourceRoot":"","sources":["../../src/signals/AudioSignals.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,SAAS,CAAC;AAEtD,qBAAa,YAAY;IACvB,GAAG,EAAE,YAAY,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,0BAA0B,GAAG,IAAI,CAAQ;IACjD,MAAM,EAAE,WAAW,GAAG,IAAI,CAAQ;IAElC,OAAO,SAAQ;IACf,SAAS,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;IACnC,aAAa,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;IAGvC,qBAAqB,SAAQ;IAC7B,aAAa,SAAO;IAGpB,MAAM;;;;;MAKJ;IAEF,KAAK;;;;;MAKH;IAEF,OAAO,CAAC,YAAY,CAAS;;IAa7B,UAAU,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI;IAQlC,QAAQ,CAAC,IAAI,EAAE,cAAc;IA0CnC,IAAI,aAIF;IAEF,MAAM;IAoCN,OAAO,CAAC,YAAY;IAoBpB,OAAO,CAAC,UAAU;IAYlB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ;CAGrD;AAED,eAAO,MAAM,YAAY,cAAqB,CAAC"}
@@ -0,0 +1,18 @@
1
+ export declare class MidiSignals {
2
+ midiAccess: any;
3
+ values: Map<string, number>;
4
+ isListening: boolean;
5
+ resolveListen: ((id: string) => void) | null;
6
+ listeningCallback: (() => void) | null;
7
+ constructor();
8
+ init(): Promise<void>;
9
+ setupInputs(): void;
10
+ handleMessage(message: any): void;
11
+ getIdFromMessage(message: any): string;
12
+ normalizeValue(data: Uint8Array): number;
13
+ listen(): Promise<string>;
14
+ cancelListen(): void;
15
+ getSignal(id: string): () => number;
16
+ }
17
+ export declare const midiSignals: MidiSignals;
18
+ //# sourceMappingURL=MidiSignals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MidiSignals.d.ts","sourceRoot":"","sources":["../../src/signals/MidiSignals.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW;IACtB,UAAU,EAAE,GAAG,CAAQ;IACvB,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAa;IACxC,WAAW,UAAS;IACpB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,CAAQ;IACpD,iBAAiB,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAQ;;IAMxC,IAAI;IAoBV,WAAW;IAQX,aAAa,CAAC,OAAO,EAAE,GAAG;IA0B1B,gBAAgB,CAAC,OAAO,EAAE,GAAG;IAa7B,cAAc,CAAC,IAAI,EAAE,UAAU;IAiB/B,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAQzB,YAAY;IAKZ,SAAS,CAAC,EAAE,EAAE,MAAM;CAGrB;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { type Ease } from "../utils/easings";
2
+ export type SignalBehaviour = "forward" | "backward" | "loopForward" | "loopBackward" | "pingpong";
3
+ export interface SignalHandlerOptions {
4
+ container: HTMLElement;
5
+ onChange: (easedValue: number, behaviour: SignalBehaviour) => void;
6
+ }
7
+ export interface SignalHandlerState {
8
+ type: string | null;
9
+ midiId: string | null;
10
+ ease: Ease;
11
+ behaviour: SignalBehaviour;
12
+ }
13
+ export declare class SignalHandler {
14
+ private rafId;
15
+ private currentSignalType;
16
+ private currentMidiId;
17
+ private currentEase;
18
+ private currentBehaviour;
19
+ private signalSelect;
20
+ private midiRow;
21
+ private midiBtn;
22
+ private easeRow;
23
+ private easeSelect;
24
+ private behaviourRow;
25
+ private behaviourSelect;
26
+ private onChange;
27
+ constructor(options: SignalHandlerOptions);
28
+ private setupControllers;
29
+ private createSettingSelect;
30
+ setSignalType(val: string | null): void;
31
+ setMidiId(id: string | null): void;
32
+ setEase(val: Ease): void;
33
+ setBehaviour(val: SignalBehaviour): void;
34
+ private loop;
35
+ start(): void;
36
+ stop(): void;
37
+ save(): SignalHandlerState;
38
+ load(data: SignalHandlerState | null): void;
39
+ reset(): void;
40
+ }
41
+ //# sourceMappingURL=SignalHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignalHandler.d.ts","sourceRoot":"","sources":["../../src/signals/SignalHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAW,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,MAAM,eAAe,GACvB,SAAS,GACT,UAAU,GACV,aAAa,GACb,cAAc,GACd,UAAU,CAAC;AAEf,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;CACpE;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,eAAe,CAAC;CAC5B;AAED,qBAAa,aAAa;IAExB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,iBAAiB,CAMT;IAChB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,gBAAgB,CAA8B;IAGtD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,eAAe,CAAqB;IAG5C,OAAO,CAAC,QAAQ,CAA2D;gBAE/D,OAAO,EAAE,oBAAoB;IAKzC,OAAO,CAAC,gBAAgB;IAgExB,OAAO,CAAC,mBAAmB;IAyB3B,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IA4BhC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK3B,OAAO,CAAC,GAAG,EAAE,IAAI;IAKjB,YAAY,CAAC,GAAG,EAAE,eAAe;IAKjC,OAAO,CAAC,IAAI,CAkBV;IAEF,KAAK;IAML,IAAI;IAOJ,IAAI,IAAI,kBAAkB;IAS1B,IAAI,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IASpC,KAAK;CAMN"}
@@ -0,0 +1,11 @@
1
+ export declare class Stats {
2
+ domElement: HTMLElement;
3
+ frames: number;
4
+ pollingInterval: number;
5
+ prevTime: number;
6
+ rafId: number;
7
+ constructor();
8
+ render: () => void;
9
+ destroy(): void;
10
+ }
11
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"AAEA,qBAAa,KAAK;IAChB,UAAU,EAAE,WAAW,CAAC;IACxB,MAAM,SAAK;IACX,eAAe,SAAQ;IACvB,QAAQ,SAAqB;IAC7B,KAAK,EAAE,MAAM,CAAC;;IAOd,MAAM,aAoBJ;IAEF,OAAO;CAGR"}
@@ -0,0 +1,2 @@
1
+ export declare function lerpColor(a: string, b: string, amount: number): string;
2
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/utils/color.ts"],"names":[],"mappings":"AA2CA,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAuBtE"}
@@ -0,0 +1,3 @@
1
+ export declare function createElement<K extends keyof HTMLElementTagNameMap>(tag: K, attributes?: Record<string, string | number | boolean | object>, children?: (string | HTMLElement)[]): HTMLElementTagNameMap[K];
2
+ export declare function createDeleteButton(onClick: () => void): HTMLButtonElement;
3
+ //# sourceMappingURL=dom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,qBAAqB,EACjE,GAAG,EAAE,CAAC,EACN,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAM,EACnE,QAAQ,GAAE,CAAC,MAAM,GAAG,WAAW,CAAC,EAAO,GACtC,qBAAqB,CAAC,CAAC,CAAC,CA4B1B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,iBAAiB,CAUzE"}
@@ -0,0 +1,3 @@
1
+ export type Ease = "linear" | "quadIn" | "quadOut" | "quadInOut" | "cubicIn" | "cubicOut" | "cubicInOut" | "expoIn" | "expoOut" | "expoInOut" | "sineIn" | "sineOut" | "sineInOut";
2
+ export declare const easings: Record<Ease, (t: number) => number>;
3
+ //# sourceMappingURL=easings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"easings.d.ts","sourceRoot":"","sources":["../../src/utils/easings.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,IAAI,GACZ,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,WAAW,GACX,SAAS,GACT,UAAU,GACV,YAAY,GACZ,QAAQ,GACR,SAAS,GACT,WAAW,GACX,QAAQ,GACR,SAAS,GACT,WAAW,CAAC;AAEhB,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAuBvD,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function clamp(value: number, min: number, max: number): number;
2
+ export declare function map_range(value: number, inputRange: number[], outputRange: number[]): number;
3
+ //# sourceMappingURL=math.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../../src/utils/math.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,UAE5D;AAID,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAAE,EACpB,WAAW,EAAE,MAAM,EAAE,UA8BtB"}
@@ -0,0 +1,2 @@
1
+ export declare function formatStringCamelToSentence(str: string): string;
2
+ //# sourceMappingURL=strings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../../src/utils/strings.ts"],"names":[],"mappings":"AAAA,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalmeadow/control-panel",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "type": "module",
5
5
  "description": "A minimalist, framework-agnostic control panel GUI",
6
6
  "author": "Digital Meadow <inbox@digitalmeadow.studio> (https://digitalmeadow.studio)",
@@ -16,19 +16,19 @@
16
16
  "files": [
17
17
  "dist"
18
18
  ],
19
- "main": "./dist/control-panel.umd.cjs",
20
- "module": "./dist/control-panel.js",
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.js",
21
21
  "types": "./dist/index.d.ts",
22
22
  "exports": {
23
23
  ".": {
24
24
  "types": "./dist/index.d.ts",
25
- "import": "./dist/control-panel.js",
26
- "require": "./dist/control-panel.umd.cjs"
25
+ "import": "./dist/index.js",
26
+ "require": "./dist/index.cjs"
27
27
  }
28
28
  },
29
29
  "scripts": {
30
30
  "dev": "vite",
31
- "build": "vite build",
31
+ "build": "vite build && tsc",
32
32
  "preview": "vite preview"
33
33
  },
34
34
  "devDependencies": {
File without changes