@digitalmeadow/control-panel 1.0.18 → 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/dist/ControlPanel.d.ts +0 -1
- package/dist/ControlPanel.d.ts.map +1 -1
- package/dist/index.js +151 -131
- package/dist/index.umd.cjs +22 -2
- package/dist/styles.d.ts.map +1 -1
- package/package.json +2 -3
- package/dist/fonts/font.css +0 -19
- package/dist/index.css +0 -1
package/dist/ControlPanel.d.ts
CHANGED
|
@@ -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":"
|
|
1
|
+
{"version":3,"file":"ControlPanel.d.ts","sourceRoot":"","sources":["../src/ControlPanel.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
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
19
|
--cp-scale: 1;
|
|
4
20
|
|
|
@@ -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='
|
|
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
|
|
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 =
|
|
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],
|
|
432
|
-
return (n - i) / (a - i) * (l -
|
|
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]),
|
|
479
|
-
this.processLevel("bass", i), this.processLevel("mids", a), this.processLevel("highs",
|
|
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),
|
|
525
|
-
this.values.set(a,
|
|
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,
|
|
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,
|
|
604
|
-
return this.normalizeOutput(
|
|
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,
|
|
612
|
-
return this.normalizeOutput(
|
|
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,
|
|
616
|
-
return this.normalizeOutput(
|
|
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 =
|
|
645
|
-
const i = s.label ?? J(e), a =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
776
|
+
const s = r(
|
|
757
777
|
"label",
|
|
758
778
|
{ className: "cp-setting-label" },
|
|
759
779
|
["Midi"]
|
|
760
780
|
);
|
|
761
|
-
this.midiBtn =
|
|
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 =
|
|
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
|
|
789
|
-
t.appendChild(
|
|
808
|
+
const o = r("hr", { className: "cp-separator" });
|
|
809
|
+
t.appendChild(o);
|
|
790
810
|
}
|
|
791
811
|
createSettingSelect(t, e, s) {
|
|
792
|
-
const i =
|
|
812
|
+
const i = r("div", { className: "cp-setting-row" }), a = r("label", { className: "cp-setting-label" }, [
|
|
793
813
|
t
|
|
794
|
-
]),
|
|
814
|
+
]), o = r("select", {
|
|
795
815
|
className: "cp-select cp-input-small"
|
|
796
816
|
});
|
|
797
817
|
return e.forEach((l) => {
|
|
798
|
-
const p =
|
|
799
|
-
|
|
800
|
-
}),
|
|
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,
|
|
803
|
-
const l =
|
|
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 =
|
|
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) ||
|
|
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,
|
|
822
|
-
t === "random" ? a = 30 : t === "constant" && (s = "Speed", i = 0.01, a = 2,
|
|
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
|
-
|
|
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 =
|
|
930
|
+
const i = r("details", {
|
|
911
931
|
className: "cp-controller-details"
|
|
912
|
-
}), a =
|
|
932
|
+
}), a = r("summary", {
|
|
913
933
|
className: "cp-controller-summary"
|
|
914
934
|
});
|
|
915
|
-
this.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 =
|
|
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
|
|
927
|
-
isNaN(
|
|
928
|
-
}), this.input.addEventListener("click", (
|
|
929
|
-
|
|
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
|
|
951
|
+
const o = r("div", {
|
|
932
952
|
className: "cp-controller-summary-content"
|
|
933
953
|
});
|
|
934
|
-
|
|
935
|
-
const l =
|
|
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
|
-
(
|
|
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
|
-
(
|
|
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
|
-
(
|
|
970
|
+
(g) => this.setStep(g)
|
|
951
971
|
);
|
|
952
972
|
this.stepInput = d.input, l.appendChild(d.row);
|
|
953
|
-
const y =
|
|
973
|
+
const y = r("hr", { className: "cp-separator" });
|
|
954
974
|
l.appendChild(y), this.signalHandler = new H({
|
|
955
975
|
container: l,
|
|
956
|
-
onChange: (
|
|
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 =
|
|
1010
|
+
const i = r("div", { className: "cp-setting-row" }), a = r("label", { className: "cp-setting-label" }, [
|
|
991
1011
|
t
|
|
992
|
-
]),
|
|
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 && (
|
|
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 =
|
|
1041
|
-
const
|
|
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(
|
|
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 =
|
|
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 =
|
|
1088
|
+
this.button = r("button", { className: "cp-button" }, [
|
|
1069
1089
|
String(a)
|
|
1070
1090
|
]), this.button.addEventListener("click", () => {
|
|
1071
|
-
const
|
|
1072
|
-
typeof
|
|
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 =
|
|
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 =
|
|
1094
|
-
const a =
|
|
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
|
|
1129
|
+
class ot extends u {
|
|
1110
1130
|
constructor(t, e, s = {}) {
|
|
1111
|
-
super(t, e, s), this.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,
|
|
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
|
|
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), [
|
|
1146
|
-
return
|
|
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 =
|
|
1174
|
+
const i = r("details", {
|
|
1155
1175
|
className: "cp-controller-details"
|
|
1156
|
-
}), a =
|
|
1176
|
+
}), a = r("summary", {
|
|
1157
1177
|
className: "cp-controller-summary"
|
|
1158
|
-
}),
|
|
1178
|
+
}), o = r("div", {
|
|
1159
1179
|
className: "cp-controller-summary-content"
|
|
1160
1180
|
});
|
|
1161
|
-
this.displayText =
|
|
1181
|
+
this.displayText = r(
|
|
1162
1182
|
"span",
|
|
1163
1183
|
{ className: "cp-value-display" },
|
|
1164
1184
|
[String(this.value)]
|
|
1165
|
-
),
|
|
1166
|
-
const l =
|
|
1167
|
-
this.stopsContainer =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
1296
|
+
const i = r("details", {
|
|
1277
1297
|
className: "cp-controller-details"
|
|
1278
|
-
}), a =
|
|
1298
|
+
}), a = r("summary", {
|
|
1279
1299
|
className: "cp-controller-summary"
|
|
1280
|
-
}),
|
|
1300
|
+
}), o = r("div", {
|
|
1281
1301
|
className: "cp-controller-summary-content"
|
|
1282
|
-
}), l =
|
|
1302
|
+
}), l = r("span", { className: "cp-value-display" }, [
|
|
1283
1303
|
`${this.items.length} items`
|
|
1284
1304
|
]);
|
|
1285
|
-
|
|
1286
|
-
const p =
|
|
1287
|
-
this.itemsContainer =
|
|
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 =
|
|
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 =
|
|
1352
|
+
const s = r("div", { className: "cp-array-row" });
|
|
1333
1353
|
let i;
|
|
1334
|
-
this.itemType === "color" ? i =
|
|
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 =
|
|
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 =
|
|
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", (
|
|
1348
|
-
this.items[e] =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
1492
|
+
super(), this.title = t, this.domElement = r("details", {
|
|
1473
1493
|
className: "cp-folder",
|
|
1474
1494
|
open: !0
|
|
1475
|
-
}), this.summaryElement =
|
|
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 =
|
|
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 =
|
|
1508
|
+
super(), _(), this.domElement = r("details", {
|
|
1489
1509
|
className: "cp-root",
|
|
1490
1510
|
open: !0
|
|
1491
|
-
}), this.summaryElement =
|
|
1511
|
+
}), this.summaryElement = r("summary", {
|
|
1492
1512
|
className: "cp-summary cp-summary-root"
|
|
1493
1513
|
}), this.domElement.appendChild(this.summaryElement);
|
|
1494
|
-
const s =
|
|
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,
|
|
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,
|
|
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 -
|
|
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 =
|
|
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
|
|
1541
|
-
this.presetStoragePrefix = `cp-presets-${
|
|
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
|
-
},
|
|
1573
|
+
}, f = {
|
|
1554
1574
|
selected: "Default",
|
|
1555
1575
|
save: () => {
|
|
1556
|
-
const c = prompt("Preset Name:",
|
|
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),
|
|
1585
|
+
S.setOptions(v), f.selected = c, S.setValue(c);
|
|
1566
1586
|
}
|
|
1567
1587
|
},
|
|
1568
1588
|
load: () => {
|
|
1569
|
-
const c =
|
|
1570
|
-
this.loadFromLocalStorage(m),
|
|
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 (
|
|
1593
|
+
if (f.selected === "Default") {
|
|
1574
1594
|
alert("Cannot delete Default preset");
|
|
1575
1595
|
return;
|
|
1576
1596
|
}
|
|
1577
|
-
if (confirm(`Delete preset "${
|
|
1578
|
-
const c = this.presetStoragePrefix +
|
|
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),
|
|
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:
|
|
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 =
|
|
1605
|
-
x.download = `${
|
|
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),
|
|
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(
|
|
1663
|
+
}, V = E(), S = b.addSelect(f, "selected", {
|
|
1644
1664
|
label: "Preset",
|
|
1645
1665
|
options: V
|
|
1646
1666
|
});
|
|
1647
|
-
b.addButton("Load", () =>
|
|
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
|
-
|
|
1726
|
+
ot as ColorController,
|
|
1707
1727
|
ut as ControlPanel,
|
|
1708
1728
|
U as ControlPanelContainer,
|
|
1709
1729
|
u as Controller,
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
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
19
|
--cp-scale: 1;
|
|
4
20
|
|
|
@@ -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='
|
|
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"})}));
|
package/dist/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"
|
|
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.
|
|
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,8 +24,7 @@
|
|
|
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",
|
package/dist/fonts/font.css
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
@font-face {
|
|
2
|
-
font-family: "IosevkaTermNF";
|
|
3
|
-
src: url("./IosevkaTermNF-Regular.woff2") format("woff2");
|
|
4
|
-
font-weight: 400;
|
|
5
|
-
font-style: normal;
|
|
6
|
-
font-display: swap;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
@font-face {
|
|
10
|
-
font-family: "IosevkaTermNF";
|
|
11
|
-
src: url("./IosevkaTermNFP-SemiBold.woff2") format("woff2");
|
|
12
|
-
font-weight: 600;
|
|
13
|
-
font-style: normal;
|
|
14
|
-
font-display: swap;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
:root {
|
|
18
|
-
--cp-font-family: "IosevkaTermNF";
|
|
19
|
-
}
|
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"}
|