@digitalmeadow/control-panel 1.0.5 → 1.0.7

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/dist/index.js CHANGED
@@ -1,25 +1,53 @@
1
- const z = `
1
+ const W = `
2
2
  .cp-root {
3
- position: fixed;
4
- top: 10px;
5
- right: 10px;
6
- width: 280px;
3
+ position: absolute;
4
+ top: 0;
5
+ right: 0;
6
+ width: min(280px, 90%);
7
7
  max-height: 90vh;
8
8
  overflow: auto;
9
9
  background: transparent;
10
+ resize: both;
10
11
  color: #fff;
11
- mix-blend-mode: exclusion;
12
+ min-width: 200px;
13
+ min-height: 50px;
12
14
  font-family:
13
15
  -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
14
16
  sans-serif;
15
17
  font-size: 10px;
16
18
  line-height: 1.2;
17
19
  padding: 8px;
18
- z-index: 100;
20
+ }
21
+
22
+ /* Apply blend mode to all children except color inputs */
23
+ .cp-root .cp-label,
24
+ .cp-root .cp-setting-label,
25
+ .cp-root .cp-summary,
26
+ .cp-root .cp-controller-summary,
27
+ .cp-root .cp-separator,
28
+ .cp-root .cp-value-display,
29
+ .cp-root .cp-button,
30
+ .cp-root .cp-input-number,
31
+ .cp-root .cp-input-range,
32
+ .cp-root .cp-select,
33
+ .cp-root .cp-radio
34
+ {
35
+ mix-blend-mode: difference;
36
+ }
37
+
38
+ .cp-root .cp-input-color,
39
+ .cp-root .cp-color-swatch {
40
+ mix-blend-mode: normal;
41
+ isolation: isolate;
42
+ }
43
+
44
+ .cp-root:not([open]) .cp-summary-root {
45
+ opacity: 0.5;
19
46
  }
20
47
 
21
48
  .cp-root::-webkit-scrollbar {
22
49
  width: 1px;
50
+ height: 1px;
23
51
  }
