Play in your browserDoom handheld
A real Doom handheld: an RP2350 (Pico Plus 2) under a 2.8″ ILI9341 screen with ten buttons, on a routed red keycard.
Ready to order42 parts2 layersGPL-2.0
Tell your agent what you want to build. PCBKit turns it into a real circuit board: wired, checked, simulated, running its firmware and ready for the factory, in minutes. In your browser, or right in Claude, ChatGPT, Claude Code and Codex.
Works withClaudeClaude CodeChatGPTCodexCursorGemini CLIOpenCode
Have a KiCad board? Drop it anywhere on this page to open it in PCBKit.
A .kicad_pcb with its project and rules, a folder or a zip of a KiCad project.
The board stays on your computer: nothing is uploaded.
Open the app and drop it thereThe renderer
Not a mock-up: every frame is PCBKit’s own renderer drawing real open boards, the same one that runs in the app on your screen.
AI guide
Rendered frame by frame by PCBKit’s own renderer; the radio board routed by PCBKit from bare pads. Open boards by their authors: MIST.1010 by Eugene Lozovoy (MIT), HBR MK2 RX/TX by Aleksander Alekseev (MIT), Cynthion by Great Scott Gadgets (CERN-OHL-P-2.0), moco RD501 by ZiTe (CERN-OHL-P-2.0), ESP32-WROOM-32 USB Development Board by Habib Ur Rehman (CERN-OHL-S-2.0), pslab hardware by FOSSASIA (Apache-2.0).
The lab
Doom.Design the board, write its firmware, press Run. PCBKit compiles your C in the browser tab and runs the image on models of the board’s own chips, screen and buttons included: the same image you would flash onto the board when it arrives. We built eleven Doom handhelds to prove it. Pick one and play.
11
Doom handhelds, every one routed, checked and ready to order
7
processors: RP2040, RP2350, ESP32-S3, ESP32-C3, STM32F411, i.MX RT1062, CH32V003
3
instruction sets in the page: Arm, RISC-V and Xtensa
0
things to install: the compilers run in your browser tab
Play in your browserA real Doom handheld: an RP2350 (Pico Plus 2) under a 2.8″ ILI9341 screen with ten buttons, on a routed red keycard.
Ready to order42 parts2 layersGPL-2.0
Play in your browserThe big-screen ESP32-S3: its LCD_CAM scans a raw 480 × 272 RGB panel out of a frame buffer in the octal PSRAM by DMA, ten buttons on an I2C expander, two 18650 cells.
Ready to order97 parts4 layersGPL-2.0
Play in your browserThe most capable variant: a Teensy 4.1 (i.MX RT1062, Cortex-M7 at 600 MHz) behind a 3.5″ 320 × 480 touch screen, the WAD in its 8 MB flash, ten buttons, audio to headphones and a speaker, two 18650 cells.
Ready to order88 parts4 layersGPL-2.0
Play in your browserThe cheapest chip that runs Doom, by emulation: a CH32V003 with 2 KB of RAM interprets a larger RISC-V computer whose program boots from a 16 MB SPI flash and runs in an 8 MB SPI PSRAM, on a Nokia 5110 screen.
Ready to order67 parts2 layersGPL-2.0
Play in your browserA through-hole Doom kit: a Raspberry Pi Pico on sockets behind a 2.42″ 128 × 64 OLED, the shareware game compressed into its 2 MB flash (rp2040-doom), each frame dithered to one bit, eight buttons, two 18650 cells.
Ready to order43 parts2 layersGPL-2.0
Play in your browserA Game Boy-shaped Doom handheld on an ESP32-C3 module (RISC-V, 400 KB of SRAM, no PSRAM): the shareware game read in place from its 4 MB flash, a 1.3″ 240 × 240 IPS screen, eight buttons, two 18650 cells charged from USB-C.
Ready to order58 parts2 layersGPL-2.0
Play in your browserThe Black Pill's STM32F411 (Cortex-M4F, 128 KB of SRAM) with an 8 MB SPI PSRAM and a 16 MB SPI flash: it runs a RISC-V computer built from the serial chips, through a cache, on a 2.0″ IPS.
Ready to order79 parts4 layersGPL-2.0
Play in your browserThe RP2040 chip without a module: Raspberry Pi's minimal design with a 16 MB flash, the shareware game in it, a 1.8″ colour TFT, eight buttons, two 18650 cells charged from USB-C, on four layers.
Ready to order92 parts4 layersGPL-2.0
Play in your browserThe classic ESP32 Doom: an ESP32-S3 module with 16 MB of flash and 8 MB of octal PSRAM under a 2.8″ ILI9341 touch screen, the WAD in flash and the heap in PSRAM, ten buttons, two 18650 cells.
Ready to order75 parts4 layersGPL-2.0
Play in your browserThe RP2350A without a module: QSPI flash and an 8 MB PSRAM on one bus, both mapped through the XIP cache, a 2.0″ IPS, microSD, an I2S amplifier and a fuel gauge on four layers.
Ready to order100 parts4 layersGPL-2.0
Play in your browserThe reference device made orderable: a carrier for the Pimoroni Pico Plus 2 (RP2350, 16 MB flash, 8 MB PSRAM) with a 2.8″ ILI9341 touch screen, ten buttons and a headphone DAC.
Ready to order62 parts2 layersGPL-2.0

