Skip to content

fix(footprint): emit (layer B.Cu) for bottom-layer components#293

Open
gsdali wants to merge 1 commit intotscircuit:mainfrom
gsdali:fix-footprint-bottom-layer
Open

fix(footprint): emit (layer B.Cu) for bottom-layer components#293
gsdali wants to merge 1 commit intotscircuit:mainfrom
gsdali:fix-footprint-bottom-layer

Conversation

@gsdali
Copy link
Copy Markdown

@gsdali gsdali commented May 8, 2026

Summary

When a circuit-json pcb_component has layer: "bottom", the KiCad
exporter currently emits (layer F.Cu) at the top of the resulting
(footprint ...) block. KiCad's pcbnew reads that header line to
populate the footprint's "Board Side" property, so every back-side
component shows up as "Board Side: Front" even though its pads,
silkscreen and paste are correctly placed on B.Cu / B.Paste / B.Mask
inside the same block.

Reproducible on a board with any layer="bottom" component:

<board width="20mm" height="14mm">
  <resistor name="R_BOTTOM" resistance="10k" footprint="0402"
    pcbX={5} pcbY={0} layer="bottom" />
</board>

Output before this PR — R_BOTTOM opens "Front" in pcbnew:

(footprint
  "tscircuit:resistor_0402"
  (layer F.Cu)        ← wrong
  ...
  (pad ... (layers B.Cu B.Paste B.Mask) ...)   ← pads are right

Fix

AddFootprintsStage._step builds the footprint with a hardcoded
layer: "F.Cu". Read component.layer from the circuit-json
pcb_component and map "bottom""B.Cu", everything else
("top", undefined, inner layers) keeps "F.Cu".

const footprintLayer = component.layer === "bottom" ? "B.Cu" : "F.Cu"
const footprint = new Footprint({
  libraryLink: `tscircuit:${footprintName}`,
  layer: footprintLayer,
  at: [...],
  uuid: ...,
})

Total diff: +9 / −1 lines in AddFootprintsStage.ts (most of which
is an explanatory comment), plus a new regression test.

Tests

tests/pcb/basics/basics17-bottom-layer-footprint.test.tsx builds
a board with one layer="top" and one layer="bottom" resistor,
extracts both (footprint ...) blocks from the rendered s-expression,
classifies each by whether any pad inside is on B.Cu, and asserts
the footprint header layer is F.Cu / B.Cu respectively.

The suite goes from 8 pass / 10 fail on main to 9 pass / 10 fail
on this branch
— one more pass (the new test). The 10 pre-existing
failures are PNG-snapshot environmental diffs (KiCad CLI version)
unrelated to this fix; the basics01–basics05 / 06 / 09 / 10 / 14 / 15
PNGs differ on main as well.

Test plan

  • New regression test passes locally
  • Suite count check vs upstream/main: same fail count, +1 pass
  • CI green
  • Reviewer can open the test fixture in KiCad pcbnew and confirm
    the back-side resistor's "Properties → Board Side" reads "Back"

🤖 Generated with Claude Code

When a circuit-json pcb_component has layer "bottom", KiCad needs
the footprint-block header to read (layer B.Cu) so the component
shows "Board Side: Back" in pcbnew. Without this, KiCad falls
through to "Front" — even though the pad-level layers inside the
footprint are correctly emitted as B.Cu / B.Paste / B.Mask by
CreateSmdPadFromCircuitJson.

The header layer was hardcoded to F.Cu in
AddFootprintsStage._step (line 127). Two-line fix: read
component.layer and map "bottom" -> "B.Cu", anything else -> "F.Cu".
"top", undefined, and inner layers all keep the old behaviour.

Tests:
- New regression test
  tests/pcb/basics/basics17-bottom-layer-footprint.test.tsx —
  builds a board with one top-layer and one bottom-layer resistor,
  classifies the two footprint blocks by their pad-level layer,
  and asserts each block's header layer is F.Cu / B.Cu
  respectively.
- All previously-passing tests still pass; the suite goes from
  8 pass / 10 fail on main to 9 pass / 10 fail on this branch
  (one more pass from the new test). The 10 unrelated failures
  are pre-existing PNG-snapshot diffs from KiCad CLI environment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 8, 2026

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

Project Deployment Actions Updated (UTC)
circuit-json-to-kicad Ready Ready Preview, Comment May 8, 2026 4:11am

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