diff --git a/webapp/path_navigator.html b/webapp/path_navigator.html
index a3e5945..4d050f7 100644
--- a/webapp/path_navigator.html
+++ b/webapp/path_navigator.html
@@ -1106,14 +1106,19 @@
// 1. Shift+click → SuperCollider (FIRST)
if (isShift) {
const endpoint = '/api/play-freq';
+ const octave = parseInt(document.getElementById('octaveInput').value) || 0;
- const requestBody = {
+ // If ghost node with its own frequency, send directly; otherwise use chordIndex/nodeIndex
+ const requestBody = node.data('frequency') ? {
+ frequency: node.data('frequency'),
+ octave: octave,
+ } : {
chordIndex: chordIndex,
nodeIndex: localId,
- octave: parseInt(document.getElementById('octaveInput').value) || 0,
+ octave: octave,
};
- console.log('Sending to SuperCollider:', chordIndex, localId);
+ console.log('Sending to SuperCollider:', node.data('frequency') ? 'direct frequency' : chordIndex + ',' + localId);
fetch(endpoint, {
method: 'POST',
diff --git a/webapp/server.py b/webapp/server.py
index c49a09f..b3884c2 100644
--- a/webapp/server.py
+++ b/webapp/server.py
@@ -111,7 +111,24 @@ def play_freq():
chord_index = data.get("chordIndex")
node_index = data.get("nodeIndex")
octave = data.get("octave", 0)
+ frequency_input = data.get("frequency") # direct frequency for ghost nodes
+ # If frequency provided directly (ghost node), use it
+ if frequency_input is not None:
+ frequency = float(frequency_input) * (2**octave)
+ voice = 1 # Use voice 1 for ghost nodes
+ osc_sender.send_single(frequency, voice)
+
+ return jsonify(
+ {
+ "frequency": frequency,
+ "voice": voice,
+ "fundamental": fundamental,
+ "fraction": "ghost",
+ }
+ )
+
+ # Original node: calculate from chordIndex/nodeIndex
if chord_index < 0 or chord_index >= len(chords):
return jsonify({"error": "Invalid chord index"}), 400