Skip to content

fix: apply nominalTraceWidth from <net> and nested <group> - #3423

Open
Msa360 wants to merge 1 commit into
tscircuit:mainfrom
Msa360:fix/net-and-group-nominal-trace-width
Open

fix: apply nominalTraceWidth from <net> and nested <group>#3423
Msa360 wants to merge 1 commit into
tscircuit:mainfrom
Msa360:fix/net-and-group-nominal-trace-width

Conversation

@Msa360

@Msa360 Msa360 commented Aug 25, 2026

Copy link
Copy Markdown

Problem

nominalTraceWidth is declared in @tscircuit/props for both netProps and baseGroupProps, but core only read it off the subcircuit that runs autorouting (Group._runLocalAutorouting). Both of these are parsed and then silently dropped:

<board width="20mm" height="20mm">
  {/* ignored — traces on VBUS still render at 0.15mm */}
  <net name="VBUS" nominalTraceWidth="0.5mm" />

  {/* ignored — group is not a subcircuit, so nothing reads its props */}
  <group nominalTraceWidth="0.4mm">
    <resistor name="R1" resistance="1k" footprint="0402" pcbX={-5} />
    <resistor name="R2" resistance="1k" footprint="0402" pcbX={5} />
    <trace from=".R1 > .pin2" to=".R2 > .pin1" />
  </group>
</board>

No error or warning is emitted. Setting nominalTraceWidth on <board>, or on a group that has the subcircuit prop set, already worked.

Fix

A trace resolves its width by falling back through the things that can specify it:

  1. the trace's own thickness / width
  2. nominalTraceWidth of the nets it connects to (widest wins if it connects several)
  3. defaultTraceWidth / nominalTraceWidth of the closest ancestor group
  4. the subcircuit/board value — unchanged, still applied to the whole SimpleRouteJson

The resolved width is written to source_trace.min_trace_thickness, which getSimpleRouteJsonFromCircuitJson already reads for both direct-trace and net connections, so autorouted, manual, and per-trace-ijump routes all pick it up.

The ancestor walk stops before the enclosing subcircuit, since that value is already applied by Group._runLocalAutorouting — this keeps existing board-level behaviour identical.

Tests

tests/features/net-and-group-nominal-trace-width-autorouting.test.tsx covers:

  • <net nominalTraceWidth> sets the autorouted width
  • explicit trace thickness beats net nominalTraceWidth
  • non-subcircuit <group nominalTraceWidth> sets the autorouted width
  • innermost group wins over the board's
  • net wins over the enclosing group's

bunx tsc --noEmit is clean. bun test tests/groups tests/subcircuits tests/drc tests/utils tests/breakout trace passes apart from 4 tests that time out identically on unmodified main locally (repro-bq25895-cross-net-trace-overlap, repro-rp2040-gamepad-trace-alignment, example35-minimize-trace-crossing, ground-net-label-preserves-solver-orientation).

nominalTraceWidth was declared in @tscircuit/props for both netProps and
baseGroupProps, but core only read it off the subcircuit that runs
autorouting. A <net nominalTraceWidth> and a non-subcircuit
<group nominalTraceWidth> were both parsed and then silently dropped.

Traces now resolve their width as:
  trace thickness/width > connected net nominalTraceWidth >
  closest ancestor group defaultTraceWidth/nominalTraceWidth >
  subcircuit/board nominalTraceWidth (unchanged)

The resolved width is written to source_trace.min_trace_thickness, which
getSimpleRouteJsonFromCircuitJson already uses for both direct-trace and
net connections.
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tscircuit-core-benchmarks Ready Ready Preview Aug 25, 2026 1:12am

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant