From 2d7c26feac69dc8546b5bbf154d6960e70c8df34 Mon Sep 17 00:00:00 2001 From: Viktor Vaczi Date: Wed, 26 Nov 2025 10:46:44 +0100 Subject: [PATCH] Initial project setup for KiCad WebAssembly port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .gitignore | 29 ++ .gitmodules | 3 + README.md | 55 +++ docs/IMPLEMENTATION_PLAN.md | 335 ++++++++++++++ docs/KNOWLEDGE_BASE.md | 136 ++++++ docs/KNOWLEDGE_BASE_FULL.md | 846 ++++++++++++++++++++++++++++++++++++ kicad | 1 + 7 files changed, 1405 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 README.md create mode 100644 docs/IMPLEMENTATION_PLAN.md create mode 100644 docs/KNOWLEDGE_BASE.md create mode 100644 docs/KNOWLEDGE_BASE_FULL.md create mode 160000 kicad diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7bb37ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Build directories +build/ +build-*/ +cmake-build-*/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Compiled objects +*.o +*.obj +*.a +*.so +*.dylib +*.dll + +# WebAssembly output +*.wasm +*.js.map + +# macOS +.DS_Store + +# Emscripten cache +.emscripten_cache/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..55e859a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "kicad"] + path = kicad + url = git@github.com:VV-EE/kicad-source-mirror.git diff --git a/README.md b/README.md new file mode 100644 index 0000000..abab26a --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# KiCad WebAssembly Port + +Experimental project to run KiCad's core logic in WebAssembly. + +## Project Structure + +``` +kicad-wasm/ +β”œβ”€β”€ kicad/ # KiCad source (git submodule) +β”œβ”€β”€ patches/ # Patches to make deps optional +β”œβ”€β”€ stubs/ # Stub headers for disabled deps +β”œβ”€β”€ cmake/ # CMake modules +β”œβ”€β”€ scripts/ # Build and maintenance scripts +β”œβ”€β”€ core/ # Extracted core library for Wasm +└── docs/ # Knowledge base and plans +``` + +## Goals + +1. **Phase 1**: Build KiCad with optional deps disabled (curl, git, OCC, ngspice) +2. **Phase 2**: Extract core computation code as standalone library +3. **Phase 3**: Compile core to WebAssembly +4. **Phase 4**: Run native GUI with Wasm worker backend +5. **Phase 5**: Browser-based UI + +## Documentation + +- [Implementation Plan](docs/IMPLEMENTATION_PLAN.md) +- [Knowledge Base (Summary)](docs/KNOWLEDGE_BASE.md) +- [Knowledge Base (Full)](docs/KNOWLEDGE_BASE_FULL.md) + +## Design Decisions + +- **Memory**: Serialize/deserialize on every operation (proof of concept) +- **Threading**: Web Workers (browser-first design) +- **Updates**: Full board re-serialization + +## Getting Started + +```bash +# Clone with submodules +git clone --recursive + +# Apply patches +./scripts/prepare.sh + +# Build with optional deps disabled +mkdir build && cd build +cmake .. -DKICAD_USE_CURL=OFF -DKICAD_USE_GIT=OFF -DKICAD_USE_OCC=OFF +make -j$(nproc) +``` + +## License + +KiCad is GPL-3.0. This wrapper/tooling follows the same license. \ No newline at end of file diff --git a/docs/IMPLEMENTATION_PLAN.md b/docs/IMPLEMENTATION_PLAN.md new file mode 100644 index 0000000..6c0475d --- /dev/null +++ b/docs/IMPLEMENTATION_PLAN.md @@ -0,0 +1,335 @@ +# KiCad Wasm Port - Implementation Plan + +## Goal + +Run KiCad with native wxWidgets GUI, but with core logic (file parsing, geometry, DRC, routing) executing in a WebAssembly module. This validates the Wasm build before tackling the browser UI. + +--- + +## Phase 1: Minimal Build with Stubs + +**Objective**: Get KiCad compiling with optional deps disabled via preprocessor guards. + +### 1.1 Create Project Structure + +``` +kicad-wasm/ +β”œβ”€β”€ kicad/ # Git submodule β†’ upstream KiCad +β”œβ”€β”€ patches/ +β”‚ └── 0001-optional-deps.patch +β”œβ”€β”€ stubs/ +β”‚ └── include/ +β”‚ β”œβ”€β”€ git2.h # Minimal stub headers +β”‚ └── curl/curl.h +β”œβ”€β”€ cmake/ +β”‚ └── KicadWasmOptions.cmake +β”œβ”€β”€ CMakeLists.txt +└── scripts/ + β”œβ”€β”€ prepare.sh # Apply patches + └── update-kicad.sh # Update to new KiCad version +``` + +### 1.2 Create the Patch + +Add CMake options to `CMakeLists.txt` (after line 107): + +```cmake +option( KICAD_USE_CURL "Enable network features" ON ) +option( KICAD_USE_GIT "Enable git integration" ON ) +option( KICAD_USE_OCC "Enable OpenCASCADE for STEP" ON ) +option( KICAD_USE_NGSPICE "Enable SPICE simulation" ON ) +option( KICAD_USE_DATABASE "Enable database libraries" ON ) +``` + +Wrap `find_package` calls conditionally: + +```cmake +if( KICAD_USE_CURL ) + find_package( CURL REQUIRED ) + add_compile_definitions( KICAD_USE_CURL ) +else() + add_library( CURL::libcurl INTERFACE IMPORTED ) +endif() +``` + +### 1.3 Create Stub Headers + +Minimal headers that let code compile without the actual libraries: + +```cpp +// stubs/include/git2.h +#pragma once +typedef struct git_repository git_repository; +// Stub functions return error codes +``` + +### 1.4 Add Preprocessor Guards to Source + +Wrap implementations in `common/git/*.cpp`, `common/kicad_curl/*.cpp`: + +```cpp +#ifdef KICAD_USE_GIT +// actual implementation +#else +// return error or throw "feature disabled" +#endif +``` + +### 1.5 Verify Native Build + +```bash +cd kicad-wasm +./scripts/prepare.sh +mkdir build && cd build +cmake .. -DKICAD_USE_CURL=OFF -DKICAD_USE_GIT=OFF -DKICAD_USE_OCC=OFF +make -j$(nproc) +``` + +Confirm KiCad launches and can open/edit PCB files (without git/network/STEP features). + +--- + +## Phase 2: Extract Core Library + +**Objective**: Build core computation code as a standalone library that can be compiled to both native and Wasm. + +### 2.1 Identify Core Components + +Create `kicad-wasm/core/CMakeLists.txt` targeting: + +| Component | Source Location | Notes | +|-----------|-----------------|-------| +| Math/Geometry | `libs/kimath/` | Pure C++, no deps | +| Core utilities | `libs/core/` | Pure C++ | +| KiCad file parser | `common/io/kicad/` | Needs minimal deps | +| S-expression parser | `libs/sexpr/` | Pure C++ | +| Board data model | `pcbnew/board*.cpp` | Extract carefully | + +### 2.2 Define API Boundary + +Create a C API for the core (easier Wasm interop than C++): + +```cpp +// kicad-wasm/core/include/kicad_core_api.h +extern "C" { + // File operations + void* kicad_load_pcb(const char* data, size_t len); + void kicad_free_pcb(void* board); + char* kicad_serialize_pcb(void* board); + + // Query + int kicad_get_track_count(void* board); + + // Modification + void kicad_add_track(void* board, /* params */); +} +``` + +### 2.3 Build Core as Static Library + +```cmake +# kicad-wasm/core/CMakeLists.txt +add_library(kicad_core STATIC + ${KIMATH_SOURCES} + ${SEXPR_SOURCES} + ${IO_KICAD_SOURCES} + api/kicad_core_api.cpp +) + +target_compile_definitions(kicad_core PRIVATE + KICAD_CORE_ONLY=1 +) +``` + +--- + +## Phase 3: Compile Core to WebAssembly + +**Objective**: Build `kicad_core.wasm` using Emscripten. + +### 3.1 Emscripten Build + +```bash +source /path/to/emsdk/emsdk_env.sh + +cd kicad-wasm +mkdir build-wasm && cd build-wasm + +emcmake cmake ../core \ + -DCMAKE_BUILD_TYPE=Release \ + -DKICAD_WASM_BUILD=ON + +emmake make +``` + +### 3.2 Export Functions + +```cmake +# For Emscripten +if(EMSCRIPTEN) + set_target_properties(kicad_core PROPERTIES + LINK_FLAGS "-s EXPORTED_FUNCTIONS='[_kicad_load_pcb,_kicad_free_pcb,...]' \ + -s EXPORTED_RUNTIME_METHODS='[ccall,cwrap]' \ + -s MODULARIZE=1 \ + -s EXPORT_NAME='KicadCore'" + ) +endif() +``` + +### 3.3 Test Wasm Module + +Create a simple test that loads a `.kicad_pcb` file: + +```javascript +// test/test_core.mjs +import KicadCore from './kicad_core.js'; + +const core = await KicadCore(); +const pcbData = fs.readFileSync('test.kicad_pcb', 'utf8'); +const board = core.ccall('kicad_load_pcb', 'number', ['string', 'number'], + [pcbData, pcbData.length]); +console.log('Track count:', core.ccall('kicad_get_track_count', 'number', ['number'], [board])); +``` + +--- + +## Phase 4: Native App with Wasm Worker + +**Objective**: Run native KiCad GUI but delegate core operations to the Wasm module. + +### 4.1 Choose Wasm Runtime + +Options for running Wasm in native app: +- **Wasmtime** - Rust-based, mature, good C API +- **wasm3** - Small, fast interpreter +- **WAMR** - WebAssembly Micro Runtime, lightweight + +Recommend: **Wasmtime** for development (better debugging), **wasm3** for size. + +### 4.2 Create Wasm Bridge + +```cpp +// kicad-wasm/bridge/wasm_bridge.h +class WasmBridge { +public: + WasmBridge(const std::string& wasmPath); + + BOARD* LoadPCB(const std::string& data); + std::string SerializePCB(BOARD* board); + void RunDRC(BOARD* board); + +private: + wasmtime_instance_t* m_instance; +}; +``` + +### 4.3 Integrate with KiCad + +Modify KiCad to optionally use the Wasm bridge: + +```cpp +// In pcbnew loading code +#ifdef USE_WASM_CORE + auto board = WasmBridge::Get().LoadPCB(fileContent); +#else + auto board = IO_KICAD::Load(filename); +#endif +``` + +### 4.4 Validate Correctness + +1. Load same PCB file via native code and via Wasm bridge +2. Compare serialized output (should be identical) +3. Run DRC via both paths, compare results +4. Profile performance difference + +--- + +## Phase 5: Incremental Migration + +**Objective**: Move more functionality to Wasm core, validate stability. + +### Priority Order + +1. **File I/O** - parsing and serialization +2. **DRC engine** - computationally intensive, isolated +3. **Router** - Push & Shove algorithms +4. **ERC** - schematic checks + +### Validation Strategy + +For each migrated component: +1. Keep both native and Wasm implementations +2. Add flag to switch between them +3. Run test suite with both +4. Benchmark performance +5. Remove native implementation once confident + +--- + +## Milestones + +| Milestone | Deliverable | Validation | +|-----------|-------------|------------| +| M1 | KiCad builds with deps disabled | Opens PCB files, basic editing works | +| M2 | Core library extracts cleanly | Compiles as standalone static lib | +| M3 | Core compiles to Wasm | Passes unit tests via Node.js | +| M4 | Native app loads Wasm worker | Can load/save PCB via Wasm bridge | +| M5 | DRC runs in Wasm | Results match native DRC | + +--- + +## Design Decisions + +### Memory Management + +**Decision**: Serialize/deserialize on every operation + +- Proof of concept - simplicity over performance +- Clean interface between GUI and Wasm core +- Easy to debug +- Browser-friendly (no shared memory complexity) +- Can optimize later if needed + +``` +GUI Wasm Core + β”‚ β”‚ + │──serialize(board)─────────────▢│ + β”‚ │──process + │◀─────────────serialize(board)──│ + β”‚ β”‚ +``` + +### Threading Model + +**Decision**: Web Workers + +- Target is browser, design for it from the start +- Each heavy operation (DRC, routing) runs in dedicated worker +- Clean message-passing interface +- No shared memory complexity + +```javascript +// Main thread spawns workers for heavy operations +const drcWorker = new Worker('drc-worker.js'); +drcWorker.postMessage({ board: serializedBoard }); +drcWorker.onmessage = (e) => updateUI(e.data.violations); +``` + +### Incremental Updates + +**Decision**: Re-serialize entire board + +- Simple for proof of concept +- Board files typically <10MB, acceptable latency +- Can add delta operations later if performance requires it + +--- + +## Next Steps + +1. Fork KiCad repo, set up as submodule +2. Write the minimal patch for optional deps +3. Create stub headers +4. Verify native build with features disabled +5. Begin core library extraction \ No newline at end of file diff --git a/docs/KNOWLEDGE_BASE.md b/docs/KNOWLEDGE_BASE.md new file mode 100644 index 0000000..c3dadfd --- /dev/null +++ b/docs/KNOWLEDGE_BASE.md @@ -0,0 +1,136 @@ +# KiCad WebAssembly Port - Knowledge Base + +## Architecture Overview + +KiCad is a modular EDA suite with these main components: +- **Project Manager** (`kicad/`) - launches other tools +- **PCB Editor** (`pcbnew/`) - board layout +- **Schematic Editor** (`eeschema/`) - circuit design +- **3D Viewer** (`3d-viewer/`) - 3D visualization + +Shared code lives in: +- `common/` - shared library (kicommon), includes GUI, I/O, git, curl +- `libs/core/` - utilities +- `libs/kimath/` - geometry and math (pure C++, no deps) + +## Key Dependencies + +| Dependency | Purpose | Wasm Strategy | +|------------|---------|---------------| +| **wxWidgets** | All GUI | Keep native initially; replace with web UI later | +| **OpenGL** | 2D rendering via GAL | WebGL (Emscripten handles this) | +| **Cairo** | Fallback 2D rendering | Compile with Emscripten or skip | +| **OpenCASCADE** | STEP import/export, 3D | Disable for MVP; huge (~40MB) | +| **libcurl** | PCM, update check, HTTP libs | Stub out; replace with Fetch API | +| **libgit2** | Version control integration | Stub out; optional feature | +| **ngspice** | Circuit simulation | Stub out; separate concern | +| **nanoodbc** | Database libraries | Stub out; enterprise feature | +| **Freetype/HarfBuzz** | Font rendering | Compile with Emscripten (works) | +| **Boost** | Locale, unit tests | Minimize; locale needed for nanoodbc only | + +## Graphics Abstraction Layer (GAL) + +Location: `common/gal/`, `include/gal/` + +KiCad abstracts rendering through GAL with two backends: +- `OPENGL_GAL` (`common/gal/opengl/`) - primary, uses GLSL shaders +- `CAIRO_GAL` (`common/gal/cairo/`) - fallback, vector graphics + +Key files: +- `include/gal/graphics_abstraction_layer.h` - base interface +- `common/gal/opengl/opengl_gal.cpp` - OpenGL implementation +- `common/gal/shaders/` - GLSL shaders (need ES conversion for WebGL) + +For Wasm: OpenGL ES subset via Emscripten maps to WebGL. Shaders need `#version` removal and precision qualifiers. + +## File I/O System + +Location: `common/io/`, `include/io/` + +Plugin-based architecture supporting multiple formats: +- KiCad native (`.kicad_pcb`, `.kicad_sch`) +- Eagle, Altium, CADSTAR, EasyEDA imports + +Key class: `IO_BASE` in `include/io/io_base.h` + +Parsers are mostly pure C++ - good candidates for Wasm core. + +## Python Scripting + +Location: `scripting/`, `pcbnew/python/` + +Uses SWIG to generate CPython bindings (~3,500 lines of `.i` files). + +For Wasm: SWIG bindings won't work. Options: +1. Use Emscripten's `embind` instead +2. Use Pyodide with custom FFI +3. Skip Python for MVP + +## Optional Features to Disable + +These have minimal impact on core editing functionality: + +| Feature | CMake Area | Files | +|---------|-----------|-------| +| Git integration | `common/git/` | 15 handler files | +| Network (PCM, updates) | `common/kicad_curl/`, `common/http_lib/` | ~5 files | +| Database libraries | `common/database/` | 2-3 files | +| STEP/3D export | `pcbnew/exporters/step/`, `plugins/3d/oce/` | Isolated | +| SPICE simulation | `eeschema/sim/` | Isolated subsystem | + +## Build System Notes + +Main CMake: `CMakeLists.txt` + +Currently all deps are REQUIRED (lines 820-892). No options exist to disable curl/git/OCC. + +Libraries link in `common/CMakeLists.txt:316-343`: +```cmake +target_link_libraries( kicommon + CURL::libcurl + ${LIBGIT2_LIBRARIES} + ... +) +``` + +## IPC/Communication + +`KIWAY` system (`include/kiway.h`, `include/kiway_holder.h`) handles inter-frame communication. Frames inherit from `KIWAY_PLAYER`. + +For Wasm worker architecture: This could be adapted for message-passing between native GUI and Wasm worker. + +## Potential Problem Areas + +1. **Threading**: KiCad uses threads for DRC, rendering. Wasm has Web Workers but different threading model. + +2. **File dialogs**: `wxFileDialog` throughout - needs abstraction for browser File API. + +3. **Memory**: Large boards can use 1GB+. Wasm has 4GB limit, but browser tabs may have lower practical limits. + +4. **Clipboard**: Native clipboard integration in multiple places. + +5. **Printing**: Cairo-based printing system won't work in browser. + +## Files of Interest for Core Extraction + +Pure computation, no GUI deps - good Wasm candidates: +- `libs/kimath/` - all geometry code +- `libs/core/` - utilities +- `common/io/kicad/` - native format parser +- `pcbnew/router/` - Push & Shove routing algorithms +- `pcbnew/drc/` - Design Rule Check engine +- `eeschema/erc/` - Electrical Rule Check + +## Reference Paths + +| Component | Path | +|-----------|------| +| Main CMake | `CMakeLists.txt` | +| Common library | `common/CMakeLists.txt` | +| GAL system | `common/gal/`, `include/gal/` | +| File I/O | `common/io/` | +| PCB data model | `pcbnew/board.h`, `pcbnew/footprint.h` | +| Git integration | `common/git/` | +| Curl wrapper | `common/kicad_curl/` | +| Python bindings | `scripting/`, `pcbnew/python/swig/` | +| 3D/STEP | `pcbnew/exporters/step/`, `3d-viewer/` | diff --git a/docs/KNOWLEDGE_BASE_FULL.md b/docs/KNOWLEDGE_BASE_FULL.md new file mode 100644 index 0000000..35634f6 --- /dev/null +++ b/docs/KNOWLEDGE_BASE_FULL.md @@ -0,0 +1,846 @@ +# KiCad WebAssembly Port - Complete Knowledge Base + +## Table of Contents +1. [Architecture Overview](#architecture-overview) +2. [Dependencies Deep Dive](#dependencies-deep-dive) +3. [Graphics System (GAL)](#graphics-system-gal) +4. [File I/O System](#file-io-system) +5. [Python Scripting](#python-scripting) +6. [Build System](#build-system) +7. [Features to Disable](#features-to-disable) +8. [Code Extraction Candidates](#code-extraction-candidates) +9. [Technical Challenges](#technical-challenges) +10. [Design Decisions](#design-decisions) +11. [File Reference](#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 (`.kiface` on Linux/Mac, `.dll` on Windows) + +This allows: +- Standalone operation +- Project manager integration via dynamic loading + +Key files: +- `include/kiway.h` - KIWAY system for inter-module communication +- `include/kiway_holder.h` - Mixin for frames that participate in KIWAY +- `include/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` - windows +- `wxGLCanvas` - OpenGL context +- `wxFileDialog` - file selection +- `wxAuiManager` - dockable panes +- `wxPropertyGrid` - 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`, add `precision` qualifiers) + +### 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 export +- `pcbnew/exporters/step/exporter_step.cpp` - Export orchestration +- `plugins/3d/oce/loadmodel.cpp` - 3D model loading +- `plugins/3d/oce/oce.cpp` - Plugin entry point + +**Headers imported** (from `step_pcb_model.cpp`): +```cpp +#include +#include +#include +#include +#include +// ... ~30 more OCC headers +``` + +**Wasm strategy**: Disable for MVP. OCC is huge (~40MB compiled). Alternative: [opencascade.js](https://github.com/nicholaseasmith/opencascade.js) exists but experimental. + +### libcurl + +**Purpose**: HTTP requests for: +1. Plugin Content Manager (PCM) - `kicad/pcm/pcm.cpp` +2. Update checker - `kicad/update_manager.cpp` +3. 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` +```cpp +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` + +```cpp +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& 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.h` +- `common/gal/opengl/opengl_gal.cpp` +- `common/gal/opengl/shader.cpp` - GLSL shader management +- `common/gal/opengl/vertex_manager.cpp` - Vertex buffer management +- `common/gal/opengl/gpu_manager.cpp` - GPU memory management +- `common/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: +```glsl +// 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.h` +- `common/gal/cairo/cairo_gal.cpp` +- `common/gal/cairo/cairo_compositor.cpp` - Layer compositing +- `common/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` + +```cpp +class IO_BASE { + struct IO_FILE_DESC { + wxString m_Description; + std::vector m_FileExtensions; + bool m_CanRead; + bool m_CanWrite; + }; + + virtual std::vector 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: +```lisp +(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 + +1. SWIG reads `.i` interface files +2. Generates C++ wrapper code for CPython +3. Wrapper compiled to shared library (`_pcbnew.so`) +4. Python imports the module + +```python +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: + +1. **Emscripten embind**: Rewrite bindings (~3500 lines to port) + ```cpp + #include + EMSCRIPTEN_BINDINGS(pcbnew) { + class_("Board") + .function("GetTracks", &BOARD::Tracks); + } + ``` + +2. **Pyodide**: If we want Python in browser, use Pyodide with custom FFI + +3. **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` + +```cmake +# 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: +```cmake +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: +```cmake +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.cpp` +- `git_branch_handler.cpp` +- `git_clone_handler.cpp` +- `git_commit_handler.cpp` +- `git_config_handler.cpp` +- `git_compare_handler.cpp` +- `git_init_handler.cpp` +- `git_pull_handler.cpp` +- `git_push_handler.cpp` +- `git_remove_from_index_handler.cpp` +- `git_remove_vcs_handler.cpp` +- `git_resolve_conflict_handler.cpp` +- `git_revert_handler.cpp` +- `git_status_handler.cpp` +- `git_switch_branch_handler.cpp` +- `git_sync_handler.cpp` +- `kicad_git_common.cpp` +- `git_backend.cpp` +- `libgit_backend.cpp` +- `project_git_utils.cpp` + +**Stub header needed**: `stubs/include/git2.h` + +### Network Features (curl) + +**Files to stub** (`common/kicad_curl/`): +- `kicad_curl.cpp` +- `kicad_curl_easy.cpp` + +**Files to stub** (`common/http_lib/`): +- `http_lib_connection.cpp` + +**Files affected** (`kicad/`): +- `pcm/pcm.cpp` - Plugin Content Manager +- `pcm/pcm_task_manager.cpp` +- `update_manager.cpp` + +**Stub header needed**: `stubs/include/curl/curl.h` + +### OpenCASCADE (STEP/3D) + +**Files to exclude**: +- `pcbnew/exporters/step/*.cpp` +- `plugins/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.cpp` +- `database_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**: +1. **Web Workers**: Spawn separate Wasm instances +2. **Wasm threads** (experimental): SharedArrayBuffer + pthreads +3. **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**: +1. **Serialize/deserialize**: Simple, proof of concept +2. **Shared memory**: Complex, requires careful synchronization +3. **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**: +```cpp +// 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**: +```javascript +// 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` | diff --git a/kicad b/kicad new file mode 160000 index 0000000..4bfed3f --- /dev/null +++ b/kicad @@ -0,0 +1 @@ +Subproject commit 4bfed3f1746e8cc0a7d942767770f56fa28b393c