From 5f378ed411cb7241d7a2f4174fda7b3f225bfa7f Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Mon, 18 May 2026 10:44:51 -0300 Subject: [PATCH] fix(spice): allow hyphens in voltage-source name regex (root cause of dark-LED bug) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user-reported 'LED with proper series resistor shows 1.84 V at the anode but never visually lights up' had its root cause here, not in ngspice / not in the LED brightness handler / not in any component id naming choice. ngspice parses 'V_led-builtin_sense' just fine; the diode conducts and the node voltage is exactly what you'd compute by hand. What breaks is the JS regex that scans the emitted netlist to collect voltage-source names so CircuitSimulationService can ask the scheduler to read their branch-current vectors: const m = card.match(/^([Vv][_\w]*)\s/); [_\w]* doesn't accept '-'. For a card 'V_led-builtin_sense …' the capture is 'V_led' (truncated at the hyphen). The voltageSources array gets the wrong name; CircuitSimulationService pushes 'i(v_led)' into extraVectorsOfInterest; ngspice has no such vector so the readVec promise rejects silently; branchCurrents['v_led-builtin_sense'] is never populated; the LED handler in BasicParts.ts sees raw = undefined, the SPICE-memo path is skipped, and the digital fallback runs but only sets the LED on when the PinResolver classifies the anode as a direct GPIO connection (which it does NOT when an intermediate resistor is in series). Dark LED. Fix is adding '-' to the character class. One character. All five existing examples I previously 'fixed' by just adding a series resistor will now light up correctly without renaming any of their component ids. Same for any saved user project with hyphenated ids and for the auto-generated picker ids that used to contain hyphens. The earlier underscore-id workarounds (default canvas + picker template) stay in place as defense in depth — they don't break anything and they keep the SPICE side clear of avoidable special characters. --- frontend/src/simulation/spice/NetlistBuilder.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/src/simulation/spice/NetlistBuilder.ts b/frontend/src/simulation/spice/NetlistBuilder.ts index 0ed5b0e9..ccbb0919 100644 --- a/frontend/src/simulation/spice/NetlistBuilder.ts +++ b/frontend/src/simulation/spice/NetlistBuilder.ts @@ -201,9 +201,20 @@ export function buildNetlist(input: BuildNetlistInput): BuildNetlistResult { // by an underscore or digit. ngspice's case-insensitive match means // both `Vname` and `vname` count. We emit only uppercase prefixes // from componentToSpice + NetlistBuilder, so this regex is safe. + // + // The character class MUST include `-` (hyphen). Component ids in + // examples and user-drawn circuits commonly contain hyphens + // (`led-builtin`, `led-red`, auto-generated `led-1717…-abc`), and + // SPICE itself happily parses identifiers with hyphens. If the regex + // doesn't accept them it truncates the captured name at the first + // hyphen ⇒ wrong voltageSources entry ⇒ CircuitSimulationService + // asks ngspice for the WRONG branch-current vector ⇒ branchCurrents + // lookup returns undefined ⇒ LED brightness stays at zero even though + // the circuit conducts correctly. Single-character fix, but it + // unblocks every hyphenated id across every existing project. const voltageSources: string[] = []; for (const card of cards) { - const m = card.match(/^([Vv][_\w]*)\s/); + const m = card.match(/^([Vv][_\w-]*)\s/); if (m) voltageSources.push(m[1]); }