@digitalmeadow/control-panel 1.0.17 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  GUI control panel for creative coding.
4
4
 
5
+ ## Installation
6
+ ```bash
7
+ npm install @digitalmeadow/control-panel
8
+ ```
9
+
5
10
  ## Features
6
11
 
7
12
  - Dependency free
@@ -11,6 +16,7 @@ GUI control panel for creative coding.
11
16
  ## Controllers
12
17
 
13
18
  - Number
19
+ - Range
14
20
  - Select
15
21
  - Boolean
16
22
  - Button
@@ -27,7 +33,7 @@ import { ControlPanel } from "@digitalmeadow/control-panel";
27
33
  const state = { number: 50, color: "#3498db", enabled: true };
28
34
  const controlPanel = new ControlPanel();
29
35
 
30
- controlPanel.addNumber(state, "number", { min: 0, max: 100, step: 1 });
36
+ controlPanel.addRange(state, "number", { min: 0, max: 100, step: 1 });
31
37
  controlPanel.addColor(state, "color");
32
38
  controlPanel.addBoolean(state, "enabled");
33
39
  controlPanel.addButton("Reset", () => controlPanel.reset());
@@ -56,6 +62,7 @@ pnpm build
56
62
 
57
63
  ```typescript
58
64
  controlPanel.addNumber(object, property, options?)
65
+ controlPanel.addRange(object, property, options?)
59
66
  controlPanel.addSelect(object, property, options?)
60
67
  controlPanel.addBoolean(object, property, options?)
61
68
  controlPanel.addButton(label, fn, options?)
@@ -1,4 +1,3 @@
1
- import "./fonts/font.css";
2
1
  import { Controller } from "./controllers/Controller";
3
2
  import { NumberController, type NumberControllerOptions } from "./controllers/NumberController";
4
3
  import { RangeController, type RangeControllerOptions } from "./controllers/RangeController";
@@ -1 +1 @@
1
- {"version":3,"file":"ControlPanel.d.ts","sourceRoot":"","sources":["../src/ControlPanel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ControlPanel.d.ts","sourceRoot":"","sources":["../src/ControlPanel.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,22 @@
1
1
  const W = `
2
+ @font-face {
3
+ font-family: "IosevkaTermNF";
4
+ src: url("./IosevkaTermNF-Regular.woff2") format("woff2");
5
+ font-weight: 400;
6
+ font-style: normal;
7
+ font-display: swap;
8
+ }
9
+
10
+ @font-face {
11
+ font-family: "IosevkaTermNF";
12
+ src: url("./IosevkaTermNFP-SemiBold.woff2") format("woff2");
13
+ font-weight: 600;
14
+ font-style: normal;
15
+ font-display: swap;
16
+ }
17
+
2
18
  .cp-root {
3
- --cp-scale: 2;
19
+ --cp-scale: 1;
4
20
 
5
21
  --cp-space-1: calc(1px * var(--cp-scale));
6
22
  --cp-space-2: calc(2px * var(--cp-scale));
@@ -10,6 +26,7 @@ const W = `
10
26
 
11
27
  --cp-border-width: calc(1px * var(--cp-scale));
12
28
 
29
+ --cp-font-family: "IosevkaTermNF";
13
30
  --cp-font-size-main: calc(10px * var(--cp-scale));
14
31
  --cp-font-size-details: calc(10px * var(--cp-scale));
15
32
 
@@ -48,6 +65,9 @@ const W = `
48
65
  sans-serif;
49
66
  font-size: var(--cp-font-size-main);
50
67
  line-height: 1.1;
68
+
69
+ -webkit-font-smoothing: antialiased
70
+ font-synthesis: none;
51
71
  }
52
72
 
53
73
  /* Apply blend mode to selected children except color inputs */
