CtrlK
BlogDocsLog inGet started
Tessl Logo

replicator-pcb

Use before Project Replicator PCB source, layout, routing, DRC, fabrication, or PCB visual-review work.

67

Quality

81%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Replicator PCB

This skill owns Replicator-specific PCB source authority, layout, routing, DRC, visual review, and fabrication policy. Load the separate tscircuit skill for upstream tscircuit syntax, elements, and CLI behavior.

Replicator uses tscircuit as the editable circuit, footprint, and placement source layer. pcb.run(profile="preview") compiles and renders placement previews. pcb.run(profile="check") compiles the netlist, routes it with bundled Freerouting, backports routed copper into authoritative Circuit JSON, runs deterministic checks plus KiCad DRC, and publishes a Build. pcb.run(profile="release") exports every manufacturing deliverable from that Build into one package and records per-deliverable readiness in sections.

Release is the only profile that runs KiCad's exporters, so Gerbers, drill files, assembly.step, and assembly.glb do not exist until a release is published — a Build holds the routed board, its previews, and the component 3D-model libraries, not the board's own geometry. Finish a board-design request with a release rather than a ready check; release takes no target, and the pipeline skill's Required Read Order item 6 governs how to report what it published.

Local API References

  • Load tscircuit before authoring or revising tscircuit TSX.
  • Read references/built-in-elements.md and references/footprints.md for Replicator-specific integration notes, verified runtime behavior, footprint constraints, and local component-library policy.
  • Read references/pcb-config.md before editing source/pcb.config.json. It is the full accepted shape of every field, including the exception lists (allowedOverlaps, allowedViaInPadComponents, footprintExceptions, keepouts, net escape rules). The file is parsed strictly, so a guessed shape fails the run — look it up there rather than probing the installation.
  • Treat the vendored upstream tscircuit skill plus the installed @tscircuit/props package as the source of truth for general tscircuit JSX/API syntax.
  • If syntax is uncertain, prefer a small editable source change followed by pcb.run(profile="preview") or pcb.run(profile="check") diagnostics over guessing online documentation paths.

Source Ownership

  • design/<design>/source/main.tsx owns components, footprints, nets, ports, and source traces.
  • design/<design>/source/layout.ts owns reusable board dimensions, coordinate helpers, mounting holes, keepouts, and placement constants.
  • design/<design>/source/pcb.config.json is the only routing-policy source. It owns the manufacturing profile, eight semantic net classes, per-net evidence, automatic GND pours, stitching vias, keepouts, BOM bindings, and placement/orientation intent.
  • Generated files under generated/current, build/, previews/, kicad/, and reports/ are backend feedback. Read them for diagnostics, but make durable fixes in source/main.tsx, source/layout.ts, source/pcb.config.json, or another declared editable source contract.
  • pcb/<design>/release/ appears once a release is published: a readable copy of that release's Gerbers, drill files, previews, JLC SMT BOM/CPL and manifests. It is derived — the release itself is frozen and hashed elsewhere, so editing this copy changes nothing. assembly.step is included whenever the mechanical section published, so CAD can import it directly. Render-only GLB stays in the immutable release package and is listed by release-manifest.json. A file that is absent is absent because its section is blocked; release-manifest.json says which and why. pcb.export writes one section on its own to pcb/<design>/release/packages/<section>.zip when a single upload needs just that deliverable.

Existing CAD after a PCB Release

When a PCB Release completes and design/ contains a model, inspect each current document.json for assets[].provenance.pcbRelease. Compare the recorded Release with the newly published Release before ending the PCB query.

  • Report a CAD concern when board outline, thickness, holes, cutouts, mounting, enclosure-facing connector/control/display/microphone placement, component height, cable access, acoustic paths, thermal space, or an enclosure clearance changed.
  • Treat copper routing, vias, pours, net names, internal labels, and firmware-only edits as compatible unless the actual released assembly shows a physical change.
  • Check an internal component or package move against the existing enclosure clearance. Placement movement by itself does not prove an enclosure change.
  • Name the changed PCB feature and the CAD feature it can affect. Do not emit a generic stale-CAD warning.
  • This check can report needed CAD follow-up. It does not enter the CAD stage or authorize editing the model.

Connectivity Diagnosis And Minimal Repair

Treat generated routing advice as a hypothesis, not a proven root cause. Before changing placement, widths, footprints, nets, or components for an incomplete connection:

  1. Read the editable source connection and identify the intended net and whether a source-owned pour is supposed to complete it.
  2. Inspect build/circuit.json to distinguish one logical source_port/pcb_port from its physical pad shapes and confirm that every shape carries the intended net.
  3. Inspect the generated DSN/SES to see the actual emitted pin count, width, clearance, and routed clusters. A declared escape.widthMm does not prove that the DSN used it.
  4. For a source-poured ground net, let pcb.run(profile="check") defer Freerouting completion, materialize the zones, and use the final filled-board connectivity plus KiCad DRC as authority. Verify that every required pad shape touches same-net copper; do not diagnose an SES-level ground ratsnest as a trace-routing failure.
  5. Only after those checks, change editable placement, zone connection style, cutout/keepout geometry, footprint semantics, or evidenced routing rules and rebuild.

Keep routing repair topology-stable. A routing, zone, placement, or footprint-connectivity repair must not add components, split a net, or change the BOM unless the original electrical design intent independently requires that topology. In particular, do not insert a link or create an escape net merely to make separated shapes of one logical ground terminal routable; first bind the logical pin directly to the intended ground net and test the completed pour.