Not just games
Write C for an ATmega328P and watch it run on the board in 3D: real instructions, simulated sensors, and a display that lights up because your code drove it. Make the room warmer, breathe some CO₂ into it, and see what your program does about it.
Drag temperature, humidity and CO₂. The SHT31 and the SCD40 sample them on their own clocks; the display changes only when your firmware writes it.
An ATmega328P executes your program instruction by instruction, with I²C and SPI timed from its clock. Anything not modelled stops with a message instead of a guess.
Charge, average draw, peak current and hours left, from each part’s current profile and what your code switches on.
#define CO2_ORANGE_PPM 800
#define CO2_RED_PPM 1200
static void co2_indicators(void) {
uint8_t bytes[9];
if (!scd_command(0xec, 0x05) || !scd_read(bytes, 9)) { PORTD = 0; return; }
for (uint8_t i = 0; i < 9; i += 3)
if (crc(bytes + i) != bytes[i + 2]) { PORTD = 0; return; }
uint16_t ppm = ((uint16_t)bytes[0] << 8) | bytes[1];
PORTD = ppm < CO2_ORANGE_PPM ? 1 << PD5
: ppm < CO2_RED_PPM ? 1 << PD6
: 1 << PD7;
}The firmware is a plain C file in the project, next to the board. Change the thresholds, build, and the simulated chip restarts with your program, keeping the room and the battery as they were. A compiler error leaves the last image paused and points at the line.
Sensors are timed digital models, not analog physics, and the battery figures are estimates. Anything a model does not cover stops with a message instead of a guess.
Ready to orderAir quality meterAn air meter you can run: an Arduino Nano with real C firmware reads an SHT31 and an SCD40 and shows temperature and humidity on a MAX7219 display, with green, orange and red CO₂ lights.
Ready to orderServo controllerA device you can run: an Arduino Nano reads a knob and a button and drives a servo with PWM, sleeping between interrupts.
Ready to orderSerial command deviceA device you talk to over UART: an Arduino Nano echoes every byte and turns its light on for 1 and off for 0.
Ready to orderLED ringTwelve lights round a black disc, each dimmed by software PWM from a timer interrupt: a spinning comet with a fading tail, a dial gauge of the knob from green to red, a breathing wave.
Ready to orderStopwatchA watch face that keeps time: a 1 kHz timer interrupt counts in decimal digits and a MAX7219 shows hours to hundredths.
Ready to orderReaction gameHow fast are you? Press to start: red, amber, a random wait, then green and GO.
Ready to orderGreenhouse controllerA house-shaped board that opens its window: an SHT31 reads the temperature, an SCD40 the CO₂, and a servo opens the window when it is too warm or stuffy.
Ready to orderServo sequencerThree servos from one timer interrupt.
Ready to orderPedestrian crossingA traffic light for cars and one for people, as a state machine: press PUSH and the countdown starts, cars get amber and red, WALK shows the seconds left and flashes before it ends.
Ready to orderMessage scrollerType into the serial console and your words scroll across eight seven-segment digits, letters included, in a font of the program's own.From the blog
An open toolchain repositoryPCBKit runs GCC in your browser to build Arduino sketches and GCC is GPL. So the compilers live in github.com/pcbkit-io/toolchain: built from pinned published sources to WebAssembly, each release with its source archives and licences. What is in it, how reproducible it is and how fast the compilers are.
Doom, real Arduino and boards on any page: what changed this weekEleven Doom handhelds that build and play in the browser, twelve Arduino boards with real sketches, open toolchains, a registry that says which boards are ready to order and a way to put any GitHub board on any web page. A short tour, with links to the long posts.
Put your board on any web pageOne line of HTML shows the board of any GitHub repository live on your site, in 3D, its layers apart, its AI tour. Or as a picture for a README, a post or a slide. It reads the board from GitHub, so there is nothing to host and nothing to sign up for.Arduino
In a tab.Real sketches with the libraries everyone uses, built in your browser exactly as the Arduino IDE builds them, running on a whole simulated ATmega328P beside the board in 3D. Change the weather, press the buttons, turn the knobs. Then order the board and flash the same sketch onto it.
Ready to orderWeather stationAn Arduino Nano reads an SHT31 and shows the temperature and humidity large on an OLED, with the dew point and how the air feels, the day's lowest and highest and a graph of the last two minutes.
Ready to orderCO₂ monitorSensirion's SCD40 measures CO₂, temperature and humidity every five seconds; the OLED shows the concentration with a ten-minute graph and a traffic light says when to open a window.
Ready to orderThermostatA room thermostat that turns a radiator valve: a PI controller opens a servo as far as an SHT31 finds the room below the setpoint, the red light shows heating, − and + set the target and the EEPROM keeps it.
Ready to orderLCD runnerThe classic 16 × 2 character LCD on LiquidCrystal's wiring: a dinosaur made of custom characters runs along the bottom line, jumps cacti with the button and runs under birds; turn the trimmer and the contrast changes as on the real module.
Ready to orderEgg catcherThe 1980s pocket game on a battery: eggs roll down four chutes and the catcher's basket goes where you press, Q and A on the left, P and L on the right; three broken eggs end it.
Ready to orderSnakeSnake on the pocket console, an Arduino Nano behind a 0.96" OLED with a D-pad and two buttons: steer with the arrow keys, eat, grow and go faster; the best score stays in the EEPROM.
Ready to orderPongPong on the pocket console: you on the left with up and down, the computer on the right; the ball speeds up with every return and leaves the paddle at an angle.
Ready to orderFlappy birdA flappy bird on the pocket console: X flaps, gravity does the rest, pipes scroll in with a gap to fly through; one point a pipe and the best kept in the EEPROM.
Ready to orderBreakoutBreakout on the pocket console: move the paddle with left and right, serve with X; five rows of bricks, three balls, the angle off the paddle set by where the ball lands.
Ready to orderFalling blocksFalling blocks on the pocket console: a 10 × 20 well beside the next piece and the score; left and right move, X turns, down drops faster, Z drops at once; full lines clear and the pace rises.
Ready to orderDiceDice on the pocket console: X rolls one to five dice that tumble before they settle, up and down choose how many, Z shows how often each sum came up.
Ready to orderSimonSimon on a round board: four coloured lights, each with its button; the Nano plays a sequence and you repeat it, one more every round, a little faster.
Ready to orderMagic drawing screenTwo knobs draw on an OLED, one across and one up and down, as on the toy; the button wipes the picture.
#include <Wire.h>
#include <SensirionI2cScd4x.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 display(128, 64, &Wire, -1);
SensirionI2cScd4x scd40;
void setup() {
pinMode(GREEN, OUTPUT);
Wire.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
scd40.begin(Wire, SCD40_I2C_ADDR_62);
scd40.wakeUp();
sensorFound = scd40.startPeriodicMeasurement() == 0;
}All Arduino boards in the appThe boards and sketches on GitHub
Toolchains and chips
No installer, no SDK download, no USB cable. The compilers are open-source toolchains built to WebAssembly from their published sources, and the chips are models that run the image instruction by instruction. Anything a model does not cover stops with a message instead of a guess.
AVR and Arduino
avr-gcc 15.2.0, binutils 2.45, avr-libc 2.2.1, ArduinoCore-avr 1.8.8, fourteen libraries and Arduino’s ctags, built to WebAssembly from pinned sources; a rebuild reproduces the tools byte for byte.
ATmega328P, ATmega168P
Clang and LLD 19
RISC-V and Arm Cortex-M from one compiler, with a kit per chip: start-up code, link layout and register headers.
RP2040, RP2350, STM32F411, CH32V003, i.MX RT1062
Espressif Clang 22
Espressif’s LLVM for the Xtensa cores, compiled to WebAssembly and checked against the real boot ROMs.
ESP32-S3, ESP32-C3
| Test sketch | Against simavr |
|---|---|
| serial | 53 bytes on the USART, equal |
| interrupts | equal intervals, but 4 cycles to enter each interrupt (the data sheet’s 4; simavr counts none) |
| pwm | Timer0 periods equal; simavr drives no Timer1 or Timer2 compare output |
| eeprom | 30 bytes equal; each EEPROM write takes 3.4 ms here, none in simavr |
| servo | 20 ms frames and pulse widths equal; writing TCNT1 blocks the next match, as the data sheet says |
How it works
A circuit board is the green card inside every gadget: chips sit on it and thin copper tracks connect them. Drawing those tracks by hand takes days. With PCBKit you describe the device, your agent writes the design, and PCBKit lays out the copper so it follows every rule. Say “move the connector to the left edge”, and the board follows.
“A USB-C sensor node, 50 × 30 mm, two layers, a port for an I2C sensor.” Plain words are enough.
It picks proven circuits and real parts and writes them into one small file. PCBKit checks every line as it lands.
It places the parts, routes every connection in copper and fills the ground plane, while you watch in 3D.
Gerber and drill files, the parts list and the placement file, zipped the way board factories ask for them.
Colour, finish and quantity, checked against what the factory can make, ordered from the app.
The router
We put PCBKit’s router against another open-source autorouter, on that router’s own benchmarks: the same boards stripped to bare pads, the same machine, 120 seconds and 8 threads each, one run. KiCad’s own design-rule checker judged every result.
1,026/1,157
human-designed PCBench boards routed clean from bare pads, judged by KiCad’s own DRC (the other router: 958)
16×
faster on the median board of tier A: 0.4 s against 6.6 s, with the same 120 s and 8 threads each
½
about half the vias on the boards both routers finish, with slightly shorter copper, in a quarter of the memory
| Set | Boards | PCBKit clean | Other router clean | Median s, PCBKit | Median s, other router |
|---|---|---|---|---|---|
| PCBench A | 453 | 449 | 447 | 0.4 | 6.6 |
| PCBench B | 560 | 491 | 436 | 3.4 | 30.0 |
| PCBench C | 122 | 77 | 66 | 9.4 | 101.7 |
| PCBench D | 22 | 9 | 9 | 102.3 | 103.2 |
| KiCad demos | 20 | 12 | 7 | 17.2 | 102.1 |
Routing is a hard search: thousands of connections competing for the same few millimetres. Here is how PCBKit solves it in seconds, on a laptop, inside a browser tab.
All nets are routed at once, overlapping at first. Each pass makes contested space more expensive, until no two nets share it. The search grid has eight directions and spans every layer.
The grid guides the search, but every clearance is checked against exact geometry, to a fraction of a micron. Fine-pitch escapes with zero slack still fit.
Next it rips up a window around whatever is still unrouted, routes it again and keeps the result if it is better. Eight candidate states are searched side by side.
Copper pours are modelled while routing: the fill, the clearance around other nets, islands and thermal spokes. The router knows which pads a pour actually connects.
A pad on a dense part gets up to eight exact, full-width exits. Neighbouring pads negotiate for them instead of each getting a fixed stub.
It knows where the solder mask opens, which vias are untented and where thin mask webs sit between pads, and routes so the fab can keep them.
Analysis and simulation
Where does the power go, which track runs hot, how many millivolts reach the far connector? Ask the board. PCBKit solves the physics of the copper you actually routed, in your browser, and says plainly what it could not know.

