From cb4f913009e9a3f9a1c64b9e84e541336d056f0a Mon Sep 17 00:00:00 2001 From: seveibar Date: Thu, 23 Oct 2025 14:16:58 -0700 Subject: [PATCH 1/2] trace pcb path thickness --- ...b-path-thickness-with-empty-array.test.tsx | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/components/primitive-components/trace-pcb-path-thickness-with-empty-array.test.tsx diff --git a/tests/components/primitive-components/trace-pcb-path-thickness-with-empty-array.test.tsx b/tests/components/primitive-components/trace-pcb-path-thickness-with-empty-array.test.tsx new file mode 100644 index 000000000..a4150feee --- /dev/null +++ b/tests/components/primitive-components/trace-pcb-path-thickness-with-empty-array.test.tsx @@ -0,0 +1,41 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("trace pcbPath selectors can set thickness", async () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + , + ) + + await circuit.renderUntilSettled() + + const pcbTrace = circuit.db.pcb_trace.list()[0] + expect(pcbTrace).toBeDefined() + if (!pcbTrace) throw new Error("Expected trace to be routed") + expect( + pcbTrace.route + .filter((segment) => segment.route_type === "wire") + .every((segment) => segment.width === 0.5), + ).toBe(true) + + await expect(circuit).toMatchPcbSnapshot( + `${import.meta.path}-selectors-thickness`, + ) +}) From 4c287744a29c469e4528b439e553f7f6e76ec5ba Mon Sep 17 00:00:00 2001 From: seveibar Date: Thu, 23 Oct 2025 14:56:53 -0700 Subject: [PATCH 2/2] refactor(trace): unify trace thickness handling using _getExplicitTraceThickness method feat(trace): support 'width' as alias for 'thickness' in trace props fix(trace_doInitialPcbManualTraceRender): handle empty pcbPath correctly perf(trace_doInitialPcbManualTraceRender): use explicit trace thickness fallback chain perf(trace_doInitialPcbTraceRender): use explicit trace thickness fallback chain feat(autorouting): add optional width property to SimpleRouteConnection for trace thickness feat(autorouting): include trace min_trace_thickness as width in route JSON generation build: update @tscircuit/props dependency to 0.0.378 test(trace): add snapshot test for pcb path thickness with empty array scenario test(primitive-components): add test for trace width alias prop to verify thickness mapping test(primitive-components): add SVG snapshot for trace width alias PCB rendering to ensure visual consistency --- .../primitive-components/Trace/Trace.ts | 9 ++++- .../Trace_doInitialPcbManualTraceRender.ts | 6 ++- .../Trace/Trace_doInitialPcbTraceRender.ts | 4 +- lib/utils/autorouting/SimpleRouteJson.ts | 1 + .../getSimpleRouteJsonFromCircuitJson.ts | 1 + package.json | 2 +- ....test.tsx-selectors-thickness-pcb.snap.svg | 1 + .../trace-width-alias-pcb.snap.svg | 1 + .../trace-width-alias.test.tsx | 38 +++++++++++++++++++ 9 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 tests/components/primitive-components/__snapshots__/trace-pcb-path-thickness-with-empty-array.test.tsx-selectors-thickness-pcb.snap.svg create mode 100644 tests/components/primitive-components/__snapshots__/trace-width-alias-pcb.snap.svg create mode 100644 tests/components/primitive-components/trace-width-alias.test.tsx diff --git a/lib/components/primitive-components/Trace/Trace.ts b/lib/components/primitive-components/Trace/Trace.ts index c1a6b2153..f70c9441c 100644 --- a/lib/components/primitive-components/Trace/Trace.ts +++ b/lib/components/primitive-components/Trace/Trace.ts @@ -62,6 +62,13 @@ export class Trace this._portsRoutedOnPcb = [] } + /** + * Get the explicit trace thickness, supporting 'width' as an alias for 'thickness' + */ + _getExplicitTraceThickness(): number | undefined { + return this._parsedProps.thickness ?? this._parsedProps.width + } + get config() { return { zodProps: traceProps, @@ -276,7 +283,7 @@ export class Trace { db }, ) ?? props.maxLength, display_name: displayName, - min_trace_thickness: props.thickness, + min_trace_thickness: this._getExplicitTraceThickness(), }) this.source_trace_id = trace.source_trace_id diff --git a/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts b/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts index 685bd841a..73911c553 100644 --- a/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts +++ b/lib/components/primitive-components/Trace/Trace_doInitialPcbManualTraceRender.ts @@ -10,7 +10,7 @@ export function Trace_doInitialPcbManualTraceRender(trace: Trace) { const { _parsedProps: props } = trace const subcircuit = trace.getSubcircuit() - if (!props.pcbPath || props.pcbPath.length === 0) return + if (!props.pcbPath) return const { allPortsFound, ports, portsWithSelectors } = trace._findConnectedPorts() @@ -57,7 +57,9 @@ export function Trace_doInitialPcbManualTraceRender(trace: Trace) { const layer = anchorPort.getAvailablePcbLayers()[0] || "top" const width = - props.thickness ?? trace.getSubcircuit()._parsedProps.minTraceWidth ?? 0.16 + trace._getExplicitTraceThickness() ?? + trace.getSubcircuit()._parsedProps.minTraceWidth ?? + 0.16 const anchorPos = anchorPort._getGlobalPcbPositionAfterLayout() const otherPos = otherPort._getGlobalPcbPositionAfterLayout() diff --git a/lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts b/lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts index b2a262d86..15fa473fa 100644 --- a/lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts +++ b/lib/components/primitive-components/Trace/Trace_doInitialPcbTraceRender.ts @@ -277,7 +277,9 @@ export function Trace_doInitialPcbTraceRender(trace: Trace) { const pcbPortB = "pcb_port_id" in b ? b.pcb_port_id : null const minTraceWidth = - trace.getSubcircuit()._parsedProps.minTraceWidth ?? 0.16 + trace._getExplicitTraceThickness() ?? + trace.getSubcircuit()._parsedProps.minTraceWidth ?? + 0.16 const ijump = new MultilayerIjump({ OBSTACLE_MARGIN: minTraceWidth * 2, diff --git a/lib/utils/autorouting/SimpleRouteJson.ts b/lib/utils/autorouting/SimpleRouteJson.ts index b33be75d8..3f40f5275 100644 --- a/lib/utils/autorouting/SimpleRouteJson.ts +++ b/lib/utils/autorouting/SimpleRouteJson.ts @@ -32,6 +32,7 @@ export type Obstacle = { export interface SimpleRouteConnection { name: string source_trace_id?: string + width?: number // Trace width/thickness, falls back to minTraceWidth if not specified pointsToConnect: Array<{ x: number y: number diff --git a/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts b/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts index 74b527317..990198fc3 100644 --- a/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts +++ b/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts @@ -187,6 +187,7 @@ export const getSimpleRouteJsonFromCircuitJson = ({ connMap.getNetConnectedToId(trace.source_trace_id) ?? "", source_trace_id: trace.source_trace_id, + width: trace.min_trace_thickness, pointsToConnect: [ { x: portA.x!, diff --git a/package.json b/package.json index d114e5790..c5ba8f117 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@tscircuit/matchpack": "^0.0.16", "@tscircuit/math-utils": "^0.0.29", "@tscircuit/miniflex": "^0.0.4", - "@tscircuit/props": "0.0.371", + "@tscircuit/props": "0.0.378", "@tscircuit/schematic-autolayout": "^0.0.6", "@tscircuit/schematic-match-adapt": "^0.0.16", "@tscircuit/schematic-trace-solver": "^0.0.41", diff --git a/tests/components/primitive-components/__snapshots__/trace-pcb-path-thickness-with-empty-array.test.tsx-selectors-thickness-pcb.snap.svg b/tests/components/primitive-components/__snapshots__/trace-pcb-path-thickness-with-empty-array.test.tsx-selectors-thickness-pcb.snap.svg new file mode 100644 index 000000000..980cf415f --- /dev/null +++ b/tests/components/primitive-components/__snapshots__/trace-pcb-path-thickness-with-empty-array.test.tsx-selectors-thickness-pcb.snap.svg @@ -0,0 +1 @@ +R1R2 \ No newline at end of file diff --git a/tests/components/primitive-components/__snapshots__/trace-width-alias-pcb.snap.svg b/tests/components/primitive-components/__snapshots__/trace-width-alias-pcb.snap.svg new file mode 100644 index 000000000..980cf415f --- /dev/null +++ b/tests/components/primitive-components/__snapshots__/trace-width-alias-pcb.snap.svg @@ -0,0 +1 @@ +R1R2 \ No newline at end of file diff --git a/tests/components/primitive-components/trace-width-alias.test.tsx b/tests/components/primitive-components/trace-width-alias.test.tsx new file mode 100644 index 000000000..c114a6e77 --- /dev/null +++ b/tests/components/primitive-components/trace-width-alias.test.tsx @@ -0,0 +1,38 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +test("trace width prop works as alias for thickness", async () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + , + ) + + await circuit.renderUntilSettled() + + const pcbTrace = circuit.db.pcb_trace.list()[0] + expect(pcbTrace).toBeDefined() + if (!pcbTrace) throw new Error("Expected trace to be routed") + expect( + pcbTrace.route + .filter((segment) => segment.route_type === "wire") + .every((segment) => segment.width === 0.5), + ).toBe(true) + + await expect(circuit).toMatchPcbSnapshot(import.meta.path) +})