- Add KiCad fork as git submodule - Create project structure (patches, stubs, cmake, scripts, core, docs) - Add knowledge base and implementation plan documentation - Add README with project overview and goals 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
24 KiB
KiCad WebAssembly Port - Complete Knowledge Base
Table of Contents
- Architecture Overview
- Dependencies Deep Dive
- Graphics System (GAL)
- File I/O System
- Python Scripting
- Build System
- Features to Disable
- Code Extraction Candidates
- Technical Challenges
- Design Decisions
- File Reference
Architecture Overview
Main Applications
| Application | Directory | Purpose |
|---|---|---|
kicad |
kicad/ |
Project manager, launcher |
pcbnew |
pcbnew/ |
PCB layout editor |
eeschema |
eeschema/ |
Schematic capture |
gerbview |
gerbview/ |
Gerber file viewer |
cvpcb |
cvpcb/ |
Component-footprint association |
bitmap2component |
bitmap2component/ |
Image to footprint converter |
pcb_calculator |
pcb_calculator/ |
Engineering calculators |
pagelayout_editor |
pagelayout_editor/ |
Drawing sheet editor |
kicad-cli |
kicad/cli/ |
Command-line interface |
Shared Libraries
| Library | Location | Purpose |
|---|---|---|
kicommon |
common/ |
Shared UI, I/O, utilities (SHARED lib) |
kigal |
common/gal/ |
Graphics Abstraction Layer (SHARED lib) |
kimath |
libs/kimath/ |
Geometry and math (STATIC lib) |
core |
libs/core/ |
Base utilities (STATIC lib) |
sexpr |
libs/sexpr/ |
S-expression parser (STATIC lib) |
kiplatform |
libs/kiplatform/ |
Platform abstraction |
Plugin Architecture (KIFACE)
Each major application is built as both:
- Standalone executable
- KIFACE module (
.kifaceon Linux/Mac,.dllon Windows)
This allows:
- Standalone operation
- Project manager integration via dynamic loading
Key files:
include/kiway.h- KIWAY system for inter-module communicationinclude/kiway_holder.h- Mixin for frames that participate in KIWAYinclude/kiway_player.h- Frame base class (KIWAY_PLAYER : public wxFrame)
Frame Hierarchy
wxFrame
└── KIWAY_PLAYER (include/kiway_player.h)
└── EDA_BASE_FRAME (include/eda_base_frame.h)
├── PCB_BASE_FRAME (pcbnew/)
│ └── PCB_EDIT_FRAME
├── SCH_BASE_FRAME (eeschema/)
│ └── SCH_EDIT_FRAME
└── ...other frames
Dependencies Deep Dive
wxWidgets (GUI Framework)
Version: 3.2.0+
Components used: gl aui adv html core net base propgrid xml stc richtext webview
Location: Found via find_package(wxWidgets) in CMakeLists.txt:1089
KiCad requires GTK3 port on Linux. All GUI code depends on wxWidgets.
Key wxWidgets classes used:
wxFrame,wxDialog,wxPanel- windowswxGLCanvas- OpenGL contextwxFileDialog- file selectionwxAuiManager- dockable paneswxPropertyGrid- property editors
Wasm strategy: Keep native initially. Eventually replace with web framework (React/Vue/Svelte).
OpenGL / GLEW
Purpose: Hardware-accelerated 2D rendering via GAL
Location: common/gal/opengl/
Uses OpenGL 2.1+ with shaders. GLEW handles extension loading.
Wasm strategy: Emscripten maps OpenGL ES to WebGL automatically. Need to:
- Use OpenGL ES subset
- Convert shaders to GLSL ES (remove
#version, addprecisionqualifiers)
Cairo
Version: 1.12+
Purpose: Software 2D rendering fallback, printing, PDF export
Location: common/gal/cairo/
Wasm strategy: Can compile Cairo with Emscripten. Or skip for MVP (OpenGL-only).
OpenCASCADE (OCC/OCCT)
Version: 7.5.0+ Purpose:
- STEP file import/export (mechanical CAD interchange)
- 3D model loading for component visualization
- Boolean operations on 3D geometry
Files using OCC:
pcbnew/exporters/step/step_pcb_model.cpp- STEP exportpcbnew/exporters/step/exporter_step.cpp- Export orchestrationplugins/3d/oce/loadmodel.cpp- 3D model loadingplugins/3d/oce/oce.cpp- Plugin entry point
Headers imported (from step_pcb_model.cpp):
#include <IGESCAFControl_Reader.hxx>
#include <STEPCAFControl_Reader.hxx>
#include <STEPCAFControl_Writer.hxx>
#include <TopoDS.hxx>
#include <XCAFDoc_ShapeTool.hxx>
// ... ~30 more OCC headers
Wasm strategy: Disable for MVP. OCC is huge (~40MB compiled). Alternative: opencascade.js exists but experimental.
libcurl
Purpose: HTTP requests for:
- Plugin Content Manager (PCM) -
kicad/pcm/pcm.cpp - Update checker -
kicad/update_manager.cpp - HTTP component libraries -
common/http_lib/http_lib_connection.cpp
Wrapper: common/kicad_curl/kicad_curl_easy.cpp (~400 lines)
Key class: KICAD_CURL_EASY
class KICAD_CURL_EASY {
void SetURL(const std::string& url);
void Perform();
std::string GetBuffer();
};
Wasm strategy: Stub out. Replace with Emscripten Fetch API or JavaScript fetch via embind.
libgit2
Version: 1.5+ Purpose: Built-in version control for projects
Files (common/git/):
| File | Purpose |
|---|---|
git_clone_handler.cpp |
Clone repositories |
git_commit_handler.cpp |
Create commits |
git_push_handler.cpp |
Push to remote |
git_pull_handler.cpp |
Pull from remote |
git_branch_handler.cpp |
Branch management |
git_status_handler.cpp |
Status display |
git_revert_handler.cpp |
Revert changes |
kicad_git_common.cpp |
Common utilities |
kigit_pcb_merge.cpp |
Custom PCB merge driver |
UI integration:
- Project tree shows git status icons
- Menus for git operations
- Conflict resolution dialogs
Wasm strategy: Stub out entirely. Optional feature. Could use isomorphic-git in browser later.
ngspice
Purpose: SPICE circuit simulation in eeschema
Location: eeschema/sim/
Wasm strategy: Stub out. Simulation is a separate concern. Could compile ngspice to Wasm later.
nanoodbc (ODBC)
Purpose: Database Libraries feature - fetch component data from SQL databases
Location: common/database/database_connection.cpp
What it does: Connects to external databases (MySQL, PostgreSQL, SQLite, SQL Server) to fetch component information instead of using local .kicad_sym files.
Enterprise feature - most users don't use this.
Wasm strategy: Stub out. Would need REST API backend in browser.
Boost
Version: 1.71.0+
Components: locale, unit_test_framework
boost::locale is used by nanoodbc for Unicode handling.
Wasm strategy: Minimize. If we disable database libraries, we may not need boost::locale.
Freetype / HarfBuzz / Fontconfig
Purpose: Text rendering with outline fonts Versions: Freetype 2.11.1+, HarfBuzz (any), Fontconfig (any)
Location: common/font/
Wasm strategy: Compile with Emscripten. These work. May need to bundle fonts or use browser fonts.
Protobuf
Purpose: IPC API for external tool integration
Location: api/
Wasm strategy: Can compile Protobuf to Wasm. Or stub out IPC API for MVP.
Graphics System (GAL)
Architecture
┌─────────────────────────────────────────┐
│ VIEW (common/view/) │
│ Manages what's visible, handles zoom │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ PAINTER (include/gal/painter.h) │
│ Converts board objects to draw calls │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ GAL (graphics_abstraction_layer) │
│ Abstract interface for drawing │
└─────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ OPENGL_GAL │ │ CAIRO_GAL │
│ (Hardware accel)│ │ (Software/print)│
└─────────────────┘ └─────────────────┘
GAL Base Class
File: include/gal/graphics_abstraction_layer.h
namespace KIGFX {
class GAL : public GAL_DISPLAY_OPTIONS_OBSERVER {
// Primitives
virtual void DrawLine(const VECTOR2D& start, const VECTOR2D& end);
virtual void DrawCircle(const VECTOR2D& center, double radius);
virtual void DrawArc(const VECTOR2D& center, double radius, ...);
virtual void DrawRectangle(const VECTOR2D& start, const VECTOR2D& end);
virtual void DrawPolygon(const std::deque<VECTOR2D>& points);
// State
virtual void SetFillColor(const COLOR4D& color);
virtual void SetStrokeColor(const COLOR4D& color);
virtual void SetLineWidth(float width);
// Transformations
virtual void Transform(const MATRIX3x3D& matrix);
virtual void Translate(const VECTOR2D& translation);
virtual void Scale(const VECTOR2D& scale);
virtual void Rotate(double angle);
// Layers
virtual void SetLayerDepth(double depth);
};
}
OpenGL GAL
Files:
include/gal/opengl/opengl_gal.hcommon/gal/opengl/opengl_gal.cppcommon/gal/opengl/shader.cpp- GLSL shader managementcommon/gal/opengl/vertex_manager.cpp- Vertex buffer managementcommon/gal/opengl/gpu_manager.cpp- GPU memory managementcommon/gal/opengl/cached_container.cpp- Geometry caching
Canvas: HIDPI_GL_CANVAS wraps wxGLCanvas
Shader files (common/gal/shaders/):
| File | Purpose |
|---|---|
kicad_vert.glsl |
Main vertex shader |
kicad_frag.glsl |
Main fragment shader |
smaa_base.glsl |
SMAA antialiasing base |
smaa_pass_1_frag.glsl |
SMAA edge detection |
smaa_pass_2_frag.glsl |
SMAA blending weights |
smaa_pass_3_frag.glsl |
SMAA neighborhood blending |
Shaders are embedded as C strings at build time.
For WebGL: Need to convert shaders:
// Before (desktop GLSL)
#version 120
varying vec4 color;
// After (WebGL/GLSL ES)
precision mediump float;
varying vec4 color;
Cairo GAL
Files:
include/gal/cairo/cairo_gal.hcommon/gal/cairo/cairo_gal.cppcommon/gal/cairo/cairo_compositor.cpp- Layer compositingcommon/gal/cairo/cairo_print.cpp- Printing support
Used for:
- Software rendering fallback
- Printing
- PDF/SVG export
Draw Panel
File: include/class_draw_panel_gal.h
EDA_DRAW_PANEL_GAL wraps GAL and handles:
- Mouse events
- Keyboard events
- Tool dispatching
- View management
File I/O System
Architecture
Plugin-based system with base class IO_BASE:
File: include/io/io_base.h
class IO_BASE {
struct IO_FILE_DESC {
wxString m_Description;
std::vector<std::string> m_FileExtensions;
bool m_CanRead;
bool m_CanWrite;
};
virtual std::vector<IO_FILE_DESC> GetFileDescriptors();
virtual void SetReporter(REPORTER* reporter);
virtual void SetProgressReporter(PROGRESS_REPORTER* reporter);
};
Format Plugins
KiCad Native (common/io/kicad/):
- S-expression based format
.kicad_pcb,.kicad_sch,.kicad_sym,.kicad_mod
Import Plugins (common/io/):
| Plugin | Location | Formats |
|---|---|---|
| Eagle | common/io/eagle/ |
.brd, .sch |
| Altium | common/io/altium/ |
.PcbDoc, .SchDoc |
| CADSTAR | common/io/cadstar/ |
.cpa, .csa |
| EasyEDA | common/io/easyeda/ |
.json |
| EasyEDA Pro | common/io/easyedapro/ |
.epro |
S-Expression Parser
Location: libs/sexpr/
KiCad native files use S-expressions:
(kicad_pcb (version 20221018)
(generator pcbnew)
(layers
(0 "F.Cu" signal)
(31 "B.Cu" signal))
(footprint "Package_SO:SOIC-8"
(at 100 100)
(pad "1" smd rect (at -1.905 -2.475) (size 0.6 1.5))))
Parser is pure C++, good candidate for Wasm.
PCB Data Model
Key classes (in pcbnew/):
| Class | File | Purpose |
|---|---|---|
BOARD |
board.h |
Top-level PCB container |
FOOTPRINT |
footprint.h |
Component footprint |
PAD |
pad.h |
Footprint pad |
PCB_TRACK |
pcb_track.h |
Trace segment |
PCB_VIA |
pcb_track.h |
Via |
ZONE |
zone.h |
Copper pour |
PCB_SHAPE |
pcb_shape.h |
Graphical shape |
PCB_TEXT |
pcb_text.h |
Text |
Hierarchy:
BOARD
├── FOOTPRINT[]
│ ├── PAD[]
│ ├── PCB_SHAPE[]
│ └── PCB_TEXT[]
├── PCB_TRACK[]
├── PCB_VIA[]
├── ZONE[]
├── PCB_SHAPE[]
└── PCB_TEXT[]
Python Scripting
SWIG Bindings
Location: scripting/, common/swig/, pcbnew/python/swig/
Interface files (.i):
| File | Lines | Purpose |
|---|---|---|
kicadplugins.i |
695 | Plugin framework |
wx.i |
348 | wxWidgets types |
board.i |
201 | BOARD class |
board_item.i |
222 | Base item class |
footprint.i |
200 | FOOTPRINT class |
pad.i |
128 | PAD class |
pcbnew.i |
148 | Main pcbnew module |
| Others | ~1600 | Various classes |
| Total | ~3500 |
How SWIG Works
- SWIG reads
.iinterface files - Generates C++ wrapper code for CPython
- Wrapper compiled to shared library (
_pcbnew.so) - Python imports the module
import pcbnew
board = pcbnew.GetBoard()
for track in board.GetTracks():
print(track.GetStart(), track.GetEnd())
Plugin Types
| Type | Purpose | Interface |
|---|---|---|
| FootprintWizard | Generate footprints programmatically | FootprintWizardPlugin |
| ActionPlugin | Custom toolbar actions | ActionPlugin |
| FilePlugin | Custom file formats | FilePlugin |
Wasm Strategy
SWIG generates CPython-specific code. Options for Wasm:
-
Emscripten embind: Rewrite bindings (~3500 lines to port)
#include <emscripten/bind.h> EMSCRIPTEN_BINDINGS(pcbnew) { class_<BOARD>("Board") .function("GetTracks", &BOARD::Tracks); } -
Pyodide: If we want Python in browser, use Pyodide with custom FFI
-
Skip for MVP: Python scripting is optional for basic editing
Build System
Main CMakeLists.txt Structure
CMakeLists.txt
├── Project setup (lines 1-100)
├── Options (lines 110-290)
│ ├── KICAD_SPICE_QA
│ ├── KICAD_USE_SENTRY
│ ├── KICAD_BUILD_I18N
│ ├── KICAD_BUILD_QA_TESTS
│ ├── KICAD_SCRIPTING_WXPYTHON
│ ├── KICAD_UPDATE_CHECK
│ └── ... more options
├── Compiler setup (lines 300-800)
├── Dependencies (lines 800-1200)
│ ├── find_package(ZLIB)
│ ├── find_package(CURL) # Line 825 - REQUIRED
│ ├── find_package(libgit2) # Line 842 - REQUIRED
│ ├── find_package(ngspice) # Line 877 - REQUIRED
│ ├── find_package(OCC) # Line 880 - FATAL if not found
│ └── ... more deps
├── wxWidgets setup (lines 1080-1140)
└── Subdirectories (lines 1250+)
Common Library Build
File: common/CMakeLists.txt
# KICOMMON_SRCS includes:
# - git/*.cpp (lines 75-95)
# - kicad_curl/*.cpp (lines 140-141)
# - database/*.cpp
# - All UI code
target_link_libraries(kicommon
CURL::libcurl # Line 325
${LIBGIT2_LIBRARIES} # Line 330
# ...
)
Adding CMake Options for Optional Deps
Need to add after line 107:
option( KICAD_USE_CURL "Enable network features" ON )
option( KICAD_USE_GIT "Enable git integration" ON )
option( KICAD_USE_OCC "Enable STEP/3D via OpenCASCADE" ON )
option( KICAD_USE_NGSPICE "Enable SPICE simulation" ON )
option( KICAD_USE_DATABASE "Enable database libraries" ON )
Then wrap find_package calls:
if( KICAD_USE_CURL )
find_package( CURL REQUIRED )
add_compile_definitions( KICAD_USE_CURL )
else()
add_library( CURL::libcurl INTERFACE IMPORTED )
endif()
Features to Disable
Git Integration
Files to stub (common/git/):
git_add_to_index_handler.cppgit_branch_handler.cppgit_clone_handler.cppgit_commit_handler.cppgit_config_handler.cppgit_compare_handler.cppgit_init_handler.cppgit_pull_handler.cppgit_push_handler.cppgit_remove_from_index_handler.cppgit_remove_vcs_handler.cppgit_resolve_conflict_handler.cppgit_revert_handler.cppgit_status_handler.cppgit_switch_branch_handler.cppgit_sync_handler.cppkicad_git_common.cppgit_backend.cpplibgit_backend.cppproject_git_utils.cpp
Stub header needed: stubs/include/git2.h
Network Features (curl)
Files to stub (common/kicad_curl/):
kicad_curl.cppkicad_curl_easy.cpp
Files to stub (common/http_lib/):
http_lib_connection.cpp
Files affected (kicad/):
pcm/pcm.cpp- Plugin Content Managerpcm/pcm_task_manager.cppupdate_manager.cpp
Stub header needed: stubs/include/curl/curl.h
OpenCASCADE (STEP/3D)
Files to exclude:
pcbnew/exporters/step/*.cppplugins/3d/oce/*.cpp
Approach: Don't build these targets rather than stubbing.
SPICE Simulation
Files affected: eeschema/sim/
Approach: Disable simulator UI, don't build sim targets.
Database Libraries
Files to stub (common/database/):
database_connection.cppdatabase_cache.cpp
Code Extraction Candidates
Tier 1: Pure Computation (No Dependencies)
| Component | Location | Lines (approx) | Notes |
|---|---|---|---|
| Math library | libs/kimath/src/ |
~5000 | Vectors, matrices, geometry |
| Core utilities | libs/core/src/ |
~2000 | String utils, exceptions |
| S-expr parser | libs/sexpr/ |
~1500 | Pure parsing |
Tier 2: File I/O (Minimal Dependencies)
| Component | Location | Notes |
|---|---|---|
| KiCad PCB parser | common/io/kicad/ |
Needs kimath, sexpr |
| Board data model | pcbnew/*.cpp |
Core classes only |
| Schematic parser | common/io/eeschema/ |
Needs kimath |
Tier 3: Algorithms (May Need Adaptation)
| Component | Location | Notes |
|---|---|---|
| DRC engine | pcbnew/drc/ |
May use threading |
| Router | pcbnew/router/ |
Push & Shove |
| ERC | eeschema/erc/ |
Electrical checks |
| Connectivity | pcbnew/connectivity/ |
Net analysis |
Technical Challenges
Threading
Current usage:
- DRC runs checks in parallel
- Router uses threading for optimization
- Background jobs system
Wasm limitation: Single-threaded by default.
Solutions:
- Web Workers: Spawn separate Wasm instances
- Wasm threads (experimental): SharedArrayBuffer + pthreads
- Sequential fallback: Slower but works
Decision: Use Web Workers. Design for async message-passing.
Memory Management
Challenge: Need to share board state between native GUI and Wasm core.
Options:
- Serialize/deserialize: Simple, proof of concept
- Shared memory: Complex, requires careful synchronization
- Authoritative Wasm copy: GUI requests views
Decision: Serialize/deserialize. Proof of concept, simplicity over performance.
File Access
Native: Direct filesystem, wxFileDialog
Browser: No filesystem access without user interaction
Solutions:
- Emscripten virtual filesystem (MEMFS, IDBFS)
- File System Access API (Chrome)
- IndexedDB for persistence
- Drag & drop / file picker
Clipboard
Native: wxClipboard, platform integration
Browser: Async Clipboard API (permissions required)
Fonts
Native: System fonts via Fontconfig
Browser: Bundle fonts or use CSS fonts
Design Decisions
Memory Management
Decision: Serialize/deserialize on every operation
Rationale:
- Proof of concept phase
- Simplicity over performance
- Clean interface between GUI and core
- Easy to debug
- Browser-friendly (no shared memory complexity)
Implementation:
// GUI → Wasm: Send operation + serialized state
std::string boardJson = SerializeBoard(board);
wasmCore.ApplyOperation(boardJson, operation);
std::string newBoardJson = wasmCore.GetBoardState();
board = DeserializeBoard(newBoardJson);
Threading Model
Decision: Web Workers
Rationale:
- Target is browser
- Clean message-passing interface
- Each worker is isolated Wasm instance
- No shared memory complexity
Implementation:
// Main thread
const worker = new Worker('kicad-core-worker.js');
worker.postMessage({ type: 'runDRC', board: boardData });
worker.onmessage = (e) => { handleDRCResults(e.data); };
// Worker
importScripts('kicad_core.js');
onmessage = async (e) => {
const core = await KicadCore();
if (e.data.type === 'runDRC') {
const results = core.runDRC(e.data.board);
postMessage(results);
}
};
Incremental Updates
Decision: Re-serialize entire board (for now)
Rationale:
- Simple implementation
- Board files are typically <10MB
- Performance acceptable for proof of concept
- Can optimize later with deltas if needed
File Reference
Core Headers
| Purpose | File |
|---|---|
| GAL interface | include/gal/graphics_abstraction_layer.h |
| OpenGL GAL | include/gal/opengl/opengl_gal.h |
| Cairo GAL | include/gal/cairo/cairo_gal.h |
| Draw panel | include/class_draw_panel_gal.h |
| Base frame | include/eda_base_frame.h |
| KIWAY | include/kiway.h |
| KIWAY holder | include/kiway_holder.h |
| I/O base | include/io/io_base.h |
| Board | pcbnew/board.h |
| Footprint | pcbnew/footprint.h |
| Track | pcbnew/pcb_track.h |
Build Files
| Purpose | File |
|---|---|
| Main build | CMakeLists.txt |
| Common lib | common/CMakeLists.txt |
| GAL lib | common/gal/CMakeLists.txt |
| PCBnew | pcbnew/CMakeLists.txt |
| Eeschema | eeschema/CMakeLists.txt |
| 3D viewer | 3d-viewer/CMakeLists.txt |
SWIG Bindings
| Purpose | File |
|---|---|
| Main entry | scripting/kicadplugins.i |
| Common | common/swig/kicad.i |
| wxWidgets | common/swig/wx.i |
| Math | common/swig/math.i |
| Shapes | common/swig/shape.i |
| Board | pcbnew/python/swig/board.i |
| PCBnew main | pcbnew/python/swig/pcbnew.i |
Git Integration
| Purpose | File |
|---|---|
| Common class | common/git/kicad_git_common.cpp |
| Clone | common/git/git_clone_handler.cpp |
| Commit | common/git/git_commit_handler.cpp |
| Push | common/git/git_push_handler.cpp |
| Pull | common/git/git_pull_handler.cpp |
| Status | common/git/git_status_handler.cpp |
| PCB merge | pcbnew/git/kigit_pcb_merge.cpp |
Curl/Network
| Purpose | File |
|---|---|
| Curl wrapper | common/kicad_curl/kicad_curl_easy.cpp |
| Curl init | common/kicad_curl/kicad_curl.cpp |
| HTTP lib | common/http_lib/http_lib_connection.cpp |
| PCM | kicad/pcm/pcm.cpp |
| Updates | kicad/update_manager.cpp |
OpenCASCADE/STEP
| Purpose | File |
|---|---|
| STEP model | pcbnew/exporters/step/step_pcb_model.cpp |
| STEP export | pcbnew/exporters/step/exporter_step.cpp |
| OCC plugin | plugins/3d/oce/oce.cpp |
| Model loader | plugins/3d/oce/loadmodel.cpp |