@@ -198,7 +218,7 @@ const W = `
198
218
 
199
219
  .cp-checkbox:checked {
200
220
  background: transparent;
201
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='var(--cp-swatch-size)' height='var(--cp-swatch-size)' viewBox='0 0 8 8'%3E%3Ccircle cx='4' cy='4' r='2' fill='%23fff'/%3E%3C/svg%3E");
221
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%' viewBox='0 0 8 8'%3E%3Ccircle cx='4' cy='4' r='2' fill='%23fff'/%3E%3C/svg%3E");
202
222
  }
203
223
 
204
224
  .cp-button {
@@ -392,7 +412,7 @@ function _() {
392
412
  const n = document.createElement("style");
393
413
  n.id = "control-panel-styles", n.textContent = W, document.head.appendChild(n), B = !0;
394
414
  }
395
- function o(n, t = {}, e = []) {
415
+ function r(n, t = {}, e = []) {
396
416
  const s = document.createElement(n);
397
417
  for (const [i, a] of Object.entries(t))
398
418
  i === "className" ? s.className = String(a) : i === "style" && typeof a == "object" ? Object.assign(s.style, a) : i === "open" && typeof a == "boolean" ? a ? s.setAttribute("open", "") : s.removeAttribute("open") : typeof a != "object" && s.setAttribute(i, String(a));
@@ -401,7 +421,7 @@ function o(n, t = {}, e = []) {
401
421
  return s;
402
422
  }
403
423
  function j(n) {
404
- const t = o(
424
+ const t = r(
405
425
  "button",
406
426
  {
407
427
  className: "cp-button cp-button-delete"
@@ -428,8 +448,8 @@ function Y(n, t, e) {
428
448
  return e[e.length - 1];
429
449
  if (s === 0 && n < t[0])
430
450
  return e[0];
431
- const i = t[s], a = t[s + 1], r = e[s], l = e[s + 1];
432
- return (n - i) / (a - i) * (l - r) + r;
451
+ const i = t[s], a = t[s + 1], o = e[s], l = e[s + 1];
452
+ return (n - i) / (a - i) * (l - o) + o;
433
453
  }
434
454
  class X {
435
455
  constructor() {
@@ -475,8 +495,8 @@ class X {
475
495
  this.dataArray[h] = Math.min(255, this.dataArray[h] * y);
476
496
  }
477
497
  }
478
- const t = [2, 10], e = [10, 150], s = [150, 600], i = this.getAverage(t[0], t[1]), a = this.getAverage(e[0], e[1]), r = this.getAverage(s[0], s[1]), l = this.getAverage(0, s[1]);
479
- this.processLevel("bass", i), this.processLevel("mids", a), this.processLevel("highs", r), this.processLevel("volume", l);
498
+ const t = [2, 10], e = [10, 150], s = [150, 600], i = this.getAverage(t[0], t[1]), a = this.getAverage(e[0], e[1]), o = this.getAverage(s[0], s[1]), l = this.getAverage(0, s[1]);
499
+ this.processLevel("bass", i), this.processLevel("mids", a), this.processLevel("highs", o), this.processLevel("volume", l);
480
500
  }
481
501
  processLevel(t, e) {
482
502
  this.peaks[t] -= 5e-4, this.peaks[t] = q(this.peaks[t], 0.1, 1), e > this.peaks[t] && (this.peaks[t] = e), this.levels[t] = q(
@@ -521,11 +541,11 @@ class G {
521
541
  handleMessage(t) {
522
542
  const e = t.data, [s] = e;
523
543
  if ((s & 240) >= 240) return;
524
- const a = this.getIdFromMessage(t), r = this.normalizeValue(e);
525
- this.values.set(a, r), this.isListening && this.resolveListen && r > 0 && (this.resolveListen(a), this.isListening = !1, this.resolveListen = null, this.listeningCallback && this.listeningCallback());
544
+ const a = this.getIdFromMessage(t), o = this.normalizeValue(e);
545
+ this.values.set(a, o), this.isListening && this.resolveListen && o > 0 && (this.resolveListen(a), this.isListening = !1, this.resolveListen = null, this.listeningCallback && this.listeningCallback());
526
546
  }
527
547
  getIdFromMessage(t) {
528
- const e = t.data, [s, i] = e, a = s & 240, r = t.currentTarget.name || "unknown", l = a === 144 || a === 128 ? "note" : "ctrl", p = r.replace(/[^a-zA-Z0-9]/g, "");
548
+ const e = t.data, [s, i] = e, a = s & 240, o = t.currentTarget.name || "unknown", l = a === 144 || a === 128 ? "note" : "ctrl", p = o.replace(/[^a-zA-Z0-9]/g, "");
529
549
  return `${i}_${l}_${p}`;
530
550
  }
531
551
  normalizeValue(t) {
@@ -600,20 +620,20 @@ class K {
600
620
  return this.normalizeOutput(i, e);
601
621
  }
602
622
  sine(t) {
603
- const e = t ? { ...this.configs.get("sine"), ...t } : this.configs.get("sine"), s = this.getTime(), i = e.phase * Math.PI * 2, r = (Math.sin(s * e.frequency * Math.PI * 2 + i) + 1) / 2;
604
- return this.normalizeOutput(r, e);
623
+ const e = t ? { ...this.configs.get("sine"), ...t } : this.configs.get("sine"), s = this.getTime(), i = e.phase * Math.PI * 2, o = (Math.sin(s * e.frequency * Math.PI * 2 + i) + 1) / 2;
624
+ return this.normalizeOutput(o, e);
605
625
  }
606
626
  sawtooth(t) {
607
627
  const e = t ? { ...this.configs.get("sawtooth"), ...t } : this.configs.get("sawtooth"), s = this.getTime(), i = e.phase, a = (s * e.frequency + i) % 1 + i % 1;
608
628
  return this.normalizeOutput(a % 1, e);
609
629
  }
610
630
  triangle(t) {
611
- const e = t ? { ...this.configs.get("triangle"), ...t } : this.configs.get("triangle"), s = this.getTime(), i = e.phase, a = (s * e.frequency + i) % 1, r = a < 0.5 ? a * 2 : 2 - a * 2;
612
- return this.normalizeOutput(r, e);
631
+ const e = t ? { ...this.configs.get("triangle"), ...t } : this.configs.get("triangle"), s = this.getTime(), i = e.phase, a = (s * e.frequency + i) % 1, o = a < 0.5 ? a * 2 : 2 - a * 2;
632
+ return this.normalizeOutput(o, e);
613
633
  }
614
634
  square(t) {
615
- const e = t ? { ...this.configs.get("square"), ...t } : this.configs.get("square"), s = this.getTime(), i = e.phase, r = (s * e.frequency + i) % 1 < 0.5 ? 0 : 1;
616
- return this.normalizeOutput(r, e);
635
+ const e = t ? { ...this.configs.get("square"), ...t } : this.configs.get("square"), s = this.getTime(), i = e.phase, o = (s * e.frequency + i) % 1 < 0.5 ? 0 : 1;
636
+ return this.normalizeOutput(o, e);
617
637
  }
618
638
  random(t) {
619
639
  const e = t ? { ...this.configs.get("random"), ...t } : this.configs.get("random"), s = performance.now(), i = 1e3 / e.frequency;
@@ -641,8 +661,8 @@ class K {
641
661
  }
642
662
  const Q = new K(), A = class A {
643
663
  constructor(t, e, s = {}) {
644
- this.changeFns = /* @__PURE__ */ new Set(), this.object = t, this.property = e, this.key = s.id ?? e, this.initialValue = this.object[this.property], this.domElement = o("div", { className: "cp-controller" });
645
- const i = s.label ?? J(e), a = o("label", { className: "cp-label" }, [
664
+ this.changeFns = /* @__PURE__ */ new Set(), this.object = t, this.property = e, this.key = s.id ?? e, this.initialValue = this.object[this.property], this.domElement = r("div", { className: "cp-controller" });
665
+ const i = s.label ?? J(e), a = r("label", { className: "cp-label" }, [
646
666
  String(i)
647
667
  ]);
648
668
  a.setAttribute("title", String(i)), this.domElement.appendChild(a), s.disabled && this.domElement.setAttribute("data-disabled", "true");
@@ -677,7 +697,7 @@ A.audio = k, A.midi = Z, A.math = Q;
677
697
  let u = A;
678
698
  class tt extends u {
679
699
  constructor(t, e, s = {}) {
680
- super(t, e, s), this.input = o("input", {
700
+ super(t, e, s), this.input = r("input", {
681
701
  type: "number",
682
702
  className: "cp-input-number",
683
703
  value: String(this.value)
@@ -749,16 +769,16 @@ class H {
749
769
  ],
750
770
  (l) => this.setSignalType(l)
751
771
  );
752
- this.signalSelect = e.select, t.appendChild(e.row), this.midiRow = o("div", {
772
+ this.signalSelect = e.select, t.appendChild(e.row), this.midiRow = r("div", {
753
773
  className: "cp-setting-row",
754
774
  style: "display: none;"
755
775
  });
756
- const s = o(
776
+ const s = r(
757
777
  "label",
758
778
  { className: "cp-setting-label" },
759
779
  ["Midi"]
760
780
  );
761
- this.midiBtn = o(
781
+ this.midiBtn = r(
762
782
  "button",
763
783
  { className: "cp-button cp-input-small" },
764
784
  ["Learn"]
@@ -770,7 +790,7 @@ class H {
770
790
  this.midiBtn.textContent = "Listening...";
771
791
  const l = await u.midi.listen();
772
792
  this.setMidiId(l);
773
- }), this.midiRow.appendChild(s), this.midiRow.appendChild(this.midiBtn), t.appendChild(this.midiRow), this.mathParamsContainer = o("div", {
793
+ }), this.midiRow.appendChild(s), this.midiRow.appendChild(this.midiBtn), t.appendChild(this.midiRow), this.mathParamsContainer = r("div", {
774
794
  className: "cp-number-settings"
775
795
  }), t.appendChild(this.mathParamsContainer);
776
796
  const i = this.createSettingSelect(
@@ -785,24 +805,24 @@ class H {
785
805
  (l) => this.setEase(l)
786
806
  );
787
807
  this.easeRow = a.row, this.easeSelect = a.select, this.easeRow.style.display = "none", this.easeSelect.value = this.currentEase, t.appendChild(this.easeRow);
788
- const r = o("hr", { className: "cp-separator" });
789
- t.appendChild(r);
808
+ const o = r("hr", { className: "cp-separator" });
809
+ t.appendChild(o);
790
810
  }
791
811
  createSettingSelect(t, e, s) {
792
- const i = o("div", { className: "cp-setting-row" }), a = o("label", { className: "cp-setting-label" }, [
812
+ const i = r("div", { className: "cp-setting-row" }), a = r("label", { className: "cp-setting-label" }, [
793
813
  t
794
- ]), r = o("select", {
814
+ ]), o = r("select", {
795
815
  className: "cp-select cp-input-small"
796
816
  });
797
817
  return e.forEach((l) => {
798
- const p = o("option", { value: l }, [l]);
799
- r.appendChild(p);
800
- }), r.addEventListener("change", () => s(r.value)), i.appendChild(a), i.appendChild(r), { row: i, select: r };
818
+ const p = r("option", { value: l }, [l]);
819
+ o.appendChild(p);
820
+ }), o.addEventListener("change", () => s(o.value)), i.appendChild(a), i.appendChild(o), { row: i, select: o };
801
821
  }
802
- createNumberInput(t, e, s, i, a, r) {
803
- const l = o("div", { className: "cp-setting-row" }), p = o("label", { className: "cp-setting-label" }, [
822
+ createNumberInput(t, e, s, i, a, o) {
823
+ const l = r("div", { className: "cp-setting-row" }), p = r("label", { className: "cp-setting-label" }, [
804
824
  t
805
- ]), h = o("input", {
825
+ ]), h = r("input", {
806
826
  className: "cp-input-number cp-input-small",
807
827
  type: "number",
808
828
  value: String(e),
@@ -812,20 +832,20 @@ class H {
812
832
  });
813
833
  return h.addEventListener("input", () => {
814
834
  const d = parseFloat(h.value);
815
- isNaN(d) || r(d);
835
+ isNaN(d) || o(d);
816
836
  }), l.appendChild(p), l.appendChild(h), { row: l, input: h };
817
837
  }
818
838
  updateMathParams(t) {
819
839
  this.mathParamsContainer.innerHTML = "";
820
840
  const e = u.math.getConfig(t);
821
- let s = "Frequency", i = 0.1, a = 10, r = 0.1;
822
- t === "random" ? a = 30 : t === "constant" && (s = "Speed", i = 0.01, a = 2, r = 0.01);
841
+ let s = "Frequency", i = 0.1, a = 10, o = 0.1;
842
+ t === "random" ? a = 30 : t === "constant" && (s = "Speed", i = 0.01, a = 2, o = 0.01);
823
843
  const l = this.createNumberInput(
824
844
  s,
825
845
  e.frequency,
826
846
  i,
827
847
  a,
828
- r,
848
+ o,
829
849
  (d) => u.math.setConfig(t, { frequency: d })
830
850
  );
831
851
  this.mathParamsContainer.appendChild(l.row);
@@ -907,53 +927,53 @@ class H {
907
927
  class et extends u {
908
928
  constructor(t, e, s = {}) {
909
929
  super(t, e, s), this.pingPongDirection = 1, this.min = 0, this.max = 100, this.initialOptions = s, this.min = s.min ?? 0, this.max = s.max ?? 100;
910
- const i = o("details", {
930
+ const i = r("details", {
911
931
  className: "cp-controller-details"
912
- }), a = o("summary", {
932
+ }), a = r("summary", {
913
933
  className: "cp-controller-summary"
914
934
  });
915
- this.input = o("input", {
935
+ this.input = r("input", {
916
936
  type: "range",
917
937
  className: "cp-input-range",
918
938
  step: s.step ?? "any"
919
- }), s.min !== void 0 && (this.input.min = String(s.min)), s.max !== void 0 && (this.input.max = String(s.max)), this.input.value = String(this.value), this.display = o(
939
+ }), s.min !== void 0 && (this.input.min = String(s.min)), s.max !== void 0 && (this.input.max = String(s.max)), this.input.value = String(this.value), this.display = r(
920
940
  "span",
921
941
  {
922
942
  className: "cp-value-display"
923
943
  },
924
944
  [String(this.value.toFixed(1))]
925
945
  ), this.input.addEventListener("input", () => {
926
- const f = parseFloat(this.input.value);
927
- isNaN(f) || (this.setValue(f), this.display.textContent = String(f.toFixed(1)));
928
- }), this.input.addEventListener("click", (f) => {
929
- f.stopPropagation();
946
+ const g = parseFloat(this.input.value);
947
+ isNaN(g) || (this.setValue(g), this.display.textContent = String(g.toFixed(1)));
948
+ }), this.input.addEventListener("click", (g) => {
949
+ g.stopPropagation();
930
950
  });
931
- const r = o("div", {
951
+ const o = r("div", {
932
952
  className: "cp-controller-summary-content"
933
953
  });
934
- r.appendChild(this.input), r.appendChild(this.display), a.appendChild(r), i.appendChild(a);
935
- const l = o("div", { className: "cp-number-settings" }), p = this.createSetting(
954
+ o.appendChild(this.input), o.appendChild(this.display), a.appendChild(o), i.appendChild(a);
955
+ const l = r("div", { className: "cp-number-settings" }), p = this.createSetting(
936
956
  "min",
937
957
  s.min,
938
- (f) => this.setMin(f)
958
+ (g) => this.setMin(g)
939
959
  );
940
960
  this.minInput = p.input, l.appendChild(p.row);
941
961
  const h = this.createSetting(
942
962
  "max",
943
963
  s.max,
944
- (f) => this.setMax(f)
964
+ (g) => this.setMax(g)
945
965
  );
946
966
  this.maxInput = h.input, l.appendChild(h.row);
947
967
  const d = this.createSetting(
948
968
  "step",
949
969
  s.step,
950
- (f) => this.setStep(f)
970
+ (g) => this.setStep(g)
951
971
  );
952
972
  this.stepInput = d.input, l.appendChild(d.row);
953
- const y = o("hr", { className: "cp-separator" });
973
+ const y = r("hr", { className: "cp-separator" });
954
974
  l.appendChild(y), this.signalHandler = new H({
955
975
  container: l,
956
- onChange: (f, b) => this.applySignal(f, b)
976
+ onChange: (g, b) => this.applySignal(g, b)
957
977
  }), i.appendChild(l), this.appendWidget(i);
958
978
  }
959
979
  // Setters
@@ -987,14 +1007,14 @@ class et extends u {
987
1007
  return i + Math.round((t - i) / s) * s;
988
1008
  }
989
1009
  createSetting(t, e, s) {
990
- const i = o("div", { className: "cp-setting-row" }), a = o("label", { className: "cp-setting-label" }, [
1010
+ const i = r("div", { className: "cp-setting-row" }), a = r("label", { className: "cp-setting-label" }, [
991
1011
  t
992
- ]), r = o("input", {
1012
+ ]), o = r("input", {
993
1013
  type: "number",
994
1014
  className: "cp-input-number cp-input-small",
995
1015
  step: "any"
996
1016
  });
997
- return e !== void 0 && (r.value = String(e)), r.addEventListener("input", () => s(r.value)), i.appendChild(a), i.appendChild(r), { row: i, input: r };
1017
+ return e !== void 0 && (o.value = String(e)), o.addEventListener("input", () => s(o.value)), i.appendChild(a), i.appendChild(o), { row: i, input: o };
998
1018
  }
999
1019
  updateDisplay() {
1000
1020
  this.input.value = String(this.value), this.display.textContent = String(this.value.toFixed(1));
@@ -1037,11 +1057,11 @@ class et extends u {
1037
1057
  }
1038
1058
  class st extends u {
1039
1059
  constructor(t, e, s) {
1040
- super(t, e, s), this.optionValues = [], this.select = o("select", { className: "cp-select" }), this.optionValues = s.options || [], this.optionValues.forEach((i, a) => {
1041
- const r = o("option", { value: String(a) }, [
1060
+ super(t, e, s), this.optionValues = [], this.select = r("select", { className: "cp-select" }), this.optionValues = s.options || [], this.optionValues.forEach((i, a) => {
1061
+ const o = r("option", { value: String(a) }, [
1042
1062
  String(i)
1043
1063
  ]);
1044
- this.select.appendChild(r);
1064
+ this.select.appendChild(o);
1045
1065
  }), this.updateDisplay(), this.select.addEventListener("change", () => {
1046
1066
  const i = parseInt(this.select.value), a = this.optionValues[i];
1047
1067
  this.setValue(a);
@@ -1049,7 +1069,7 @@ class st extends u {
1049
1069
  }
1050
1070
  setOptions(t) {
1051
1071
  this.select.innerHTML = "", this.optionValues = t, this.optionValues.forEach((e, s) => {
1052
- const i = o("option", { value: String(s) }, [
1072
+ const i = r("option", { value: String(s) }, [
1053
1073
  String(e)
1054
1074
  ]);
1055
1075
  this.select.appendChild(i);
@@ -1065,11 +1085,11 @@ class it extends u {
1065
1085
  const i = { action: e };
1066
1086
  super(i, "action", s), this.domElement.querySelector(".cp-label")?.remove();
1067
1087
  const a = s.label ?? t;
1068
- this.button = o("button", { className: "cp-button" }, [
1088
+ this.button = r("button", { className: "cp-button" }, [
1069
1089
  String(a)
1070
1090
  ]), this.button.addEventListener("click", () => {
1071
- const r = this.value;
1072
- typeof r == "function" && r(), this.emitChange(r);
1091
+ const o = this.value;
1092
+ typeof o == "function" && o(), this.emitChange(o);
1073
1093
  }), this.appendWidget(this.button);
1074
1094
  }
1075
1095
  updateDisplay() {
@@ -1077,7 +1097,7 @@ class it extends u {
1077
1097
  }
1078
1098
  class nt extends u {
1079
1099
  constructor(t, e, s = {}) {
1080
- super(t, e, s), this.input = o("input", {
1100
+ super(t, e, s), this.input = r("input", {
1081
1101
  type: "checkbox",
1082
1102
  className: "cp-checkbox"
1083
1103
  }), this.input.checked = this.value, this.input.addEventListener("change", () => {
@@ -1090,8 +1110,8 @@ class nt extends u {
1090
1110
  }
1091
1111
  class at extends u {
1092
1112
  constructor(t, e, s) {
1093
- super(t, e, s), this.buttons = [], this.optionValues = [], this.container = o("div", { className: "cp-radios" }), this.optionValues = s.options || [], this.optionValues.forEach((i) => {
1094
- const a = o("button", { className: "cp-button cp-radio" }, [
1113
+ super(t, e, s), this.buttons = [], this.optionValues = [], this.container = r("div", { className: "cp-radios" }), this.optionValues = s.options || [], this.optionValues.forEach((i) => {
1114
+ const a = r("button", { className: "cp-button cp-radio" }, [
1095
1115
  String(i)
1096
1116
  ]);
1097
1117
  a.addEventListener("click", () => {
@@ -1106,9 +1126,9 @@ class at extends u {
1106
1126
  });
1107
1127
  }
1108
1128
  }
1109
- class rt extends u {
1129
+ class ot extends u {
1110
1130
  constructor(t, e, s = {}) {
1111
- super(t, e, s), this.input = o("input", {
1131
+ super(t, e, s), this.input = r("input", {
1112
1132
  type: "color",
1113
1133
  className: "cp-input-color",
1114
1134
  value: this.value || "#000000"
@@ -1123,7 +1143,7 @@ class rt extends u {
1123
1143
  }
1124
1144
  function $(n) {
1125
1145
  const t = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
1126
- n = n.replace(t, (s, i, a, r) => i + i + a + a + r + r);
1146
+ n = n.replace(t, (s, i, a, o) => i + i + a + a + o + o);
1127
1147
  const e = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(n);
1128
1148
  return e ? [
1129
1149
  parseInt(e[1], 16),
@@ -1131,7 +1151,7 @@ function $(n) {
1131
1151
  parseInt(e[3], 16)
1132
1152
  ] : [0, 0, 0];
1133
1153
  }
1134
- function ot(n, t, e) {
1154
+ function rt(n, t, e) {
1135
1155
  return "#" + ((1 << 24) + (Math.round(n) << 16) + (Math.round(t) << 8) + Math.round(e)).toString(16).slice(1);
1136
1156
  }
1137
1157
  function T(n) {
@@ -1142,8 +1162,8 @@ function F(n) {
1142
1162
  return n <= 31308e-7 ? n * 12.92 * 255 : (1.055 * Math.pow(n, 1 / 2.4) - 0.055) * 255;
1143
1163
  }
1144
1164
  function lt(n, t, e) {
1145
- const [s, i, a] = $(n), [r, l, p] = $(t), h = T(s), d = T(i), y = T(a), f = T(r), b = T(l), E = T(p), g = h + e * (f - h), V = d + e * (b - d), S = y + e * (E - y), c = F(g), m = F(V), v = F(S);
1146
- return ot(c, m, v);
1165
+ const [s, i, a] = $(n), [o, l, p] = $(t), h = T(s), d = T(i), y = T(a), g = T(o), b = T(l), E = T(p), f = h + e * (g - h), V = d + e * (b - d), S = y + e * (E - y), c = F(f), m = F(V), v = F(S);
1166
+ return rt(c, m, v);
1147
1167
  }
1148
1168
  class ct extends u {
1149
1169
  constructor(t, e, s = {}) {
@@ -1151,23 +1171,23 @@ class ct extends u {
1151
1171
  { color: "#000000", position: 0 },
1152
1172
  { color: "#ffffff", position: 1 }
1153
1173
  ], this.sortStops();
1154
- const i = o("details", {
1174
+ const i = r("details", {
1155
1175
  className: "cp-controller-details"
1156
- }), a = o("summary", {
1176
+ }), a = r("summary", {
1157
1177
  className: "cp-controller-summary"
1158
- }), r = o("div", {
1178
+ }), o = r("div", {
1159
1179
  className: "cp-controller-summary-content"
1160
1180
  });
1161
- this.displayText = o(
1181
+ this.displayText = r(
1162
1182
  "span",
1163
1183
  { className: "cp-value-display" },
1164
1184
  [String(this.value)]
1165
- ), r.appendChild(this.displayText), a.appendChild(r), i.appendChild(a);
1166
- const l = o("div", { className: "cp-number-settings" });
1167
- this.stopsContainer = o("div", {
1185
+ ), o.appendChild(this.displayText), a.appendChild(o), i.appendChild(a);
1186
+ const l = r("div", { className: "cp-number-settings" });
1187
+ this.stopsContainer = r("div", {
1168
1188
  className: "cp-stops-container"
1169
1189
  }), this.renderStops(), l.appendChild(this.stopsContainer);
1170
- const p = o(
1190
+ const p = r(
1171
1191
  "button",
1172
1192
  {
1173
1193
  className: "cp-button"
@@ -1177,7 +1197,7 @@ class ct extends u {
1177
1197
  p.addEventListener("click", () => {
1178
1198
  this.stops.push({ color: "#ffffff", position: 0.5 }), this.sortStops(), this.renderStops(), this.updateOutput();
1179
1199
  }), l.appendChild(p);
1180
- const h = o("hr", { className: "cp-separator" });
1200
+ const h = r("hr", { className: "cp-separator" });
1181
1201
  l.appendChild(h), this.signalHandler = new H({
1182
1202
  container: l,
1183
1203
  onChange: (d, y) => this.applySignal(d, y)
@@ -1188,7 +1208,7 @@ class ct extends u {
1188
1208
  }
1189
1209
  renderStops() {
1190
1210
  this.stopsContainer.innerHTML = "", this.stops.forEach((t, e) => {
1191
- const s = o("div", { className: "cp-gradient-stop-row" }), i = o("input", {
1211
+ const s = r("div", { className: "cp-gradient-stop-row" }), i = r("input", {
1192
1212
  type: "color",
1193
1213
  className: "cp-input-color",
1194
1214
  value: t.color
@@ -1196,7 +1216,7 @@ class ct extends u {
1196
1216
  i.addEventListener("input", (l) => {
1197
1217
  t.color = l.target.value, this.updateOutput();
1198
1218
  });
1199
- const a = o("input", {
1219
+ const a = r("input", {
1200
1220
  type: "number",
1201
1221
  className: "cp-input-number cp-input-small",
1202
1222
  min: "0",
@@ -1208,10 +1228,10 @@ class ct extends u {
1208
1228
  let p = parseFloat(l.target.value);
1209
1229
  isNaN(p) && (p = 0), t.position = Math.max(0, Math.min(1, p)), this.sortStops(), this.renderStops(), this.updateOutput();
1210
1230
  });
1211
- const r = j(() => {
1231
+ const o = j(() => {
1212
1232
  this.stops.splice(e, 1), this.renderStops(), this.updateOutput();
1213
1233
  });
1214
- s.appendChild(i), s.appendChild(a), s.appendChild(r), this.stopsContainer.appendChild(s);
1234
+ s.appendChild(i), s.appendChild(a), s.appendChild(o), this.stopsContainer.appendChild(s);
1215
1235
  });
1216
1236
  }
1217
1237
  // Calculate color at t (0-1) and update value
@@ -1230,7 +1250,7 @@ class ct extends u {
1230
1250
  for (let s = 0; s < this.stops.length - 1; s++) {
1231
1251
  const i = this.stops[s], a = this.stops[s + 1];
1232
1252
  if (t >= i.position && t <= a.position) {
1233
- const r = a.position - i.position, l = r === 0 ? 0 : (t - i.position) / r;
1253
+ const o = a.position - i.position, l = o === 0 ? 0 : (t - i.position) / o;
1234
1254
  e = lt(i.color, a.color, l);
1235
1255
  break;
1236
1256
  }
@@ -1273,21 +1293,21 @@ class ct extends u {
1273
1293
  class pt extends u {
1274
1294
  constructor(t, e, s = {}) {
1275
1295
  super(t, e, s), this.items = [], this.initialOptions = s, this.itemType = s.itemType || "string", this.items = this.parseValue(this.value);
1276
- const i = o("details", {
1296
+ const i = r("details", {
1277
1297
  className: "cp-controller-details"
1278
- }), a = o("summary", {
1298
+ }), a = r("summary", {
1279
1299
  className: "cp-controller-summary"
1280
- }), r = o("div", {
1300
+ }), o = r("div", {
1281
1301
  className: "cp-controller-summary-content"
1282
- }), l = o("span", { className: "cp-value-display" }, [
1302
+ }), l = r("span", { className: "cp-value-display" }, [
1283
1303
  `${this.items.length} items`
1284
1304
  ]);
1285
- r.appendChild(l), a.appendChild(r), i.appendChild(a);
1286
- const p = o("div", { className: "cp-number-settings" });
1287
- this.itemsContainer = o("div", {
1305
+ o.appendChild(l), a.appendChild(o), i.appendChild(a);
1306
+ const p = r("div", { className: "cp-number-settings" });
1307
+ this.itemsContainer = r("div", {
1288
1308
  className: "cp-stops-container"
1289
1309
  }), this.renderItems(), p.appendChild(this.itemsContainer);
1290
- const h = o(
1310
+ const h = r(
1291
1311
  "button",
1292
1312
  {
1293
1313
  className: "cp-button cp-input-small",
@@ -1329,23 +1349,23 @@ class pt extends u {
1329
1349
  }
1330
1350
  renderItems() {
1331
1351
  this.itemsContainer.innerHTML = "", this.items.forEach((t, e) => {
1332
- const s = o("div", { className: "cp-array-row" });
1352
+ const s = r("div", { className: "cp-array-row" });
1333
1353
  let i;
1334
- this.itemType === "color" ? i = o("input", {
1354
+ this.itemType === "color" ? i = r("input", {
1335
1355
  type: "color",
1336
1356
  className: "cp-input-color",
1337
1357
  value: t
1338
- }) : this.itemType === "number" ? i = o("input", {
1358
+ }) : this.itemType === "number" ? i = r("input", {
1339
1359
  type: "number",
1340
1360
  className: "cp-input-number cp-input-small",
1341
1361
  step: "any",
1342
1362
  value: t
1343
- }) : i = o("input", {
1363
+ }) : i = r("input", {
1344
1364
  type: "text",
1345
1365
  className: "cp-input-number cp-input-small",
1346
1366
  value: t
1347
- }), i.addEventListener("input", (r) => {
1348
- this.items[e] = r.target.value, this.updateValue();
1367
+ }), i.addEventListener("input", (o) => {
1368
+ this.items[e] = o.target.value, this.updateValue();
1349
1369
  });
1350
1370
  const a = j(() => {
1351
1371
  this.items.splice(e, 1), this.renderItems(), this.updateValue();
@@ -1378,7 +1398,7 @@ class ht {
1378
1398
  i && (s = ` / ${Math.round(i.usedJSHeapSize / 1048576)}MB`), this.domElement.textContent = `${e} FPS${s}`, this.prevTime = t, this.frames = 0;
1379
1399
  }
1380
1400
  this.rafId = requestAnimationFrame(this.render);
1381
- }, this.domElement = o("span", { className: "cp-stats" }), this.rafId = requestAnimationFrame(this.render);
1401
+ }, this.domElement = r("span", { className: "cp-stats" }), this.rafId = requestAnimationFrame(this.render);
1382
1402
  }
1383
1403
  destroy() {
1384
1404
  cancelAnimationFrame(this.rafId);
@@ -1413,7 +1433,7 @@ class U {
1413
1433
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1414
1434
  }
1415
1435
  addColor(t, e, s = {}) {
1416
- const i = new rt(t, e, s);
1436
+ const i = new ot(t, e, s);
1417
1437
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1418
1438
  }
1419
1439
  addGradient(t, e, s = {}) {
@@ -1429,7 +1449,7 @@ class U {
1429
1449
  return this.addSeparator(), this.contentElement.appendChild(e.domElement), this.folders.push(e), e;
1430
1450
  }
1431
1451
  addSeparator() {
1432
- const t = o("hr", { className: "cp-separator" });
1452
+ const t = r("hr", { className: "cp-separator" });
1433
1453
  this.contentElement.appendChild(t);
1434
1454
  }
1435
1455
  save() {
@@ -1469,47 +1489,47 @@ class U {
1469
1489
  }
1470
1490
  class dt extends U {
1471
1491
  constructor(t) {
1472
- super(), this.title = t, this.domElement = o("details", {
1492
+ super(), this.title = t, this.domElement = r("details", {
1473
1493
  className: "cp-folder",
1474
1494
  open: !0
1475
- }), this.summaryElement = o(
1495
+ }), this.summaryElement = r(
1476
1496
  "summary",
1477
1497
  {
1478
1498
  className: "cp-summary"
1479
1499
  },
1480
1500
  [t]
1481
- ), this.domElement.appendChild(this.summaryElement), this.contentElement = o("div", {
1501
+ ), this.domElement.appendChild(this.summaryElement), this.contentElement = r("div", {
1482
1502
  className: "cp-content cp-folder-content"
1483
1503
  }), this.domElement.appendChild(this.contentElement);
1484
1504
  }
1485
1505
  }
1486
1506
  class ut extends U {
1487
1507
  constructor(t, e = {}) {
1488
- super(), _(), this.domElement = o("details", {
1508
+ super(), _(), this.domElement = r("details", {
1489
1509
  className: "cp-root",
1490
1510
  open: !0
1491
- }), this.summaryElement = o("summary", {
1511
+ }), this.summaryElement = r("summary", {
1492
1512
  className: "cp-summary cp-summary-root"
1493
1513
  }), this.domElement.appendChild(this.summaryElement);
1494
- const s = o("span", {}, [
1514
+ const s = r("span", {}, [
1495
1515
  e.title || "ControlPanel"
1496
1516
  ]);
1497
1517
  this.summaryElement.appendChild(s), this.stats = new ht(), this.summaryElement.appendChild(this.stats.domElement);
1498
- let i = !1, a = 0, r = 0, l = 0, p = 0;
1518
+ let i = !1, a = 0, o = 0, l = 0, p = 0;
1499
1519
  this.summaryElement.addEventListener("mousedown", (c) => {
1500
1520
  if (c.target !== this.summaryElement && c.target !== s) return;
1501
- i = !0, a = c.clientX, r = c.clientY;
1521
+ i = !0, a = c.clientX, o = c.clientY;
1502
1522
  const m = this.domElement.getBoundingClientRect();
1503
1523
  l = m.left, p = m.top, c.preventDefault();
1504
1524
  }), document.addEventListener("mousemove", (c) => {
1505
1525
  if (!i) return;
1506
- const m = c.clientX - a, v = c.clientY - r, w = l + m, M = p + v;
1526
+ const m = c.clientX - a, v = c.clientY - o, w = l + m, M = p + v;
1507
1527
  this.domElement.style.left = `${w}px`, this.domElement.style.top = `${M}px`, this.domElement.style.right = "auto", this.domElement.style.bottom = "auto";
1508
1528
  }), document.addEventListener("mouseup", () => {
1509
1529
  i && (i = !1, this.savePositionAndSize());
1510
1530
  }), new ResizeObserver(() => {
1511
1531
  i || this.savePositionAndSize();
1512
- }).observe(this.domElement), this.restorePositionAndSize(), this.contentElement = o("div", { className: "cp-content" }), this.domElement.appendChild(this.contentElement);
1532
+ }).observe(this.domElement), this.restorePositionAndSize(), this.contentElement = r("div", { className: "cp-content" }), this.domElement.appendChild(this.contentElement);
1513
1533
  const d = this.addFolder("_Signals"), y = {
1514
1534
  audioInput: null,
1515
1535
  fftSize: 2048
@@ -1537,8 +1557,8 @@ class ut extends U {
1537
1557
  step: 0.1,
1538
1558
  label: "Compression"
1539
1559
  }), t ? t.appendChild(this.domElement) : document.body.appendChild(this.domElement);
1540
- const f = e.title || "ControlPanel";
1541
- this.presetStoragePrefix = `cp-presets-${f}-`;
1560
+ const g = e.title || "ControlPanel";
1561
+ this.presetStoragePrefix = `cp-presets-${g}-`;
1542
1562
  const b = this.addFolder("_User Presets"), E = () => {
1543
1563
  const c = ["Default"];
1544
1564
  if (typeof localStorage > "u") return c;
@@ -1550,10 +1570,10 @@ class ut extends U {
1550
1570
  }
1551
1571
  }
1552
1572
  return c.sort();
1553
- }, g = {
1573
+ }, f = {
1554
1574
  selected: "Default",
1555
1575
  save: () => {
1556
- const c = prompt("Preset Name:", g.selected);
1576
+ const c = prompt("Preset Name:", f.selected);
1557
1577
  if (c) {
1558
1578
  if (c === "Default") {
1559
1579
  alert("Cannot overwrite Default preset");
@@ -1562,23 +1582,23 @@ class ut extends U {
1562
1582
  const m = this.presetStoragePrefix + c;
1563
1583
  this.saveToLocalStorage(m);
1564
1584
  const v = E();
1565
- S.setOptions(v), g.selected = c, S.setValue(c);
1585
+ S.setOptions(v), f.selected = c, S.setValue(c);
1566
1586
  }
1567
1587
  },
1568
1588
  load: () => {
1569
- const c = g.selected, m = this.presetStoragePrefix + c;
1570
- this.loadFromLocalStorage(m), g.selected = c, S.setValue(c);
1589
+ const c = f.selected, m = this.presetStoragePrefix + c;
1590
+ this.loadFromLocalStorage(m), f.selected = c, S.setValue(c);
1571
1591
  },
1572
1592
  delete: () => {
1573
- if (g.selected === "Default") {
1593
+ if (f.selected === "Default") {
1574
1594
  alert("Cannot delete Default preset");
1575
1595
  return;
1576
1596
  }
1577
- if (confirm(`Delete preset "${g.selected}"?`)) {
1578
- const c = this.presetStoragePrefix + g.selected;
1597
+ if (confirm(`Delete preset "${f.selected}"?`)) {
1598
+ const c = this.presetStoragePrefix + f.selected;
1579
1599
  localStorage.removeItem(c);
1580
1600
  const m = E();
1581
- S.setOptions(m), g.selected = "Default", S.setValue("Default"), this.reset();
1601
+ S.setOptions(m), f.selected = "Default", S.setValue("Default"), this.reset();
1582
1602
  }
1583
1603
  },
1584
1604
  export: () => {
@@ -1595,14 +1615,14 @@ class ut extends U {
1595
1615
  z.startsWith("_") || (L.folders[z] = m(O));
1596
1616
  return L;
1597
1617
  }, v = m(c), w = {
1598
- _presetName: g.selected || "CustomPreset",
1618
+ _presetName: f.selected || "CustomPreset",
1599
1619
  _exportDate: (/* @__PURE__ */ new Date()).toISOString(),
1600
1620
  _instructions: "To add as factory preset: Copy 'controllers' and 'folders' fields into the presets.json file",
1601
1621
  ...v
1602
1622
  }, M = JSON.stringify(w, null, 2), C = new Blob([M], { type: "application/json" }), I = URL.createObjectURL(C), x = document.createElement("a");
1603
1623
  x.href = I;
1604
- const N = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], D = g.selected.replace(/[^a-z0-9]/gi, "-").toLowerCase();
1605
- x.download = `${f.toLowerCase()}-preset-${D}-${N}.json`, document.body.appendChild(x), x.click(), document.body.removeChild(x), URL.revokeObjectURL(I);
1624
+ const N = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], D = f.selected.replace(/[^a-z0-9]/gi, "-").toLowerCase();
1625
+ x.download = `${g.toLowerCase()}-preset-${D}-${N}.json`, document.body.appendChild(x), x.click(), document.body.removeChild(x), URL.revokeObjectURL(I);
1606
1626
  },
1607
1627
  import: () => {
1608
1628
  const c = document.createElement("input");
@@ -1630,7 +1650,7 @@ class ut extends U {
1630
1650
  const P = this.presetStoragePrefix + N;
1631
1651
  this.saveToLocalStorage(P);
1632
1652
  const L = E();
1633
- S.setOptions(L), g.selected = N, S.setValue(N);
1653
+ S.setOptions(L), f.selected = N, S.setValue(N);
1634
1654
  }
1635
1655
  } catch (C) {
1636
1656
  alert(
@@ -1640,11 +1660,11 @@ class ut extends U {
1640
1660
  }, w.readAsText(v);
1641
1661
  }, c.click();
1642
1662
  }
1643
- }, V = E(), S = b.addSelect(g, "selected", {
1663
+ }, V = E(), S = b.addSelect(f, "selected", {
1644
1664
  label: "Preset",
1645
1665
  options: V
1646
1666
  });
1647
- b.addButton("Load", () => g.load()), b.addButton("Save", () => g.save()), b.addButton("Delete", () => g.delete()), b.addButton("Export", () => g.export()), b.addButton("Import", () => g.import());
1667
+ b.addButton("Load", () => f.load()), b.addButton("Save", () => f.save()), b.addButton("Delete", () => f.delete()), b.addButton("Export", () => f.export()), b.addButton("Import", () => f.import());
1648
1668
  }
1649
1669
  saveToLocalStorage(t) {
1650
1670
  const e = this.save();
@@ -1703,7 +1723,7 @@ export {
1703
1723
  X as AudioSignals,
1704
1724
  nt as BooleanController,
1705
1725
  it as ButtonController,
1706
- rt as ColorController,
1726
+ ot as ColorController,
1707
1727
  ut as ControlPanel,
1708
1728
  U as ControlPanelContainer,
1709
1729
  u as Controller,
@@ -1,6 +1,22 @@
1
1
  (function(h,L){typeof exports=="object"&&typeof module<"u"?L(exports):typeof define=="function"&&define.amd?define(["exports"],L):(h=typeof globalThis<"u"?globalThis:h||self,L(h.ControlPanel={}))})(this,(function(h){"use strict";const L=`
