From 4395e0227cf253ca4391f0e9b6578aa37a6882d8 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Sun, 21 Sep 2025 05:04:03 +0000
Subject: [PATCH 1/2] Feat: Update mixer layout and add master volume dial
- Move deck volume controls and crossfader below the automix button.
- Change the master volume control from a slider to a dial.
---
index.html | 36 +++++++++++++++----------------
js/main.js | 63 +++++++++++++++++++++++++++++++++++-------------------
2 files changed, 59 insertions(+), 40 deletions(-)
diff --git a/index.html b/index.html
index cf4f80c..b75ad4f 100644
--- a/index.html
+++ b/index.html
@@ -92,25 +92,9 @@
-
+
-
-
-
-
-
-
@@ -129,6 +113,22 @@
🎧 DJ Toolkit Pro
+
+
+
+
+
+
+
diff --git a/js/main.js b/js/main.js
index 8370048..96930aa 100644
--- a/js/main.js
+++ b/js/main.js
@@ -727,9 +727,18 @@ class Deck {
function setMasterVolume(value) {
masterGain.gain.value = value / 100;
+ updateMasterVolumeKnobUI(value / 100);
saveSettings();
}
+ function updateMasterVolumeKnobUI(value) {
+ const knob = document.getElementById('masterVolumeKnob');
+ if (knob) {
+ const rotation = -135 + (value * 270); // -135 to 135 degrees
+ knob.style.transform = `rotate(${rotation}deg)`;
+ }
+ }
+
function setCrossfader(value) {
crossfaderValue = parseFloat(value);
const x = crossfaderValue / 100;
@@ -774,6 +783,7 @@ class Deck {
// Knob turning logic
let activeKnob = {
+ type: null, // 'effect' or 'master'
deck: null,
effect: null,
element: null,
@@ -781,26 +791,32 @@ class Deck {
initialValue: 0,
};
- function startKnobTurn(event, deckId, effect) {
+ function startKnobTurn(event, type, parameter) {
event.preventDefault();
- const deck = deckId === 'A' ? deckA : deckB;
-
- activeKnob.deck = deck;
- activeKnob.effect = effect;
activeKnob.element = event.target;
activeKnob.initialY = event.clientY;
- activeKnob.initialValue = deck.effects[effect].value;
-
- // Toggle active state on simple click without drag
- if (event.detail === 1) {
- const wasActive = deck.effects[effect].active;
- // A small timeout to differentiate from a drag
- setTimeout(() => {
- if (activeKnob.element && Math.abs(event.clientY - activeKnob.initialY) < 5) {
- deck.effects[effect].active = !wasActive;
- deck.toggleEffect(effect);
- }
- }, 200);
+
+ if (type === 'master') {
+ activeKnob.type = 'master';
+ activeKnob.initialValue = masterGain.gain.value;
+ } else {
+ const deck = type === 'A' ? deckA : deckB;
+ activeKnob.type = 'effect';
+ activeKnob.deck = deck;
+ activeKnob.effect = parameter;
+ activeKnob.initialValue = deck.effects[parameter].value;
+
+ // Toggle active state on simple click without drag
+ if (event.detail === 1) {
+ const wasActive = deck.effects[parameter].active;
+ // A small timeout to differentiate from a drag
+ setTimeout(() => {
+ if (activeKnob.element && Math.abs(event.clientY - activeKnob.initialY) < 5) {
+ deck.effects[parameter].active = !wasActive;
+ deck.toggleEffect(parameter);
+ }
+ }, 200);
+ }
}
window.addEventListener('mousemove', handleKnobTurn);
@@ -815,11 +831,16 @@ class Deck {
let value = activeKnob.initialValue + dy * sensitivity;
value = Math.max(0, Math.min(1, value)); // clamp between 0 and 1
- activeKnob.deck.toggleEffect(activeKnob.effect, value);
+ if (activeKnob.type === 'master') {
+ setMasterVolume(value * 100);
+ } else {
+ activeKnob.deck.toggleEffect(activeKnob.effect, value);
+ }
}
function endKnobTurn(event) {
activeKnob.element = null;
+ activeKnob.type = null;
window.removeEventListener('mousemove', handleKnobTurn);
window.removeEventListener('mouseup', endKnobTurn);
}
@@ -1011,7 +1032,7 @@ class Deck {
keylock: deckB.keylock,
effects: deckB.effects
},
- masterVolume: document.getElementById('masterVolume').value,
+ masterVolume: masterGain.gain.value * 100,
crossfader: document.getElementById('crossfader').value,
playlist: playlist.map(item => ({ name: item.name }))
};
@@ -1038,7 +1059,6 @@ class Deck {
document.getElementById('volumeB').value = session.deckB.volume;
document.getElementById('tempoA').value = session.deckA.tempo;
document.getElementById('tempoB').value = session.deckB.tempo;
- document.getElementById('masterVolume').value = session.masterVolume;
document.getElementById('crossfader').value = session.crossfader;
setVolume('A', session.deckA.volume);
@@ -1095,7 +1115,7 @@ class Deck {
keylock: deckB.keylock,
effects: deckB.effects
},
- masterVolume: document.getElementById('masterVolume').value,
+ masterVolume: masterGain.gain.value * 100,
crossfader: document.getElementById('crossfader').value,
crossfaderCurve: document.getElementById('crossfaderCurve').value,
theme: document.getElementById('theme').value,
@@ -1111,7 +1131,6 @@ class Deck {
// Restore Mixer
setMasterVolume(settings.masterVolume);
- document.getElementById('masterVolume').value = settings.masterVolume;
setCrossfader(settings.crossfader);
document.getElementById('crossfader').value = settings.crossfader;
From 914662fdb8936b39ae6a99a565da5f93a6d1cbe0 Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Sun, 21 Sep 2025 05:13:37 +0000
Subject: [PATCH 2/2] Feat: Refine volume control labels
- Add a single "Volume" label above the deck volume sliders.
- Change the individual slider labels to "A" and "B" and move them below the sliders.
- Fix a bug where the master volume knob's UI was not updated when loading settings.
---
css/style.css | 8 ++++++++
index.html | 17 ++++++++++-------
js/main.js | 2 +-
3 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/css/style.css b/css/style.css
index ba96f59..2e35103 100644
--- a/css/style.css
+++ b/css/style.css
@@ -253,6 +253,14 @@
}
.deck-volume-controls {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ align-items: center;
+ width: 100%;
+ }
+
+ .deck-volume-sliders {
display: flex;
gap: 40px;
justify-content: center;
diff --git a/index.html b/index.html
index b75ad4f..3bd1a3a 100644
--- a/index.html
+++ b/index.html
@@ -115,13 +115,16 @@
🎧 DJ Toolkit Pro
-
-
-
-
-
diff --git a/js/main.js b/js/main.js
index 96930aa..76fb5c3 100644
--- a/js/main.js
+++ b/js/main.js
@@ -728,7 +728,6 @@ class Deck {
function setMasterVolume(value) {
masterGain.gain.value = value / 100;
updateMasterVolumeKnobUI(value / 100);
- saveSettings();
}
function updateMasterVolumeKnobUI(value) {
@@ -833,6 +832,7 @@ class Deck {
if (activeKnob.type === 'master') {
setMasterVolume(value * 100);
+ saveSettings();
} else {
activeKnob.deck.toggleEffect(activeKnob.effect, value);
}