Content is user-generated and unverified.

KiCad Schematic → Three.js 3D Visualizer

A Python tool that parses real .kicad_sch files (KiCad 7/8 S-expression format) and generates interactive Three.js 3D PCB visualizations in a single standalone HTML file.


Quick Start

bash
python kicad_sch_to_3d.py <input.kicad_sch> [output.html]
bash
# Examples
python kicad_sch_to_3d.py TPS54302_BuckConverter.kicad_sch
# → TPS54302_BuckConverter.3d.html

python kicad_sch_to_3d.py NE555_Astable.kicad_sch my_output.html
# → my_output.html

No dependencies required — pure Python 3 standard library.


Architecture

┌──────────────────────────────────────────────────────────┐
│                    .kicad_sch file                        │
│  (S-expression: symbols, wires, labels, junctions, ...)  │
└──────────────┬───────────────────────────────────────────┘
               │
       ┌───────▼───────┐
       │  SExprParser   │  Tokenizer + recursive descent
       │                │  → nested Python lists
       └───────┬───────┘
               │
    ┌──────────▼──────────┐
    │ KiCadSchExtractor    │  Walk S-expr tree, extract:
    │                      │  - lib_symbols (pin defs)
    │                      │  - components (ref, value, xy)
    │                      │  - wires (x1,y1 → x2,y2)
    │                      │  - junctions, labels
    └──────────┬──────────┘
               │
        ┌──────▼──────┐
        │ NetResolver   │  BFS flood-fill from wire
        │               │  endpoints + label/power coords
        │               │  → assign net name per wire
        └──────┬──────┘
               │
    ┌──────────▼──────────┐
    │  HTML Generator      │  Serialize to JSON, inject into
    │                      │  Three.js template with:
    │                      │  - 3D component models
    │                      │  - Colored PCB traces
    │                      │  - Interactive UI (orbit, hover)
    └──────────┬──────────┘
               │
       ┌───────▼───────┐
       │  .html output  │  Standalone, zero-dependency
       │  (Three.js r128│  Open in any browser
       │   via CDN)     │
       └───────────────┘

Pipeline Stages

Stage 1 — S-Expression Parser (SExprParser)

KiCad uses Lisp-style S-expressions. The parser handles:

Token TypeExamplePython Output
List(wire (pts ...))['wire', ['pts', ...]]
Quoted string"TPS54302"'TPS54302'
Integer4242
Float139.7139.7
Atomdefault'default'
Comment; this is ignored(skipped)