2
+ @font-face {
3
+ font-family: "IosevkaTermNF";
4
+ src: url("./IosevkaTermNF-Regular.woff2") format("woff2");
5
+ font-weight: 400;
6
+ font-style: normal;
7
+ font-display: swap;
8
+ }
9
+
10
+ @font-face {
11
+ font-family: "IosevkaTermNF";
12
+ src: url("./IosevkaTermNFP-SemiBold.woff2") format("woff2");
13
+ font-weight: 600;
14
+ font-style: normal;
15
+ font-display: swap;
16
+ }
17
+
2
18
  .cp-root {
3
- --cp-scale: 2;
19
+ --cp-scale: 1;
4
20
 
5
21
  --cp-space-1: calc(1px * var(--cp-scale));
6
22
  --cp-space-2: calc(2px * var(--cp-scale));
@@ -10,6 +26,7 @@
10
26
 
11
27
  --cp-border-width: calc(1px * var(--cp-scale));
12
28
 
29
+ --cp-font-family: "IosevkaTermNF";
13
30
  --cp-font-size-main: calc(10px * var(--cp-scale));
14
31
  --cp-font-size-details: calc(10px * var(--cp-scale));
15
32
 
@@ -48,6 +65,9 @@
48
65
  sans-serif;
49
66
  font-size: var(--cp-font-size-main);
50
67
  line-height: 1.1;
68
+
69
+ -webkit-font-smoothing: antialiased
70
+ font-synthesis: none;
51
71
  }
