tscircuit / tscircuit/core

Add global board viaTenting prop with per-via overrides, mask rendering and exports

Open
#3,903 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
58
Forks
203
Avg merge
7h 39m
Merged PRs (30d)
286

Description

Versions: tscircuit 0.0.2516, @tscircuit/core 0.0.1892, @tscircuit/props 0.0.649, circuit-json 0.0.484, circuit-to-svg 0.0.413, circuit-json-to-gltf 0.0.118, CLI 0.1.2057, Bun 1.4.2, Linux. Native export comparison uses KiCad 10.0.2.

Request

Please expose via tenting in TSX and carry it consistently into mask-aware SVG/3D rendering and manufacturing exports. Our two-layer board uses local ground vias next to each SMD ground pin and a continuous bottom ground plane. We want both faces of these vias covered by solder mask while connector holes remain exposed.

Primary usage: one global board-level default (proposed API, not currently implemented):

<board viaTenting="both">
  {/* All manual and autorouted vias inherit tenting on both faces. */}
  <via name="GND_U1" pcbX={-1.85} pcbY={0}
    holeDiameter="0.3mm" outerDiameter="0.6mm"
    fromLayer="top" toLayer="bottom" connectsTo="net.GND" />
</board>

The global setting is required for this workflow: users should not have to repeat it on every via. Suggested values: "both" | "top" | "bottom" | "none". Inheritance should reach nested components/subcircuits and all generated routing vias belonging to this PCB; it should not spill into a separate child PCB.

Per-via overrides for exceptions:

<via name="GND_U1" pcbX={-1.85} pcbY={0}
  holeDiameter="0.3mm" outerDiameter="0.6mm"
  fromLayer="top" toLayer="bottom" connectsTo="net.GND"
  tented />

tented would mean both sides. For asymmetric mask requirements, consider tented={{ top: true, bottom: false }}. The board default <board viaTenting="both"> must also apply to autorouter-generated vias, with explicit per-via overrides. Preserve existing behavior when no setting is supplied.

Current observations

  • The installed ViaProps/viaProps schema has no tenting property.
  • Circuit JSON already supports optional pcb_via.is_tented; reuse it for the both-sides case rather than introducing a competing boolean. Per-side support would need a backward-compatible schema extension.
  • circuit-to-svg renders otherwise identical vias with is_tented: true and false identically even with showSolderMask: true. Its createSvgObjectsFromPcbVia always emits exposed copper and drill circles.
  • circuit-json-to-gltf bakes board textures with this SVG path, so our detailed model also shows the vias as exposed.

Minimal texture-path reproduction:

import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
const board = { type: "pcb_board", pcb_board_id: "b", width: 4, height: 4,
  center: { x: 0, y: 0 }, num_layers: 2, thickness: 1.6 }
const via = { type: "pcb_via", pcb_via_id: "pcb_via_1", x: 0, y: 0,
  outer_diameter: 0.6, hole_diameter: 0.3, layers: ["top", "bottom"] }
const render = (is_tented: boolean) => convertCircuitJsonToPcbSvg(
  [board, { ...via, is_tented }] as any,
  { showSolderMask: true, layer: "top" })
console.log(render(true) === render(false)) // true in the versions above

Expected acceptance checks

  • A single board prop tents every manual and autorouted via, including vias inside nested components, without repeating props. Explicit per-via overrides take precedence; a separate child PCB has its own policy.
  • TSX manual vias and board defaults for routed vias preserve explicit mask intent in circuit JSON.
  • Mask-aware top/bottom SVGs and GLB textures show mask coverage on the selected faces. Copper inspection views can still show via copper and drills.
  • KiCad exports preserve front/back tenting; Gerber mask output has no aperture at a tented via. Drill files retain the original plated hole. Tenting must not silently imply filled or plugged vias.
  • Exposed connector pads/plated holes are unaffected.
  • Test omitted settings, explicit false, both sides, one side, and overridden board defaults.

Local workaround: retain real pcb_via records with is_tented: true, set KiCad front/back tenting through its native API, and use mask-covered circular surfaces only in the rendering input. The workaround is not an upstream PR. This issue tracks the requested implementation so another agent need not rediscover the gap.

Related ground-plane workflow issues (different defects): #3901 and #3902.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the ViaProps/viaProps schema and trace how board defaults, nested components, and autorouter-generated vias become Circuit JSON pcb_via records. Inspect createSvgObjectsFromPcbVia in circuit-to-svg and the convertCircuitJsonToPcbSvg path used by circuit-json-to-gltf, then follow the manufacturing export paths. Done means global and per-via settings preserve explicit mask intent across JSON, SVG, GLB, KiCad, and Gerber outputs without changing drills or connector exposure.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
computer-graphics, embedded-iot
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.