Escaped characters in strings (\") are handled. Nested lists recurse to arbitrary depth.

Stage 2 — Schematic Extractor (KiCadSchExtractor)

Walks the parsed tree and populates a KiSchematic data model:

python
@dataclass
class KiSchematic:
    title: str              # from (title_block ...)
    date: str
    rev: str
    company: str
    lib_symbols: dict       # name → KiLibSymbol (pin definitions)
    components: list        # KiComponent (ref, value, x, y, angle, ...)
    wires: list             # KiWire (x1, y1, x2, y2)
    junctions: list         # KiJunction (x, y)
    labels: list            # KiLabel (text, x, y, type)

Component classification uses both lib_id and reference prefix:

PatternType
lib_id = C, C_Polarized or ref starts with CCapacitor
lib_id = R, R_Small or ref starts with RResistor
lib_id = L or ref starts with LInductor
ref starts with U or ICIC
#PWR, #FLG, or lib marked (power)Power symbol

Stage 3 — Net Resolver (NetResolver)

Assigns a net name to every wire segment using BFS flood-fill:

  1. Seed net names from labels and power symbols at their coordinates
  2. Nearest-endpoint matching — for each label/power symbol, find the closest wire endpoint within 5mm tolerance and inject the net name there
  3. Build adjacency graph — wire endpoints snapped to 0.5mm grid connect wires sharing a point
  4. Flood-fill — BFS from each unvisited wire, propagating net names through connected clusters
  5. Unnamed fallback — wires not reached by any label get NET_<index>
Label "VCC" @ (160, 70)
       ↓ nearest endpoint
Wire endpoint (160, 72.39)
       ↓ flood-fill
Wire (160, 72.39)→(160, 80.01) = VCC
       ↓ shared endpoint
Wire (160, 80.01)→(160, 82.55) = VCC
       ...

Stage 4 — Three.js HTML Generator

Converts all extracted data to JSON and embeds it in a self-contained HTML template:

javascript
// Auto-generated from parser output
const COMPS = [
  {"ref":"U1","value":"NE555","x":0.0,"z":0.0,"type":"IC",...},
  {"ref":"R1","value":"1kΩ","x":3.66,"z":-2.29,"type":"R",...},
  ...
];
const WIRES = [
  {"x1":-1.2,"z1":-0.5,"x2":3.6,"z2":-0.5,"net":"VCC"},
  ...
];

3D models are procedurally generated per component type:

Type3D Model
ICDark box + marking surface + pin-1 dot + gull-wing pads
Capacitor (electrolytic)Tall dark box + terminal pads
Capacitor (ceramic)Short tan box
ResistorSmall dark box + end pads
InductorLarge dark box (shielded style)

Output Features

Interactive Controls

ActionEffect
Mouse dragOrbit camera
Scroll wheelZoom in/out
Touch dragOrbit (mobile)
PinchZoom (mobile)
Hover componentTooltip with ref, value, footprint, pins
PANEL → click netHighlight all traces/components on that net
GLOW buttonToggle ambient glow under components
LABELS buttonToggle floating ref/value labels
RESET buttonReset camera to default view

Visual Design

  • Dark PCB substrate (#0a3020) with copper grid overlay
  • Net-colored traces with emissive glow (power nets thicker)
  • ACES filmic tone mapping + fog for depth
  • Three-point lighting (key + fill + rim)
  • Pulsating glow halos under each component
  • Floating billboard labels (ref + value)
  • Scanline + vignette post-processing overlays
  • Responsive — works on desktop and mobile

Supported KiCad Elements

ElementParsedUsed in 3D
(title_block ...)HUD display
(lib_symbols ...)Pin names, component classification
(symbol ...) (instances)3D component placement
(wire ...)PCB traces
(junction ...)Junction spheres
(label ...)Net name resolution
(global_label ...)Net name resolution
(hierarchical_label ...)Net name resolution
(no_connect ...)Not yet
(bus ...)Not yet
(sheet ...) (hierarchy)Single-sheet only
(polyline ...) / (arc ...)Decorative, not parsed

Limitations

  • Single-sheet schematics only — hierarchical sheets are not followed
  • Component models are generic — the 3D shapes are type-based (IC/C/R/L), not footprint-accurate
  • Net resolution depends on label placement — labels must be within ~5mm of a wire endpoint for proper connectivity. If nets show as NET_<n>, move the label closer to a wire endpoint in KiCad
  • No ERC — electrical rule checks are not performed
  • No bus expansion — buses like D[0..7] are not expanded into individual nets

Troubleshooting

Nets showing as NET_0, NET_5, etc.

The net resolver couldn't match a label to those wire segments. Common fixes:

  1. Ensure net labels sit directly on a wire endpoint (not mid-wire)
  2. Place (junction ...) at T-connections
  3. Add explicit (label ...) nodes on isolated wire clusters

Components missing or misplaced

The parser uses the (at x y angle) field from each (symbol ...) instance. Verify coordinates match your KiCad layout. Components classified as power symbols (#PWR*, #FLG*) are hidden from the 3D view by design.

Parser fails on a .kicad_sch file

Ensure it's KiCad 7 or 8 format (starts with (kicad_sch (version 2023...)). KiCad 5/6 legacy formats use a different syntax and are not supported.


Example Output

$ python kicad_sch_to_3d.py NE555_Astable.kicad_sch

[1/5] Reading NE555_Astable.kicad_sch ...
[2/5] Parsing S-expressions (21,740 chars) ...
[3/5] Extracting schematic data ...
       Title:      555 Timer — Astable Multivibrator
       Components: 8
       Wires:      27
       Junctions:  3
       Labels:     6
       Lib syms:   6
[4/5] Resolving nets ...
       Nets found:  6 named, 1 unnamed
         CTRL       — 2 wire segments
         DISCH      — 5 wire segments
         GND        — 5 wire segments
         OUT        — 1 wire segments
         TIMING     — 8 wire segments
         VCC        — 5 wire segments
[5/5] Generating Three.js HTML ...
       Output: NE555_Astable.3d.html (25,761 bytes)
       Done!

File Structure

kicad_sch_to_3d.py          # Main script (single file, no deps)
├── SExprParser              # S-expression tokenizer & parser
├── KiCadSchExtractor        # Schematic data extractor
├── NetResolver              # BFS net connectivity resolver
├── generate_threejs_html()  # Three.js HTML generator
├── classify_component()     # Ref/lib_id → type classifier
└── main()                   # CLI entry point

License

This tool is provided as-is for educational and prototyping purposes.

Content is user-generated and unverified.
    KiCad Schematic to 3D Visualizer – Interactive PCB Tool | Claude