24
52
  .cp-root::-webkit-scrollbar-track {
25
53
  background: transparent;
@@ -38,6 +66,7 @@ const z = `
38
66
  .cp-summary-root {
39
67
  position: sticky;
40
68
  top: 0;
69
+ cursor: grab;
41
70
  }
42
71
 
43
72
  .cp-stats {
@@ -83,7 +112,7 @@ const z = `
83
112
  .cp-input-number {
84
113
  width: 50%;
85
114
  background: transparent;
86
- border: 1px solid #fff;
115
+ border: 1px solid rgba(255, 255, 255, 0.3);
87
116
  color: inherit;
88
117
  padding: 2px 4px;
89
118
  border-radius: 2px;
@@ -99,6 +128,7 @@ const z = `
99
128
 
100
129
  .cp-select {
101
130
  width: 50%;
131
+ color: inherit;
102
132
  background: rgba(255, 255, 255, 0.3);
103
133
  border: none;
104
134
  padding: 2px 4px;
@@ -113,6 +143,7 @@ const z = `
113
143
 
114
144
  .cp-button {
115
145
  width: 100%;
146
+ color: inherit;
116
147
  background: rgba(255, 255, 255, 0.3);
117
148
  border: none;
118
149
  padding: 4px 2px;
@@ -259,9 +290,6 @@ const z = `
259
290
  border: none;
260
291
  background: none;
261
292
  outline: none;
262
-
263
- isolation: isolate;
264
- mix-blend-mode: normal;
265
293
  cursor: pointer;
266
294
  }
267
295
 
@@ -277,11 +305,11 @@ const z = `
277
305
  gap: 4px;
278
306
  }
279
307
  `;
280
- let V = !1;
281
- function R() {
282
- if (V) return;
308
+ let B = !1;
309
+ function _() {
310
+ if (B) return;
283
311
  const n = document.createElement("style");
284
- n.id = "control-panel-styles", n.textContent = z, document.head.appendChild(n), V = !0;
312
+ n.id = "control-panel-styles", n.textContent = W, document.head.appendChild(n), B = !0;
285
313
  }
286
314
  function r(n, t = {}, e = []) {
287
315
  const s = document.createElement(n);
@@ -291,7 +319,7 @@ function r(n, t = {}, e = []) {
291
319
  typeof i == "string" ? s.appendChild(document.createTextNode(i)) : s.appendChild(i);
292
320
  return s;
293
321
  }
294
- function D(n) {
322
+ function j(n) {
295
323
  const t = r(
296
324
  "button",
297
325
  {
@@ -301,13 +329,13 @@ function D(n) {
301
329
  );
302
330
  return t.addEventListener("click", n), t;
303
331
  }
304
- function j(n) {
332
+ function J(n) {
305
333
  return n.replace(/([A-Z])/g, " $1").replace(/^./, (t) => t.toUpperCase()).trim();
306
334
  }
307
- function O(n, t, e) {
335
+ function q(n, t, e) {
308
336
  return Math.min(Math.max(n, t), e);
309
337
  }
310
- function $(n, t, e) {
338
+ function Y(n, t, e) {
311
339
  if (t.length !== e.length)
312
340
  throw new Error("Input and output ranges must have the same length");
313
341
  if (t.length < 2)
@@ -319,10 +347,10 @@ function $(n, t, e) {
319
347
  return e[e.length - 1];
320
348
  if (s === 0 && n < t[0])
321
349
  return e[0];
322
- const i = t[s], a = t[s + 1], o = e[s], c = e[s + 1];
323
- return (n - i) / (a - i) * (c - o) + o;
350
+ const i = t[s], a = t[s + 1], o = e[s], l = e[s + 1];
351
+ return (n - i) / (a - i) * (l - o) + o;
324
352
  }
325
- class U {
353
+ class X {
326
354
  constructor() {
327
355
  this.source = null, this.stream = null, this.fftSize = 2048, this.smoothingTimeConstant = 0.82, this.spectrumBoost = 3, this.levels = {
328
356
  volume: 0,
@@ -360,18 +388,18 @@ class U {
360
388
  }
361
389
  update() {
362
390
  if (this.analyser.getByteFrequencyData(this.dataArray), this.analyser.getByteTimeDomainData(this.waveformArray), this.spectrumBoost !== 1) {
363
- const p = this.dataArray.length;
364
- for (let h = 0; h < p; h++) {
365
- const m = 1 + h / p * (this.spectrumBoost - 1);
366
- this.dataArray[h] = Math.min(255, this.dataArray[h] * m);
391
+ const h = this.dataArray.length;
392
+ for (let p = 0; p < h; p++) {
393
+ const b = 1 + p / h * (this.spectrumBoost - 1);
394
+ this.dataArray[p] = Math.min(255, this.dataArray[p] * b);
367
395
  }
368
396
  }
369
- 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]), c = this.getAverage(0, s[1]);
370
- this.processLevel("bass", i), this.processLevel("mids", a), this.processLevel("highs", o), this.processLevel("volume", c);
397
+ 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]);
398
+ this.processLevel("bass", i), this.processLevel("mids", a), this.processLevel("highs", o), this.processLevel("volume", l);
371
399
  }
372
400
  processLevel(t, e) {
373
- this.peaks[t] -= 5e-4, this.peaks[t] = O(this.peaks[t], 0.1, 1), e > this.peaks[t] && (this.peaks[t] = e), this.levels[t] = O(
374
- $(e, [0, this.peaks[t]], [0, 1]),
401
+ 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(
402
+ Y(e, [0, this.peaks[t]], [0, 1]),
375
403
  0,
376
404
  1
377
405
  );
@@ -388,8 +416,8 @@ class U {
388
416
  return () => this.levels[t];
389
417
  }
390
418
  }
391
- const C = new U();
392
- class H {
419
+ const M = new X();
420
+ class G {
393
421
  constructor() {
394
422
  this.midiAccess = null, this.values = /* @__PURE__ */ new Map(), this.isListening = !1, this.resolveListen = null, this.listeningCallback = null, this.init();
395
423
  }
@@ -416,8 +444,8 @@ class H {
416
444
  this.values.set(a, o), this.isListening && this.resolveListen && o > 0 && (this.resolveListen(a), this.isListening = !1, this.resolveListen = null, this.listeningCallback && this.listeningCallback());
417
445
  }
418
446
  getIdFromMessage(t) {
419
- const e = t.data, [s, i] = e, a = s & 240, o = t.currentTarget.name || "unknown", c = a === 144 || a === 128 ? "note" : "ctrl", p = o.replace(/[^a-zA-Z0-9]/g, "");
420
- return `${i}_${c}_${p}`;
447
+ const e = t.data, [s, i] = e, a = s & 240, o = t.currentTarget.name || "unknown", l = a === 144 || a === 128 ? "note" : "ctrl", h = o.replace(/[^a-zA-Z0-9]/g, "");
448
+ return `${i}_${l}_${h}`;
421
449
  }
422
450
  normalizeValue(t) {
423
451
  const [e, s, i] = t, a = e & 240;
@@ -435,8 +463,8 @@ class H {
435
463
  return () => this.values.get(t) ?? 0;
436
464
  }
437
465
  }
438
- const W = new H();
439
- class _ {
466
+ const Z = new G();
467
+ class K {
440
468
  constructor() {
441
469
  this.configs = /* @__PURE__ */ new Map(), this.lastRandomUpdateTime = 0, this.currentRandomValue = 0, this.startTime = performance.now(), this.configs.set("constant", {
442
470
  frequency: 0.1,
@@ -530,10 +558,10 @@ class _ {
530
558
  this.startTime = performance.now(), this.lastRandomUpdateTime = 0, this.currentRandomValue = 0;
531
559
  }
532
560
  }
533
- const J = new _(), T = class T {
561
+ const Q = new K(), P = class P {
534
562
  constructor(t, e, s = {}) {
535
563
  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" });
536
- const i = s.label ?? j(e), a = r("label", { className: "cp-label" }, [
564
+ const i = s.label ?? J(e), a = r("label", { className: "cp-label" }, [
537
565
  String(i)
538
566
  ]);
539
567
  a.setAttribute("title", String(i)), this.domElement.appendChild(a), s.disabled && this.domElement.setAttribute("data-disabled", "true");
@@ -564,9 +592,9 @@ const J = new _(), T = class T {
564
592
  this.domElement.appendChild(t);
565
593
  }
566
594
  };
567
- T.audio = C, T.midi = W, T.math = J;
568
- let d = T;
569
- const P = {
595
+ P.audio = M, P.midi = Z, P.math = Q;
596
+ let u = P;
597
+ const R = {
570
598
  linear: (n) => n,
571
599
  quadIn: (n) => n * n,
572
600
  quadOut: (n) => n * (2 - n),
@@ -581,24 +609,24 @@ const P = {
581
609
  sineOut: (n) => Math.sin(n * Math.PI / 2),
582
610
  sineInOut: (n) => -(Math.cos(Math.PI * n) - 1) / 2
583
611
  };
584
- class B {
612
+ class H {
585
613
  constructor(t) {
586
614
  this.rafId = null, this.currentSignalType = null, this.currentMidiId = null, this.currentEase = "linear", this.currentBehaviour = "forward", this.loop = () => {
587
615
  if (this.currentSignalType) {
588
616
  let e = 0;
589
- this.currentSignalType === "midi" ? this.currentMidiId && (e = d.midi.getSignal(this.currentMidiId)()) : [
617
+ this.currentSignalType === "midi" ? this.currentMidiId && (e = u.midi.getSignal(this.currentMidiId)()) : [
590
618
  "constant",
591
619
  "sine",
592
620
  "sawtooth",
593
621
  "triangle",
594
622
  "square",
595
623
  "random"
596
- ].includes(this.currentSignalType) ? e = d.math.getSignal(
624
+ ].includes(this.currentSignalType) ? e = u.math.getSignal(
597
625
  this.currentSignalType
598
- )() : ["volume", "bass", "mids", "highs"].includes(this.currentSignalType) && (e = d.audio.getSignal(
626
+ )() : ["volume", "bass", "mids", "highs"].includes(this.currentSignalType) && (e = u.audio.getSignal(
599
627
  this.currentSignalType
600
628
  )());
601
- const s = P[this.currentEase](e);
629
+ const s = R[this.currentEase](e);
602
630
  this.onChange(s, this.currentBehaviour), this.rafId = requestAnimationFrame(this.loop);
603
631
  }
604
632
  }, this.onChange = t.onChange, this.setupControllers(t.container);
@@ -637,11 +665,11 @@ class B {
637
665
  ["Learn"]
638
666
  ), this.midiBtn.addEventListener("click", async () => {
639
667
  if (this.midiBtn.textContent === "Listening...") {
640
- d.midi.cancelListen(), this.setMidiId(null);
668
+ u.midi.cancelListen(), this.setMidiId(null);
641
669
  return;
642
670
  }
643
671
  this.midiBtn.textContent = "Listening...";
644
- const o = await d.midi.listen();
672
+ const o = await u.midi.listen();
645
673
  this.setMidiId(o);
646
674
  }), this.midiRow.appendChild(s), this.midiRow.appendChild(this.midiBtn), t.appendChild(this.midiRow), this.mathParamsContainer = r("div", {
647
675
  style: "display: none; flex-direction: column; gap: 4px;"
@@ -654,7 +682,7 @@ class B {
654
682
  this.behaviourRow = i.row, this.behaviourSelect = i.select, this.behaviourRow.style.display = "none", this.behaviourSelect.value = this.currentBehaviour, t.appendChild(this.behaviourRow);
655
683
  const a = this.createSettingSelect(
656
684
  "ease",
657
- Object.keys(P),
685
+ Object.keys(R),
658
686
  (o) => this.setEase(o)
659
687
  );
660
688
  this.easeRow = a.row, this.easeSelect = a.select, this.easeRow.style.display = "none", this.easeSelect.value = this.currentEase, t.appendChild(this.easeRow);
@@ -665,15 +693,15 @@ class B {
665
693
  ]), o = r("select", {
666
694
  className: "cp-select cp-input-small"
667
695
  });
668
- return e.forEach((c) => {
669
- const p = r("option", { value: c }, [c]);
670
- o.appendChild(p);
696
+ return e.forEach((l) => {
697
+ const h = r("option", { value: l }, [l]);
698
+ o.appendChild(h);
671
699
  }), o.addEventListener("change", () => s(o.value)), i.appendChild(a), i.appendChild(o), { row: i, select: o };
672
700
  }
673
701
  createNumberInput(t, e, s, i, a, o) {
674
- const c = r("div", { className: "cp-setting-row" }), p = r("label", { className: "cp-setting-label" }, [
702
+ const l = r("div", { className: "cp-setting-row" }), h = r("label", { className: "cp-setting-label" }, [
675
703
  t
676
- ]), h = r("input", {
704
+ ]), p = r("input", {
677
705
  className: "cp-input-number cp-input-small",
678
706
  type: "number",
679
707
  value: String(e),
@@ -681,52 +709,52 @@ class B {
681
709
  max: String(i),
682
710
  step: String(a)
683
711
  });
684
- return h.addEventListener("input", () => {
685
- const u = parseFloat(h.value);
686
- isNaN(u) || o(u);
687
- }), c.appendChild(p), c.appendChild(h), { row: c, input: h };
712
+ return p.addEventListener("input", () => {
713
+ const d = parseFloat(p.value);
714
+ isNaN(d) || o(d);
715
+ }), l.appendChild(h), l.appendChild(p), { row: l, input: p };
688
716
  }
689
717
  updateMathParams(t) {
690
718
  this.mathParamsContainer.innerHTML = "";
691
- const e = d.math.getConfig(t);
719
+ const e = u.math.getConfig(t);
692
720
  let s = "Frequency", i = 0.1, a = 10, o = 0.1;
693
721
  t === "random" ? a = 30 : t === "constant" && (s = "Speed", i = 0.01, a = 2, o = 0.01);
694
- const c = this.createNumberInput(
722
+ const l = this.createNumberInput(
695
723
  s,
696
724
  e.frequency,
697
725
  i,
698
726
  a,
699
727
  o,
700
- (u) => d.math.setConfig(t, { frequency: u })
728
+ (d) => u.math.setConfig(t, { frequency: d })
701
729
  );
702
- this.mathParamsContainer.appendChild(c.row);
703
- const p = this.createNumberInput(
730
+ this.mathParamsContainer.appendChild(l.row);
731
+ const h = this.createNumberInput(
704
732
  "Amplitude",
705
733
  e.amplitude,
706
734
  0,
707
735
  2,
708
736
  0.1,
709
- (u) => d.math.setConfig(t, { amplitude: u })
737
+ (d) => u.math.setConfig(t, { amplitude: d })
710
738
  );
711
- this.mathParamsContainer.appendChild(p.row);
712
- const h = this.createNumberInput(
739
+ this.mathParamsContainer.appendChild(h.row);
740
+ const p = this.createNumberInput(
713
741
  "Offset",
714
742
  e.offset,
715
743
  0,
716
744
  1,
717
745
  0.1,
718
- (u) => d.math.setConfig(t, { offset: u })
746
+ (d) => u.math.setConfig(t, { offset: d })
719
747
  );
720
- if (this.mathParamsContainer.appendChild(h.row), ["sine", "sawtooth", "triangle", "square"].includes(t)) {
721
- const u = this.createNumberInput(
748
+ if (this.mathParamsContainer.appendChild(p.row), ["sine", "sawtooth", "triangle", "square"].includes(t)) {
749
+ const d = this.createNumberInput(
722
750
  "Phase",
723
751
  e.phase,
724
752
  0,
725
753
  1,
726
754
  0.01,
727
- (m) => d.math.setConfig(t, { phase: m })
755
+ (b) => u.math.setConfig(t, { phase: b })
728
756
  );
729
- this.mathParamsContainer.appendChild(u.row);
757
+ this.mathParamsContainer.appendChild(d.row);
730
758
  }
731
759
  }
732
760
  setSignalType(t) {
@@ -742,7 +770,7 @@ class B {
742
770
  "square",
743
771
  "random"
744
772
  ].includes(t), i = ["volume", "bass", "mids", "highs"].includes(t);
745
- this.midiRow.style.display = e ? "flex" : "none", this.mathParamsContainer.style.display = s ? "flex" : "none", s && this.updateMathParams(t), this.easeRow.style.display = "flex", this.behaviourRow.style.display = "flex", 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);
773
+ this.midiRow.style.display = e ? "flex" : "none", this.mathParamsContainer.style.display = s ? "flex" : "none", s && this.updateMathParams(t), this.easeRow.style.display = "flex", this.behaviourRow.style.display = "flex", i ? (this.currentMidiId = null, u.audio.ctx.state === "suspended" && u.audio.setInput("microphone")) : e || (this.currentMidiId = null), this.start(), this.signalSelect.value !== t && (this.signalSelect.value = t);
746
774
  }
747
775
  }
748
776
  setMidiId(t) {
@@ -775,7 +803,7 @@ class B {
775
803
  this.setSignalType("none"), this.setEase("linear"), this.setBehaviour("forward"), this.setMidiId(null);
776
804
  }
777
805
  }
778
- class G extends d {
806
+ class tt extends u {
779
807
  constructor(t, e, s = {}) {
780
808
  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;
781
809
  const i = r("details", {
@@ -794,38 +822,38 @@ class G extends d {
794
822
  },
795
823
  [String(this.value.toFixed(1))]
796
824
  ), this.input.addEventListener("input", () => {
797
- const l = parseFloat(this.input.value);
798
- isNaN(l) || (this.setValue(l), this.display.textContent = String(l.toFixed(1)));
799
- }), this.input.addEventListener("click", (l) => {
800
- l.stopPropagation();
825
+ const g = parseFloat(this.input.value);
826
+ isNaN(g) || (this.setValue(g), this.display.textContent = String(g.toFixed(1)));
827
+ }), this.input.addEventListener("click", (g) => {
828
+ g.stopPropagation();
801
829
  });
802
830
  const o = r("div", {
803
831
  className: "cp-controller-summary-content"
804
832
  });
805
833
  o.appendChild(this.input), o.appendChild(this.display), a.appendChild(o), i.appendChild(a);
806
- const c = r("div", { className: "cp-number-settings" }), p = this.createSetting(
834
+ const l = r("div", { className: "cp-number-settings" }), h = this.createSetting(
807
835
  "min",
808
836
  s.min,
809
- (l) => this.setMin(l)
837
+ (g) => this.setMin(g)
810
838
  );
811
- this.minInput = p.input, c.appendChild(p.row);
812
- const h = this.createSetting(
839
+ this.minInput = h.input, l.appendChild(h.row);
840
+ const p = this.createSetting(
813
841
  "max",
814
842
  s.max,
815
- (l) => this.setMax(l)
843
+ (g) => this.setMax(g)
816
844
  );
817
- this.maxInput = h.input, c.appendChild(h.row);
818
- const u = this.createSetting(
845
+ this.maxInput = p.input, l.appendChild(p.row);
846
+ const d = this.createSetting(
819
847
  "step",
820
848
  s.step,
821
- (l) => this.setStep(l)
849
+ (g) => this.setStep(g)
822
850
  );
823
- this.stepInput = u.input, c.appendChild(u.row);
824
- const m = r("hr", { className: "cp-separator" });
825
- c.appendChild(m), this.signalHandler = new B({
826
- container: c,
827
- onChange: (l, f) => this.applySignal(l, f)
828
- }), i.appendChild(c), this.appendWidget(i);
851
+ this.stepInput = d.input, l.appendChild(d.row);
852
+ const b = r("hr", { className: "cp-separator" });
853
+ l.appendChild(b), this.signalHandler = new H({
854
+ container: l,
855
+ onChange: (g, v) => this.applySignal(g, v)
856
+ }), i.appendChild(l), this.appendWidget(i);
829
857
  }
830
858
  // Setters
831
859
  setMin(t) {
@@ -906,7 +934,7 @@ class G extends d {
906
934
  ), this.setStep(this.initialOptions.step), this.signalHandler?.reset();
907
935
  }
908
936
  }
909
- class Z extends d {
937
+ class et extends u {
910
938
  constructor(t, e, s) {
911
939
  super(t, e, s), this.optionValues = [], this.select = r("select", { className: "cp-select" }), this.optionValues = s.options || [], this.optionValues.forEach((i, a) => {
912
940
  const o = r("option", { value: String(a) }, [
@@ -931,7 +959,7 @@ class Z extends d {
931
959
  t !== -1 && (this.select.value = String(t));
932
960
  }
933
961
  }
934
- class K extends d {
962
+ class st extends u {
935
963
  constructor(t, e, s = {}) {
936
964
  const i = { action: e };
937
965
  super(i, "action", s);
@@ -946,7 +974,7 @@ class K extends d {
946
974
  updateDisplay() {
947
975
  }
948
976
  }
949
- class Y extends d {
977
+ class it extends u {
950
978
  constructor(t, e, s = {}) {
951
979
  super(t, e, s), this.input = r("input", {
952
980
  type: "checkbox",
@@ -959,7 +987,7 @@ class Y extends d {
959
987
  this.input.checked = this.value;
960
988
  }
961
989
  }
962
- class Q extends d {
990
+ class nt extends u {
963
991
  constructor(t, e, s) {
964
992
  super(t, e, s), this.buttons = [], this.optionValues = [], this.container = r("div", { className: "cp-radios" }), this.optionValues = s.options || [], this.optionValues.forEach((i) => {
965
993
  const a = r("button", { className: "cp-button cp-radio" }, [
@@ -977,7 +1005,7 @@ class Q extends d {
977
1005
  });
978
1006
  }
979
1007
  }
980
- class X extends d {
1008
+ class at extends u {
981
1009
  constructor(t, e, s = {}) {
982
1010
  super(t, e, s), this.input = r("input", {
983
1011
  type: "color",
@@ -992,7 +1020,7 @@ class X extends d {
992
1020
  this.input.value = this.value;
993
1021
  }
994
1022
  }
995
- function F(n) {
1023
+ function $(n) {
996
1024
  const t = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
997
1025
  n = n.replace(t, (s, i, a, o) => i + i + a + a + o + o);
998
1026
  const e = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(n);
@@ -1002,21 +1030,21 @@ function F(n) {
1002
1030
  parseInt(e[3], 16)
1003
1031
  ] : [0, 0, 0];
1004
1032
  }
1005
- function tt(n, t, e) {
1033
+ function ot(n, t, e) {
1006
1034
  return "#" + ((1 << 24) + (Math.round(n) << 16) + (Math.round(t) << 8) + Math.round(e)).toString(16).slice(1);
1007
1035
  }
1008
- function w(n) {
1036
+ function T(n) {
1009
1037
  const t = n / 255;
1010
1038
  return t <= 0.04045 ? t / 12.92 : Math.pow((t + 0.055) / 1.055, 2.4);
1011
1039
  }
1012
- function L(n) {
1040
+ function D(n) {
1013
1041
  return n <= 31308e-7 ? n * 12.92 * 255 : (1.055 * Math.pow(n, 1 / 2.4) - 0.055) * 255;
1014
1042
  }
1015
- function et(n, t, e) {
1016
- const [s, i, a] = F(n), [o, c, p] = F(t), h = w(s), u = w(i), m = w(a), l = w(o), f = w(c), g = w(p), b = h + e * (l - h), I = u + e * (f - u), v = m + e * (g - m), S = L(b), y = L(I), x = L(v);
1017
- return tt(S, y, x);
1043
+ function rt(n, t, e) {
1044
+ const [s, i, a] = $(n), [o, l, h] = $(t), p = T(s), d = T(i), b = T(a), g = T(o), v = T(l), E = T(h), f = p + e * (g - p), V = d + e * (v - d), x = b + e * (E - b), c = D(f), m = D(V), y = D(x);
1045
+ return ot(c, m, y);
1018
1046
  }
1019
- class st extends d {
1047
+ class lt extends u {
1020
1048
  constructor(t, e, s = {}) {
1021
1049
  super(t, e, s), this.stops = [], this.pingPongDirection = 1, this.animationT = 0, this.manualPosition = 0, this.initialOptions = s, this.stops = s.stops || [
1022
1050
  { color: "#000000", position: 0 },
@@ -1037,25 +1065,25 @@ class st extends d {
1037
1065
  { className: "cp-value-display" },
1038
1066
  [String(this.value)]
1039
1067
  ), o.appendChild(this.displayColor), o.appendChild(this.displayText), a.appendChild(o), i.appendChild(a);
1040
- const c = r("div", { className: "cp-number-settings" });
1068
+ const l = r("div", { className: "cp-number-settings" });
1041
1069
  this.stopsContainer = r("div", {
1042
1070
  className: "cp-stops-container"
1043
- }), this.renderStops(), c.appendChild(this.stopsContainer);
1044
- const p = r(
1071
+ }), this.renderStops(), l.appendChild(this.stopsContainer);
1072
+ const h = r(
1045
1073
  "button",
1046
1074
  {
1047
1075
  className: "cp-button"
1048
1076
  },
1049
1077
  ["+ Add Stop"]
1050
1078
  );
1051
- p.addEventListener("click", () => {
1079
+ h.addEventListener("click", () => {
1052
1080
  this.stops.push({ color: "#ffffff", position: 0.5 }), this.sortStops(), this.renderStops(), this.updateOutput();
1053
- }), c.appendChild(p);
1054
- const h = r("hr", { className: "cp-separator" });
1055
- c.appendChild(h), this.signalHandler = new B({
1056
- container: c,
1057
- onChange: (u, m) => this.applySignal(u, m)
1058
- }), i.appendChild(c), this.appendWidget(i), this.updateOutput(0);
1081
+ }), l.appendChild(h);
1082
+ const p = r("hr", { className: "cp-separator" });
1083
+ l.appendChild(p), this.signalHandler = new H({
1084
+ container: l,
1085
+ onChange: (d, b) => this.applySignal(d, b)
1086
+ }), i.appendChild(l), this.appendWidget(i), this.updateOutput(0);
1059
1087
  }
1060
1088
  sortStops() {
1061
1089
  this.stops.sort((t, e) => t.position - e.position);
@@ -1067,8 +1095,8 @@ class st extends d {
1067
1095
  className: "cp-input-color",
1068
1096
  value: t.color
1069
1097
  });
1070
- i.addEventListener("input", (c) => {
1071
- t.color = c.target.value, this.updateOutput();
1098
+ i.addEventListener("input", (l) => {
1099
+ t.color = l.target.value, this.updateOutput();
1072
1100
  });
1073
1101
  const a = r("input", {
1074
1102
  type: "number",
@@ -1078,11 +1106,11 @@ class st extends d {
1078
1106
  step: "0.01",
1079
1107
  value: String(t.position)
1080
1108
  });
1081
- a.addEventListener("change", (c) => {
1082
- let p = parseFloat(c.target.value);
1083
- isNaN(p) && (p = 0), t.position = Math.max(0, Math.min(1, p)), this.sortStops(), this.renderStops(), this.updateOutput();
1109
+ a.addEventListener("change", (l) => {
1110
+ let h = parseFloat(l.target.value);
1111
+ isNaN(h) && (h = 0), t.position = Math.max(0, Math.min(1, h)), this.sortStops(), this.renderStops(), this.updateOutput();
1084
1112
  });
1085
- const o = D(() => {
1113
+ const o = j(() => {
1086
1114
  this.stops.splice(e, 1), this.renderStops(), this.updateOutput();
1087
1115
  });
1088
1116
  s.appendChild(i), s.appendChild(a), s.appendChild(o), this.stopsContainer.appendChild(s);
@@ -1104,8 +1132,8 @@ class st extends d {
1104
1132
  for (let s = 0; s < this.stops.length - 1; s++) {
1105
1133
  const i = this.stops[s], a = this.stops[s + 1];
1106
1134
  if (t >= i.position && t <= a.position) {
1107
- const o = a.position - i.position, c = o === 0 ? 0 : (t - i.position) / o;
1108
- e = et(i.color, a.color, c);
1135
+ const o = a.position - i.position, l = o === 0 ? 0 : (t - i.position) / o;
1136
+ e = rt(i.color, a.color, l);
1109
1137
  break;
1110
1138
  }
1111
1139
  }
@@ -1144,7 +1172,7 @@ class st extends d {
1144
1172
  ], this.sortStops(), this.renderStops(), this.signalHandler?.reset(), this.updateOutput(0);
1145
1173
  }
1146
1174
  }
1147
- class it extends d {
1175
+ class ct extends u {
1148
1176
  constructor(t, e, s = {}) {
1149
1177
  super(t, e, s), this.items = [], this.initialOptions = s, this.itemType = s.itemType || "string", this.items = this.parseValue(this.value);
1150
1178
  const i = r("details", {
@@ -1153,15 +1181,15 @@ class it extends d {
1153
1181
  className: "cp-controller-summary"
1154
1182
  }), o = r("div", {
1155
1183
  className: "cp-controller-summary-content"
1156
- }), c = r("span", { className: "cp-value-display" }, [
1184
+ }), l = r("span", { className: "cp-value-display" }, [
1157
1185
  `${this.items.length} items`
1158
1186
  ]);
1159
- o.appendChild(c), a.appendChild(o), i.appendChild(a);
1160
- const p = r("div", { className: "cp-number-settings" });
1187
+ o.appendChild(l), a.appendChild(o), i.appendChild(a);
1188
+ const h = r("div", { className: "cp-number-settings" });
1161
1189
  this.itemsContainer = r("div", {
1162
1190
  className: "cp-stops-container"
1163
- }), this.renderItems(), p.appendChild(this.itemsContainer);
1164
- const h = r(
1191
+ }), this.renderItems(), h.appendChild(this.itemsContainer);
1192
+ const p = r(
1165
1193
  "button",
1166
1194
  {
1167
1195
  className: "cp-button cp-input-small",
@@ -1169,9 +1197,9 @@ class it extends d {
1169
1197
  },
1170
1198
  ["+ Add Item"]
1171
1199
  );
1172
- h.addEventListener("click", () => {
1200
+ p.addEventListener("click", () => {
1173
1201
  this.addItem();
1174
- }), p.appendChild(h), i.appendChild(p), this.appendWidget(i);
1202
+ }), h.appendChild(p), i.appendChild(h), this.appendWidget(i);
1175
1203
  }
1176
1204
  parseValue(t) {
1177
1205
  return !t || t.trim() === "" ? [] : t.split(",").map((e) => e.trim());
@@ -1221,7 +1249,7 @@ class it extends d {
1221
1249
  }), i.addEventListener("input", (o) => {
1222
1250
  this.items[e] = o.target.value, this.updateValue();
1223
1251
  });
1224
- const a = D(() => {
1252
+ const a = j(() => {
1225
1253
  this.items.splice(e, 1), this.renderItems(), this.updateValue();
1226
1254
  });
1227
1255
  s.appendChild(i), s.appendChild(a), this.itemsContainer.appendChild(s);
@@ -1240,7 +1268,7 @@ class it extends d {
1240
1268
  this.items = this.parseValue(t), this.renderItems(), this.updateValue();
1241
1269
  }
1242
1270
  }
1243
- class nt {
1271
+ class ht {
1244
1272
  constructor() {
1245
1273
  this.frames = 0, this.pollingInterval = 1e3, this.prevTime = performance.now(), this.render = () => {
1246
1274
  this.frames++;
@@ -1258,44 +1286,44 @@ class nt {
1258
1286
  cancelAnimationFrame(this.rafId);
1259
1287
  }
1260
1288
  }
1261
- class q {
1289
+ class U {
1262
1290
  constructor() {
1263
1291
  this.controllers = [], this.folders = [];
1264
1292
  }
1265
1293
  addNumber(t, e, s = {}) {
1266
- const i = new G(t, e, s);
1294
+ const i = new tt(t, e, s);
1267
1295
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1268
1296
  }
1269
1297
  addSelect(t, e, s = {}) {
1270
- const i = new Z(t, e, s);
1298
+ const i = new et(t, e, s);
1271
1299
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1272
1300
  }
1273
1301
  addBoolean(t, e, s = {}) {
1274
- const i = new Y(t, e, s);
1302
+ const i = new it(t, e, s);
1275
1303
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1276
1304
  }
1277
1305
  addButton(t, e, s = {}) {
1278
- const i = new K(t, e, s);
1306
+ const i = new st(t, e, s);
1279
1307
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1280
1308
  }
1281
1309
  addRadio(t, e, s = {}) {
1282
- const i = new Q(t, e, s);
1310
+ const i = new nt(t, e, s);
1283
1311
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1284
1312
  }
1285
1313
  addColor(t, e, s = {}) {
1286
- const i = new X(t, e, s);
1314
+ const i = new at(t, e, s);
1287
1315
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1288
1316
  }
1289
1317
  addGradient(t, e, s = {}) {
1290
- const i = new st(t, e, s);
1318
+ const i = new lt(t, e, s);
1291
1319
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1292
1320
  }
1293
1321
  addArray(t, e, s = {}) {
1294
- const i = new it(t, e, s);
1322
+ const i = new ct(t, e, s);
1295
1323
  return this.contentElement.appendChild(i.domElement), this.controllers.push(i), i;
1296
1324
  }
1297
1325
  addFolder(t) {
1298
- const e = new at(t);
1326
+ const e = new pt(t);
1299
1327
  return this.contentElement.appendChild(e.domElement), this.folders.push(e), e;
1300
1328
  }
1301
1329
  save() {
@@ -1333,7 +1361,7 @@ class q {
1333
1361
  t.reset();
1334
1362
  }
1335
1363
  }
1336
- class at extends q {
1364
+ class pt extends U {
1337
1365
  constructor(t) {
1338
1366
  super(), this.title = t, this.domElement = r("details", {
1339
1367
  className: "cp-folder",
@@ -1351,9 +1379,9 @@ class at extends q {
1351
1379
  );
1352
1380
  }
1353
1381
  }
1354
- class ot extends q {
1382
+ class dt extends U {
1355
1383
  constructor(t, e = {}) {
1356
- super(), R(), this.domElement = r("details", {
1384
+ super(), _(), this.domElement = r("details", {
1357
1385
  className: "cp-root",
1358
1386
  open: !0
1359
1387
  }), this.summaryElement = r("summary", {
@@ -1362,142 +1390,157 @@ class ot extends q {
1362
1390
  const s = r("span", {}, [
1363
1391
  e.title || "ControlPanel"
1364
1392
  ]);
1365
- this.summaryElement.appendChild(s), this.stats = new nt(), this.summaryElement.appendChild(this.stats.domElement), this.contentElement = r("div", { className: "cp-content" }), this.domElement.appendChild(this.contentElement);
1366
- const i = this.addFolder("_Signals"), a = {
1393
+ this.summaryElement.appendChild(s), this.stats = new ht(), this.summaryElement.appendChild(this.stats.domElement);
1394
+ let i = !1, a = 0, o = 0, l = 0, h = 0;
1395
+ this.summaryElement.addEventListener("mousedown", (c) => {
1396
+ if (c.target !== this.summaryElement && c.target !== s) return;
1397
+ i = !0, a = c.clientX, o = c.clientY;
1398
+ const m = this.domElement.getBoundingClientRect();
1399
+ l = m.left, h = m.top, c.preventDefault();
1400
+ }), document.addEventListener("mousemove", (c) => {
1401
+ if (!i) return;
1402
+ const m = c.clientX - a, y = c.clientY - o, S = l + m, k = h + y;
1403
+ this.domElement.style.left = `${S}px`, this.domElement.style.top = `${k}px`, this.domElement.style.right = "auto", this.domElement.style.bottom = "auto";
1404
+ }), document.addEventListener("mouseup", () => {
1405
+ i && (i = !1, this.savePositionAndSize());
1406
+ }), new ResizeObserver(() => {
1407
+ i || this.savePositionAndSize();
1408
+ }).observe(this.domElement), this.restorePositionAndSize(), this.contentElement = r("div", { className: "cp-content" }), this.domElement.appendChild(this.contentElement);
1409
+ const d = this.addFolder("_Signals"), b = {
1367
1410
  audioInput: null,
1368
1411
  fftSize: 2048
1369
1412
  };
1370
- i.addRadio(a, "audioInput", {
1413
+ d.addRadio(b, "audioInput", {
1371
1414
  label: "Audio Signal",
1372
1415
  options: ["microphone", "browser"]
1373
- }).onChange((l) => {
1374
- C.setInput(l);
1375
- }), i.addSelect(a, "fftSize", {
1416
+ }).onChange((c) => {
1417
+ M.setInput(c);
1418
+ }), d.addSelect(b, "fftSize", {
1376
1419
  label: "FFT Size",
1377
1420
  options: [256, 512, 1024, 2048]
1378
- }).onChange((l) => {
1379
- C.setFFTSize(l);
1380
- }), i.addNumber(C, "smoothingTimeConstant", {
1421
+ }).onChange((c) => {
1422
+ M.setFFTSize(c);
1423
+ }), d.addNumber(M, "smoothingTimeConstant", {
1381
1424
  min: 0,
1382
1425
  max: 0.99,
1383
1426
  step: 0.01,
1384
1427
  label: "Smoothing"
1385
- }).onChange((l) => {
1386
- C.analyser.smoothingTimeConstant = l;
1387
- }), i.addNumber(C, "spectrumBoost", {
1428
+ }).onChange((c) => {
1429
+ M.analyser.smoothingTimeConstant = c;
1430
+ }), d.addNumber(M, "spectrumBoost", {
1388
1431
  min: 1,
1389
1432
  max: 5,
1390
1433
  step: 0.1,
1391
1434
  label: "Compression"
1392
1435
  }), t ? t.appendChild(this.domElement) : document.body.appendChild(this.domElement);
1393
- const o = e.title || "ControlPanel";
1394
- this.presetStoragePrefix = `cp-presets-${o}-`;
1395
- const c = this.addFolder("_User Presets"), p = () => {
1396
- const l = ["Default"];
1397
- if (typeof localStorage > "u") return l;
1398
- for (let f = 0; f < localStorage.length; f++) {
1399
- const g = localStorage.key(f);
1400
- if (g && g.startsWith(this.presetStoragePrefix)) {
1401
- const b = g.substring(this.presetStoragePrefix.length);
1402
- b !== "Default" && !l.includes(b) && l.push(b);
1436
+ const g = e.title || "ControlPanel";
1437
+ this.presetStoragePrefix = `cp-presets-${g}-`;
1438
+ const v = this.addFolder("_User Presets"), E = () => {
1439
+ const c = ["Default"];
1440
+ if (typeof localStorage > "u") return c;
1441
+ for (let m = 0; m < localStorage.length; m++) {
1442
+ const y = localStorage.key(m);
1443
+ if (y && y.startsWith(this.presetStoragePrefix)) {
1444
+ const S = y.substring(this.presetStoragePrefix.length);
1445
+ S !== "Default" && !c.includes(S) && c.push(S);
1403
1446
  }
1404
1447
  }
1405
- return l.sort();
1406
- }, h = {
1448
+ return c.sort();
1449
+ }, f = {
1407
1450
  selected: "Default",
1408
1451
  save: () => {
1409
- const l = prompt("Preset Name:", h.selected);
1410
- if (l) {
1411
- if (l === "Default") {
1452
+ const c = prompt("Preset Name:", f.selected);
1453
+ if (c) {
1454
+ if (c === "Default") {
1412
1455
  alert("Cannot overwrite Default preset");
1413
1456
  return;
1414
1457
  }
1415
- const f = this.presetStoragePrefix + l;
1416
- this.saveToLocalStorage(f);
1417
- const g = p();
1418
- m.setOptions(g), h.selected = l, m.setValue(l);
1458
+ const m = this.presetStoragePrefix + c;
1459
+ this.saveToLocalStorage(m);
1460
+ const y = E();
1461
+ x.setOptions(y), f.selected = c, x.setValue(c);
1419
1462
  }
1420
1463
  },
1421
1464
  load: () => {
1422
- const l = h.selected, f = this.presetStoragePrefix + l;
1423
- this.loadFromLocalStorage(f), h.selected = l, m.setValue(l);
1465
+ const c = f.selected, m = this.presetStoragePrefix + c;
1466
+ this.loadFromLocalStorage(m), f.selected = c, x.setValue(c);
1424
1467
  },
1425
1468
  delete: () => {
1426
- if (h.selected === "Default") {
1469
+ if (f.selected === "Default") {
1427
1470
  alert("Cannot delete Default preset");
1428
1471
  return;
1429
1472
  }
1430
- if (confirm(`Delete preset "${h.selected}"?`)) {
1431
- const l = this.presetStoragePrefix + h.selected;
1432
- localStorage.removeItem(l);
1433
- const f = p();
1434
- m.setOptions(f), h.selected = "Default", m.setValue("Default"), this.reset();
1473
+ if (confirm(`Delete preset "${f.selected}"?`)) {
1474
+ const c = this.presetStoragePrefix + f.selected;
1475
+ localStorage.removeItem(c);
1476
+ const m = E();
1477
+ x.setOptions(m), f.selected = "Default", x.setValue("Default"), this.reset();
1435
1478
  }
1436
1479
  },
1437
1480
  export: () => {
1438
- const l = this.save(), f = (M) => {
1439
- const N = {
1481
+ const c = this.save(), m = (O) => {
1482
+ const L = {
1440
1483
  controllers: {},
1441
1484
  folders: {}
1442
1485
  };
1443
- for (const [E, k] of Object.entries(M.controllers))
1444
- E.startsWith("_") || (N.controllers[E] = k);
1445
- for (const [E, k] of Object.entries(
1446
- M.folders
1486
+ for (const [A, F] of Object.entries(O.controllers))
1487
+ A.startsWith("_") || (L.controllers[A] = F);
1488
+ for (const [A, F] of Object.entries(
1489
+ O.folders
1447
1490
  ))
1448
- E.startsWith("_") || (N.folders[E] = f(k));
1449
- return N;
1450
- }, g = f(l), b = {
1451
- _presetName: h.selected || "CustomPreset",
1491
+ A.startsWith("_") || (L.folders[A] = m(F));
1492
+ return L;
1493
+ }, y = m(c), S = {
1494
+ _presetName: f.selected || "CustomPreset",
1452
1495
  _exportDate: (/* @__PURE__ */ new Date()).toISOString(),
1453
1496
  _instructions: "To add as factory preset: Copy 'controllers' and 'folders' fields into the presets.json file",
1454
- ...g
1455
- }, I = JSON.stringify(b, null, 2), v = new Blob([I], { type: "application/json" }), S = URL.createObjectURL(v), y = document.createElement("a");
1456
- y.href = S;
1457
- const x = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], A = h.selected.replace(/[^a-z0-9]/gi, "-").toLowerCase();
1458
- y.download = `${o.toLowerCase()}-preset-${A}-${x}.json`, document.body.appendChild(y), y.click(), document.body.removeChild(y), URL.revokeObjectURL(S);
1497
+ ...y
1498
+ }, k = JSON.stringify(S, null, 2), C = new Blob([k], { type: "application/json" }), I = URL.createObjectURL(C), w = document.createElement("a");
1499
+ w.href = I;
1500
+ const N = (/* @__PURE__ */ new Date()).toISOString().split("T")[0], z = f.selected.replace(/[^a-z0-9]/gi, "-").toLowerCase();
1501
+ w.download = `${g.toLowerCase()}-preset-${z}-${N}.json`, document.body.appendChild(w), w.click(), document.body.removeChild(w), URL.revokeObjectURL(I);
1459
1502
  },
1460
1503
  import: () => {
1461
- const l = document.createElement("input");
1462
- l.type = "file", l.accept = ".json", l.onchange = (f) => {
1463
- const g = f.target.files?.[0];
1464
- if (!g) return;
1465
- const b = new FileReader();
1466
- b.onload = (I) => {
1504
+ const c = document.createElement("input");
1505
+ c.type = "file", c.accept = ".json", c.onchange = (m) => {
1506
+ const y = m.target.files?.[0];
1507
+ if (!y) return;
1508
+ const S = new FileReader();
1509
+ S.onload = (k) => {
1467
1510
  try {
1468
- const v = I.target?.result, S = JSON.parse(v), y = {
1469
- controllers: S.controllers || {},
1470
- folders: S.folders || {}
1511
+ const C = k.target?.result, I = JSON.parse(C), w = {
1512
+ controllers: I.controllers || {},
1513
+ folders: I.folders || {}
1471
1514
  };
1472
- if (!y.controllers || !y.folders) {
1515
+ if (!w.controllers || !w.folders) {
1473
1516
  alert(
1474
1517
  "Invalid preset file: missing 'controllers' or 'folders'"
1475
1518
  );
1476
1519
  return;
1477
1520
  }
1478
- this.load(y);
1479
- const x = S._presetName || "ImportedPreset";
1521
+ this.load(w);
1522
+ const N = I._presetName || "ImportedPreset";
1480
1523
  if (confirm(
1481
- `Preset loaded! Save as "${x}" to User Presets?`
1524
+ `Preset loaded! Save as "${N}" to User Presets?`
1482
1525
  )) {
1483
- const M = this.presetStoragePrefix + x;
1484
- this.saveToLocalStorage(M);
1485
- const N = p();
1486
- m.setOptions(N), h.selected = x, m.setValue(x);
1526
+ const O = this.presetStoragePrefix + N;
1527
+ this.saveToLocalStorage(O);
1528
+ const L = E();
1529
+ x.setOptions(L), f.selected = N, x.setValue(N);
1487
1530
  }
1488
- } catch (v) {
1531
+ } catch (C) {
1489
1532
  alert(
1490
- `Failed to import preset: ${v instanceof Error ? v.message : "Invalid JSON"}`
1491
- ), console.error("Import error:", v);
1533
+ `Failed to import preset: ${C instanceof Error ? C.message : "Invalid JSON"}`
1534
+ ), console.error("Import error:", C);
1492
1535
  }
1493
- }, b.readAsText(g);
1494
- }, l.click();
1536
+ }, S.readAsText(y);
1537
+ }, c.click();
1495
1538
  }
1496
- }, u = p(), m = c.addSelect(h, "selected", {
1539
+ }, V = E(), x = v.addSelect(f, "selected", {
1497
1540
  label: "Preset",
1498
- options: u
1541
+ options: V
1499
1542
  });
1500
- c.addButton("Load", () => h.load()), c.addButton("Save / New", () => h.save()), c.addButton("Delete", () => h.delete()), c.addButton("Export JSON", () => h.export()), c.addButton("Import JSON", () => h.import());
1543
+ v.addButton("Load", () => f.load()), v.addButton("Save / New", () => f.save()), v.addButton("Delete", () => f.delete()), v.addButton("Export JSON", () => f.export()), v.addButton("Import JSON", () => f.import());
1501
1544
  }
1502
1545
  saveToLocalStorage(t) {
1503
1546
  const e = this.save();
@@ -1522,27 +1565,52 @@ class ot extends q {
1522
1565
  const t = this.presetStoragePrefix + "Default";
1523
1566
  this.save(), this.saveToLocalStorage(t);
1524
1567
  }
1568
+ savePositionAndSize() {
1569
+ const t = this.domElement.getBoundingClientRect(), e = `cp-position-${this.presetStoragePrefix}`, s = {
1570
+ left: t.left,
1571
+ top: t.top,
1572
+ width: this.domElement.offsetWidth,
1573
+ height: this.domElement.offsetHeight
1574
+ };
1575
+ try {
1576
+ sessionStorage.setItem(e, JSON.stringify(s));
1577
+ } catch (i) {
1578
+ console.warn("Failed to save panel position/size", i);
1579
+ }
1580
+ }
1581
+ restorePositionAndSize() {
1582
+ const t = `cp-position-${this.presetStoragePrefix}`;
1583
+ try {
1584
+ const e = sessionStorage.getItem(t);
1585
+ if (e) {
1586
+ const s = JSON.parse(e);
1587
+ 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`;
1588
+ }
1589
+ } catch (e) {
1590
+ console.warn("Failed to restore panel position/size", e);
1591
+ }
1592
+ }
1525
1593
  destroy() {
1526
1594
  this.stats.destroy(), this.domElement.remove(), this.controllers = [], this.folders = [];
1527
1595
  }