When several plausible fixes exist, try the smallest reversible source change first and compare fresh build evidence. Prefer, in order: restore intended net binding and pour completion; adjust solid/thermal zone connection; adjust placement or mechanical clearance; correct logical pad grouping; then replace a footprint proven geometrically wrong. Do not redraw a footprint solely because one logical pin uses several physical shapes.

Copper Pour Islands: Locate Before Editing

Treat isolated_copper, filled-zone unconnected, zone-to-itself, and zone-to-zone findings as local layout/connectivity defects by default. They are not evidence that the board's global manufacturing rules are too strict.

Before changing editable source, require actionable location evidence for the actual disconnected filled-copper component:

  1. Identify its net, layer, zone name, and filled-polygon/lobe centroid, representative point, or bounding box.
  2. Inspect the nearby pads, vias, tracks, keepouts, cutouts, and board edge to find what severed the return path.
  3. Distinguish a filled-copper location from zone metadata. A repeated zone anchor/origin, a zone-to-itself record with the same UUID/reference, or the position of the whole zone does not locate the island and must not be used as a stitching-via coordinate.
  4. If the automated report identifies only the zone and cannot locate the disconnected filled polygon, stop speculative source edits and report copper_island_location_unavailable. The required next action is improved polygon-level diagnostics or inspection in a local KiCad connectivity view, not another guessed configuration change.

Repair the localized geometry in this order:

  1. Move or rotate movable parts, reroute the track that pinches off the pour, adjust a local keepout/cutout, or add a deliberate same-net copper neck so the filled region joins the intended return path.
  2. Add one targeted GND via only when the diagnosed location and same-net copper on another layer prove that the via will bridge the disconnected component. Stitching vias are through vias spanning the whole stack, so on a multilayer board the bridging copper may be on any other layer, not only the opposite face. Record the evidenced coordinate in the editable layout source.
  3. Remove a genuinely unnecessary isolated lobe, or remove an unused pour layer when the electrical design does not require it.
  4. Change footprint pad or zone-connection semantics only when generated geometry proves them wrong.

Do not lower global pour/track clearance, board-edge clearance, via pad/drill floors, or the manufacturing profile merely to make an island diagnostic disappear. Do not add scattershot stitching-via arrays. source/pcb.config.json may own a diagnosed stitching-via coordinate or another declared layout policy, but the fact that a value is configurable is not evidence that changing it is the correct repair. Make one localized hypothesis at a time, rerun pcb.run(profile="check"), and confirm the original filled-copper component is now connected without creating a new island.

Layout Changes During Routing

  • Treat routing congestion and repeated autorouter failure as layout feedback. Placement is editable unless product, enclosure, interface, antenna, thermal, or verified mechanical evidence fixes it.
  • Before routing, classify components and regions as fixed, constrained, or movable. Preserve fixed interfaces and hard mechanical geometry; freely move or rotate movable passives, small actives, and functional blocks when that shortens crossings or opens routing channels.
  • Do not preserve arbitrary coordinates merely because they already exist. When a route cannot pass cleanly, the first thing to try is more room: widen the pitch inside the crowded block and push its neighbours away. Repeated failures concentrated in one region almost always mean that region is too dense for the nets crossing it, not that the router needs help there. Only after spacing has been opened should rotation, block rearrangement, or board geometry change — and tightening fabrication rules or adding vias to squeeze through comes last.
  • A layout repair is not a topology change. Keep nets, component identities, and BOM stable unless independent electrical evidence requires a circuit version.
  • After every material placement change, rerun the appropriate profile and inspect fresh top and bottom previews. Compare the result against fixed interface, side, orientation, keepout, and assembly constraints.