52
72
 
53
73
  /* Apply blend mode to selected children except color inputs */
@@ -198,7 +218,7 @@
198
218
 
199
219
  .cp-checkbox:checked {
200
220
  background: transparent;
201
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='var(--cp-swatch-size)' height='var(--cp-swatch-size)' viewBox='0 0 8 8'%3E%3Ccircle cx='4' cy='4' r='2' fill='%23fff'/%3E%3C/svg%3E");
221
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%' height='100%' viewBox='0 0 8 8'%3E%3Ccircle cx='4' cy='4' r='2' fill='%23fff'/%3E%3C/svg%3E");
202
222
  }
203
223
 
204
224
  .cp-button {
@@ -385,4 +405,4 @@
385
405
  flex-direction: column;
386
406
  gap: var(--cp-space-2);
387
407
  }
388
- `;let R=!1;function lt(){if(R)return;const n=document.createElement("style");n.id="control-panel-styles",n.textContent=L,document.head.appendChild(n),R=!0}function o(n,t={},e=[]){const s=document.createElement(n);for(const[i,a]of Object.entries(t))i==="className"?s.className=String(a):i==="style"&&typeof a=="object"?Object.assign(s.style,a):i==="open"&&typeof a=="boolean"?a?s.setAttribute("open",""):s.removeAttribute("open"):typeof a!="object"&&s.setAttribute(i,String(a));for(const i of e)typeof i=="string"?s.appendChild(document.createTextNode(i)):s.appendChild(i);return s}function j(n){const t=o("button",{className:"cp-button cp-button-delete"},["×"]);return t.addEventListener("click",n),t}function ct(n){return n.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}function $(n,t,e){return Math.min(Math.max(n,t),e)}function pt(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 s=0;for(;s<t.length-1&&n>t[s+1];)s++;if(s===t.length-1)return e[e.length-1];if(s===0&&n<t[0])return e[0];const i=t[s],a=t[s+1],r=e[s],l=e[s+1];return(n-i)/(a-i)*(l-r)+r}class H{constructor(){this.source=null,this.stream=null,this.fftSize=2048,this.smoothingTimeConstant=.82,this.spectrumBoost=3,this.levels={volume:0,bass:0,mids:0,highs:0},this.peaks={volume:0,bass:0,mids:0,highs: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 s=await e;this.ctx.state==="suspended"&&this.ctx.resume(),this.source&&this.source.disconnect(),this.stream&&this.stream.getTracks().forEach(i=>i.stop()),this.stream=s,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 u=0;u<p;u++){const b=1+u/p*(this.spectrumBoost-1);this.dataArray[u]=Math.min(255,this.dataArray[u]*b)}}const t=[2,10],e=[10,150],s=[150,600],i=this.getAverage(t[0],t[1]),a=this.getAverage(e[0],e[1]),r=this.getAverage(s[0],s[1]),l=this.getAverage(0,s[1]);this.processLevel("bass",i),this.processLevel("mids",a),this.processLevel("highs",r),this.processLevel("volume",l)}processLevel(t,e){this.peaks[t]-=5e-4,this.peaks[t]=$(this.peaks[t],.1,1),e>this.peaks[t]&&(this.peaks[t]=e),this.levels[t]=$(pt(e,[0,this.peaks[t]],[0,1]),0,1)}getAverage(t,e){let s=0;const i=e-t;if(i<=0)return 0;for(let a=t;a<e;a++)s+=this.dataArray[a];return s/i/255}getSignal(t){return()=>this.levels[t]}}const E=new H;class U{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,[s]=e;if((s&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,[s,i]=e,a=s&240,r=t.currentTarget.name||"unknown",l=a===144||a===128?"note":"ctrl",p=r.replace(/[^a-zA-Z0-9]/g,"");return`${i}_${l}_${p}`}normalizeValue(t){const[e,s,i]=t,a=e&240;return a===144?i>0?1:0:a===128?0:a===176?i/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 W=new U;class _{constructor(){this.configs=new Map,this.lastRandomUpdateTime=0,this.currentRandomValue=0,this.startTime=performance.now(),this.configs.set("constant",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("sine",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("sawtooth",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("triangle",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("square",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("random",{frequency:10,amplitude:1,offset:0,phase:0})}setConfig(t,e){const s=this.configs.get(t);this.configs.set(t,{...s,...e})}getConfig(t){return{...this.configs.get(t)}}getTime(){return(performance.now()-this.startTime)/1e3}normalizeOutput(t,e){const s=t*e.amplitude+e.offset;return Math.max(0,Math.min(1,s))}constant(t){const e=t?{...this.configs.get("constant"),...t}:this.configs.get("constant"),i=this.getTime()*e.frequency%1;return this.normalizeOutput(i,e)}sine(t){const e=t?{...this.configs.get("sine"),...t}:this.configs.get("sine"),s=this.getTime(),i=e.phase*Math.PI*2,r=(Math.sin(s*e.frequency*Math.PI*2+i)+1)/2;return this.normalizeOutput(r,e)}sawtooth(t){const e=t?{...this.configs.get("sawtooth"),...t}:this.configs.get("sawtooth"),s=this.getTime(),i=e.phase,a=(s*e.frequency+i)%1+i%1;return this.normalizeOutput(a%1,e)}triangle(t){const e=t?{...this.configs.get("triangle"),...t}:this.configs.get("triangle"),s=this.getTime(),i=e.phase,a=(s*e.frequency+i)%1,r=a<.5?a*2:2-a*2;return this.normalizeOutput(r,e)}square(t){const e=t?{...this.configs.get("square"),...t}:this.configs.get("square"),s=this.getTime(),i=e.phase,r=(s*e.frequency+i)%1<.5?0:1;return this.normalizeOutput(r,e)}random(t){const e=t?{...this.configs.get("random"),...t}:this.configs.get("random"),s=performance.now(),i=1e3/e.frequency;return s-this.lastRandomUpdateTime>i&&(this.currentRandomValue=Math.random(),this.lastRandomUpdateTime=s),this.normalizeOutput(this.currentRandomValue,e)}getSignal(t){switch(t){case"constant":return()=>this.constant();case"sine":return()=>this.sine();case"sawtooth":return()=>this.sawtooth();case"triangle":return()=>this.triangle();case"square":return()=>this.square();case"random":return()=>this.random()}}reset(){this.startTime=performance.now(),this.lastRandomUpdateTime=0,this.currentRandomValue=0}}const J=new _,z=class z{constructor(t,e,s={}){this.changeFns=new Set,this.object=t,this.property=e,this.key=s.id??e,this.initialValue=this.object[this.property],this.domElement=o("div",{className:"cp-controller"});const i=s.label??ct(e),a=o("label",{className:"cp-label"},[String(i)]);a.setAttribute("title",String(i)),this.domElement.appendChild(a),s.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)}};z.audio=E,z.midi=W,z.math=J;let d=z;class Y extends d{constructor(t,e,s={}){super(t,e,s),this.input=o("input",{type:"number",className:"cp-input-number",value:String(this.value)}),this.input.addEventListener("input",()=>{}),this.input.addEventListener("blur",()=>{const i=parseFloat(this.input.value);isNaN(i)?this.input.value=String(this.value):this.setValue(i)}),this.input.addEventListener("keydown",i=>{i.key==="Enter"&&this.input.blur()}),this.appendWidget(this.input)}updateDisplay(){this.input.value=String(this.value)}}const X={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 G{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=d.midi.getSignal(this.currentMidiId)()):["constant","sine","sawtooth","triangle","square","random"].includes(this.currentSignalType)?e=d.math.getSignal(this.currentSignalType)():["volume","bass","mids","highs"].includes(this.currentSignalType)&&(e=d.audio.getSignal(this.currentSignalType)());const s=X[this.currentEase](e);this.onChange(s,this.currentBehaviour),this.rafId=requestAnimationFrame(this.loop)}},this.onChange=t.onChange,this.setupControllers(t.container)}setupControllers(t){const e=this.createSettingSelect("signal",["none","volume","bass","mids","highs","constant","sine","sawtooth","triangle","square","random","midi"],l=>this.setSignalType(l));this.signalSelect=e.select,t.appendChild(e.row),this.midiRow=o("div",{className:"cp-setting-row",style:"display: none;"});const s=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..."){d.midi.cancelListen(),this.setMidiId(null);return}this.midiBtn.textContent="Listening...";const l=await d.midi.listen();this.setMidiId(l)}),this.midiRow.appendChild(s),this.midiRow.appendChild(this.midiBtn),t.appendChild(this.midiRow),this.mathParamsContainer=o("div",{className:"cp-number-settings"}),t.appendChild(this.mathParamsContainer);const i=this.createSettingSelect("behaviour",["forward","backward","loopForward","loopBackward","pingpong"],l=>this.setBehaviour(l));this.behaviourRow=i.row,this.behaviourSelect=i.select,this.behaviourRow.style.display="none",this.behaviourSelect.value=this.currentBehaviour,t.appendChild(this.behaviourRow);const a=this.createSettingSelect("ease",Object.keys(X),l=>this.setEase(l));this.easeRow=a.row,this.easeSelect=a.select,this.easeRow.style.display="none",this.easeSelect.value=this.currentEase,t.appendChild(this.easeRow);const r=o("hr",{className:"cp-separator"});t.appendChild(r)}createSettingSelect(t,e,s){const i=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(l=>{const p=o("option",{value:l},[l]);r.appendChild(p)}),r.addEventListener("change",()=>s(r.value)),i.appendChild(a),i.appendChild(r),{row:i,select:r}}createNumberInput(t,e,s,i,a,r){const l=o("div",{className:"cp-setting-row"}),p=o("label",{className:"cp-setting-label"},[t]),u=o("input",{className:"cp-input-number cp-input-small",type:"number",value:String(e),min:String(s),max:String(i),step:String(a)});return u.addEventListener("input",()=>{const m=parseFloat(u.value);isNaN(m)||r(m)}),l.appendChild(p),l.appendChild(u),{row:l,input:u}}updateMathParams(t){this.mathParamsContainer.innerHTML="";const e=d.math.getConfig(t);let s="Frequency",i=.1,a=10,r=.1;t==="random"?a=30:t==="constant"&&(s="Speed",i=.01,a=2,r=.01);const l=this.createNumberInput(s,e.frequency,i,a,r,m=>d.math.setConfig(t,{frequency:m}));this.mathParamsContainer.appendChild(l.row);const p=this.createNumberInput("Amplitude",e.amplitude,0,2,.1,m=>d.math.setConfig(t,{amplitude:m}));this.mathParamsContainer.appendChild(p.row);const u=this.createNumberInput("Offset",e.offset,0,1,.1,m=>d.math.setConfig(t,{offset:m}));if(this.mathParamsContainer.appendChild(u.row),["sine","sawtooth","triangle","square"].includes(t)){const m=this.createNumberInput("Phase",e.phase,0,1,.01,b=>d.math.setConfig(t,{phase:b}));this.mathParamsContainer.appendChild(m.row)}}setSignalType(t){if(!t||t==="none")this.currentSignalType=null,this.currentMidiId=null,this.midiRow.style.display="none",this.mathParamsContainer.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",s=["constant","sine","sawtooth","triangle","square","random"].includes(t),i=["volume","bass","mids","highs"].includes(t);this.midiRow.style.display=e?"grid":"none",this.mathParamsContainer.style.display=s?"grid":"none",s&&this.updateMathParams(t),this.easeRow.style.display="grid",this.behaviourRow.style.display="grid",i?(this.currentMidiId=null,d.audio.ctx.state==="suspended"&&d.audio.setInput("microphone")):e||(this.currentMidiId=null),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 d{constructor(t,e,s={}){super(t,e,s),this.pingPongDirection=1,this.min=0,this.max=100,this.initialOptions=s,this.min=s.min??0,this.max=s.max??100;const i=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"});this.input=o("input",{type:"range",className:"cp-input-range",step:s.step??"any"}),s.min!==void 0&&(this.input.min=String(s.min)),s.max!==void 0&&(this.input.max=String(s.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 v=parseFloat(this.input.value);isNaN(v)||(this.setValue(v),this.display.textContent=String(v.toFixed(1)))}),this.input.addEventListener("click",v=>{v.stopPropagation()});const r=o("div",{className:"cp-controller-summary-content"});r.appendChild(this.input),r.appendChild(this.display),a.appendChild(r),i.appendChild(a);const l=o("div",{className:"cp-number-settings"}),p=this.createSetting("min",s.min,v=>this.setMin(v));this.minInput=p.input,l.appendChild(p.row);const u=this.createSetting("max",s.max,v=>this.setMax(v));this.maxInput=u.input,l.appendChild(u.row);const m=this.createSetting("step",s.step,v=>this.setStep(v));this.stepInput=m.input,l.appendChild(m.row);const b=o("hr",{className:"cp-separator"});l.appendChild(b),this.signalHandler=new G({container:l,onChange:(v,w)=>this.applySignal(v,w)}),i.appendChild(l),this.appendWidget(i)}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 s=this.max-this.min;let i;if(e==="forward")i=this.min+t*s;else if(e==="backward")i=this.max-t*s;else{const a=t*(s*.01);i=this.value,e==="loopForward"?(i+=a,i>this.max&&(i=this.min+(i-this.min)%s)):e==="loopBackward"?(i-=a,i<this.min&&(i=this.max-(this.max-i)%s)):e==="pingpong"&&(i+=a*this.pingPongDirection,i>=this.max?(i=this.max,this.pingPongDirection=-1):i<=this.min&&(i=this.min,this.pingPongDirection=1))}i=this.roundToStep(i),this.setValue(i),this.input.value=String(i),this.display.textContent=String(i.toFixed(1))}roundToStep(t){const e=this.input.step;if(e==="any"||e===""||isNaN(parseFloat(e)))return t;const s=parseFloat(e),i=this.min;return i+Math.round((t-i)/s)*s}createSetting(t,e,s){const i=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",()=>s(r.value)),i.appendChild(a),i.appendChild(r),{row:i,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 s=t.value;!isNaN(this.min)&&s<this.min&&(s=this.min),!isNaN(this.max)&&s>this.max&&(s=this.max),this.setValue(s),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 K extends d{constructor(t,e,s){super(t,e,s),this.optionValues=[],this.select=o("select",{className:"cp-select"}),this.optionValues=s.options||[],this.optionValues.forEach((i,a)=>{const r=o("option",{value:String(a)},[String(i)]);this.select.appendChild(r)}),this.updateDisplay(),this.select.addEventListener("change",()=>{const i=parseInt(this.select.value),a=this.optionValues[i];this.setValue(a)}),this.appendWidget(this.select)}setOptions(t){this.select.innerHTML="",this.optionValues=t,this.optionValues.forEach((e,s)=>{const i=o("option",{value:String(s)},[String(e)]);this.select.appendChild(i)}),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 d{constructor(t,e,s={}){const i={action:e};super(i,"action",s),this.domElement.querySelector(".cp-label")?.remove();const a=s.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 tt extends d{constructor(t,e,s={}){super(t,e,s),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 et extends d{constructor(t,e,s){super(t,e,s),this.buttons=[],this.optionValues=[],this.container=o("div",{className:"cp-radios"}),this.optionValues=s.options||[],this.optionValues.forEach(i=>{const a=o("button",{className:"cp-button cp-radio"},[String(i)]);a.addEventListener("click",()=>{this.setValue(i)}),this.container.appendChild(a),this.buttons.push(a)}),this.updateDisplay(),this.appendWidget(this.container)}updateDisplay(){const t=this.value;this.buttons.forEach((e,s)=>{this.optionValues[s]===t?e.setAttribute("data-active","true"):e.removeAttribute("data-active")})}}class st extends d{constructor(t,e,s={}){super(t,e,s),this.input=o("input",{type:"color",className:"cp-input-color",value:this.value||"#000000"}),this.appendWidget(this.input),this.input.addEventListener("input",i=>{const a=i.target;this.setValue(a.value)}),this.updateDisplay()}updateDisplay(){this.input.value=this.value}}function it(n){const t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;n=n.replace(t,(s,i,a,r)=>i+i+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 ht(n,t,e){return"#"+((1<<24)+(Math.round(n)<<16)+(Math.round(t)<<8)+Math.round(e)).toString(16).slice(1)}function N(n){const t=n/255;return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function F(n){return n<=.0031308?n*12.92*255:(1.055*Math.pow(n,1/2.4)-.055)*255}function dt(n,t,e){const[s,i,a]=it(n),[r,l,p]=it(t),u=N(s),m=N(i),b=N(a),v=N(r),w=N(l),T=N(p),f=u+e*(v-u),B=m+e*(w-m),C=b+e*(T-b),c=F(f),g=F(B),y=F(C);return ht(c,g,y)}class nt extends d{constructor(t,e,s={}){super(t,e,s),this.stops=[],this.pingPongDirection=1,this.animationT=0,this.manualPosition=0,this.initialOptions=s,this.stops=s.stops||[{color:"#000000",position:0},{color:"#ffffff",position:1}],this.sortStops();const i=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"});this.displayText=o("span",{className:"cp-value-display"},[String(this.value)]),r.appendChild(this.displayText),a.appendChild(r),i.appendChild(a);const l=o("div",{className:"cp-number-settings"});this.stopsContainer=o("div",{className:"cp-stops-container"}),this.renderStops(),l.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()}),l.appendChild(p);const u=o("hr",{className:"cp-separator"});l.appendChild(u),this.signalHandler=new G({container:l,onChange:(m,b)=>this.applySignal(m,b)}),i.appendChild(l),this.appendWidget(i),this.updateOutput(0)}sortStops(){this.stops.sort((t,e)=>t.position-e.position)}renderStops(){this.stopsContainer.innerHTML="",this.stops.forEach((t,e)=>{const s=o("div",{className:"cp-gradient-stop-row"}),i=o("input",{type:"color",className:"cp-input-color",value:t.color});i.addEventListener("input",l=>{t.color=l.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",l=>{let p=parseFloat(l.target.value);isNaN(p)&&(p=0),t.position=Math.max(0,Math.min(1,p)),this.sortStops(),this.renderStops(),this.updateOutput()});const r=j(()=>{this.stops.splice(e,1),this.renderStops(),this.updateOutput()});s.appendChild(i),s.appendChild(a),s.appendChild(r),this.stopsContainer.appendChild(s)})}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 s=0;s<this.stops.length-1;s++){const i=this.stops[s],a=this.stops[s+1];if(t>=i.position&&t<=a.position){const r=a.position-i.position,l=r===0?0:(t-i.position)/r;e=dt(i.color,a.color,l);break}}this.setValue(e),this.updateDisplay()}updateDisplay(){this.displayText&&(this.displayText.textContent=this.value)}applySignal(t,e){let s=t;if(e==="forward")s=t;else if(e==="backward")s=1-t;else{const i=t*.05;e==="loopForward"?(this.animationT=(this.animationT+i)%1,s=this.animationT):e==="loopBackward"?(this.animationT=(this.animationT-i+1)%1,s=this.animationT):e==="pingpong"&&(this.animationT+=i*this.pingPongDirection,this.animationT>=1?(this.animationT=1,this.pingPongDirection=-1):this.animationT<=0&&(this.animationT=0,this.pingPongDirection=1),s=this.animationT)}this.updateOutput(s),this.manualPosition=s}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 at extends d{constructor(t,e,s={}){super(t,e,s),this.items=[],this.initialOptions=s,this.itemType=s.itemType||"string",this.items=this.parseValue(this.value);const i=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"}),l=o("span",{className:"cp-value-display"},[`${this.items.length} items`]);r.appendChild(l),a.appendChild(r),i.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 u=o("button",{className:"cp-button cp-input-small",style:"margin-top: 8px; width: 100%;"},["+ Add Item"]);u.addEventListener("click",()=>{this.addItem()}),p.appendChild(u),i.appendChild(p),this.appendWidget(i)}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 s=o("div",{className:"cp-array-row"});let i;this.itemType==="color"?i=o("input",{type:"color",className:"cp-input-color",value:t}):this.itemType==="number"?i=o("input",{type:"number",className:"cp-input-number cp-input-small",step:"any",value:t}):i=o("input",{type:"text",className:"cp-input-number cp-input-small",value:t}),i.addEventListener("input",r=>{this.items[e]=r.target.value,this.updateValue()});const a=j(()=>{this.items.splice(e,1),this.renderItems(),this.updateValue()});s.appendChild(i),s.appendChild(a),this.itemsContainer.appendChild(s)})}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 ut{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 s="";const i=performance.memory;i&&(s=` / ${Math.round(i.usedJSHeapSize/1048576)}MB`),this.domElement.textContent=`${e} FPS${s}`,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 D{constructor(){this.controllers=[],this.folders=[]}addNumber(t,e,s={}){const i=new Y(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addRange(t,e,s={}){const i=new Z(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addSelect(t,e,s={}){const i=new K(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addBoolean(t,e,s={}){const i=new tt(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addButton(t,e,s={}){const i=new Q(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addRadio(t,e,s={}){const i=new et(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addColor(t,e,s={}){const i=new st(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addGradient(t,e,s={}){const i=new nt(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addArray(t,e,s={}){const i=new at(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addFolder(t){const e=new ot(t);return this.addSeparator(),this.contentElement.appendChild(e.domElement),this.folders.push(e),e}addSeparator(){const t=o("hr",{className:"cp-separator"});this.contentElement.appendChild(t)}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 s=t.controllers[e.key];s!==void 0&&e.load(s)}else e.reset();for(const e of this.folders){const s=t.folders?t.folders[e.title]:void 0;e.load(s)}}reset(){for(const t of this.controllers)typeof t.value!="function"&&t.reset();for(const t of this.folders)t.reset()}}class ot extends D{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)}}class mt extends D{constructor(t,e={}){super(),lt(),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 s=o("span",{},[e.title||"ControlPanel"]);this.summaryElement.appendChild(s),this.stats=new ut,this.summaryElement.appendChild(this.stats.domElement);let i=!1,a=0,r=0,l=0,p=0;this.summaryElement.addEventListener("mousedown",c=>{if(c.target!==this.summaryElement&&c.target!==s)return;i=!0,a=c.clientX,r=c.clientY;const g=this.domElement.getBoundingClientRect();l=g.left,p=g.top,c.preventDefault()}),document.addEventListener("mousemove",c=>{if(!i)return;const g=c.clientX-a,y=c.clientY-r,S=l+g,A=p+y;this.domElement.style.left=`${S}px`,this.domElement.style.top=`${A}px`,this.domElement.style.right="auto",this.domElement.style.bottom="auto"}),document.addEventListener("mouseup",()=>{i&&(i=!1,this.savePositionAndSize())}),new ResizeObserver(()=>{i||this.savePositionAndSize()}).observe(this.domElement),this.restorePositionAndSize(),this.contentElement=o("div",{className:"cp-content"}),this.domElement.appendChild(this.contentElement);const m=this.addFolder("_Signals"),b={audioInput:null,fftSize:2048};m.addRadio(b,"audioInput",{label:"Audio Signal",options:["microphone","browser"]}).onChange(c=>{E.setInput(c)}),m.addSelect(b,"fftSize",{label:"FFT Size",options:[256,512,1024,2048]}).onChange(c=>{E.setFFTSize(c)}),m.addRange(E,"smoothingTimeConstant",{min:0,max:.99,step:.01,label:"Smoothing"}).onChange(c=>{E.analyser.smoothingTimeConstant=c}),m.addRange(E,"spectrumBoost",{min:1,max:5,step:.1,label:"Compression"}),t?t.appendChild(this.domElement):document.body.appendChild(this.domElement);const v=e.title||"ControlPanel";this.presetStoragePrefix=`cp-presets-${v}-`;const w=this.addFolder("_User Presets"),T=()=>{const c=["Default"];if(typeof localStorage>"u")return c;for(let g=0;g<localStorage.length;g++){const y=localStorage.key(g);if(y&&y.startsWith(this.presetStoragePrefix)){const S=y.substring(this.presetStoragePrefix.length);S!=="Default"&&!c.includes(S)&&c.push(S)}}return c.sort()},f={selected:"Default",save:()=>{const c=prompt("Preset Name:",f.selected);if(c){if(c==="Default"){alert("Cannot overwrite Default preset");return}const g=this.presetStoragePrefix+c;this.saveToLocalStorage(g);const y=T();C.setOptions(y),f.selected=c,C.setValue(c)}},load:()=>{const c=f.selected,g=this.presetStoragePrefix+c;this.loadFromLocalStorage(g),f.selected=c,C.setValue(c)},delete:()=>{if(f.selected==="Default"){alert("Cannot delete Default preset");return}if(confirm(`Delete preset "${f.selected}"?`)){const c=this.presetStoragePrefix+f.selected;localStorage.removeItem(c);const g=T();C.setOptions(g),f.selected="Default",C.setValue("Default"),this.reset()}},export:()=>{const c=this.save(),g=O=>{const P={controllers:{},folders:{}};for(const[V,q]of Object.entries(O.controllers))V.startsWith("_")||(P.controllers[V]=q);for(const[V,q]of Object.entries(O.folders))V.startsWith("_")||(P.folders[V]=g(q));return P},y=g(c),S={_presetName:f.selected||"CustomPreset",_exportDate:new Date().toISOString(),_instructions:"To add as factory preset: Copy 'controllers' and 'folders' fields into the presets.json file",...y},A=JSON.stringify(S,null,2),I=new Blob([A],{type:"application/json"}),M=URL.createObjectURL(I),x=document.createElement("a");x.href=M;const k=new Date().toISOString().split("T")[0],rt=f.selected.replace(/[^a-z0-9]/gi,"-").toLowerCase();x.download=`${v.toLowerCase()}-preset-${rt}-${k}.json`,document.body.appendChild(x),x.click(),document.body.removeChild(x),URL.revokeObjectURL(M)},import:()=>{const c=document.createElement("input");c.type="file",c.accept=".json",c.onchange=g=>{const y=g.target.files?.[0];if(!y)return;const S=new FileReader;S.onload=A=>{try{const I=A.target?.result,M=JSON.parse(I),x={controllers:M.controllers||{},folders:M.folders||{}};if(!x.controllers||!x.folders){alert("Invalid preset file: missing 'controllers' or 'folders'");return}this.load(x);const k=M._presetName||"ImportedPreset";if(confirm(`Preset loaded! Save as "${k}" to User Presets?`)){const O=this.presetStoragePrefix+k;this.saveToLocalStorage(O);const P=T();C.setOptions(P),f.selected=k,C.setValue(k)}}catch(I){alert(`Failed to import preset: ${I instanceof Error?I.message:"Invalid JSON"}`),console.error("Import error:",I)}},S.readAsText(y)},c.click()}},B=T(),C=w.addSelect(f,"selected",{label:"Preset",options:B});w.addButton("Load",()=>f.load()),w.addButton("Save",()=>f.save()),w.addButton("Delete",()=>f.delete()),w.addButton("Export",()=>f.export()),w.addButton("Import",()=>f.import())}saveToLocalStorage(t){const e=this.save();try{localStorage.setItem(t,JSON.stringify(e))}catch(s){console.warn("ControlPanel: Failed to save to localStorage",s)}}loadFromLocalStorage(t){try{const e=localStorage.getItem(t);if(e){const s=JSON.parse(e);this.load(s)}}catch(e){console.warn("ControlPanel: Failed to load from localStorage",e)}}saveDefaultPreset(){const t=this.presetStoragePrefix+"Default";this.save(),this.saveToLocalStorage(t)}savePositionAndSize(){const t=this.domElement.getBoundingClientRect(),e=`cp-position-${this.presetStoragePrefix}`,s={left:t.left,top:t.top,width:this.domElement.offsetWidth,height:this.domElement.offsetHeight};try{sessionStorage.setItem(e,JSON.stringify(s))}catch(i){console.warn("Failed to save panel position/size",i)}}restorePositionAndSize(){const t=`cp-position-${this.presetStoragePrefix}`;try{const e=sessionStorage.getItem(t);if(e){const s=JSON.parse(e);this.domElement.style.left=`${s.left}px`,this.domElement.style.top=`${s.top}px`,this.domElement.style.right="auto",this.domElement.style.bottom="auto",this.domElement.style.width=`${s.width}px`,this.domElement.style.height=`${s.height}px`}}catch(e){console.warn("Failed to restore panel position/size",e)}}destroy(){this.stats.destroy(),this.domElement.remove(),this.controllers=[],this.folders=[]}}h.ArrayController=at,h.AudioSignals=H,h.BooleanController=tt,h.ButtonController=Q,h.ColorController=st,h.ControlPanel=mt,h.ControlPanelContainer=D,h.Controller=d,h.Folder=ot,h.GradientController=nt,h.MathSignals=_,h.MidiSignals=U,h.NumberController=Y,h.RadioController=et,h.RangeController=Z,h.SelectController=K,h.audioSignals=E,h.mathSignals=J,h.midiSignals=W,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
408
+ `;let R=!1;function lt(){if(R)return;const n=document.createElement("style");n.id="control-panel-styles",n.textContent=L,document.head.appendChild(n),R=!0}function o(n,t={},e=[]){const s=document.createElement(n);for(const[i,a]of Object.entries(t))i==="className"?s.className=String(a):i==="style"&&typeof a=="object"?Object.assign(s.style,a):i==="open"&&typeof a=="boolean"?a?s.setAttribute("open",""):s.removeAttribute("open"):typeof a!="object"&&s.setAttribute(i,String(a));for(const i of e)typeof i=="string"?s.appendChild(document.createTextNode(i)):s.appendChild(i);return s}function j(n){const t=o("button",{className:"cp-button cp-button-delete"},["×"]);return t.addEventListener("click",n),t}function ct(n){return n.replace(/([A-Z])/g," $1").replace(/^./,t=>t.toUpperCase()).trim()}function $(n,t,e){return Math.min(Math.max(n,t),e)}function pt(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 s=0;for(;s<t.length-1&&n>t[s+1];)s++;if(s===t.length-1)return e[e.length-1];if(s===0&&n<t[0])return e[0];const i=t[s],a=t[s+1],r=e[s],l=e[s+1];return(n-i)/(a-i)*(l-r)+r}class H{constructor(){this.source=null,this.stream=null,this.fftSize=2048,this.smoothingTimeConstant=.82,this.spectrumBoost=3,this.levels={volume:0,bass:0,mids:0,highs:0},this.peaks={volume:0,bass:0,mids:0,highs: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 s=await e;this.ctx.state==="suspended"&&this.ctx.resume(),this.source&&this.source.disconnect(),this.stream&&this.stream.getTracks().forEach(i=>i.stop()),this.stream=s,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 u=0;u<p;u++){const b=1+u/p*(this.spectrumBoost-1);this.dataArray[u]=Math.min(255,this.dataArray[u]*b)}}const t=[2,10],e=[10,150],s=[150,600],i=this.getAverage(t[0],t[1]),a=this.getAverage(e[0],e[1]),r=this.getAverage(s[0],s[1]),l=this.getAverage(0,s[1]);this.processLevel("bass",i),this.processLevel("mids",a),this.processLevel("highs",r),this.processLevel("volume",l)}processLevel(t,e){this.peaks[t]-=5e-4,this.peaks[t]=$(this.peaks[t],.1,1),e>this.peaks[t]&&(this.peaks[t]=e),this.levels[t]=$(pt(e,[0,this.peaks[t]],[0,1]),0,1)}getAverage(t,e){let s=0;const i=e-t;if(i<=0)return 0;for(let a=t;a<e;a++)s+=this.dataArray[a];return s/i/255}getSignal(t){return()=>this.levels[t]}}const E=new H;class U{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,[s]=e;if((s&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,[s,i]=e,a=s&240,r=t.currentTarget.name||"unknown",l=a===144||a===128?"note":"ctrl",p=r.replace(/[^a-zA-Z0-9]/g,"");return`${i}_${l}_${p}`}normalizeValue(t){const[e,s,i]=t,a=e&240;return a===144?i>0?1:0:a===128?0:a===176?i/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 W=new U;class _{constructor(){this.configs=new Map,this.lastRandomUpdateTime=0,this.currentRandomValue=0,this.startTime=performance.now(),this.configs.set("constant",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("sine",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("sawtooth",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("triangle",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("square",{frequency:.1,amplitude:1,offset:0,phase:0}),this.configs.set("random",{frequency:10,amplitude:1,offset:0,phase:0})}setConfig(t,e){const s=this.configs.get(t);this.configs.set(t,{...s,...e})}getConfig(t){return{...this.configs.get(t)}}getTime(){return(performance.now()-this.startTime)/1e3}normalizeOutput(t,e){const s=t*e.amplitude+e.offset;return Math.max(0,Math.min(1,s))}constant(t){const e=t?{...this.configs.get("constant"),...t}:this.configs.get("constant"),i=this.getTime()*e.frequency%1;return this.normalizeOutput(i,e)}sine(t){const e=t?{...this.configs.get("sine"),...t}:this.configs.get("sine"),s=this.getTime(),i=e.phase*Math.PI*2,r=(Math.sin(s*e.frequency*Math.PI*2+i)+1)/2;return this.normalizeOutput(r,e)}sawtooth(t){const e=t?{...this.configs.get("sawtooth"),...t}:this.configs.get("sawtooth"),s=this.getTime(),i=e.phase,a=(s*e.frequency+i)%1+i%1;return this.normalizeOutput(a%1,e)}triangle(t){const e=t?{...this.configs.get("triangle"),...t}:this.configs.get("triangle"),s=this.getTime(),i=e.phase,a=(s*e.frequency+i)%1,r=a<.5?a*2:2-a*2;return this.normalizeOutput(r,e)}square(t){const e=t?{...this.configs.get("square"),...t}:this.configs.get("square"),s=this.getTime(),i=e.phase,r=(s*e.frequency+i)%1<.5?0:1;return this.normalizeOutput(r,e)}random(t){const e=t?{...this.configs.get("random"),...t}:this.configs.get("random"),s=performance.now(),i=1e3/e.frequency;return s-this.lastRandomUpdateTime>i&&(this.currentRandomValue=Math.random(),this.lastRandomUpdateTime=s),this.normalizeOutput(this.currentRandomValue,e)}getSignal(t){switch(t){case"constant":return()=>this.constant();case"sine":return()=>this.sine();case"sawtooth":return()=>this.sawtooth();case"triangle":return()=>this.triangle();case"square":return()=>this.square();case"random":return()=>this.random()}}reset(){this.startTime=performance.now(),this.lastRandomUpdateTime=0,this.currentRandomValue=0}}const J=new _,z=class z{constructor(t,e,s={}){this.changeFns=new Set,this.object=t,this.property=e,this.key=s.id??e,this.initialValue=this.object[this.property],this.domElement=o("div",{className:"cp-controller"});const i=s.label??ct(e),a=o("label",{className:"cp-label"},[String(i)]);a.setAttribute("title",String(i)),this.domElement.appendChild(a),s.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)}};z.audio=E,z.midi=W,z.math=J;let d=z;class Y extends d{constructor(t,e,s={}){super(t,e,s),this.input=o("input",{type:"number",className:"cp-input-number",value:String(this.value)}),this.input.addEventListener("input",()=>{}),this.input.addEventListener("blur",()=>{const i=parseFloat(this.input.value);isNaN(i)?this.input.value=String(this.value):this.setValue(i)}),this.input.addEventListener("keydown",i=>{i.key==="Enter"&&this.input.blur()}),this.appendWidget(this.input)}updateDisplay(){this.input.value=String(this.value)}}const X={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 G{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=d.midi.getSignal(this.currentMidiId)()):["constant","sine","sawtooth","triangle","square","random"].includes(this.currentSignalType)?e=d.math.getSignal(this.currentSignalType)():["volume","bass","mids","highs"].includes(this.currentSignalType)&&(e=d.audio.getSignal(this.currentSignalType)());const s=X[this.currentEase](e);this.onChange(s,this.currentBehaviour),this.rafId=requestAnimationFrame(this.loop)}},this.onChange=t.onChange,this.setupControllers(t.container)}setupControllers(t){const e=this.createSettingSelect("signal",["none","volume","bass","mids","highs","constant","sine","sawtooth","triangle","square","random","midi"],l=>this.setSignalType(l));this.signalSelect=e.select,t.appendChild(e.row),this.midiRow=o("div",{className:"cp-setting-row",style:"display: none;"});const s=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..."){d.midi.cancelListen(),this.setMidiId(null);return}this.midiBtn.textContent="Listening...";const l=await d.midi.listen();this.setMidiId(l)}),this.midiRow.appendChild(s),this.midiRow.appendChild(this.midiBtn),t.appendChild(this.midiRow),this.mathParamsContainer=o("div",{className:"cp-number-settings"}),t.appendChild(this.mathParamsContainer);const i=this.createSettingSelect("behaviour",["forward","backward","loopForward","loopBackward","pingpong"],l=>this.setBehaviour(l));this.behaviourRow=i.row,this.behaviourSelect=i.select,this.behaviourRow.style.display="none",this.behaviourSelect.value=this.currentBehaviour,t.appendChild(this.behaviourRow);const a=this.createSettingSelect("ease",Object.keys(X),l=>this.setEase(l));this.easeRow=a.row,this.easeSelect=a.select,this.easeRow.style.display="none",this.easeSelect.value=this.currentEase,t.appendChild(this.easeRow);const r=o("hr",{className:"cp-separator"});t.appendChild(r)}createSettingSelect(t,e,s){const i=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(l=>{const p=o("option",{value:l},[l]);r.appendChild(p)}),r.addEventListener("change",()=>s(r.value)),i.appendChild(a),i.appendChild(r),{row:i,select:r}}createNumberInput(t,e,s,i,a,r){const l=o("div",{className:"cp-setting-row"}),p=o("label",{className:"cp-setting-label"},[t]),u=o("input",{className:"cp-input-number cp-input-small",type:"number",value:String(e),min:String(s),max:String(i),step:String(a)});return u.addEventListener("input",()=>{const m=parseFloat(u.value);isNaN(m)||r(m)}),l.appendChild(p),l.appendChild(u),{row:l,input:u}}updateMathParams(t){this.mathParamsContainer.innerHTML="";const e=d.math.getConfig(t);let s="Frequency",i=.1,a=10,r=.1;t==="random"?a=30:t==="constant"&&(s="Speed",i=.01,a=2,r=.01);const l=this.createNumberInput(s,e.frequency,i,a,r,m=>d.math.setConfig(t,{frequency:m}));this.mathParamsContainer.appendChild(l.row);const p=this.createNumberInput("Amplitude",e.amplitude,0,2,.1,m=>d.math.setConfig(t,{amplitude:m}));this.mathParamsContainer.appendChild(p.row);const u=this.createNumberInput("Offset",e.offset,0,1,.1,m=>d.math.setConfig(t,{offset:m}));if(this.mathParamsContainer.appendChild(u.row),["sine","sawtooth","triangle","square"].includes(t)){const m=this.createNumberInput("Phase",e.phase,0,1,.01,b=>d.math.setConfig(t,{phase:b}));this.mathParamsContainer.appendChild(m.row)}}setSignalType(t){if(!t||t==="none")this.currentSignalType=null,this.currentMidiId=null,this.midiRow.style.display="none",this.mathParamsContainer.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",s=["constant","sine","sawtooth","triangle","square","random"].includes(t),i=["volume","bass","mids","highs"].includes(t);this.midiRow.style.display=e?"grid":"none",this.mathParamsContainer.style.display=s?"grid":"none",s&&this.updateMathParams(t),this.easeRow.style.display="grid",this.behaviourRow.style.display="grid",i?(this.currentMidiId=null,d.audio.ctx.state==="suspended"&&d.audio.setInput("microphone")):e||(this.currentMidiId=null),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 d{constructor(t,e,s={}){super(t,e,s),this.pingPongDirection=1,this.min=0,this.max=100,this.initialOptions=s,this.min=s.min??0,this.max=s.max??100;const i=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"});this.input=o("input",{type:"range",className:"cp-input-range",step:s.step??"any"}),s.min!==void 0&&(this.input.min=String(s.min)),s.max!==void 0&&(this.input.max=String(s.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 v=parseFloat(this.input.value);isNaN(v)||(this.setValue(v),this.display.textContent=String(v.toFixed(1)))}),this.input.addEventListener("click",v=>{v.stopPropagation()});const r=o("div",{className:"cp-controller-summary-content"});r.appendChild(this.input),r.appendChild(this.display),a.appendChild(r),i.appendChild(a);const l=o("div",{className:"cp-number-settings"}),p=this.createSetting("min",s.min,v=>this.setMin(v));this.minInput=p.input,l.appendChild(p.row);const u=this.createSetting("max",s.max,v=>this.setMax(v));this.maxInput=u.input,l.appendChild(u.row);const m=this.createSetting("step",s.step,v=>this.setStep(v));this.stepInput=m.input,l.appendChild(m.row);const b=o("hr",{className:"cp-separator"});l.appendChild(b),this.signalHandler=new G({container:l,onChange:(v,w)=>this.applySignal(v,w)}),i.appendChild(l),this.appendWidget(i)}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 s=this.max-this.min;let i;if(e==="forward")i=this.min+t*s;else if(e==="backward")i=this.max-t*s;else{const a=t*(s*.01);i=this.value,e==="loopForward"?(i+=a,i>this.max&&(i=this.min+(i-this.min)%s)):e==="loopBackward"?(i-=a,i<this.min&&(i=this.max-(this.max-i)%s)):e==="pingpong"&&(i+=a*this.pingPongDirection,i>=this.max?(i=this.max,this.pingPongDirection=-1):i<=this.min&&(i=this.min,this.pingPongDirection=1))}i=this.roundToStep(i),this.setValue(i),this.input.value=String(i),this.display.textContent=String(i.toFixed(1))}roundToStep(t){const e=this.input.step;if(e==="any"||e===""||isNaN(parseFloat(e)))return t;const s=parseFloat(e),i=this.min;return i+Math.round((t-i)/s)*s}createSetting(t,e,s){const i=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",()=>s(r.value)),i.appendChild(a),i.appendChild(r),{row:i,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 s=t.value;!isNaN(this.min)&&s<this.min&&(s=this.min),!isNaN(this.max)&&s>this.max&&(s=this.max),this.setValue(s),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 K extends d{constructor(t,e,s){super(t,e,s),this.optionValues=[],this.select=o("select",{className:"cp-select"}),this.optionValues=s.options||[],this.optionValues.forEach((i,a)=>{const r=o("option",{value:String(a)},[String(i)]);this.select.appendChild(r)}),this.updateDisplay(),this.select.addEventListener("change",()=>{const i=parseInt(this.select.value),a=this.optionValues[i];this.setValue(a)}),this.appendWidget(this.select)}setOptions(t){this.select.innerHTML="",this.optionValues=t,this.optionValues.forEach((e,s)=>{const i=o("option",{value:String(s)},[String(e)]);this.select.appendChild(i)}),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 d{constructor(t,e,s={}){const i={action:e};super(i,"action",s),this.domElement.querySelector(".cp-label")?.remove();const a=s.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 tt extends d{constructor(t,e,s={}){super(t,e,s),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 et extends d{constructor(t,e,s){super(t,e,s),this.buttons=[],this.optionValues=[],this.container=o("div",{className:"cp-radios"}),this.optionValues=s.options||[],this.optionValues.forEach(i=>{const a=o("button",{className:"cp-button cp-radio"},[String(i)]);a.addEventListener("click",()=>{this.setValue(i)}),this.container.appendChild(a),this.buttons.push(a)}),this.updateDisplay(),this.appendWidget(this.container)}updateDisplay(){const t=this.value;this.buttons.forEach((e,s)=>{this.optionValues[s]===t?e.setAttribute("data-active","true"):e.removeAttribute("data-active")})}}class st extends d{constructor(t,e,s={}){super(t,e,s),this.input=o("input",{type:"color",className:"cp-input-color",value:this.value||"#000000"}),this.appendWidget(this.input),this.input.addEventListener("input",i=>{const a=i.target;this.setValue(a.value)}),this.updateDisplay()}updateDisplay(){this.input.value=this.value}}function it(n){const t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;n=n.replace(t,(s,i,a,r)=>i+i+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 ht(n,t,e){return"#"+((1<<24)+(Math.round(n)<<16)+(Math.round(t)<<8)+Math.round(e)).toString(16).slice(1)}function N(n){const t=n/255;return t<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function F(n){return n<=.0031308?n*12.92*255:(1.055*Math.pow(n,1/2.4)-.055)*255}function dt(n,t,e){const[s,i,a]=it(n),[r,l,p]=it(t),u=N(s),m=N(i),b=N(a),v=N(r),w=N(l),T=N(p),g=u+e*(v-u),B=m+e*(w-m),C=b+e*(T-b),c=F(g),f=F(B),y=F(C);return ht(c,f,y)}class nt extends d{constructor(t,e,s={}){super(t,e,s),this.stops=[],this.pingPongDirection=1,this.animationT=0,this.manualPosition=0,this.initialOptions=s,this.stops=s.stops||[{color:"#000000",position:0},{color:"#ffffff",position:1}],this.sortStops();const i=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"});this.displayText=o("span",{className:"cp-value-display"},[String(this.value)]),r.appendChild(this.displayText),a.appendChild(r),i.appendChild(a);const l=o("div",{className:"cp-number-settings"});this.stopsContainer=o("div",{className:"cp-stops-container"}),this.renderStops(),l.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()}),l.appendChild(p);const u=o("hr",{className:"cp-separator"});l.appendChild(u),this.signalHandler=new G({container:l,onChange:(m,b)=>this.applySignal(m,b)}),i.appendChild(l),this.appendWidget(i),this.updateOutput(0)}sortStops(){this.stops.sort((t,e)=>t.position-e.position)}renderStops(){this.stopsContainer.innerHTML="",this.stops.forEach((t,e)=>{const s=o("div",{className:"cp-gradient-stop-row"}),i=o("input",{type:"color",className:"cp-input-color",value:t.color});i.addEventListener("input",l=>{t.color=l.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",l=>{let p=parseFloat(l.target.value);isNaN(p)&&(p=0),t.position=Math.max(0,Math.min(1,p)),this.sortStops(),this.renderStops(),this.updateOutput()});const r=j(()=>{this.stops.splice(e,1),this.renderStops(),this.updateOutput()});s.appendChild(i),s.appendChild(a),s.appendChild(r),this.stopsContainer.appendChild(s)})}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 s=0;s<this.stops.length-1;s++){const i=this.stops[s],a=this.stops[s+1];if(t>=i.position&&t<=a.position){const r=a.position-i.position,l=r===0?0:(t-i.position)/r;e=dt(i.color,a.color,l);break}}this.setValue(e),this.updateDisplay()}updateDisplay(){this.displayText&&(this.displayText.textContent=this.value)}applySignal(t,e){let s=t;if(e==="forward")s=t;else if(e==="backward")s=1-t;else{const i=t*.05;e==="loopForward"?(this.animationT=(this.animationT+i)%1,s=this.animationT):e==="loopBackward"?(this.animationT=(this.animationT-i+1)%1,s=this.animationT):e==="pingpong"&&(this.animationT+=i*this.pingPongDirection,this.animationT>=1?(this.animationT=1,this.pingPongDirection=-1):this.animationT<=0&&(this.animationT=0,this.pingPongDirection=1),s=this.animationT)}this.updateOutput(s),this.manualPosition=s}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 at extends d{constructor(t,e,s={}){super(t,e,s),this.items=[],this.initialOptions=s,this.itemType=s.itemType||"string",this.items=this.parseValue(this.value);const i=o("details",{className:"cp-controller-details"}),a=o("summary",{className:"cp-controller-summary"}),r=o("div",{className:"cp-controller-summary-content"}),l=o("span",{className:"cp-value-display"},[`${this.items.length} items`]);r.appendChild(l),a.appendChild(r),i.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 u=o("button",{className:"cp-button cp-input-small",style:"margin-top: 8px; width: 100%;"},["+ Add Item"]);u.addEventListener("click",()=>{this.addItem()}),p.appendChild(u),i.appendChild(p),this.appendWidget(i)}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 s=o("div",{className:"cp-array-row"});let i;this.itemType==="color"?i=o("input",{type:"color",className:"cp-input-color",value:t}):this.itemType==="number"?i=o("input",{type:"number",className:"cp-input-number cp-input-small",step:"any",value:t}):i=o("input",{type:"text",className:"cp-input-number cp-input-small",value:t}),i.addEventListener("input",r=>{this.items[e]=r.target.value,this.updateValue()});const a=j(()=>{this.items.splice(e,1),this.renderItems(),this.updateValue()});s.appendChild(i),s.appendChild(a),this.itemsContainer.appendChild(s)})}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 ut{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 s="";const i=performance.memory;i&&(s=` / ${Math.round(i.usedJSHeapSize/1048576)}MB`),this.domElement.textContent=`${e} FPS${s}`,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 D{constructor(){this.controllers=[],this.folders=[]}addNumber(t,e,s={}){const i=new Y(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addRange(t,e,s={}){const i=new Z(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addSelect(t,e,s={}){const i=new K(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addBoolean(t,e,s={}){const i=new tt(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addButton(t,e,s={}){const i=new Q(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addRadio(t,e,s={}){const i=new et(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addColor(t,e,s={}){const i=new st(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addGradient(t,e,s={}){const i=new nt(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addArray(t,e,s={}){const i=new at(t,e,s);return this.contentElement.appendChild(i.domElement),this.controllers.push(i),i}addFolder(t){const e=new ot(t);return this.addSeparator(),this.contentElement.appendChild(e.domElement),this.folders.push(e),e}addSeparator(){const t=o("hr",{className:"cp-separator"});this.contentElement.appendChild(t)}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 s=t.controllers[e.key];s!==void 0&&e.load(s)}else e.reset();for(const e of this.folders){const s=t.folders?t.folders[e.title]:void 0;e.load(s)}}reset(){for(const t of this.controllers)typeof t.value!="function"&&t.reset();for(const t of this.folders)t.reset()}}class ot extends D{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)}}class mt extends D{constructor(t,e={}){super(),lt(),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 s=o("span",{},[e.title||"ControlPanel"]);this.summaryElement.appendChild(s),this.stats=new ut,this.summaryElement.appendChild(this.stats.domElement);let i=!1,a=0,r=0,l=0,p=0;this.summaryElement.addEventListener("mousedown",c=>{if(c.target!==this.summaryElement&&c.target!==s)return;i=!0,a=c.clientX,r=c.clientY;const f=this.domElement.getBoundingClientRect();l=f.left,p=f.top,c.preventDefault()}),document.addEventListener("mousemove",c=>{if(!i)return;const f=c.clientX-a,y=c.clientY-r,S=l+f,A=p+y;this.domElement.style.left=`${S}px`,this.domElement.style.top=`${A}px`,this.domElement.style.right="auto",this.domElement.style.bottom="auto"}),document.addEventListener("mouseup",()=>{i&&(i=!1,this.savePositionAndSize())}),new ResizeObserver(()=>{i||this.savePositionAndSize()}).observe(this.domElement),this.restorePositionAndSize(),this.contentElement=o("div",{className:"cp-content"}),this.domElement.appendChild(this.contentElement);const m=this.addFolder("_Signals"),b={audioInput:null,fftSize:2048};m.addRadio(b,"audioInput",{label:"Audio Signal",options:["microphone","browser"]}).onChange(c=>{E.setInput(c)}),m.addSelect(b,"fftSize",{label:"FFT Size",options:[256,512,1024,2048]}).onChange(c=>{E.setFFTSize(c)}),m.addRange(E,"smoothingTimeConstant",{min:0,max:.99,step:.01,label:"Smoothing"}).onChange(c=>{E.analyser.smoothingTimeConstant=c}),m.addRange(E,"spectrumBoost",{min:1,max:5,step:.1,label:"Compression"}),t?t.appendChild(this.domElement):document.body.appendChild(this.domElement);const v=e.title||"ControlPanel";this.presetStoragePrefix=`cp-presets-${v}-`;const w=this.addFolder("_User Presets"),T=()=>{const c=["Default"];if(typeof localStorage>"u")return c;for(let f=0;f<localStorage.length;f++){const y=localStorage.key(f);if(y&&y.startsWith(this.presetStoragePrefix)){const S=y.substring(this.presetStoragePrefix.length);S!=="Default"&&!c.includes(S)&&c.push(S)}}return c.sort()},g={selected:"Default",save:()=>{const c=prompt("Preset Name:",g.selected);if(c){if(c==="Default"){alert("Cannot overwrite Default preset");return}const f=this.presetStoragePrefix+c;this.saveToLocalStorage(f);const y=T();C.setOptions(y),g.selected=c,C.setValue(c)}},load:()=>{const c=g.selected,f=this.presetStoragePrefix+c;this.loadFromLocalStorage(f),g.selected=c,C.setValue(c)},delete:()=>{if(g.selected==="Default"){alert("Cannot delete Default preset");return}if(confirm(`Delete preset "${g.selected}"?`)){const c=this.presetStoragePrefix+g.selected;localStorage.removeItem(c);const f=T();C.setOptions(f),g.selected="Default",C.setValue("Default"),this.reset()}},export:()=>{const c=this.save(),f=O=>{const P={controllers:{},folders:{}};for(const[V,q]of Object.entries(O.controllers))V.startsWith("_")||(P.controllers[V]=q);for(const[V,q]of Object.entries(O.folders))V.startsWith("_")||(P.folders[V]=f(q));return P},y=f(c),S={_presetName:g.selected||"CustomPreset",_exportDate:new Date().toISOString(),_instructions:"To add as factory preset: Copy 'controllers' and 'folders' fields into the presets.json file",...y},A=JSON.stringify(S,null,2),I=new Blob([A],{type:"application/json"}),k=URL.createObjectURL(I),x=document.createElement("a");x.href=k;const M=new Date().toISOString().split("T")[0],rt=g.selected.replace(/[^a-z0-9]/gi,"-").toLowerCase();x.download=`${v.toLowerCase()}-preset-${rt}-${M}.json`,document.body.appendChild(x),x.click(),document.body.removeChild(x),URL.revokeObjectURL(k)},import:()=>{const c=document.createElement("input");c.type="file",c.accept=".json",c.onchange=f=>{const y=f.target.files?.[0];if(!y)return;const S=new FileReader;S.onload=A=>{try{const I=A.target?.result,k=JSON.parse(I),x={controllers:k.controllers||{},folders:k.folders||{}};if(!x.controllers||!x.folders){alert("Invalid preset file: missing 'controllers' or 'folders'");return}this.load(x);const M=k._presetName||"ImportedPreset";if(confirm(`Preset loaded! Save as "${M}" to User Presets?`)){const O=this.presetStoragePrefix+M;this.saveToLocalStorage(O);const P=T();C.setOptions(P),g.selected=M,C.setValue(M)}}catch(I){alert(`Failed to import preset: ${I instanceof Error?I.message:"Invalid JSON"}`),console.error("Import error:",I)}},S.readAsText(y)},c.click()}},B=T(),C=w.addSelect(g,"selected",{label:"Preset",options:B});w.addButton("Load",()=>g.load()),w.addButton("Save",()=>g.save()),w.addButton("Delete",()=>g.delete()),w.addButton("Export",()=>g.export()),w.addButton("Import",()=>g.import())}saveToLocalStorage(t){const e=this.save();try{localStorage.setItem(t,JSON.stringify(e))}catch(s){console.warn("ControlPanel: Failed to save to localStorage",s)}}loadFromLocalStorage(t){try{const e=localStorage.getItem(t);if(e){const s=JSON.parse(e);this.load(s)}}catch(e){console.warn("ControlPanel: Failed to load from localStorage",e)}}saveDefaultPreset(){const t=this.presetStoragePrefix+"Default";this.save(),this.saveToLocalStorage(t)}savePositionAndSize(){const t=this.domElement.getBoundingClientRect(),e=`cp-position-${this.presetStoragePrefix}`,s={left:t.left,top:t.top,width:this.domElement.offsetWidth,height:this.domElement.offsetHeight};try{sessionStorage.setItem(e,JSON.stringify(s))}catch(i){console.warn("Failed to save panel position/size",i)}}restorePositionAndSize(){const t=`cp-position-${this.presetStoragePrefix}`;try{const e=sessionStorage.getItem(t);if(e){const s=JSON.parse(e);this.domElement.style.left=`${s.left}px`,this.domElement.style.top=`${s.top}px`,this.domElement.style.right="auto",this.domElement.style.bottom="auto",this.domElement.style.width=`${s.width}px`,this.domElement.style.height=`${s.height}px`}}catch(e){console.warn("Failed to restore panel position/size",e)}}destroy(){this.stats.destroy(),this.domElement.remove(),this.controllers=[],this.folders=[]}}h.ArrayController=at,h.AudioSignals=H,h.BooleanController=tt,h.ButtonController=Q,h.ColorController=st,h.ControlPanel=mt,h.ControlPanelContainer=D,h.Controller=d,h.Folder=ot,h.GradientController=nt,h.MathSignals=_,h.MidiSignals=U,h.NumberController=Y,h.RadioController=et,h.RangeController=Z,h.SelectController=K,h.audioSignals=E,h.mathSignals=J,h.midiSignals=W,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAuYA,wBAAgB,YAAY,SAS3B"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AA2ZA,wBAAgB,YAAY,SAS3B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalmeadow/control-panel",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
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)",
@@ -24,12 +24,11 @@
24
24
  "types": "./dist/index.d.ts",
25
25
  "import": "./dist/index.js",
26
26
  "require": "./dist/index.cjs"
27
- },
28
- "./font.css": "./dist/fonts/font.css"
27
+ }
29
28
  },
30
29
  "scripts": {
31
30
  "dev": "vite",
32
- "build": "vite build && tsc",
31
+ "build": "vite build && tsc && cp -r src/fonts dist/fonts",
33
32
  "preview": "vite preview"
34
33
  },
35
34
  "devDependencies": {
@@ -37,4 +36,4 @@
37
36
  "typescript": "5.9.3",
38
37
  "vite": "7.3.1"
39
38
  }
40
- }
39
+ }
package/dist/index.css DELETED
@@ -1 +0,0 @@
1
- @font-face{font-family:IosevkaTermNF;src:url(data:font/woff2;base64,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) format("woff2");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:IosevkaTermNF;src:url(data:font/woff2;base64,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) format("woff2");font-weight:600;font-style:normal;font-display:swap}:root{--cp-font-family: "IosevkaTermNF"}