Voltage domains and where the power flows, the temperature rise of every power track, the board’s heat as a field, and a checklist for the factory, drawn over the board in 2D and 3D.
Every track, via and pour of a net meshed and solved: current divides the way it really does, and you see where millivolts and milliwatts go.
Operating points, AC sweeps and adaptive transients, with SPICE netlists imported: subcircuits, behavioural sources, switches.
Joule heat from the copper feeds the board’s temperature, which changes the copper’s resistance, until both agree.
2D electric fields for capacitance and impedance, and reflection, phase and loss along a transmission line.
Solvers agree with ngspice to eight digits on a 40,000-node network, the browser’s answers match native ones bit for bit, and a model PCBKit lacks is reported as missing, never filled in.
Plugins
One plugin for Claude, Claude Code, ChatGPT and Codex. It gives your agent PCBKit’s tools and teaches it how to use them, so it designs boards instead of guessing. No new assistant to learn, nothing to run on your computer, no account to start.
Add the marketplace and install the plugin.
claude plugin marketplace add seralexeev/pcbkit-plugins
claude plugin install pcbkit@pcbkitThe same repository is a Codex marketplace.
codex plugin marketplace add seralexeev/pcbkit-plugins
codex plugin add pcbkit@pcbkitAdd a custom connector in the settings with this address. Listings in both directories are in review.
https://mcp.pcbkit.io/mcpThen ask: Make a board with an LED that blinks every 2 seconds.
mcp.pcbkit.io/mcp, which any assistant that takes MCP servers can use too.pcbkit.hello("my-agent")
await pcbkit.commands("route") // what it does, its schema
await pcbkit.call("route", {}) // runs as a job
await pcbkit.wait("job")
await pcbkit.call("view.state", {}) // what the person sees
await pcbkit.call("journal.since", {}) // what changed since my turnClaude Code, Codex, Cursor, Gemini CLI or OpenCode drive the open page through a small API. You both work on the same board, and every change can be undone. A journal tells the agent what changed since its turn, and it sees what you see. Browsers with WebMCP get every command as a tool.
window.pcbkit
The pcbkit command line runs the same commands on a board repository and serves them over MCP to any local agent. Every command says what it does, what it takes and what it changes, with a JSON Schema; /agents.md and /llms.txt are generated from them.
pcbkit mcp
The language
Under the hood, a board is one short text file, design.pcbkit. It says what’s on the board and how it’s connected, with real units, and PCBKit works out where the copper goes. Your agent writes it, you can read it, and git keeps every version.
use "blocks/support.pcbkit" as support
net GND, VBUS
net V3 named "+3V3"
net USB_DP, USB_DN
net STATUS
bus I2C[2]
pair USB = (USB_DP, USB_DN)
board = Board {
name = "sensor-node"
outline = rect(50mm, 30mm)
cutouts = [circle((3.5mm, 26.5mm), 1.6mm), circle((46.5mm, 26.5mm), 1.6mm)]
layers = [signal(Cu.top), signal(Cu.bottom)]
}
usb = NetClass {
trackWidth = 0.2mm
diffPairGap = 0.2mm
nets = [USB]
}
ldo = support.Ldo(VBUS, V3, GND, bulk = 4.7uF) { at = (14mm, 24mm) }
U1 = Mcu {
at = (25mm, 14mm)
pins { VDD: V3, DP: USB.p, DN: USB.n, SDA: I2C[0], SCL: I2C[1], LED: STATUS, GND: GND }
}
status = support.StatusLed(STATUS, GND) { at = (34mm, 6mm) }
sensor = support.SensorPort(V3, I2C[0], I2C[1], GND) { at = (46mm, 15mm) }
gnd = pour(net = GND, layers = [Cu.bottom]) { outline = board.outline }
rule UsbPair {
select = copper(pair = USB)
limits { trackWidth: limit(min = 0.2mm), diffPairGap: limit(min = 0.15mm, max = 0.25mm) }
}
use "blocks/support.pcbkit" as support
// USB-powered sensor node: 3.3 V regulator, QFN-32 MCU, I2C sensor port and SWD port.
net GND, VBUS
net V3 named "+3V3"
net USB_DP, USB_DN
net STATUS
bus I2C[2]
pair USB = (USB_DP, USB_DN)
board = Board {
name = "sensor-node"
outline = rect(50mm, 30mm)
cutouts = [circle((3.5mm, 26.5mm), 1.6mm), circle((46.5mm, 26.5mm), 1.6mm)]
layers = [signal(Cu.top), signal(Cu.bottom)]
}
supply = NetClass {
trackWidth = 0.5mm
nets = [VBUS, V3, GND]
}
usb = NetClass {
trackWidth = 0.2mm
diffPairGap = 0.2mm
nets = [USB]
}
part Mcu = device(footprint = qfn(32, size = (5mm, 5mm), ep = (3.1mm, 3.1mm)), pinout = {
VDD: ["1", "17"],
DN: "3",
DP: "4",
NRST: "8",
SDA: "21",
SCL: "22",
LED: "24",
SWDIO: "29",
SWCLK: "30",
GND: "33",
})
part C100n = cap(100nF, package = "0402") // one per supply pin
J1 = header(4) {
at = (4mm, 15mm)
pins = [VBUS, USB.n, USB.p, GND]
}
ldo = support.Ldo(VBUS, V3, GND, bulk = 4.7uF) { at = (14mm, 24mm) }
U1 = Mcu {
at = (25mm, 14mm)
pins { VDD: V3, DP: USB.p, DN: USB.n, SDA: I2C[0], SCL: I2C[1], LED: STATUS, GND: GND }
}
decoupling = {
for ((i, p) in enumerate([(21mm, 17mm), (29mm, 11mm)])) {
[i]: C100n { at = p; rotation = 90deg; pins { a: V3, b: GND } },
}
}
J3 = header(5, pitch = 1.27mm) {
// debug port, joined to the MCU's pins directly
at = (25mm, 3mm)
rotation = 90deg
pins = [V3, U1.pin.SWDIO, U1.pin.SWCLK, U1.pin.NRST, GND]
}
R1 = res(10kohm, package = "0402") {
at = (20mm, 8mm)
pins { a: V3, b: U1.pin.NRST }
}
status = support.StatusLed(STATUS, GND) { at = (34mm, 6mm) }
sensor = support.SensorPort(V3, I2C[0], I2C[1], GND) { at = (46mm, 15mm) }
gnd = pour(net = GND, layers = [Cu.bottom]) { outline = board.outline }
rule UsbPair {
select = copper(pair = USB)
limits { trackWidth: limit(min = 0.2mm), diffPairGap: limit(min = 0.15mm, max = 0.25mm) }
}