1528
1596
  }
1529
1597
  export {
1530
- it as ArrayController,
1531
- U as AudioSignals,
1532
- Y as BooleanController,
1533
- K as ButtonController,
1534
- X as ColorController,
1535
- ot as ControlPanel,
1536
- q as ControlPanelContainer,
1537
- d as Controller,
1538
- at as Folder,
1539
- st as GradientController,
1540
- _ as MathSignals,
1541
- H as MidiSignals,
1542
- G as NumberController,
1543
- Q as RadioController,
1544
- Z as SelectController,
1545
- C as audioSignals,
1546
- J as mathSignals,
1547
- W as midiSignals
1598
+ ct as ArrayController,
1599
+ X as AudioSignals,
1600
+ it as BooleanController,
1601
+ st as ButtonController,
1602
+ at as ColorController,
1603
+ dt as ControlPanel,
1604
+ U as ControlPanelContainer,
1605
+ u as Controller,
1606
+ pt as Folder,
1607
+ lt as GradientController,
1608
+ K as MathSignals,
1609
+ G as MidiSignals,
1610
+ tt as NumberController,
1611
+ nt as RadioController,
1612
+ et as SelectController,
1613
+ M as audioSignals,
1614
+ Q as mathSignals,
1615
+ Z as midiSignals
1548
1616
  };