Skip to content

Commit aae9a23

Browse files
author
FlightCore Dev
committed
chore: prepare repository for open source release
Add README, MIT and Apache 2.0 licenses, update .gitignore to exclude build artifacts and unused FreeRouting versions. Include new example files, planning docs, and pending source changes.
1 parent a36a507 commit aae9a23

29 files changed

Lines changed: 5465 additions & 381 deletions

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,15 @@ crates/cypcb-parser/grammar/package-lock.json
2525

2626
# Local cargo config (machine-specific)
2727
.cargo/config.toml
28+
29+
# Unused FreeRouting versions
30+
freerouting-1.9.0.jar
31+
freerouting-2.0.1.jar
32+
33+
# Compiled Rust artifacts (loose files outside /target)
34+
*.rlib
35+
*.o
36+
37+
# Runtime artifacts
38+
logs/
39+
export-test/
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
status: diagnosed
3+
trigger: "Diagnose why the parser rejects `current 500mA` syntax in net blocks"
4+
created: 2026-01-22T00:00:00Z
5+
updated: 2026-01-22T00:02:00Z
6+
symptoms_prefilled: true
7+
goal: find_root_cause_only
8+
---
9+
10+
## Current Focus
11+
12+
hypothesis: CONFIRMED - Syntax mismatch between user expectation and grammar design
13+
test: Verified with both syntaxes
14+
expecting: N/A - Root cause found
15+
next_action: Report findings
16+
17+
## Symptoms
18+
19+
expected: Parser accepts `current 500mA` syntax inside net blocks
20+
actual: Parser returns "Syntax error: unexpected token: 'current 500mA'"
21+
errors: "Syntax error: unexpected token: 'current 500mA'"
22+
reproduction: Add `current 500mA` inside a net definition block
23+
started: Unknown - 05-01-SUMMARY claims it was implemented
24+
25+
## Eliminated
26+
27+
## Evidence
28+
29+
- timestamp: 2026-01-22T00:01:00Z
30+
checked: grammar.js lines 150-171 (net_definition and net_constraint_block)
31+
found: |
32+
Net constraints use square bracket syntax BEFORE the braces:
33+
- net_definition: seq('net', name, optional(net_constraint_block), '{', pin_ref_list, '}')
34+
- net_constraint_block: seq('[', repeat(net_constraint), ']')
35+
- current_constraint rule EXISTS at lines 186-189
36+
37+
Expected syntax: net VCC [current 500mA] { ... }
38+
User's syntax: net VCC { ... current 500mA }
39+
implication: User is placing constraint inside braces; grammar only accepts constraints in square brackets before braces
40+
41+
- timestamp: 2026-01-22T00:02:00Z
42+
checked: Ran parser test with both syntaxes
43+
found: |
44+
User syntax (inside braces): FAILS with "unexpected token: 'current 500mA'"
45+
Correct syntax (square brackets): PASSES
46+
implication: Confirms grammar design, not a bug - documentation/syntax mismatch
47+
48+
## Resolution
49+
50+
root_cause: |
51+
NOT A BUG - SYNTAX MISMATCH
52+
53+
The grammar is implemented correctly. The `current` constraint IS supported,
54+
but it must appear in square brackets BEFORE the net body braces, not inside them.
55+
56+
Grammar design (grammar.js lines 150-158):
57+
net_definition: seq('net', name, optional(net_constraint_block), '{', pin_ref_list, '}')
58+
59+
CORRECT SYNTAX:
60+
net VCC [current 500mA] {
61+
R1.1
62+
C1.1
63+
}
64+
65+
INCORRECT (user's attempt):
66+
net VCC {
67+
R1.1
68+
C1.1
69+
current 500mA // ERROR - constraints go in [ ] before braces
70+
}
71+
72+
fix: N/A - This is a documentation issue, not a code bug
73+
verification: N/A
74+
files_changed: []
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
phase: 03-validation
3+
plan: 09
4+
status: complete
5+
completed: 2026-01-22
6+
---
7+
8+
# Summary: 03-09 Visual Verification Checkpoint
9+
10+
## What Was Verified
11+
12+
Human verification of complete DRC system working end-to-end.
13+
14+
## Verification Results
15+
16+
### DRC Detection
17+
- **Clearance violations:** Detected - "Clearance violation: 0.00mm actual, 0.15mm required"
18+
- **Unconnected pins:** Detected - All unconnected pins reported (R1.1, R1.2, R2.1, R2.2, etc.)
19+
- **Multiple violation types:** Working correctly
20+
21+
### Visual Display
22+
- **Error badge:** Shows in status bar with violation count
23+
- **Error panel:** Lists all violations with [kind] message format
24+
- **Markers:** Red ring markers visible at violation locations
25+
26+
### Hot Reload
27+
- **File watch:** Working - changes trigger re-render
28+
- **DRC update:** Violations recalculated on reload
29+
- **Example tested:** blink.cypcb (12 violations), drc-test.cypcb (clearance + unconnected)
30+
31+
## Test Files Used
32+
33+
- `examples/blink.cypcb` - 12 unconnected-pin violations (3 components, 8-pin IC)
34+
- `examples/drc-test.cypcb` - Intentional clearance violation between R1/R2
35+
36+
## Console Output Verified
37+
38+
```
39+
WASM module loaded successfully
40+
Loaded snapshot: {board: {...}, components: Array(3), nets: Array(0), violations: Array(12)}
41+
[HotReload] WebSocket connected
42+
[HotReload] Reloaded snapshot
43+
```
44+
45+
## Issues Found & Fixed During Phase
46+
47+
- **DRC WASM empty violations:** Fixed in commit 9252017
48+
- Root cause: `WasmPcbEngineAdapter.get_snapshot()` returned cached JS snapshot instead of WASM engine result
49+
- Fix: Changed to return `this.wasmEngine.get_snapshot()`
50+
51+
## Phase 3 Completion Status
52+
53+
All 10 plans complete:
54+
- 03-01: DRC crate setup ✓
55+
- 03-02: IC footprints ✓
56+
- 03-03: Manufacturer presets ✓
57+
- 03-04: Custom footprint DSL ✓
58+
- 03-05: Clearance checking ✓
59+
- 03-06: Drill/trace/connectivity rules ✓
60+
- 03-07: DRC integration ✓
61+
- 03-08: Violation display ✓
62+
- 03-09: Visual verification ✓
63+
- 03-10: Zones and keepouts ✓
64+
65+
## Next Phase
66+
67+
Phase 4: Export - Gerber X2, Excellon drill, BOM generation

.planning/phases/12-tauri-desktop-foundation/12-05-PLAN.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
phase: 12-tauri-desktop-foundation
33
plan: 05
44
type: execute
5-
wave: 1
6-
depends_on: []
5+
wave: 4
6+
depends_on: ['12-03']
77
files_modified: [viewer/src/main.ts]
88
autonomous: true
99
gap_closure: true
@@ -60,8 +60,8 @@ Add these 5 event listeners:
6060
1. **desktop:open-file** - Receives `{ path: string, content: string }` in event.detail.
6161
- Call `engine.load_source(detail.content)` to parse the content
6262
- Update `snapshot = engine.get_snapshot()`
63-
- If snapshot.board exists, call `fitBoard()` and update viewport/interactionState.viewport
64-
- Update error badge via `updateErrorBadge(snapshot.violations || [])`
63+
- Update error badge via `updateErrorBadge(snapshot.violations || [])` (AFTER snapshot is assigned)
64+
- If snapshot.board exists, call `viewport = fitBoard(viewport, snapshot.board.width_nm, snapshot.board.height_nm)` and update `interactionState.viewport = viewport`
6565
- Set `currentFilePath = detail.path` (the local variable, for routing)
6666
- Update statusText with filename (extract from path using split)
6767
- Set `dirty = true`
@@ -79,18 +79,18 @@ Add these 5 event listeners:
7979
8080
3. **desktop:viewport** - Receives `{ action: 'zoom-in' | 'zoom-out' | 'fit' }` in event.detail.
8181
- For 'zoom-in': multiply viewport.scale by 1.5, update viewport and interactionState.viewport, set dirty = true
82-
- For 'zoom-out': multiply viewport.scale by (1/1.5), update viewport and interactionState.viewport, set dirty = true
82+
- For 'zoom-out': divide viewport.scale by 1.5 (i.e., multiply by 0.6667), update viewport and interactionState.viewport, set dirty = true
8383
- For 'fit': if snapshot?.board exists, call `fitBoard(viewport, snapshot.board.width_nm, snapshot.board.height_nm)`, update viewport and interactionState.viewport, set dirty = true
8484
8585
4. **desktop:toggle-theme** - No detail payload.
86-
- Cycle theme exactly like the themeToggle click handler: get current from themeManager.getTheme(), compute next (light->dark->auto->light), call themeManager.setTheme(next), call updateThemeIcon().
86+
- Cycle theme exactly like the themeToggle click handler: get current from themeManager.getTheme(), compute next (light->dark->auto->light), call themeManager.setTheme(next), call updateThemeIcon() (the existing function defined at ~line 244 in main.ts, accessible within init() scope).
8787
8888
5. **desktop:new-file** - No detail payload.
8989
- Call `engine.load_source('')` to clear
9090
- Update `snapshot = engine.get_snapshot()`
9191
- Set `currentFilePath = null`
9292
- Set `lastLoadedSource = null`
93-
- Set statusText to 'Ready (WASM) - Open a file' or 'Ready (Mock) - Open a file'
93+
- Set statusText using the existing `usingWasm` variable: `statusText = usingWasm ? 'Ready (WASM) - Open a file' : 'Ready (Mock) - Open a file'`
9494
- Set `dirty = true`
9595
9696
Also add `let lastLoadedSource: string | null = null;` near the top of init() alongside the other state variables.
@@ -112,7 +112,7 @@ All 5 desktop custom events (open-file, content-request, viewport, toggle-theme,
112112
113113
<verification>
114114
1. `grep -c "desktop:" viewer/src/main.ts` returns at least 5 (one per event type)
115-
2. `grep "lastLoadedSource" viewer/src/main.ts` shows the variable is set in reload, handleFileLoad, and desktop:open-file handler
115+
2. `grep -n "lastLoadedSource\s*=" viewer/src/main.ts` shows assignments in at least 4 locations: declaration, reload() (~line 483), handleFileLoad() (~line 317), and desktop:open-file handler
116116
3. `cd viewer && npx tsc --noEmit` passes
117117
</verification>
118118

0 commit comments

Comments
 (0)