Skip to content

Conversation

@RaghavArora14
Copy link
Contributor

Summary

Implements a two-layer soldermask approach for copper pours, following the design discussed with Rishabh. This approach avoids boolean operations and uses SVG layering instead.

Changes

Core Implementation

  • Two-layer soldermask approach: Base board soldermask layer + individual cutout/overlay elements per copper pour
  • No boolean operations: Uses SVG layering and type priorities for correct rendering order
  • Substrate-only support: Copper pours with substrate_only in ID render only substrate cutout (no copper element)

Technical Details

Rendering Order

  1. Base board soldermask (soldermask-top/soldermask-bottom, priority 3)
  2. Soldermask cutouts (pcb_soldermask_opening, type priority 25, on actual copper layer)
  3. Copper elements (traces, pads, pours, type priority 30-35)
  4. Soldermask overlays (pcb_soldermask, type priority 40, on actual copper layer)

Substrate-Only Detection

Copper pours with substrate_only in their ID skip rendering the copper element, showing only the substrate cutout. This allows testing pure substrate areas without copper blending.

Testing

All existing tests pass. New comprehensive test covers:

  • Covered copper pours (with soldermask overlay)
  • Uncovered copper pours (with substrate cutout + copper)
  • Substrate-only areas (pure substrate, no copper)
  • Both top and bottom layers
  • Various shapes (rect, polygon, rotated rect)
image

- Refactor soldermask rendering to use two-layer approach (no boolean operations)
- Fix double sorting issue - now sorts only once at the end
- Extract shared helpers for soldermask cutout/overlay elements (DRY)
- Fix substrate-only rendering - pure substrate without copper blending
- Fix bottom layer priority so copper pours render above base soldermask
- Change bottom soldermask color to green to match top layer
- Add silkscreen labels to test for better visual documentation
- Fix silkscreen text positioning - all labels on top layer for readability
@vercel
Copy link

vercel bot commented Nov 24, 2025

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

Project Deployment Preview Comments Updated (UTC)
circuit-to-svg Ready Ready Preview Comment Nov 25, 2025 6:25pm

@ShiboSoftwareDev ShiboSoftwareDev marked this pull request as ready for review November 24, 2025 19:36
@ShiboSoftwareDev
Copy link
Contributor

there is an inconsistency with what maskLayer is across files

…ng the pattern:

Base board mask (create-svg-objects-from-pcb-board.ts): Uses soldermask-top/soldermask-bottom (the soldermask layer name)
Cutouts/overlays (all other files): Use the actual element layer (top/bottom):
Holes: Use view layer (ctx.layer ?? "top") since they're through-hole
Plated holes: Use the extracted copperLayer from the element
Copper pours: Use the layer parameter
SMT pads: Use pad.layer directly
@RaghavArora14
Copy link
Contributor Author

there is an inconsistency with what maskLayer is across files

Standardized maskLayer usage across files and added comments explaining the pattern:

  1. Base board mask (create-svg-objects-from-pcb-board.ts): Uses soldermask-top/soldermask-bottom (the soldermask layer name)

  2. Cutouts/overlays (all other files): Use the actual element layer (top/bottom):

    • Holes: Use view layer (ctx.layer ?? "top") since they're through-hole
    • Plated holes: Use the extracted copperLayer from the element
    • Copper pours: Use the layer parameter
    • SMT pads: Use pad.layer directly

The distinction is:

  • Base board mask → soldermask-top/soldermask-bottom
  • Individual cutouts/overlays → top/bottom (actual copper layer)

Copy link
Contributor

@ShiboSoftwareDev ShiboSoftwareDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one time it's this:
const maskLayer = layer ?? "top"
and another time it's this:
const maskLayer = ctx.layer === "bottom" ? "soldermask-bottom" : "soldermask-top"
it should be consistent for clarity

…ayer to a layer variable first, then derive maskLayer from it. Replaced all copperLayer references with layer in the plated hole file to match the pattern and fix TypeScript errors.
@RaghavArora14
Copy link
Contributor Author

one time it's this:
const maskLayer = layer ?? "top"
and another time it's this:
const maskLayer = ctx.layer === "bottom" ? "soldermask-bottom" : "soldermask-top"
it should be consistent for clarity

Fix: Standardized maskLayer determination across files: extract the layer to a layer variable first, then derive maskLayer from it. Replaced all copperLayer references with layer in the plated hole file to match the pattern and fix TypeScript errors.

…k in SMT pads and panel files

Standardized maskLayer derivation pattern:
All files now extract layer first, then derive maskLayer from it
Board file: maskLayer = layer === "bottom" ? "soldermask-bottom" : "soldermask-top"
Other files: maskLayer = layer
Fixed SMT pads file:
Added const layer = pad.layer and const maskLayer = layer
Replaced all pad.layer references with layer or maskLayer as appropriate
Standardized data-pcb-layer usage:
Copper elements always use layer
Soldermask elements always use maskLayer
Fixed plated hole file:
Replaced all copperLayer references with layer
Added missing data-pcb-layer: maskLayer to 4 soldermask elements that were missing it
Removed direct property access:
No more pad.layer or ctx.layer in data-pcb-layer attributes
All use extracted layer or maskLayer variables
Added clarifying comments explaining when to use layer vs maskLayer in each file
@RaghavArora14
Copy link
Contributor Author

  1. Fixed variable naming typo: shouldshowSolderMaskshouldShowSolderMask in SMT pads and panel files
  2. Standardized maskLayer derivation pattern:
    • All files now extract layer first, then derive maskLayer from it
    • Board file: maskLayer = layer === "bottom" ? "soldermask-bottom" : "soldermask-top"
    • Other files: maskLayer = layer
  3. Fixed SMT pads file:
    • Added const layer = pad.layer and const maskLayer = layer
    • Replaced all pad.layer references with layer or maskLayer as appropriate
  4. Standardized data-pcb-layer usage:
    • Copper elements always use layer
    • Soldermask elements always use maskLayer
  5. Fixed plated hole file:
    • Replaced all copperLayer references with layer
    • Added missing data-pcb-layer: maskLayer to 4 soldermask elements that were missing it
  6. Removed direct property access:
    • No more pad.layer or ctx.layer in data-pcb-layer attributes
    • All use extracted layer or maskLayer variables
  7. Added clarifying comments explaining when to use layer vs maskLayer in each file

@ShiboSoftwareDev
Copy link
Contributor

update snapshots

@RaghavArora14 RaghavArora14 force-pushed the fix/copper-pour-soldermask-two-layer branch from be10fb0 to ecb8327 Compare November 25, 2025 15:34
Copy link
Contributor

@seveibar seveibar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not obfuscate, there is a ton of it. Eg layer = pad.layer

Copy link
Contributor

@seveibar seveibar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is getting better

@RaghavArora14
Copy link
Contributor Author

done all changes

@ShiboSoftwareDev ShiboSoftwareDev merged commit 8a076ff into tscircuit:main Nov 25, 2025
7 checks passed
@tscircuitbot
Copy link


Thank you for your contribution! 🎉

PR Rating: ⭐⭐⭐
Impact: Major

Track your contributions and see the leaderboard at: tscircuit Contribution Tracker


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.

5 participants