Authoring Rules

  • Express PCB placement with tscircuit layout props such as pcbX, pcbY, pcbRotation, and layer. Schematic placement is different — see "Schematic Layout" below.
  • tscircuit net names must start with a letter or underscore. Do not create nets such as net.3V3; use net.V3V3, net.VDD_3V3, or another descriptive non-numeric prefix. Component pin labels may still be 3V3; only the net identifier must avoid a leading digit.
  • Keep board geometry and mechanical coordinates in named constants or helpers, not scattered literals.
  • Define the board's side semantics before placing components. Unless the user or product constraints say otherwise, top is the user-facing/front side and bottom is the service/back side.
  • Keep side intent in source-level constants, for example primarySide, serviceSide, display.side, display.fpc.side, xiao.side, and keys.side; do not let component sides be implied by copied footprint defaults.
  • Place board outline and mounting holes first, then major modules, external connectors, displays, switches, decoupling, and deliberate debug/service test points.
  • Lay out passives and small actives as functional blocks, each block in its own region, keeping rotations consistent where assembly permits. Size the gaps by what has to route through them, not by how tight the block can look. One default-width signal trace needs roughly 0.8 mm of body-to-body gap (0.3 mm track plus 0.25 mm clearance on each side), so a 0.5 mm gap passes nothing at all. Count the nets that must leave or cross the block, divide by the sides they can escape through, and leave that many channels; for 0402 passives with a few escapes that usually means 2–4 mm between bodies. Start generous and tighten only where you can name the reason. Never let two components' bodies overlap; pcb.run(profile="check") blocks on component_body_overlap gate errors computed from component bboxes and courtyards. For deliberately stacked geometry only, declare the pair in source/pcb.config.json allowedOverlaps.
  • Separate analog and sensitive measurement blocks from noisy digital clocks, switch nodes, high-current drivers, and thermal sources. Keep decoupling at its supply pins, protection at the interface entry, and power components in current-flow order. Preserve a continuous ground-return path rather than routing a signal across a split or cutout.
  • Derive mounting keepouts from declared fasteners: use at least 3.5mm component keepout from an M2.5 screw center and 4mm from an M3 screw center, plus at least 1mm routing keepout around mounting/non-routing holes unless verified mechanics require more. Encode connector insertion, shield, antenna, enclosure, and board-edge access regions explicitly.
  • Keep heat-generating parts away from temperature-sensitive or precision components, keep metal bodies/shields clear of components and exposed conductors, and make pin-1/polarity marking directions visually consistent where assembly permits.
  • Do not impose a blind global 5 mm component-to-edge rule. Edge connectors, antennas, LEDs, controls, and other edge-coupled parts are declared mechanical exceptions. Fine-pitch and high-speed routing exceptions must name the affected nets/references and cite land-pattern or impedance evidence.
  • Group components by function, not by appearance: a sensor with its coupling and decoupling parts, an amplifier with its gain network, a supply with its bulk and bypass caps. Parts that share a signal path belong near each other because it shortens that path, and the arrangement is only worth keeping if the group's nets can still escape it. Place each part at the coordinate its own connections call for; a group is a region and a signal order, not a repeating pitch. Name the reason in a comment when a part sits where it does because of a hard constraint (a specific pin/pad, the board edge, an acoustic opening).
  • Preserve logical component names across source, BOM, KiCad, and manufacturing outputs, such as U_XIAO, J_LCD, R_BL, SW_KEY1, or MH1.
  • Use generated footprints when needed, but keep them manufacturing-clean: avoid decorative silkscreen, hide unnecessary reference/value text, and preserve only useful pin-1, polarity, or orientation marks.
  • Prefer tscircuit source semantics over KiCad postprocessing: use <hole /> for NPTH mechanical holes, <platedhole /> for electrical through-holes, <cutout /> for board slots/cutouts, and <copperpour /> for copper zones. Do not expect backend scripts to infer these from generic KiCad pads.
  • HARD RULE — footprint chirality: author every custom <footprint /> in the part's native top-side orientation from the datasheet or supplier footprint. NEVER transcribe footprint coordinates from generated artifacts (build/circuit.json, .kicad_pcb, placement CSVs, previews) for a layer="bottom" component — those coordinates are already mirrored, and copying them bakes a chirality flip into the footprint that no build, preview, netlist, or DRC check can catch. A mirrored microphone footprint created exactly this way reached JLCPCB order review with electrically scrambled pins. See "HARD RULE: author footprints in native top-side orientation" in references/footprints.md before hand-drawing any footprint.
  • Never judge chirality from a bottom-side image. Bottom views come in two camera positions and the images are mirror twins, so the same picture proves either "correct" or "flipped" depending on which one you were handed. Every bottom image carries viewpoint: from_top looks through the board and shares its X axis with build/circuit.json, the Gerbers and the drill file; from_bottom is the KiCad-style mirrored plot, which pcb.view(source="routed") and previews/pcb-routed-bottom.png both use, while previews/pcb-bottom.png uses from_top. Read that field before comparing anything, and settle a real chirality question against the drill file and board-B_Cu.gbl, which have no camera.

Schematic Layout

Schematic placement in this pipeline is fully automatic. You choose the grouping; tscircuit chooses the coordinates and draws the wires.

  • HARD RULE — never declare schX or schY. pcb.run blocks on schematic_manual_placement_declared when the schematic source contains either prop. This is not a style preference: tscircuit only auto-arranges a group when nothing inside it carries manual schematic coordinates. One schX anywhere drops the whole group back to relative placement, and every component you did not place by hand lands on its default position — the failure looks like one tidy cluster beside a column of stranded symbols, with the readable part shrunk because the renderer fits the entire drawing into the canvas.
  • Express grouping with schSectionName instead. Each section is auto-arranged on its own and the sections are then placed in rows, so functional grouping survives without a single coordinate. Group by function — a sensor with its coupling and decoupling parts, a supply with its bulk and bypass caps — the same way you would group on the PCB.
  • schRotation and schOrientation are allowed. They set symbol direction and do not affect the layout mode.
  • Use <schematicsheet /> / <schematicbox chipRef="..." /> when one large chip has to appear on several sheets. See the tscircuit skill's <schematicbox /> reference.
  • Do not add matchAdapt, flex, grid, or pack without a sch prefix. The unprefixed props are read by both the schematic and PCB layout modes, so they silently change PCB placement too. If a schematic layout mode has to be forced, use schMatchAdapt or schLayout.
  • Review the result, do not pre-empt it: run the check, look at previews/schematic.png, and if it is unreadable fix the grouping (section membership, sheet split), never the coordinates.

Verified Production Export Support

