fix: robust wire connections via data attributes + chiptune demo preset
- Replace fragile DOM position matching in finishConnection with data-module-id/data-port-name/data-port-direction attributes - Add nearby port detection (8px radius) for easier connections - Wire glow effects with drop-shadow filters - Port dots z-index above wires for reliable click targeting - Chiptune demo preset: 2x square osc, envelopes, VCAs, mixer, filter, delay, distortion, scope — full 8-bit signal chain - "Chiptune Demo" toolbar button to load the example Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { getModuleDef } from '../engine/moduleRegistry.js';
|
||||
import { state, removeModule, updateModuleParam, updateModulePosition, isPortConnected, emit } from '../engine/state.js';
|
||||
import { state, removeModule, updateModuleParam, isPortConnected, emit } from '../engine/state.js';
|
||||
import { updateParam } from '../engine/audioEngine.js';
|
||||
import Knob from './Knob.jsx';
|
||||
import ScopeDisplay from './ScopeDisplay.jsx';
|
||||
@@ -66,7 +66,12 @@ export default function ModuleNode({ mod, zoom, onStartConnect, onPortPosition }
|
||||
<div
|
||||
className={`module ${isSelected ? 'selected' : ''}`}
|
||||
style={{ left: mod.x * zoom, top: mod.y * zoom, transform: `scale(${zoom})`, transformOrigin: 'top left' }}
|
||||
onPointerDown={() => { state.selectedModuleId = mod.id; emit(); }}
|
||||
data-module-id={mod.id}
|
||||
onPointerDown={(e) => {
|
||||
// Don't deselect when clicking inside a module
|
||||
e.stopPropagation();
|
||||
state.selectedModuleId = mod.id; emit();
|
||||
}}
|
||||
>
|
||||
<div className="module-header" onPointerDown={handleHeaderDown}>
|
||||
<span className="type-icon">{def.icon}</span>
|
||||
@@ -81,6 +86,10 @@ export default function ModuleNode({ mod, zoom, onStartConnect, onPortPosition }
|
||||
<div
|
||||
className={`port-dot ${port.type} ${isPortConnected(mod.id, port.name, 'input') ? 'connected' : ''}`}
|
||||
ref={el => portRef(el, port.name, 'input')}
|
||||
data-module-id={mod.id}
|
||||
data-port-name={port.name}
|
||||
data-port-direction="input"
|
||||
data-port-type={port.type}
|
||||
onPointerDown={e => handlePortMouseDown(e, port.name, 'input')}
|
||||
/>
|
||||
<span className="port-label">{port.label}</span>
|
||||
@@ -139,6 +148,10 @@ export default function ModuleNode({ mod, zoom, onStartConnect, onPortPosition }
|
||||
<div
|
||||
className={`port-dot ${port.type} ${isPortConnected(mod.id, port.name, 'output') ? 'connected' : ''}`}
|
||||
ref={el => portRef(el, port.name, 'output')}
|
||||
data-module-id={mod.id}
|
||||
data-port-name={port.name}
|
||||
data-port-direction="output"
|
||||
data-port-type={port.type}
|
||||
onPointerDown={e => handlePortMouseDown(e, port.name, 'output')}
|
||||
/>
|
||||
<span className="port-label">{port.label}</span>
|
||||
|
||||
Reference in New Issue
Block a user