pcb · routing · post-mortem

Re-routing flexisette: ten open nets to zero, by routing the real board

2026-10-04 · Dan Newcome

flexisette is the board that taught us most of what our PCB tooling knows, and in June it beat us anyway. It is a cassette-shaped ESP32-S3 music player: an OLED glowing through the tape window, a small class-D amp, USB-C and a LiPo, on the real outline of a compact cassette with its window, reel holes, screw holes and head notch. After three days of work we called it prototype-ready with about ten connections still open, left for hand-finishing. This week we re-ran it next to the original, as we did with einhander. Same circuit, same floorplan, nobody touching KiCad. The re-run has no open connections and no DRC errors, and the routing takes six seconds.

The re-routed flexisette board on its own: a cassette-shaped outline in cyan with the rectangular tape window between two round reel holes, four corner screw holes and the head notch cut out of the bottom edge. The ESP32 module is on the left, USB-C and the charger along the top, the amplifier and speaker connector on the right, joined by magenta top-layer and blue bottom-layer traces.

01 / The two boards

The flexisette board drawn twice. Top, the June board: a long dashed orange line runs from the ESP32 module on the left to the amplifier on the right, with shorter dashed lines around the amplifier, marking 10 open connections; magenta rings mark DRC errors at the USB-C connector and at the left board edge. Bottom, the re-run: the same parts in the same places, routed, with no markers.

Shipped (June)Re-run
Open connections100
Shorts00
DRC errors, JLCPCB rules50
Pads not reached on their own layer40
Vias2647
Track length1263 mm1000 mm
Ground run as track instead of pour350 mm44 mm

Both are 2-layer boards with a ground pour on the bottom, scored the same way. The re-run's netlist is identical to the shipped board's: 22 nets, the same pads on each. It passes KiCad DRC at every severity with five silkscreen warnings, and our checks for hole spacing, via sizes and pads reached only from the wrong side. It has not been through JLCPCB's online DFM or a human review yet, so it is not an order.

02 / What went wrong in June

In June the router never saw the board we were building. The pipeline asked tscircuit for a Specctra DSN file, patched that file with scripts (keepouts for the tape window and reel holes, merged net names), routed it with Freerouting, and injected the result into KiCad through its scripting API, which needs KiCad running. That left two descriptions of the board to keep in step: the KiCad file and the DSN. Our own roadmap listed the consequence as known gap number one: move a part, and the router still routes it where it used to be.

The obvious fix is to export the DSN from KiCad itself, so the router gets exactly the board on disk. We tried that in June. KiCad's exporter returned "false" with no message, every time. A web search turned up reports of it being broken for years, so we gave up on it and built around it.

03 / The exporter was never broken

KiCad refuses to export any board that contains a footprint with an empty reference, and when run from a script it says nothing about why. tscircuit exports its bare holes and vias as footprints with no reference. flexisette has one. einhander has four, and the same export failed there last week. Give those footprints a name for the round trip and the export works first time.

What comes out is better than anything we were patching by hand:

The first run on the unchanged June placement left one item: a button pad 0.455 mm from the edge of the head notch, flagged against KiCad's default 0.5 mm edge rule. No open connections at all.

04 / The leftovers were placement questions

That first run flattered the placement. Small changes to the input moved the result between zero and three leftover items, which is what a marginal placement looks like. We treated each leftover as a question about the placement rather than a routing job, and each had an answer in the design source:

LeftoverWhat the placement was doingChange
Button pad too close to the notch edgeThe buttons sat 0.455 mm from the notch. That passes JLCPCB's 0.2 mm rule but not KiCad's default, and it is tight for a part people press.Both up 0.5 mm.
Decoupling cap's ground pad not connectedThe cap sat on the bottom, directly under the ESP32's power pin at the board edge. One bottom track boxed its ground pad off from the pour.2 mm inboard, under the module.
Battery net open at the charger's capacitorThe capacitor was on the far side of the charger chip, 5 mm of crowded routing from the pin it serves.Placed at the pin, by the same helper that places the other decoupling.

After those three changes the pipeline reports a clean board, and it does so again when run from scratch. This is the point we keep coming back to: routing difficulty is set by placement, and what a router leaves behind is the cheapest placement review you can get. In June we read the same kind of leftovers as a routing tail and went looking for a better router.

05 / Three more things the board caught

The capacity autorouter also connected every net on this board with no shorts, but left 14 clearance violations, so Freerouting's candidate is the one we kept. Both are scored by the same harness as in the benchmark post, and it keeps whichever is closest to done.

06 / What's still open

The re-run is in pcb-rerun/ at punkfab/flexisette, next to the original pcb/, with the comparison and a one-command reproduce. The pipeline (route2.sh) and every fix above are in the pcb-layout skill at punkfab/circuit-skills. Have a board stuck a few nets from done? Start a project →