Coming from KiCad
What carries over from KiCad one to one and what does not: the frame, the back side, refs, text, pads in the Gerbers, models and silk. Read it before porting a KiCad board or footprint; import.md has the importer.
The frame
- Millimetres, x right, y down, as KiCad's board and footprint editors. A coordinate copied from a
.kicad_pcbor.kicad_modlands at the same place, soat="9 -5"here is KiCad's(at 9 -5). - Rotation is counter-clockwise on screen in both: a front part at KiCad
(at 13.3 5 180)isat="13.3 5 180deg". - A footprint's origin is where its own coordinates put it. A footprint retyped from a
.kicad_modkeeps KiCad's origin. The standard library is centred on the body for most families and on pin 1 for headers and sockets, see stdlib.md, so a KiCad placement of a JST footprint moves by the offset between the two origins. pcbjs inspect J1prints every pad's board centre and its size in board axes, x across and y down the screen, as KiCad plots it.--jsonkeeps the footprint axes infootprintSize. Compare a port against KiCad with it, never by hand.
The back side
KiCad flips a back part about its local x axis, top to bottom. pcbjs mirrors it about its local y axis, left to right, then rotates it. The two differ by a half turn, so a KiCad back placement at angle a is side="B" at a + 180 here:
| KiCad | pcbjs |
|---|---|
(layer "B.Cu") (at 0 0) | at="0 0 180deg" side="B" |
(layer "B.Cu") (at 9 -5 -90) | at="9 -5 90deg" side="B" |
(layer "B.Cu") (at x y 90) | at="x y 270deg" side="B" |
Front parts need nothing. Back text follows the part and reads mirrored from the front in both tools.
Refs
Parts are numbered by prefix when the board compiles, see schematic.md. To keep the refs of a KiCad project, pin each with .ref(): letters, digits and underscores, starting with a letter, so J_HR is fine. A plain footprint with no pins, such as a mounting hole, takes ref where it is placed:
import { JST_PH, MountingHole } from '@pcbjs/lib'
const J2 = JST_PH(6, 'side', { drill: 0.8 }).ref('J_PH')
const Hole = MountingHole(3.2)
// <J2 at="9 -5 90deg" side="B" /> <Hole ref="H1" at="3.5 3.5" />Text
- pcbjs strokes
<text>in Hershey Simplex by default.font="newstroke"is KiCad's own stroke font, the same glyphs KiCad draws, and whatpcbjs importwrites for KiCad's stroke text.sizeis the cap height in both, KiCad's text height. - KiCad's
(size h w)and(thickness t)map tosize={h},width={w}andthickness={t}.widthstretches each glyph and its advance across the baseline and defaults tosize, so KiCad's 1.25 mm high, 1.35 mm wide numbers aresize={1.25} width={1.35}. atis the middle of the text by default, as KiCad's centred justification:anchorsets the horizontal end, and the vertical centre runs from the cap line to the baseline.- On silk,
thicknessis never thinner than the board'ssilkMinWidth, 0.15 mm by default.
Pads in the Gerbers
- Round copper pads and vias are flashed with a circle aperture, as KiCad does. Every other pad, and every mask opening, is written as a G36 region, a filled polygon, where KiCad flashes
R,OandRoundRectapertures. The copper is the same up to the polygon's chords on curved edges, a thin rim on an oval. - Mask openings grow every pad by the
maskExpansionrule, 0.05 mm by default. KiCad's pad to mask clearance maps to it, such as a 0.0762 mm, 3 mil, clearance. - Arcs on Edge.Cuts and silk stay arcs, G02 and G03, as in KiCad's export.
Models
- A
.kicad_mod(model ...)line maps one to one:(offset (xyz 10 0 0)) (scale (xyz -1 1 1)) (rotate (xyz 0 0 0))ismodel: { file, offset: [10, 0, 0], scale: [-1, 1, 1], rotate: [0, 0, 0] }, with the same order of scale, rotate and offset. - KiCad's
${KICAD10_3DMODEL_DIR}/...path, or an olderKICAD9orKICAD8one, works as it is throughkicadModel('${KICAD10_3DMODEL_DIR}/…')of@pcbjs/kicad, which resolves it to the installed3dmodelsfolder; an imported footprint writes it so. To own the file,pcbjs model addcopies it intomodels/; the path is then relative to the file that defines the footprint, so a footprint inlib/footprints.tsxwrites../models/...even whenpcb.tsxplaces it. 3d.md has the rules. ${KIPRJMOD}is the project root: the folder of pcb.config.ts forkicadFootprint, the folder of the.kicad_pcbin an import, never the library folder. Any other relative model path, amodeloption ofkicadFootprintincluded, is relative to the file that writes it.- A KiCad library model fits a standard library part with no transform where the origins agree, the passives,
PinHeaderandUSBC; a centred family such as JST needs the origin offset.
Silk and the mask
pcbjs clears silk from the mask openings in the Gerbers, as KiCad's --subtract-soldermask does, and the silk-over-pad warning marks each stroke that runs into an opening, so the design can be fixed rather than the fab file. The standard library's silk outlines are already broken around their pads. KiCad checks the thickness of silk text only; pcbjs checks every silk stroke against silkMinWidth, so the importer sets it to the thinnest silk the board draws. A KiCad NoSilkScreen footprint is the standard library family with silk: 'none', JST_PH(6, 'side', { silk: 'none' }); a side entry's default silk leaves its mating face open, so it may sit flush with the edge, see stdlib.md.
Gerbers against KiCad's
The importer's tests compare a pcbjs fab set with the one kicad-cli writes for the same board, two KiCad boards in packages/kicad/tests/fixtures/boards: small, library footprints of every pad shape on both sides with vias, an arc track, a pour and an outline arc, and tabs, slotted pads, a back part, an arc track, a .kicad_dru and a .kicad_sch. Copper, mask, paste and outline match KiCad's by bounding box to 2 µm and the drill files hole for hole, slots included.
Every pad lands at KiCad's position, with the half turn added on each back part. pcbjs also writes empty paste layers for a board with no SMD pads, which KiCad leaves out.
Import conventions
- A board footprint returns to its own frame: KiCad stores pad and text angles absolute, a back part's children flipped and footprint zones in board coordinates.
- A back part is placed
side="B"at KiCad's angle plus 180, as kicad.md explains, and its footprint is written front side up, so one module serves both sides. - Text keeps its anchor: left and right justification become
anchor, andatmoves to pcbjs's vertical centre. Back text is mirrored by its layer. - KiCad's stroke text is
font="newstroke", KiCad's own font, at KiCad's size, width and thickness,atmoved as KiCad places its first baseline,kicadStrokeShiftof@pcbjs/kicad; the ink lands on KiCad's, fonts.md. - Board text in a TrueType face is drawn in the installed font, copied to
fonts/with its licence infonts/LICENSES.mdand sized as KiCad draws it, fonts.md; a face not installed is drawn in Hershey.
Importing
pcbjs import footprint <Lib:Name> writes a footprint as a defineFootprint module, kicadFootprint('Lib:Name') uses one from the installed KiCad library in code, and pcbjs import board <file.kicad_pcb> writes a whole board as a skeleton to refine. import.md has what each carries and what it leaves out.
Libraries other than the installed one are listed in pcb.config.ts, folders of .pretty folders or .pretty folders themselves, relative to the config:
import { defineConfig } from '@pcbjs/core'
export default defineConfig({
entries: ['pcb.tsx'],
kicad: { footprints: ['../lib/footprints'] }, // searched before KICAD_FOOTPRINTS and the installed library
})kicad.models names the folder ${KICAD10_3DMODEL_DIR} stands for when it is not the installed one.
Seven scripted KiCad boards were imported and checked with pcbjs check --fab: the Gerber self check passes on all, drill files match KiCad's hole for hole and copper outside pours to 0.02 mm, and the findings left are .kicad_dru rules and per-pad clearances pcbjs rules do not carry. Pours differ by a few percent of their area: pcbjs draws its own reliefs, and both remove islands, see pours.md Islands.