These capabilities were smoke-tested against the installed Replicator runtime (@tscircuit/eval@0.0.955 and circuit-json-to-kicad@0.0.153):

  • <hole /> builds as pcb_hole and exports to KiCad as np_thru_hole.
  • <platedhole /> builds as pcb_plated_hole and exports to KiCad as numbered thru_hole.
  • footprint="jlcpcb:Cxxxx" can load supplier footprint geometry and available 3D model URLs into KiCad. It does not reliably populate procurement identity, so preserve matching supplierPartNumbers and BOM bindings explicitly.
  • JLCPCB and LCSC share the Cxxxx catalog identity, but the installed tscircuit runtime only provides the jlcpcb: footprint-loader namespace. Do not use footprint="lcsc:Cxxxx"; normalize LCSC identity separately while loading geometry through jlcpcb:Cxxxx.
  • Every resolved JLC/LCSC STEP is materialized and occurrence-checked in the final assembly STEP. Models in the verified registry additionally enforce filename, SHA-256, and applicable transform checks.
  • An incomplete mechanical SMT verification gate is an evidence workflow, not proof that the footprint is wrong. Execute the diagnostic's details.agentChecks in the current query; never give that list to the user as instructions. Resolve details.requiredUserConfirmations from explicit authoritative user input and ask only what remains. Set assembly.jlc_smt_verified after supplier identity, footprint, origin, side, holes/slots, Pin 1, mating direction, bottom-side mirror conversion, and expected CPL rotation are locally evidenced, then generate the JLC PCBA order package. The JLC website placement preview is the post-export confirmation: ask the user only to upload the generated Gerber, JLC BOM, and JLC CPL and return the placement screenshot. Do not say it is safe to pay until that screenshot has been checked.
  • Custom pads-only footprints do not bring 3D models unless the component also carries an explicit cadModel. Fabrication export emits cad_model_missing diagnostics when a supplier-backed component has no model source in circuit JSON; assembly.glb / STEP may omit the body. This is an advisory 3D assembly-preview completeness issue, not a PCB fabrication gate: some valid supplier parts do not have available 3D models.
  • footprint="kicad:Library/Footprint" can load KiCad cache geometry into KiCad output. Use slash form, not kicad:Library:Footprint.
  • kicadFootprintMetadata.attributes exports KiCad attributes such as smd, exclude_from_bom, and exclude_from_pos_files.
  • <cutout /> exports to KiCad Edge.Cuts.
  • <copperpour /> exports to a KiCad zone.
  • <keepout /> builds as pcb_keepout, but this converter version does not export it as a KiCad rule area. Treat keepouts as source/preview/agent intent unless a later fixture proves KiCad export support.
  • <drccheck /> adds source-level product rules to tscircuit's built-in PCB checks. Final KiCad DRC remains an independent export verification.

Orientation Intent

  • Do not rely on default footprint orientation for modules or connectors. Express the functional orientation in named layout constants, then map it to pcbRotation.
  • Comment strings such as openingFaces: "left-edge/-X" in layout.ts do not enforce orientation. They are not machine-checked unless mirrored in source/pcb.config.json and mapped through rotationForOpening().
  • For every connector with a cable/opening direction requirement, declare intent in design/<design>/source/pcb.config.json with nativeOpening, targetOpening, and expectedLayer, then set pcbRotation from rotationForOpening(nativeOpening, targetOpening) in layout.ts.
  • When using footprint="jlcpcb:Cxxxx", confirm the supplier footprint's native opening direction from preview inspection or the datasheet before choosing rotation. Supplier footprints do not carry opening-direction metadata.

Supplier Footprint Rotation

Rotate a resolved supplier footprint as one component placement with pcbRotation. Keep the exact supplier binding unchanged so pads, holes, silkscreen, courtyard, and the component identity continue to come from one supplier source:

<connector
  name="J1"
  standard="usb_c"
  footprint="jlcpcb:C165948"
  supplierPartNumbers={{ jlcpcb: ["C165948"] }}
  layer="top"
  pcbRotation={rotationForOpening("up", usb.targetOpening)}
/>
  • Use pcbRotation for the connector's physical direction on the board. Treat 0, 90, 180, and 270 as placement choices around the component origin, not as changes to the supplier land pattern.

  • For a bottom-side part, set layer="bottom" and the required pcbRotation. Let tscircuit and the fabrication exporter perform the side mirror. Do not pre-mirror or rewrite supplier pad coordinates.

  • Never rotate a supplier footprint by copying its pads into an inline <footprint />, wrapping it in a generated footprint, or passing a transformed footprint expression. Those forms create a second physical source and exact supplier-backed connectors fail source validation.

  • JLC CPL export automatically compares the authored footprint's Pin 1 frame with the resolved EasyEDA/JLC supplier footprint's Pin 1 frame. It applies the resulting quarter-turn correction after converting top or bottom placement into the JLC frame. Diodes and LEDs are excluded because their supplier physical Pin 1 may be remapped to preserve anode/cathode polarity. A relationship that requires reflection fails export with jlc_smt_orientation_incompatible; inspect the footprint and pin mapping instead of guessing an angle.

  • Use BOM assembly.jlc_smt_rotation_offset only when supplier/JLC evidence shows that the automatic Pin 1 correction is unavailable or the tape zero differs from the supplier library zero. Use assembly.jlc_smt_rotation only when the required absolute CPL angle is known and all populated instances for that BOM item share it. Keep pcbRotation unchanged when correcting only this assembly-machine angle; release export cross-checks the final CPL value.

  • Use cad_model.rotation_offset_deg or the verified supplier-model registry transform when only the 3D body is misaligned. Keep the 2D supplier footprint and its pcbRotation unchanged.

  • If the supplier footprint itself has wrong pads, holes, numbering, or origin, stop and report the exact failed evidence. Repair the supported supplier binding or verified footprint library explicitly; do not hide the defect behind a per-design inline footprint.

  • Do not replace a supplier-backed connector with a custom pads-only footprint merely to control cable/opening direction. Use the supplier footprint first, then adjust pcbRotation and source/pcb.config.json. If the external footprint fails to load or is proven mechanically wrong, follow the evidence-and-library repair above instead of switching the exact supplier-selected component to inline geometry.

  • pcb.run(profile="check") emits orientation_intent_mismatch gate diagnostics and reports blocked when declared intent does not match circuit JSON placement. Fix rotation or intent evidence before claiming the connector faces the requested edge.

  • For dev modules such as XIAO, ESP32 boards, sensor modules, or display carrier boards, define the long-axis orientation and external access direction, such as longAxis: "vertical" and usbFaces: "right-edge".

  • For FPC/FFC, USB-C, JST, headers, sockets, and similar connectors, define the cable/opening direction and pin-1 direction, such as cableExits: "top" and pin1: "left".

  • Prefer named rotation constants or small helpers over raw 0, 90, 180, or 270 literals when a footprint's default orientation is not obvious.

  • In previews, verify that the visible footprint orientation matches the functional intent. If every major part appears with the same default horizontal orientation, treat that as a source placement/orientation issue and fix layout constants or footprint rotation mapping.