The library
8,500+ open boards by the people who made them, converted to PCBKit: keyboards, radios, synths, sound cards, watches. Each opens with its AI tour: the camera flies from part to part while a guide explains what each one does. Then turn it in 3D, change it and route it again. Each keeps its author and its licence.

Keyboard
Left main PCB of the Slab keyboard system.
CERN-OHL-S-2.0

Keyboard
29-key keyboard PCB carrying an RP2040 breakout.
MIT

Open hardware
Physical chess board without turns, so both players can move at any time.
MIT

FPGA
A development board for a Freescale ColdFire MCF5213 microcontroller with a Xilinx FPGA, four layers, many parts.
CC-BY-SA-4.0

Sensors
Wooden electronic Go board that integrates with KataGo AI for play and analysis, 11x3 size.
GPL-3.0

Open hardware
Open-source standalone Bitcoin ASIC miner with a BM1366 ASIC and WiFi, mining directly to a pool.
CERN-OHL-S-2.0

Sensors
Analog front-end board of a 2-channel, ~20 MHz oscilloscope DAQ that feeds a Tang Nano 9K FPGA, with an RPi Pico for control.
GPL-3.0

Open hardware
PSLab Hardware Design and Schematics https://pslab.io
Apache-2.0
For beginners
You don’t need to know how a voltage regulator works to use one. PCBKit knows, and it watches your back while you learn.
Voltage regulators, USB-C power, LEDs, buttons, crystals, sensor ports. Each block works out its own part values from the numbers you give it, and warns you when they don’t add up.
Two outputs fighting, a chip with no power, a forgotten pull-up, millimetres added to nanofarads. PCBKit points at the line and says what’s wrong.
314 standard footprints, computed from package dimensions by the industry standard (IPC-7351B), each with a 3D body.
Every change, yours or your agent’s, is one step in the history. Try things. Nothing is lost.
Say what a part must meet (10 kΩ, 1 %, 0402) and PCBKit picks an orderable one for it, and tells you why that one.
Your agent reads a datasheet into a part sheet; PCBKit checks the pins against the package and the land pattern against the standard before it goes on the board.
One link anyone can open, no account needed: your board read-only, its AI tour first, following your changes.
Everything is plain text in git, and boards go to and from KiCad files. When you outgrow the basics, nothing is locked in.
The board in 3D as the factory will make it: mask, finish and parts on their pads. Turn it in your hand before you spend a cent.
Under the hood
The language, the checks, the router, the simulation and the renderer are one Rust codebase. It compiles natively for the command line and our servers, and to WebAssembly for the browser, and gives the same answer in both.

