Copper, holes, print, widths and distances on plan and Gerber files – 13 codes.
Each engine decides one kind of relation; a finding's code is ENGINE.relation. Severities are the catalog's defaults – a project's domains may set others; a grade is a sub-case with its own severity, a topic the part of a code a domain switches on.
GEO.copper copper from the Gerber files
errormargin: warning
The copper rasterised from the exported Gerber files connects every net, shorts no two nets and contains every connected pad.
copper from the Gerber files, rasterised at 0.02 mm, layers joined through plated holes, pads from FlyingProbeTesting.json, nets from the graph: every net connected, no short, every pad present – why it exists: do not trust EasyEDA – check what goes to the factory
Why
This is what the factory gets. Pours, islands and export settings can differ from what the editor shows, so the last connectivity check does not trust EasyEDA.
What to do
Look at the routing picture, route again or refill the pours, then export again.
Sources
edakit handbook 8.1
Replaces L-2
GEO.drc DRC
errormargin: warning
EasyEDA's design rule check reports nothing (the PCB reloaded and checked once more when it reports Connection Errors). A "Netlist Error – Import Changes" item is checked on its own: schematic and PCB are compared as edakit pcb parts and pcb nets do. With [routing] drc_rules = "check" or "write" in the board file, the rule set the DRC ran with is the board file's: the clearance and edge clearance, the least track width of every net (signal_mil, the classes of [routing.classes]), the least via and the net classes.
EasyEDA DRC 0 (reloaded and run again on Connection Errors), two rows: other kinds; schematic and PCB in sync – an Import Changes item with no difference in netlist_diff.json is "EasyEDA waits for the import acknowledgement" (still a fail – edakit route drc writes the Channel IDs and checks again; else one click), otherwise the differences and pcb parts --write / pcb nets --write. With [routing] drc_rules = "check" (or "write") a third row: the rule set the DRC ran with (drc_rules.json, read right after it) = the board file's – clearance, edge clearance, the least track width of every net, the least via, the net classes (7.5) – named, each difference with both numbers – why it exists: a DRC without findings says only that the board keeps the rules EasyEDA holds: pytree's ran with 0.102 mm from track to track, while the board was routed with 6.5 mil
Why
Clearances, widths and open connections below the manufacturer's limits. Right after API changes the DRC reports false errors, so it runs after a reload. After parts were placed in the schematic, EasyEDA reports Import Changes until its import view has been opened once – even when schematic and PCB are equal; in pytree that held the gate for 2¾ h and ten runs. A DRC without findings says only that the board keeps the rules EasyEDA holds, which are set in its GUI and in no file: pytree's DRC ran with 0.102 mm from track to track, so a track drawn by hand closer than the 6.5 mil the board was routed with passed it.
What to do
Connection Errors right after API changes: route all reloads and checks again by itself, by hand edakit route reload, then edakit route drc; then fix what remains (route all, the plan). Import Changes with no difference: edakit route drc writes the PCB parts' Channel IDs into the schematic parts and checks again; if it still says "EasyEDA waits for the import acknowledgement": open Design → Import Changes once in EasyEDA – it shows no changes. With differences: edakit pcb parts --write (parts, links, properties) or edakit pcb nets --write (pad nets), as the row says. A rule set that is not the board file's: set the values the row names in EasyEDA (Design → Design Rule: Safe Spacing, Track, Via Size, the net classes), or change [routing] of the board file.
Sources
edakit handbook 7 and 9
EasyEDA Pro 3.2.206: the rule configuration, net rules and net classes as PCB_Drc answered on 2026-10-22 (tests/fixtures/easyeda/drc_rules_3.2.206.json)
EasyEDA Pro 3.2.206, its extension API types (pro-api 0.3.50, api-types.d.ts), class PCB_Drc
Replaces L-3
GEO.width track width
errormargin: warning
Every track is at least as wide as IPC-2221 asks for 1.5 × the largest simulated current (failure) and as the practical width of its net class (warning); the voltage drop is shown as an upper bound.
track width ≥ IPC-2221 for 1.5 × the simulated current (fail), ≥ class width (warn), voltage drop upper bound (info); route check measures the same on the SES and the fixed wires before writing (7.5) – why it exists: power tracks too thin
Why
A track too narrow for its current heats up and drops voltage; the class width adds robustness for manufacturing and for later changes.
What to do
Wider tracks or a pour for the net; net classes in [routing.classes] and [net_classes] of the board file.
Sources
IPC-2221B, Generic Standard on Printed Board Design: conductor width for a current
edakit handbook 5.4
Replaces L-5
GEO.loop short current loops
errormargin: warning
Each pad pair listed in [[loops]] of the board file or in layout.loops of the graph is connected over tracks within its length limit.
short current loops ([[loops]] of the board file and layout.loops of the graph): shortest path over tracks per pad pair within its limit – why it exists: a switching regulator loop routed 61 mm around the board
Why
A switching regulator's loop carries pulsed current; a long loop radiates and rings. In pytree it was routed 61 mm across the board, and the layout review found it, not a check.
What to do
Put the regulator, its capacitors, the diode and the inductor together and route the loop first.
Sources
TI SNVA021C, AN-1149 Layout Guidelines for Switching Power Supplies (2013) – https://www.ti.com/lit/an/snva021c/snva021c.pdf
edakit handbook 8.2
Replaces L-11
GEO.mark polarity marks
errormargin: warning
Every '+' or '-' in the silkscreen – a PCB text, or a '+' a footprint draws as two crossing strokes of 0.3–2 mm in the silk Gerber file – sits next to a pad of that sign: the nearest pad on its side whose pin role has a sign (anode…, plus…, vbus '+'; cathode…, minus… '-') has the same one.
every "+" and "−" of the silkscreen next to a pad of that sign: the PCB texts "+", "−", and the "+" a footprint draws as two crossing strokes in the silk Gerber files (each 0.3–2 mm, as long as the other, at right angles, middles within 0.1 mm). Each is compared with the nearest pad on its side whose role has a sign – anode…, plus…, vbus "+", cathode…, minus… "−". Strokes of a PCB text with a "+" are that text (a "+5V" is a label); a cross on the shapes of a [[silk.art]] item (within 0.2 mm) is artwork, one between them is judged like any other. waive: {"GEO.mark": "…"} on the nearest part lists its sign as waived – why it exists: the footprint of a 5-mm LED printed "+" at the cathode: GEO.mark read only PCB texts and gave the cathode no sign, so nothing saw it; a review did, before five boards would have been assembled with the LED turned (4.4)
Why
A sign at the wrong pole makes whoever solders or inspects the board turn the part the wrong way. The sign that counts most is the footprint's own print: the assembler, the hand-solderer and JLCPCB's assembly preview go by it. In pytree the library footprint of a 5-mm LED printed '+' at the pad that symbol and datasheet call the cathode. GEO.mark read only PCB texts, and a cathode had no sign, so a '+' at a cathode was compared with the anode next to it and passed; a review found it before five boards were assembled with the LED turned.
What to do
Compare the footprint with the datasheet. The print is right: correct the roles in the parts entry. The datasheet is right: put the anode's net on the pad with the '+' and give that pin the role anode (handbook 4.4), or use another footprint. A cross on the shapes of a [[silk.art]] item is artwork and is not read – one between them, inside the item's box, is judged; a decorative cross elsewhere is accepted on the nearest part (accept GEO.mark).
Sources
edakit handbook 4.4 and 8.1
pytree's second review (M-1), 2026-10-22, and its decision on it: the footprint LED-TH_BD5.0-P2.54-FD prints '+' at pad 1, symbol and datasheet call pad 1 the cathode; the nets were swapped so that pad 1 carries the anode
Replaces L-8
GEO.formed formed leads fit one way
errormargin: warningunknown: notecounter: note
A through-hole part whose plated holes the board's footprint (pcb dump) moves away from its library footprint – a hole more than 0.05 mm from the library's hole of the same number, the two footprints laid on each other by their numbers – and that has three or more plated holes is not laid onto itself by a turn of 90°, 180° or 270° about its holes, every hole within 0.25 mm of a hole, with a pin in the hole of a pin on another net of the graph. Pins on one net do not count, two holes and a part on its library pattern are not judged; without the library footprint of edakit part import it is a note. A turn that lays the library footprint onto itself – one row by nature – lays the board's holes onto the library's pattern with the offsets at other legs: where a part bent at those legs instead puts a pin in the hole of a pin on another net, it is a note that names the legs of that counter-bend and where each pin lands.
formed leads fit only one way round: a part whose plated holes the board's footprint (pcb dump) moves away from the library footprint of edakit part import – a hole more than 0.05 mm (SYNC.footprint's tolerance) from the library's hole of its number, the two laid on each other by their numbers –, with three or more of them, is not laid onto itself by a turn of 90°, 180° or 270°, every hole within 0.25 mm of a hole, with a pin in the hole of a pin on another net; pins on one net do not count, two holes and a part on its library pattern are not judged (its orientation is the print's job, GEO.mark). The pads are matched as part diff matches them (7.3). The finding names the turn and the pins: D31: its formed holes lie on each other turned by 180° – pin 1 (V_LED) in the hole of pin 3 (STAR_G_K), pin 2 (STAR_R_K) in the hole of pin 4 (STAR_B_K); accept on the component; without the library footprint a note – finds e.g.: an RGB star LED with two legs bent the same way, which went in turned by 180° as easily – anode in a cathode's hole, the star dark –, with a "+" at the anode and every check passed
the counter-bend (grade counter, a note): a turn of 90°, 180° or 270° that lays the library footprint onto itself – one row always by 180° – lays the board's holes onto the library's pattern with the offsets at other legs; a part bent at those legs goes in turned. Where that puts a pin in the hole of a pin on another net, the note names the legs, their offsets in the footprint's frame (the offset most legs share counts as straight) and where each pin lands: D31: bent at other legs it goes in turned by 180° – pin 2 by (+0.00, +1.60) mm, pin 3 by (+0.00, -1.60) mm: pin 1 (V_LED) in the hole of pin 3 (STAR_G_K), …. A counter-bend equal to the board's own bend is the error above, not a note. acceptGEO.formed/counter (or GEO.formed) on the component, with the assembly instruction as the reason – finds e.g.: the same star LED with its legs bent the opposite ways, which a solderer holding it turned bends at pins 2 and 3 – it fits turned by 180°, the star dark, green near the supply in reverse
Why
A part fitted by hand with formed leads loses the cues of its library pattern: the longest lead is bent like the others, and the body's flat stands millimetres above the silkscreen mark. If the formed pattern maps onto itself, the part goes in turned as easily as the right way – an RGB LED with its anode in a cathode's hole stays dark, a transistor or regulator is reversed. No other check sees it: SYNC.footprint compares the PCB with the board's own footprint, GEO.mark judges a sign next to a pad, GEO.hole and GEO.ring the hole size, ring and spacing, and part diff sees the symmetry only when a part is swapped. In pytree the star LED's four legs in one row at 1.25 mm got two of them bent 1.6 mm the same way: turned by 180° the anode's hole lay on the green cathode's and red on blue, to 0.00 mm, the print had its '+' at the anode, and every check passed; the second datasheet check found it by hand. Bending one of the two legs the other way left no turn of the right bend that fits (the closest 1.25 mm off) – but not every wrong bend: a solderer bends by position, not by pin number, and holding the part turned, 'the second leg from the right up, the leftmost down' bends pins 2 and 3, and that part goes in turned by 180° exactly, anode in green's hole, green seeing close to the supply in reverse through its resistor. No hole pattern of one row avoids such a counter-bend, so it is a note, not an error.
What to do
Choose the offsets so that no turn lays the pattern onto itself: two leads in opposite directions, one lead only, or different amounts – then check ring and hole spacing again (GEO.ring). Where the pattern stays symmetric for a mechanical reason, accept GEO.formed on the component with that reason and let the print show the orientation (GEO.mark). The counter-bend (note): name the reference lead in the assembly instruction and on the board – the longest lead or the flat first, into the hole with the polarity sign (GEO.mark), then bend; where the footprint can choose, a lead left straight and long or a body outline that shows the flat narrows it further; then accept GEO.formed/counter on the component with the instruction as its reason.
Sources
pytree, decision D-49 of 2026-10-27 (docs/hardware.md, bullets 'Biegen' and 'Footprint'): pin 1 bent 1.6 mm towards the tip, pin 4 1.6 mm towards the trunk – the opposite offsets make the hole pattern asymmetric; with both legs towards the tip the star also fitted turned by 180° and would have stayed dark
pytree, hardware/release/signoff.json, the second datasheet check M-1 of 2026-10-27: all nine bend patterns computed, only the right one fits (turned 1.25 mm off); in the first round the hole pattern with pins 1 and 4 towards the tip was point-symmetric (finding 'important', fixed with pin 4 towards the trunk)
pytree's gate runs 20261027-211238 (round 1) and 20261027-214622 (round 2): D31's pads in pcb.json – pads 1 and 4 1.6 mm off the row the same way in round 1, pad 4 1.6 mm the other way in round 2; the library footprint LED-TH_4P-BD5.8-P1.25 as edakit part import C7371895 cached it (2026-10-28): one row at 1.25 mm, holes Ø 0.70 mm
0.05 mm: L-10's tolerance (pad against library position); 0.25 mm: about the radius of a formed lead (pytree's star LED: legs 0.49 mm) – the triage's choice, no standard was opened
edakit handbook 4.1 (the lead facts, P-7) and 7.3 (part diff: pads matched by position under each turn, 'symmetric: the numbers decide')
Proposal #100 from pytree, decision D-54 of 2026-11-01 (docs/hardware.md): all 81 bends of D31 (each leg −1.6, 0, +1.6 mm) in both turns – the right bend fits only at 0°, pins 2 (+1.6) and 3 (−1.6) bent fit at 180° (anode in STAR_G_K's hole); recomputed by the triage from the pads in the proposal and the library footprint LED-TH_4P-BD5.8-P1.25 (one row at 1.25 mm, order 4-3-1-2)
XINGLIGHT XL-B504RGBC datasheet (LCSC C7371895, edakit part fetch of 2026-11-01), p. 8 Outline Dimension: legs 4-3-1-2 at 1.25 mm, pin 1 the common anode (+) and the longest lead, the flat on the side of pin 2
Replaces P-8
GEO.pour copper per side
warningmargin: warning
Per copper layer the Gerber copper's share of the board area and its largest copper-free circle inside the pour outline are reported; on a layer the board file pours, and on a seen face it does not pour ([looks] visible, both faces without [looks]), a copper-free circle above [copper] max_bare_mm (5 mm) is a warning, and so is every copper-free piece a pour could fill (what is left after an opening with a disc of 2 × clearance_mm + min_width_mm, 0.75 mm by default) above [copper] max_bare_mm2 (20 mm²); a share below [copper] min_cover on any layer is one, and on every layer so is a copper piece that touches no pad, via or plated hole (copper inside an NPTH or mounting hole is drilled away).
copper per layer on GEO.copper's raster of the Gerber files, widened to the outline: the copper share of the board area (without mounting and NPTH holes) and the largest copper-free circle inside the pour outline (the outline pcb pour pours, 7.6) – information on a face without pour that [looks] does not name as visible; on a layer the board file pours ([[pours]], default GND on both) and on a seen face without pour (the one [looks] visible names, both without [looks]; the warning says the board file pours nothing there, the pieces opened with the default 0.75 mm) a circle above [copper] max_bare_mm (5 mm) warns, so does every copper-free piece a pour could fill – opened with a disc of 2 × clearance_mm + min_width_mm of its [[pours]] (0.75 mm; a narrower gap is the clearance between foreign copper) – above [copper] max_bare_mm2 (20 mm², the area of the 5 mm circle), with its area, its box and the other side's copper share there, a share below [copper] min_cover warns, and on every layer a copper piece that touches no pad (FlyingProbeTesting.json), via or plated hole warns, with its area and place. Copper inside an NPTH or mounting hole is drilled away. One row per layer, so an accepted warning covers its layer – why it exists: EasyEDA drops every pour piece without a pad of its net: half the back of a released board stayed bare (47 % copper, a copper-free circle of Ø 9.7 mm) where ground had no pads, with DRC 0 and every check passed; it was seen by eye before the order
Why
EasyEDA drops every pour piece that touches no pad of its net, so where the pour net has no pad that side stays bare – and a pour that was never filled, or was filled before the last copper change, looks the same in the files. GEO.copper checks only connectivity, EasyEDA's DRC (GEO.drc) does not report a missing fill, and route pours treats a read-back mismatch as harmless. In pytree half the back of a released board stayed bare (47 % copper, a copper-free circle of Ø 9.7 mm) where its ground net had no pads; the gate and the layout review passed it, and it was seen by eye the evening before the order. Islands kept for stitching (route pours, stitch) stay on the board as loose copper when the second fill does not run. The circle alone misses long bare strips: a GND island walled in by the tracks of other nets – between two rows of header pins, along a track pair – is a few millimetres wide and tens long, and EasyEDA drops it as a piece without a pad of its net; in the bell a released board passed with a strip of 105 mm² bare (largest circle Ø 3.4 mm) where a round spot of 21 mm² would have warned. A seen face can be left without any pour – by oversight, or because the only pour went to the other side –, and then it is mostly bare laminate: in desk-led the only pour was GND on BOTTOM of a board seen from the top, TOP held pads and a few tracks, and only the layout review found it.
What to do
A bare area on a poured layer: give it to a net that reaches it – a second pour net on the layer (pour_regions, priority) or a pad or via of the pour net there – then route pours and run the gate again; for an island walled in by other nets stitch = "<layer>" in [[pours]] puts a via into every loose island where the other side pours (the warning gives each piece's area, box and the other side's copper there). Loose copper: connect it with a via or a track, or delete it, and fill the pours again without islands. A seen face without pour (the warning says the board file pours nothing there): pour it in [[pours]] with a net that has pads or vias there (pour_only, pour_regions), or for a face meant to stay bare accept the warning with its reason. An area bare on purpose (an antenna keep-out): accept the warning with its reason. [copper] max_bare_mm, max_bare_mm2 and min_cover = {TOP = %, BOTTOM = %} in the board file set the limits of a board.
pytree, tree PCB Rev 2: release run 20261025-205344 with the back bare where GND had no pads (TOP 47 % copper, copper-free circle Ø 9.7 mm, measured by this check), passed by the gate and the layout review; the fix run 20261025-232212 with V_LED filling that area (72 %, Ø 3.8 mm) – its decisions D-48 and B-4, its layout review M-5 ("Kupfer hinten 72 % statt 46 %"), 2026-10-25
5 mm: pytree's measurement, between the bare run (9.7 mm) and the fixed run (3.8 mm); JLCPCB PCB Manufacturing Capabilities (read 2026-10-26) has no row on copper balance or coverage – https://jlcpcb.com/capabilities/pcb-capabilities
max_bare_mm2: proposal #103 from automatic_christmas_bell, its D-41 (commit 7691f53) – five boards released 2026-11-01 (commit ce35e5b), measured on their Gerber files: smd TOP one piece of 105 mm² along the Nano's lower pin row with the largest circle Ø 3.4 mm, passed by the circle (release run 20261101-005512); main TOP 446 mm² between the Nano's pin rows (Ø 12.0 mm) and 77 mm² around a button (Ø 4.9 mm); every piece a GND island without a GND pad, the other side 84–100 % copper
20 mm²: π × (5 mm / 2)² = 19.6 mm², the area of the circle max_bare_mm allows; 0.75 mm: 2 × clearance_mm + min_width_mm of [[pours]] (0.25 mm each, handbook 10) – no standard was opened
seen faces without pour: proposal #340 from desk-led, its D-6 (docs/decisions.md, commit ab1c9cb) and its layout review 1, finding 1 (pcb-reviewer, 2026-11-03) – board main, 40 × 40 mm, [looks] visible = "top", its first routing poured GND on BOTTOM only, TOP held pads and a few tracks, edakit route all and the gate reported nothing for TOP; after a pour on TOP 87 % copper, largest copper-free circle Ø 1.0 mm. The limits are those above; no large copper-free area on either face is the owner's layout principle – no standard was opened
Replaces L-15
GEO.spacing pads and holes keep their distance
errormargin: warningapart: warning
Every pad keeps the routing clearance from every pad of another part on another net, SMD pads on an assembled side the paste gap, hand-soldered joints their keep-out, and every two plated holes JLCPCB's hole-to-hole spacing. On a board that leaves its vias open, every via keeps smd_via_keep_mm from a reflowed SMD pad (grade margin). With layout.apart in the graph: the copper of each pair of nets keeps min_mm apart on every layer, measured on the Gerber files (grade apart, a warning while new).
pads of different parts on different nets at least the routing clearance (clearance_mil) apart on every copper layer both are on; a pad without a net counts as a net of its own, pads of one part are not compared. Measured as route check measures it (7.5), on the pads of route read (<artifacts>/route/<board>_board.json) – pcb.json has no pad shapes –, and only while every pad there sits where the PCB has it, on its layer and net; otherwise GEO.spacing fails and asks for route read. waive: {"GEO.spacing": "…"} on one of the two parts or nets lists the pair as waived – why it exists: two resistors stood with their pads 0.09 mm apart: the plan compares boxes, route check measured only tracks and vias, and only EasyEDA's DRC could have seen it, after the copper was written
on every side that is assembled ([release] assemblysides), SMD pads of different parts on different nets at least the paste gap (paste_gap_mm, 0.4 mm) apart, so that the stencil keeps a web between their prints; a pad without a net counts as a net of its own, pads of one part, through-hole pads and pads on a side that is not assembled are not compared. Measured on the pads of route read like GEO.spacing, and only while they are the PCB's. waive: {"GEO.spacing": "…"} on one of the two parts or nets lists the pair as waived – why it exists: the paste of a ground pad and a transistor base pad of neighbouring parts was 0.06 mm apart: above every copper rule, a bridge in reflow that the bare-board test cannot see; the layout review found it
with [routing] hand_solder_keep_mm (0 = off): on the solder side of every pad of a part with bom: false – for a through-hole pad the layer the part does not sit on, for an SMD pad its own layer, the side the part sits on – no via and no pad of another net closer than the keep, copper to copper; a pad without a net counts as a net of its own, the part's own pads are not compared, tracks do not count. Pads as route read saw them, like GEO.spacing; vias from the via drill file, with the net of the tracks of pcb.json that end on them – a via no track ends on counts as another net's ('via (no track, net unknown)'). route check measures the same before writing, and route dsn keeps vias away (7.5). waive: {"GEO.spacing": "…"} on the joint's part or net, or on the other part or net, lists the pair as waived – why it exists: the layout review found a via 0.25 mm from a hand-soldered LED joint – a bridge would have put 5 V without its resistor on an LED –, a via 0.26 mm between potentiometer pins and a resistor pad 0.37 mm from an LED joint; every check had passed; the SMD pads came in when the walkthrough's coin cell holder, soldered by hand on two SMD tabs, was not looked at – a tab soldered with an iron bridges to a via as a through-hole joint does
on a board whose vias stay open ([order] vias = "untented"), every via – of any net, the pad's own too – at least [routing] smd_via_keep_mm (0.3 mm, 0 = off) from every reflowed SMD pad: an SMD pad on an assembled side ([release] assemblysides) of a part not soldered by hand (bom: false has the keep-out above), copper to copper – a warning (grade margin), one row per pad and via, so an accept covers one pair. Tented, plugged and epoxy-filled vias are not measured: the source's mechanism is solder flowing into the via's hole, and a tented via has none open. Pads as route read saw them, vias from the via drill file as above; route check reports the same as warnings, route dsn writes a via keep-out of that size around every reflowed SMD pad, and the fanout of [[pours]] keeps it from them, its own pad too. waive: {"GEO.spacing": "…"} on the pad's part or net, or on the via's net, lists the pair as waived – why it exists: a VBAT via 0.18 mm from the reflowed plus tab of a coin cell holder, in the tab's own net; DRC and GEO.spacing passed it because via and pad shared a net, the layout review found it
Why
Pads too close bridge in soldering; holes too close break out in drilling.
What to do
Move the parts apart or change the footprint.
Sources
docs/concepts/done/maker-coverage.md, CK-31 (appendix GTP 10, 22, 23, 25, 33; GTI 16, 26, 29; MCU 6, 7) – nets kept apart, the distance from the circuit designer
JLCPCB PCB Manufacturing Capabilities, minimum clearances: SMD pad to pad clearance (different nets) 0.15 mm (read 2026-10-26) – https://jlcpcb.com/capabilities/pcb-capabilities
JLCPCB, Terms and Conditions of JLCPCB Assembly Service (updated 2026-09-09), 2.2: placement and gap of the components after IPC-7351B medium or low density, components with very small gap avoided – https://jlcpcb.com/help/article/61-Terms-and-Conditions-of-JLCPCB-Assembly-Service
edakit handbook 7.5 and 8.1
JLCPCB, Terms and Conditions of JLCPCB Assembly Service (updated 2026-09-09), 2.1 and 2.2: footprints, placement and gap of the components after IPC-7351B medium or low density, high density not supported, components with very small gap avoided – https://jlcpcb.com/help/article/61-Terms-and-Conditions-of-JLCPCB-Assembly-Service
RF Essentials, RF glossary: Courtyard (read 2026-10-26; a secondary source, IPC-7351B itself not opened): courtyard excess Level A (Most) about 0.50 mm, Level B (Nominal) about 0.25 mm, Level C (Least) about 0.10 mm and reserved for high density; the courtyard wraps the largest body outline and land protrusion; overlapping courtyards mean parts too close for the nozzle, the stencil aperture or rework – https://rfessentials.com/resources/rf-glossary/courtyard/
JLCPCB, Opening process standard of Stencil (updated 2025-04-24): engineers adjust the apertures by default (fine-pitch ICs, anti-solder-bead from 0805 up), no minimum web between apertures, through-hole apertures not opened – https://jlcpcb.com/help/article/opening-process-standard-of-stencil
JLCPCB PCB Manufacturing Capabilities: SMD pad to pad clearance (different nets) 0.15 mm (read 2026-10-26) – https://jlcpcb.com/capabilities/pcb-capabilities
0.4 mm: pytree's decision after its layout review M-5, in its decision log, 2026-10-25 (M-5: edakit handbook 8.2)
JLCPCB PCB Manufacturing Capabilities (read 2026-10-26), Traces: PTH annular ring ≧0.20 mm; 2 layers, 1 oz: recommended 0.25 mm or above, absolute minimum 0.18 mm – https://jlcpcb.com/capabilities/pcb-capabilities
JLCPCB PCB Manufacturing Capabilities (read 2026-10-26), Drilling: Via Hole-to-Hole Spacing 0.2 mm, Pad Hole-to-Hole Spacing 0.45 mm (the page says neither edge nor centre; read edge to edge, the stricter reading); via diameter 0.1 mm (0.15 mm preferred) larger than the via hole; hole size tolerance +0.13/-0.08 mm – https://jlcpcb.com/capabilities/pcb-capabilities
pytree, release run 20261025-232212: D31 (XINGLIGHT XL-B504RGBC, 1.25 mm pitch) with holes of 0.80 mm and pads of 1.06 mm – ring 0.130 mm, holes 0.449 mm apart; its decision D-40 and layout review M-5 ("D31 Restring 0,13 mm", at the fab's limit, accepted), 2026-10-25
edakit handbook 8.1 (L-9, L-13)
pytree: layout review M-5 at gate run 20261023-152935 – a via 0.25 mm copper to copper from LED D12 pad 1 (V_LED) on the electronics side, the LEDs' solder side, and a via between pins 2 and 3 of RV1; acceptance list check 1.7 (loupe check of both, commit 0ac0c9d). M-5 at gate run 20261025-193700: R51 (0 Ω, 3V3) 0.37 mm from a 5 V joint of the hand-soldered LED D23, moved to 1.07 mm in run 20261025-204229 (commit 4f10911, signoff.json M-5 note)
Owner's answer on edakit proposal #59 (2026-10-27): only vias and pads of other nets count, tracks do not; a via without a track to give its net counts as another net's – the triage's choice, the conservative side
AllPCB, Pad-to-Pad Spacing Demystified: A Practical Guide for PCB Manufacturability (read 2026-10-27; a secondary source): 'A minimum spacing of 0.3 mm (12 mils) between pads and vias is recommended' against solder wicking; through-hole pads 'around 1 mm (40 mils), due to the nature of wave soldering'; the soldering method, hand soldering among them, impacts spacing requirements, without a number – https://www.allpcb.com/allelectrohub/pad-to-pad-spacing-demystified-a-practical-guide-for-pcb-manufacturability
Freerouting 2.4.1 release (the version edakit pins): its Specctra reader app/freerouting/io/specctra/parser/Structure knows the keep-out type via_keepout (VIA_KEEPOUT, viaKeepoutList)
edakit handbook 7.5, 8.1 and 8.4 (Economic PCBA: through-hole parts you solder yourself get bom: false)
edakit handbook 17.11, the layout review of the walkthrough, note 4: hand_solder_keep_mm checked nothing at BT1, whose two SMD tabs are soldered by hand (bom: false); docs/concepts/done/walkthrough-gaps.md B5 – SMD pads of a bom: false part get the same keep on the side the part sits on (decided by the main session 2026-10-31, to be confirmed by the owner)
AllPCB, Pad-to-Pad Spacing Demystified: A Practical Guide for PCB Manufacturability, section 4 (read again 2026-11-03; a secondary source): 'Placing pads too close to vias can cause solder wicking, where solder flows into the via instead of staying on the pad. A minimum spacing of 0.3 mm (12 mils) between pads and vias is recommended to avoid this issue.' – the page says nothing on tented or plugged vias – https://www.allpcb.com/allelectrohub/pad-to-pad-spacing-demystified-a-practical-guide-for-pcb-manufacturability
proposal #341 from desk-led, its D-6 (docs/decisions.md, commit ab1c9cb) and its layout review 1, note 3 (pcb-reviewer, 2026-11-03): board main, a VBAT via 0.18 mm edge to edge from BT1 pad 1 (VBAT, reflowed on TOP), DRC 0 and GEO.spacing passed; the owner's answer on #341 (2026-11-10): only vias the board leaves open (vias = "untented"), the fanout and route dsn keep the minimum, the key [routing] smd_via_keep_mm with default 0.3 mm, a warning under grade margin
Replaces L-13, L-14, L-16, L-18
GEO.under no track between the pads of a small chip part
note
No track passes between the two pads of a two-terminal SMD chip part of 0402 to 1206 on the part's own layer, unless the track's net is the net of both pads; 0 Ω bridges are left out. A note, naming the part, the track's net and the smallest distance from the track to a pad of another net.
a small chip part is read from the pads, not from the footprint's name: exactly two SMD pads on one copper layer whose outer extent is at most 4.5 × 2.0 mm (along and across the pads; up to 1206). Between the pads is the rectangle from the facing edge of one pad to that of the other, across the width of the pads; a track whose copper enters it on the part's own layer is noted, at any distance – no source gives one –, unless its net is the net of both pads. A resistor whose parts entry has value_ohm 0 is a bridge (handbook 3.3, 0 Ω bridges) and is left out: a track passing between its pads is what it is for. Pads as route read saw them (<artifacts>/route/<board>_board.json), like GEO.spacing, tracks from pcb.json; route check reports the same on the SES. One row per part and net, information; accept: {"GEO.under": "…"} on the part or the net – why it exists: Freerouting ran LED_SW between the pads of two 0805 parts, 0.28 mm from a GND pad, with DRC 0 and every check passed; the layout review found it
Why
Under a chip part the solder mask between the pads is a thin web, and a track there runs a few tenths of a millimetre from both pads: if the part shifts or the solder flows, it bridges to a pad of another net, and once the part is soldered that cannot be repaired from outside. It also cuts a pour on that side into pieces. The track keeps the clearance, so DRC and GEO.spacing pass it. In desk-led the first routing by Freerouting ran LED_SW between the pads of R1 and of D1 (0805), 0.28 mm from D1's GND cathode, with DRC 0; only the layout review found it. Routing between the pads of 0805 and 1206 parts is common practice, and no standard gives a number – so a reminder, not a limit (GEO.spacing counts no tracks at hand-soldered joints, #59).
What to do
Route around the part, or turn or move it in [place] so that each track leaves its pad outward, then route all again. Where the track has to pass there, accept GEO.under on the part or the net with the reason.
Sources
proposal #342 from desk-led, its D-6 (docs/decisions.md, commit ab1c9cb) and its layout review 1, note 4 (pcb-reviewer, 2026-11-03): board main, net LED_SW at y 7.86 between the pads of R1 (0805) and of D1 (0805), 0.28 mm from D1's cathode pad on GND, DRC 0; fixed by moving and turning R1 and D1 – the review's judgement, no standard opened
the owner's answer on #342 (2026-11-10): a new code GEO.under, severity note, #59 stays; it fires on every track between the pads with the smallest distance named; 0 Ω parts and tracks on the net of both pads left out; a small chip part read from the pads (two SMD pads on one layer, at most 4.5 × 2.0 mm), between the pads the rectangle between their facing edges across their width, only on the part's layer; the DSN keep-out for Freerouting left to a feature proposal of its own
GEO.ring annular ring
errormargin: warning
Every plated hole keeps JLCPCB's annular ring on TOP and BOTTOM – a component hole 0.18 mm (2 layers, 1 oz; below 0.20 mm a warning), from the hole's edge to the nearest point without copper in the Gerber files, a via 0.05 mm (via Ø at least hole + 0.1 mm) on its own pad, a pour around it not counted; and every two plated holes, also two of one part, keep JLCPCB's hole-to-hole spacing edge to edge: 0.45 mm when a component hole is one of them, 0.2 mm between two vias.
every plated hole keeps JLCPCB's annular ring on TOP and BOTTOM (2 layers, 1 oz): a component hole 0.18 mm, below 0.20 mm a warning per part, a via 0.05 mm (via Ø ≥ hole + 0.1 mm) – measured in the Gerber files: a component hole from the hole's edge to the nearest point without copper, so a pad, a track or a pour around the hole counts alike; a via on its own pad, the flash at its centre as EasyEDA and KiCad write a via (a pour is a region, a track a draw), and on the copper around the hole only where a layer flashes no pad there – inside a pour of its own net the copper around the hole reached the measuring limit of 1 mm and hid a pad too small for its hole; and every two plated holes, also two of one part, keep JLCPCB's hole-to-hole spacing edge to edge: 0.45 mm when a component hole is one of them, 0.2 mm between two vias. Vias are the holes of the via drill file, the other plated holes are named by the through-hole pad of pcb.json at their place. Within 0.001 mm counts as kept (EasyEDA keeps mil and writes mm). waive: {"GEO.ring": "…"} on a part or net lists its holes as waived – why it exists: an RGB LED at 1.25 mm pitch had its holes widened for its legs (GEO.hole) to 0.80 mm with pads of 1.06 mm: a ring of 0.13 mm, below the fab's minimum of 0.18 mm, passed the gate; via pairs 0.47 mm apart were flagged by a review against a figure from memory, where the fab's table allows 0.2 mm
Why
Nothing else looks at the copper around a hole or at the web between two holes: GEO.hole compares a hole with its lead, GEO.spacing the pads of different parts. A footprint whose holes are widened so that the leads fit, as GEO.hole asks, loses ring and web on the same pitch; the fab then grows the pads, asks back (an engineering query costs about a day across time zones) or plates a ring that breaks out. In pytree a four-leg RGB LED at 1.25 mm pitch had its holes widened to 0.80 mm with pads of 1.06 mm: a ring of 0.13 mm, below the fab's absolute minimum, passed the gate and went into the order remark. Via pairs 0.47–0.50 mm apart were flagged by a review against a figure from memory and put on the order checklist; the fab's table allows 0.2 mm.
What to do
Grow the pad or shrink the hole, as far as GEO.hole's lead fit allows. Where the pitch allows neither, a footprint whose pitch carries hole + 2 × ring + the pad clearance, or a part with a matching hole pattern. Holes too close: move a via or a part, or take a smaller hole where GEO.hole still passes. A part whose ring the fab confirmed is accepted in the graph with the reason (accept GEO.ring on the part or its net).
Sources
JLCPCB PCB Manufacturing Capabilities (read 2026-10-26), Traces: PTH annular ring ≧0.20 mm; 2 layers, 1 oz: recommended 0.25 mm or above, absolute minimum 0.18 mm – https://jlcpcb.com/capabilities/pcb-capabilities
JLCPCB PCB Manufacturing Capabilities (read 2026-10-26), Drilling: Via Hole-to-Hole Spacing 0.2 mm, Pad Hole-to-Hole Spacing 0.45 mm (the page says neither edge nor centre; read edge to edge, the stricter reading); via diameter 0.1 mm (0.15 mm preferred) larger than the via hole; hole size tolerance +0.13/-0.08 mm – https://jlcpcb.com/capabilities/pcb-capabilities
pytree, release run 20261025-232212: D31 (XINGLIGHT XL-B504RGBC, 1.25 mm pitch) with holes of 0.80 mm and pads of 1.06 mm – ring 0.130 mm, holes 0.449 mm apart; its decision D-40 and layout review M-5 ("D31 Restring 0,13 mm", at the fab's limit, accepted), 2026-10-25
edakit handbook 8.1 (L-9, L-13)
docs/concepts/done/walkthrough-gaps.md B1, the walkthrough of handbook 17 on examples/coin-cell-led: protocol L reported "narrowest ring 1.000 mm" for its vias, routed at edakit's default [routing] via = [24, 12] mil (0.61 mm on a 0.305 mm hole, a ring of 0.15 mm) inside its GND pours
Replaces L-16
GEO.keepout keep-out areas free of copper
warningedge: warning
Where a part's entry gives an antenna keep-out (antenna.keepout_mm, in the footprint's frame), the board has no copper inside it on either layer – tracks, pours, pads and vias of any net – placed where the part sits; for a module plugged over a carrier the carrier's copper counts. Where the entry also gives how far inside the board's outer edge the antenna area may lie (antenna.edge_mm, the module maker's layout guide), the area lies at or over the outer outline of the Gerber files, at most that far inside it – a cut-out inside the board is no edge (grade edge). A warning while new.
the antenna at the edge (grade edge): the antenna area of antenna.keepout_mm, placed where pcb.json has the part, measured against the outer outline of the Gerber outline file with shapely – at or over it passes, inside it the distance to the outside is held to antenna.edge_mm (0.05 mm for the outline's rounding); a closed path inside the board (a hole, a cut-out) does not count as the edge, because Espressif asks for the module at the board's edge, not in the middle with a clearance hollowed out on all four sides. Espressif's modules: 1 mm for the ESP32 and ESP32-S3 modules (figures 25 and 26 of their hardware design guidelines, 'Max 1' between the antenna and the board's edge), 0 for the ESP32-C3 modules (figure 21 shows no distance; the text asks for the antenna outside the base board). The clearance of at least 15 mm beside an antenna in a cut-out and inside the housing is not checked – the pcb reviewer asks for it (domain radio) – finds e.g.: a WROOM module placed in the middle of a carrier, its antenna over the carrier's material
Why
Copper under or next to a module's printed antenna detunes it and shields it: range drops, and a design that passed every electrical check needs a new board. The area is the module maker's, so it belongs into the parts entry; the board's copper is in the Gerber files (maker-coverage CK-11; the bell's ESP32 variant had the carrier's copper under the module's antenna).
What to do
Move the copper out of the area – pours with a keep-out region, tracks around it –, or the part so that its antenna lies over the board edge, or cut the board away beside and below the antenna from its edge; take the area from the module's datasheet into antenna.keepout_mm and the distance from the maker's layout guide into antenna.edge_mm.
Sources
docs/concepts/done/maker-coverage.md, CK-11 (appendix MCU 6; the owner's bell, ESP32 variant)
Espressif, ESP32 Hardware Design Guidelines, release master (26 October 2026), 1.4.8 General Principles of PCB Layout for Modules (Positioning a Module on a Base Board), p. 27–29: 'place the module's on-board PCB antenna outside the base board, and the feed point of the antenna close to the edge of the base board'; if it cannot extend beyond the board edge, the feed point as close to the edge as possible and the base board cut off on both sides of the antenna and below it; 'the module should not be placed in the center of the board with clearance created by hollowing out on all four sides'; a clearance of at least 15 mm in all directions inside the housing; figure 25 (read from the graph): the antenna area 6.19 mm deep at the board's corner, the board's edge at most 1 mm beyond its outer side and at most 2 mm beyond the module's side, the board cut away at least 15 mm beside the antenna – https://docs.espressif.com/projects/esp-hardware-design-guidelines/en/latest/esp32/esp-hardware-design-guidelines-en-master-esp32.pdf, read 2026-10-31
Espressif, ESP32-S3 Hardware Design Guidelines, release master (26 October 2026), 1.4.7 General Principles of PCB Layout for Modules, p. 29–31, figure 26 (read from the graph): as the ESP32's, the antenna area 6 mm deep, 'Max 1' and 'Max 2', 'Min15' – read 2026-10-31
Espressif, ESP32-C3 Hardware Design Guidelines, release master (26 October 2026), 1.4.7 General Principles of PCB Layout for Modules, p. 21–23, figure 21 (read from the graph): the antenna area 6 mm deep in a cut-out of the board's edge, at least 15 mm clear to both sides and above it, no distance to the edge given – read 2026-10-31
Espressif module datasheets ESP32-WROOM-32E & -32UE v2.1, ESP32-S3-WROOM-1 & -1U v1.8, ESP32-C3-MINI-1 & -1U v2.2, 11.2 Module Placement for PCB Design: they refer to the hardware design guidelines' section on positioning a module on a base board – read 2026-10-31
GEO.hole hole fits the lead
errormargin: warningunknown: note
Every plated hole takes its lead at nominal size (lead in the entry) – on the footprint geometry before the layout, on the drill file in the gate; less than 0.05 mm play in the worst case, or a plated slot narrower than 0.5 mm, is a margin.
through-hole leads known and fitting the footprint, before the layout: GEO.hole's test (8.1) on the holes of the footprint geometry – the board's pcb dump, else the library footprint of edakit part import; plated holes without lead in the entry pending, a hole that does not take the lead an error (accept on the component), tight in the worst case or a plated slot below 0.5 mm a warning; without geometry a note – finds e.g.: a library footprint drilling 0.70 mm for □0.5 mm legs, found before anything is placed
every through hole takes its lead at nominal size (lead data in the component's parts entry – its lcsc, or without one the entry its part names, as for every other check, 3.1); worst case (hole −0.08 mm, lead + tolerance) below 0.05 mm play or plated slots narrower than 0.5 mm: warning per part. GEO.hole runs the same test before the layout, on the footprint geometry (3.3) – why it exists: two parts whose leads would not have fitted the library holes
Why
Nobody else checks library footprints: the Christmas bell's Nano footprint had 0.9 mm holes for 0.64 mm square header tails (diagonal 0.91 mm). JLCPCB drills plated holes +0.13/-0.08 mm.
What to do
A footprint with larger holes, a part with thinner leads, or a decision (D-...) if the fit is accepted.
Sources
JLCPCB PCB capabilities: hole size tolerance +0.13/-0.08 mm, minimum plated slot width 0.5 mm on 2 layers – https://jlcpcb.com/capabilities/pcb-capabilities (read 2026-10-27)
edakit's print lies on no solder-mask opening and inside the outline, every part has a visible designator, the visible side carries only the texts the board file puts there, and no print lies under a body larger than its footprint (body.box of the parts entry) – grade body.
the silkscreen from the Gerber files (silk, mask, outline), per side. edakit's own print on a solder-mask opening fails: the designators, texts and artwork of silk apply, i.e. what is not in the print silk apply found before it placed anything (it keeps that in <artifacts>/silk_footprints_<board>/). Warnings: other print on an opening, one per part (the part of the nearest pad); print beyond the board outline, one per side; a part of the designators side without a visible designator (read with the PCB), group label ([silk] groups) or line in [silk] unlabelled; a text height edakit prints below 1.0 mm (label_h_mm, board_label_h_mm, h_mm of [[silk.texts]]). Spots below 0.0005 mm² are rounding; a side or part counts from 0.001 mm² – why it exists: designators lost after reroutes and a test point never labelled were found on pictures or in a review; the released board passed the gate with footprint print on the mask openings of 11 parts, which JLCPCB clips, and 3.3 mm² of print beyond its outline
under a body larger than its footprint (grade body, a warning while new): a part whose parts entry gives body.box (4.1, the body seen from above in footprint mm – a coin cell standing out of its holder) covers the print under it. The box is placed where pcb.json has the part; where it reaches beyond the footprint's box (the geometry of pcb dump), print on the part's side in the Gerber file – a designator, a text – warns, one row per part with its spots; inside the footprint box lies the footprint's own print, which the Gerber file cannot tell from a designator, and nothing there is looked at. A part without body.box gets no row, one without footprint geometry is listed as not checked. silk apply places designators beside the body and names a fixed designator ([silk] place) under one – why it exists: in the walkthrough (handbook 17.11) silk apply put BT1's designator right above the holder's footprint box, under the coin cell; the layout review found it, every check had passed
with [looks] (7.5): every PCB text on the silkscreen of the visible side (pcb.json strings) is one the board file puts there – the board label when its side (board_label_side, default the designators side) is the visible one, the text of a [[silk.texts]] entry of that side, and, when [silk] designators is that side, a designator of the board or a key of [silk] groups; while [silk] designators names the other side, no part on the visible side shows its designator (read with the PCB, as GEO.silk). One fail per text or part, with side, text and position: BOTTOM (visible): D31 shows its designator – [silk] designators is top, TOP (visible): text 'TEST' at (15.0, 3.0) mm is neither the board label nor a [[silk.texts]] entry of this side. The footprints' own print is no PCB text (GEO.mark, GEO.silk), artwork is fills; a "+" placed by hand as a text goes into [[silk.texts]], where GEO.mark still reads it. waive: {"GEO.silk": "…"} on a part lists its designator as waived – why it exists: a part placed again after silk apply (a footprint change) came back with its designator on the LED side, whose rule was designators off and the version line as the only text; every check passed and the layout review rated it "block"
Why
Every reroute moves vias and parts, so a designator that had room loses it; silk apply only says 'without room' and goes on, its own check of the openings is a separate command, and print beyond the outline was checked nowhere. JLCPCB clips print on openings, prints nothing beyond the board edge, and calls characters below 1.0 mm unidentifiable. In pytree a test point never got a label and three designators were lost after reroutes, each found on pictures or in a review; the released tree board passed the gate with footprint print on the mask openings of 11 parts and 3.3 mm² of print beyond its outline.
What to do
Own print on an opening: run edakit silk apply again after the last routing. Footprint print on an opening or beyond the outline: correct the footprint, or accept the warning. A part without a designator: give it room, a group label ([silk] groups), or list it in [silk] unlabelled with the reason. A text below 1.0 mm: raise label_h_mm, board_label_h_mm or h_mm, or accept the warning. Print under a body: run edakit silk apply again (it places designators beside the body), move a fixed designator ([silk] place) or a text out of the body, or accept the warning.
Sources
JLCPCB PCB Manufacturing Capabilities, Legend (read 2026-10-27): minimum line width 0.15 mm; minimum text height 40 mil (1.0 mm), 'Characters height less than 40 mil(1.0mm) will be unidentifiable'; minimum distance between pad and silkscreen 0.15 mm – https://jlcpcb.com/capabilities/pcb-capabilities
edakit handbook 7.7 and 8.1
pytree's layout review M-5, 2026-10-25: footprint frames on pads, designators about 0.7 mm high accepted; JLCPCB's DFM warning 'silkscreen outside board' on its base board, accepted
pytree, hardware/release/signoff.json, the layout review M-5 of 2026-10-27: first round at gate run 20261027-211238 "'D31' vorne gedruckt (block, baum_druck lief nicht)" – fixed: on the LED side only the version line as text
pytree, hardware/easyeda/KONZEPT_bestueckungsdruck.md, section 'Baum-PCB, LED-Seite (Schaufenster)': the designators of the LED side all hidden (S-3), the version line in the hill zone; hardware/easyeda/baum_druck.py, module docstring: LED side (BOTTOM) artwork as fills and the version line as text, designators off, the footprints' polarity marks stay
pytree's gate runs 20261027-211238 and 20261027-214622: Gerber_BottomSilkscreenLayer.GBO of the first holds the glyphs 'D31' at x 1.26…3.03, y 163.37…164.17 mm (0.686 mm², not in the second); pcb.json of both has the version line 'pytree · Baum · Rev 2 · 2026' as the only PCB text of the bottom silkscreen – the 'D31' was the part's designator
edakit handbook 7.5 (the visible side, [looks]), 7.7 (silkscreen: hide, [[silk.texts]], the board label) and 8.1 (L-17)
edakit handbook 17.11, the layout review of the walkthrough on examples/coin-cell-led, note 1: BT1's designator lay under the cell, fixed in the example by [silk] place; the handover note there: the cell (Ø 20 mm) stands 2 mm out of BT1 (16 mm wide) on both long sides; docs/concepts/done/walkthrough-gaps.md B3