Side And Interface Placement

  • Treat user-facing mechanical interfaces as placement constraints, not routing conveniences. Do not move the display FPC, buttons, USB access, sockets, or service connectors to the opposite side just because routing is easier.
  • For a board with a front display, encode the display envelope on the front side and place the FPC connector according to the display's actual tail/connector geometry: side, edge, cable exit direction, and pin-1 direction. If the display datasheet or user notes do not define where the FPC tail exits, report display_fpc_side_unknown and do not claim layout quality.
  • If the visible screen is on top, do not put J_LCD on bottom unless the source also explains that the display tail passes through/around the PCB to a back-side connector and the preview shows the required access path, clearance, and orientation.
  • For dev modules such as XIAO, choose top or bottom from the product assembly: USB/service access may justify bottom-side placement, but the source must still preserve the requested USB-facing edge and long-axis orientation.
  • For MX/key products, the keycap/switch centers and shaft holes are user-facing placement constraints. A hot-swap socket may be on the back side, but the top-side key outline, center hole, locator holes, and keepout must align to the user-facing key positions.
  • Passives, pullups, decoupling, and deliberate test points may usually live on the service/back side. That does not make it acceptable to place every major interface on the back side.
  • Before finalizing a layout, produce a mental side map: what is on the front, what is on the back, which edge each connector faces, and how the user-visible parts assemble. If the side map contradicts the product intent, edit the source before routing/export.