Seconds, headless Chrome, AMD EPYC 9554. Same work budget, so the copper is identical in every run. One WebAssembly thread is within 10% of one native thread.
| Board | 1 thread | 12 threads |
|---|---|---|
| USB boardcomplete, 4 vias | 6.2 s | 2.0 s |
| MCU board, 20 netscomplete, 23 vias | 13.8 s | 4.4 s |
| Motor controller, 63 parts, 4 layerssame copper either way | 86.0 s | 28.5 s |
Measured
Every change to the router, the checks and file import is measured on public boards that people designed. An independent checker judges the result, and a board only counts if it comes out clean.
96.1%
of 482 curated public boards import and export with every pad and every connection confirmed by an independent checker
KiCad files, both ways
232/235
human-designed boards where, after a refill, pour connectivity matches the independent checker
copper pours
4–26ms
from an edit to the board on screen, on boards up to 6 MB, in the browser
headless browser
10µm
every one of 2,821 silkscreen texts on 46 boards lands within 10 µm of KiCad’s own plot
text as KiCad prints it
About
Hi, I’m Sergey Alekseev. I’m building Rabbit, an autonomous rover, and I write about it at rabbit0.dev. Rabbit runs on a Jetson Orin Nano with a stereo camera and maps the house in 3D. Its electronics are still a nest of wires, and every tool I tried for its boards made me feel slow. PCBKit is the tool I wanted: one my agent and I can work in together, from an idea to a board on my desk.
I started PCBKit to solve that problem for myself: to get Rabbit’s boards made without fighting the tools. I share how it goes in the open, what works and what the router can’t do yet. The engineering notes, with their numbers, are on the blog.
If you build something with it, or it gets in your way, write to support@pcbkit.io. We read every message.
PCBKit is free. If it saves you time, you can help keep it that way: donate once or every month.