Electromechanical Footprints

  • Treat switches, hot-swap sockets, board-edge connectors, FPC/FFC connectors, USB-C receptacles, battery holders, headers, sockets, and mounting hardware as mechanical parts with electrical nets, not as pads-only symbols.
  • If a part needs insertion, alignment, retention, strain relief, shield tabs, board cutouts, or keep-clear regions, encode those physical features explicitly in editable tscircuit source or local footprints: NPTH/PTH holes, plated slots, cutouts, keepouts, courtyards, side/layer, and orientation.
  • For exact LCSC/JLC or manufacturer part numbers, use parts.detail before relying on datasheet, pinout, package, supplier parameters, or JLC SMT library claims. When it caches a datasheet PDF, inspect it with pdf.read or pdf.render_pages before authoring or approving high-risk footprints.
  • When a supplier or KiCad footprint is authoritative, use jlcpcb:Cxxxx or kicad:Library/Footprint rather than recreating standard pad geometry by hand. For a tscircuit connector with no explicit footprint, supplierPartNumbers may resolve the same exact supplier part through the parts engine. Keep one physical source: never attach an inline or unrelated footprint beside that supplier selection. If the external footprint fails to load, report the load failure and repair the binding.
  • For keyboard switches or hot-swap sockets, do not hand-draw pad/hole coordinates in main.tsx. Use the scaffolded <HotSwapKeySwitch /> component from source/lib/footprints/index with a supported switch/socket pair such as switch="mx" socket="c41430893" or switch="choc_v1" socket="kailh_choc_v1". Supported parts may deliberately use verified local pads/holes plus an independently bound supplier STEP when the supplier footprint carries mechanically invalid courtyard data; never delete the cadModel merely to replace the 2D footprint. Do not edit copied source/lib/footprints/** inside a design package for durable fixes; update the source component in resources/footprints/key-switch/HotSwapKeySwitch.tsx and let internal library maintenance propagate it without reinitializing the existing design.
  • For XIAO boards, do not hand-draw pad coordinates or use a generic pinrow/footprinter string. Use <XiaoEsp32S3 /> for the exact XIAO ESP32S3 vendor-v2 model and <XiaoRp2040 /> for the exact XIAO RP2040 vendor-v26 model. XiaoRp2040 supports the official through_hole_header and direct_smd carrier geometries; the SMD form also exposes BAT and debug pads. Do not reuse either binding for ESP32C3, nRF52840, SAMD21, or another XIAO identity. Durable fixes belong in resources/footprints/xiao/XiaoEsp32S3.tsx or resources/footprints/development-boards/DevelopmentBoards.tsx and then propagate through internal library maintenance.
  • Treat a mounted core/development board's exact STEP as part of its PCB footprint definition. The footprint's pcbX, pcbY, pcbRotation, and layer must drive the model transform, and KiCad fabrication export must produce an assembly.step that already contains the aligned board. A pads-only core board is a blocking source defect; do not defer normal core-board insertion to a later CAD assembly step.
  • Adding or correcting a built-in 3D model is not authorization to change an existing PCB layout. Built-in library migration is internal maintenance and must preserve editable source intent. After a migration, rerun pcb.run(profile="check"), inspect the routed previews, complete a fresh PCB check, then use pcb.run(profile="release").
  • For directly soldered Espressif modules, use the scaffolded <Esp32S3Wroom1 /> or <Esp32Wroom32E /> only for that exact module. They pair the official KiCad RF_Module footprint with the matching bundled Espressif STEP. Do not use either module component or STEP as a substitute for a complete ESP32 DevKitC/development board.
  • Use <RaspberryPiPicoR3 />, <ArduinoNanoRev3 />, or <RaspberryPi4ModelB /> for those exact development boards. Each component pairs verified pin labels and carrier geometry with its registered complete-board STEP. Pico exposes THT, reflow SMD, and hand-solder SMD mounting variants. Pi 4B includes the four official mounting holes and 40-pin GPIO header coordinates.
  • Raspberry Pi Zero 2 W, ESP32 DevKitC, and STM32 Nucleo-F401RE remain unavailable as mounted PCB components because no complete, redistributable exact board STEP is bundled. Their catalog rows contain official mechanical sources and cad_model_missing_reason; do not substitute a related board, an RF-module-only STEP, an empty PCB, or a placeholder solid.
  • Any footprint you hand-author (custom <footprint /> with <smtpad />/<platedhole />/<hole />) MUST include a silkscreen body outline, a pin-1 marker, and — when the part has a mating face (connector, cable exit, polarized part) — an explicit connector-direction marker. Bare-pad footprints with no silkscreen are unreviewable: previews are the verification mechanism for orientation and footprint correctness, and a pads-only footprint gives the preview nothing to show. Treat a hand-authored footprint with no silkscreen as custom_footprint_unverified regardless of whether it builds. When the physical body extends beyond the pad extents, also add a <courtyardrect> covering the full body so the component_body_overlap gate and KiCad courtyard DRC can detect parts placed under the module body.
  • For supplier-backed hot-swap sockets supported by the local library, keep using <HotSwapKeySwitch />; the library must preserve the verified socket pads, switch-center mechanical holes, alignment logic, and required supplier STEP binding as one abstraction. The 2D geometry may be local when the supplier footprint has invalid courtyard data, but its independent cadModel binding must remain. Do not replace it with a bare supplier socket footprint unless the product no longer needs the paired switch geometry.
  • If a keyboard switch/socket combination is unclear, query the local component library the same way you would inspect a frontend component library: read design/<design>/source/lib/footprints/index.ts to find exported components, then read design/<design>/source/lib/footprints/HotSwapKeySwitch.tsx for prop types, legal switch/socket combinations, footprintFamily, compatibleParts, and examples. For durable library changes, edit the source copy under resources/footprints/; do not reinitialize an existing design package.
  • Declare socket BOM compatibility explicitly in source/pcb.config.json under bomBindings with footprintFamily. The bound LCSC code must appear in that family's compatibleParts evidence list before check or JLC SMT export can pass.
  • Use known generic footprints, verified local component libraries, datasheets, or explicit source geometry. If the exact footprint source or dimensions are unavailable during source authoring, report custom_footprint_unverified and do not claim fabrication readiness.
  • After pcb.run(profile="check") or release, inspect the generated .kicad_pcb, drill report, or fabrication readback to confirm expected mechanical holes, slots, and cutouts exist for each electromechanical footprint.

Test Points

  • If constraints request test points, implement them deliberately; do not ignore them, but do not scatter a long unexplained row across the user-facing layout.
  • Put test points in a named debug/service region in layout.ts, usually on the non-user-facing side unless the user or fixture access requires top-side pads.
  • Group and label test points by purpose, such as power, display, keys, or programming. Keep them out of display, keycap, connector-access, mounting, and enclosure-contact regions.
  • If test points remain visible on the primary side, state the reason in the layout/source intent and verify the preview still reads as a product layout rather than a debug breakout board.

Visual Review

  • Preview files existing is not the same as visual review passing.
  • Visual inspection is required before PCB check. Generated previews alone do not prove that connector direction, board-edge access, side assignment, or assembly intent is correct.
  • pcb.run(profile="check") surfaces routed Circuit JSON and PCB design-rule errors from build/circuit.json (for example pcb_trace_error) as production build gates.
  • Fix genuine routing, connectivity, clearance, placement, or footprint problems in editable source. Do not delete functional components or substitute an unverified footprint merely to make a diagnostic disappear.
  • After the latest source/layout change and latest pcb.run(profile="check"), inspect the returned current PCB top, PCB bottom, and schematic PNG artifacts before saying the layout is acceptable.
  • Look for unexplained footprints or test-point rows, wrong side/orientation, missing holes/cutouts, edge-access mismatch, all-major-interfaces-on-one-side mistakes, and obvious visual contradictions with PRD/user sketches. Build errors are reported as structured diagnostics rather than a full-screen preview text overlay.
  • Review the schematic for readability, not just correctness: reference designators legible, related parts sitting together, no cluster stranded far from the rest of the drawing, no large empty region carrying the scale. Schematic layout is automatic, so the repair is always to the grouping (schSectionName membership, sheet split) — see "Schematic Layout".
  • Explicitly compare top and bottom previews against the side map. If the product has a front display but the display FPC, MCU, switches, and service pads all appear on the back with no source-level assembly reason, treat that as a layout defect even if build, DRC, and routing pass.
  • If the final preview was not inspected, was inspected only partially, or changed after inspection, say visual_review: not_performed, partial, or stale; do not claim visual confirmation.

Preview Loop

After source edits:

  1. Run pcb.run(profile="check").
  2. Inspect its automatically generated previews/pcb-top.png, previews/pcb-bottom.png, and previews/schematic.png. Do not read SVG text as visual inspection; use SVG only as a fallback if PNG conversion failed. Use pcb.view with focus.refs for connector or dense-area placement checks; after check, use the same authoritative routed source and explicit layers for close copper/silkscreen review. The top and bottom previews show only the outer faces, so on a multilayer board request In1.Cu/In2.Cu explicitly — inner copper is otherwise never looked at.
  3. Fix wrong side, wrong orientation, connector/cable/USB facing mismatch, board-edge mismatch, overlap, missing electromechanical holes/cutouts, mounting-hole problems, connector access, or mechanical contradictions in editable source.
  4. If previews clearly contradict intent, fix source before claiming layout acceptance. Do not launch PCB check or pcb.run(profile="release") with unresolved visual risk.

3D previews come from the KiCad/STEP backend after fabrication export. Gerber previews are manufacturing verification after KiCad export. They are not the primary source layout view.

A missing supplier 3D model may make the 3D preview incomplete, but it should not block PCB completion by itself. Do not claim the 3D assembly is complete when cad_model_missing exists; do continue fabrication readiness checks through routed source build, final KiCad DRC, side/orientation, BOM, placement, Gerber, and drill evidence.

External procurement and user-supplied parts are also non-blocking when their exact design-critical identity, specifications, footprint, PCB binding, and assembly method are established. Surface missing purchase links, order screenshots, stock, and price as reminders; do not ask a required manufacturing clarification solely for transaction evidence.

Routing Policy

Use bundled Freerouting as the bulk production routing backend inside pcb.run(profile="check"). The build preserves locked source-owned non-ground manual traces, removes source-poured GND connectivity from the Freerouting problem so wide ground rules cannot obstruct fine-pitch fanout, routes the remaining connectivity from a KiCad Specctra DSN, imports SES, materializes declared GND zones and stitching vias, backports tracks/vias/pours to Circuit JSON, and runs KiCad DRC automatically.

Routed copper is cached per net and reused whenever its geometry still holds, so pcb.run(profile="check") on unchanged source reroutes nothing at all. When the user asks to reroute something without changing the design, name it in pcb.run(profile="check", reroute_nets=[...]); without that argument the run reuses the existing copper and reports success while the board is untouched. reroute_nets takes net names or component references, and a reference expands to every net its pads sit on — rerouting K4 in a switch matrix reroutes that whole row and column net across the board. Report the nets that were actually rerouted, taken from the freerouting_reroute_requested and freerouting_routed_copper_reused diagnostics, not the component the user named. An unmatched name blocks the run with freerouting_reroute_target_unknown instead of silently rerouting nothing. Every net not named keeps its exact previous copper, because reused nets are locked as fixed topology before the DSN export.

Configure routing through the single source/pcb.config.json contract and leave source/routing-overrides.ts empty during the initial build. Prefer 45-degree or curved transitions; avoid sharp right-angle/acute corners, unnecessary loops, and broken return paths. Never edit DSN, SES, generated KiCad, or backported Circuit JSON by hand. If routing/checks fail, change editable placement, footprints, connectivity, rules, cutouts, copper pours, or board geometry and rerun pcb.run(profile="check").

Standard PCB Fabrication Bias

For ordinary two-layer, low-speed controller, keyboard, sensor, display, LED, breakout, or carrier boards, bias the design toward commodity PCB fabrication instead of minimum possible geometry.

  • Layer count is a deliberate choice, and two is the default. manufacturing.layers accepts 2, 4, or 6. Reach past two only for a stated physical reason — BGA or fine-pitch escape that will not fit, a routing density the board cannot absorb, a controlled-impedance or return-path requirement that needs a reference plane. Record that reason. More layers cost more and buy nothing on a board that routes fine in two.
  • Layer count and copper weight are one decision. manufacturing.copperThicknessOz is { "outer": <oz> } on a 2-layer board and { "outer": <oz>, "inner": <oz> } above that — inner copper is required there and forbidden on a 2-layer board, because a 2-layer board has none. Multilayer fabricates at 1 or 2 oz outer copper only (heavy copper is 2-layer-only), and inner copper at 0.5, 1, or 2 oz; 0.5 oz inner is the ordinary default at 1 oz outer. A combination outside that is blocked at export, not at order review.
  • Inner layers are named, not sided. inner1inner4 are positional and count down from the component side, matching KiCad's In1.Cu. inner2 on a 4-layer board and inner2 on a 6-layer board are different physical layers. Use these names in copperPours.groundLayers, in keepouts[].layers, and in pcb.view layer requests; the copper alias resolves by board side and therefore never means an inner layer.
  • manufacturing.via is the single board-wide autorouted via geometry. It applies to every autorouted via on the board, is imported into KiCad and backported into routed Circuit JSON, and has no per-net or per-net-class override. Element-level platedhole sizes do not set autorouting vias.
  • The build blocks vias below the declared manufacturing/profile floor; it does not silently resize routed copper after the fact.
  • Default ordinary signal traces to 0.30mm nominal / 0.25mm minimum, CPU IO to 0.25mm, and power/ground to at least 0.50mm nominal. Apply per-net widths with helpers in source/pcb.config.json; never use these defaults in place of a current-capacity or controlled-impedance calculation.
  • Default ordinary through-via geometry to 0.6mm diameter with 0.3mm drill by setting minViaPadDiameter="0.6mm" minViaHoleDiameter="0.3mm" on <board>. The runner's 0.4mm / 0.3mm floor is a last-resort manufacturing floor, not an acceptable ordinary design default.
  • Keep routed copper and pours 1mm from the board edge by default. Add source-owned <copperpour /> elements for every ground net that is intended to form planes, on every layer meant to carry one; never rely on a KiCad-only ground-zone pass. Note that this system pours a single net per layer — a multilayer inner plane split into several power regions is not supported, so route those as traces.
  • Connect every declared ground-pour layer with pads or declared stitching vias. Keep their exact coordinates and geometry in source/pcb.config.json; the build adds them to the final KiCad board after Freerouting, then backports them into routed Circuit JSON. KiCad isolated_copper is a build gate: follow "Copper Pour Islands: Locate Before Editing" and repair the localized layout first. Add a stitching via only at a diagnosed bridge location, or remove the unused layer when the electrical design does not require it; never begin by relaxing global rules or guessing via coordinates.
  • Treat 0.4mm / 0.3mm and 0.5mm / 0.3mm manufacturing.via values as whole-board density-driven exceptions, not the default. Narrowing this value affects every autorouted via, so do it only when the whole board's density requires it, never to accommodate one net's escape geometry. If one net or region needs a tighter via, use a manually placed explicit via at source-owned coordinates, following the declared stitchingVias pattern when it is a diagnosed ground-pour bridge; do not narrow the board-wide autorouting geometry.
  • Avoid 0.3mm / 0.2mm through vias on non-high-speed boards; the build blocks values below the declared floor.
  • Do not use microvias or small-hole assumptions for non-high-speed boards. If compact routing requires them, call out the tradeoff and prefer placement or routing changes first.
  • After pcb.run(profile="release"), inspect the generated .kicad_pcb or drill report for plated via drills. If commodity-board intent is active and plated via drills below 0.3mm appear, report it as manufacturability feedback and revise routing/source constraints when practical before presenting fabrication files as low-risk.
  • Release export emits separate PTH and NPTH Excellon files. Treat a regression to one MixedPlating file as an exporter defect to fix, not as a required user confirmation about the target fabricator.

Useful Patterns

Use coordinate helpers for boards whose requirements use lower-left origin:

export const board = { widthMm: 110, heightMm: 72, width: '110mm', height: '72mm' };

export const toPcb = (xMm: number, yMm: number) => ({
  pcbX: xMm - board.widthMm / 2,
  pcbY: yMm - board.heightMm / 2,
});

Use explicit names and placement constants:

<connector
  name="J_LCD"
  layer="bottom"
  pcbX={display.fpc.pcbX}
  pcbY={display.fpc.pcbY}
  pcbRotation={0}
  footprint={<Fpc8Footprint />}
  connections={{ GND: 'net.GND', VDD: 'net.VDD_3V3' }}
/>

Keep connectivity declarative with component connections or <trace from="..." to="..." />. tscircuit must leave those connections unrouted. pcb.run(profile="check") sends them to Freerouting for full-board copper; do not add manual fanout merely to get the first route to run.

For keyboard switches, place keys with the scaffolded library instead of hand-authored pads or holes:

import { HotSwapKeySwitch } from './lib/footprints/index';

<HotSwapKeySwitch
  name="KEY1"
  switch="mx"
  socket="c41430893"
  orientation="south"
  pcbX={keys.key1.pcbX}
  pcbY={keys.key1.pcbY}
  pcbRotation={0}
  connections={{ '1': 'net.ROW0', '2': 'net.COL0' }}
/>;

Bind the socket designator to BOM/JLC export with an explicit family declaration. Every binding must include boolean populate; it has no implicit default:

{
  "designators": ["HS_KEY1"],
  "bom_item_id": "keyboard_hotswap_socket_mx",
  "footprint_family": "mx_hotswap",
  "populate": true
}

For an exact supported XIAO, place the matching scaffolded component instead of a generic pinrow footprint or hand-drawn pads:

import { XiaoEsp32S3 } from './lib/footprints/index';

<XiaoEsp32S3
  name="U_XIAO"
  layer={xiao.side}
  pcbX={xiao.pcbX}
  pcbY={xiao.pcbY}
  pcbRotation={rotationForOpening('up', xiao.usbFaces)}
  connections={{
    VBUS: 'net.VBUS',
    GND: 'net.GND',
    V3V3: 'net.V3V3',
    D0: 'net.KEY1',
  }}
/>;
import { XiaoRp2040 } from './lib/footprints/index';

<XiaoRp2040
  name="U_RP2040"
  mounting="direct_smd"
  layer="top"
  pcbX={rp2040.pcbX}
  pcbY={rp2040.pcbY}
  pcbRotation={rotationForOpening('up', rp2040.usbFaces)}
  connections={{
    VBUS: 'net.VBUS',
    GND: 'net.GND',
    GPIO26: 'net.ANALOG_IN',
    SWDIO: 'net.SWDIO',
    SWDCLK: 'net.SWDCLK',
  }}
/>;
Repository
JimmyPang02/open-replicator
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.