This project uses an ArchiGraph (archigraph.yaml) — a machine-readable architecture graph with 128 nodes and 547+ edges describing every component, service, and relationship.
-
Read
CLAUDE.mdfirst — it has the architecture summary, source file mappings, and critical implementation gotchas. It's designed as an AI instruction file. -
Search
archigraph.yamlfor context — every system has a node with adocs.descriptionfield explaining what it does and why. Example:- id: system.autoface kind: service docs: description: >- Three auto-face mechanisms in GeometryEngine: (1) autoCreateFaces via createEdgeWithAutoFace()...
-
Follow edges to understand connections — edges show which systems call, read, or contain others:
- kind: calls from: tool.line to: system.autoface docs: description: Line tool calls createEdgeWithAutoFace() which triggers auto-face detection.
-
Update
CLAUDE.mdwith gotchas — if you discover a non-obvious implementation detail (like "projectionMatrixInverse must be manually recomputed before raycasting"), add it to CLAUDE.md so the next contributor doesn't hit the same issue.
- Start with the README — it has the system diagram, data flow, and keyboard shortcuts
- Browse
archigraph.yaml— search for the system you want to work on by name - Read the Key Design Decisions section in the README — these are the things that will bite you if you don't know about them
- Run the E2E tests —
npx playwright testruns real Electron tests. If they pass, your changes didn't break anything.
npm install
npm run build
npx electron dist/main/main.js # Run the app
npx playwright test # Run tests- Edit source files in
src/ - Rebuild:
npx webpack --config webpack.renderer.config.js(renderer) ornpx webpack --config webpack.main.config.js(main process) - Test:
npx playwright test tests/e2e-playwright/your-test.spec.ts - Type check:
npx tsc --noEmit
All tests are Playwright E2E tests that launch the real Electron app. No mocks.
# Run all tests
npx playwright test
# Run a specific test file
npx playwright test tests/e2e-playwright/drawing-tools.spec.ts
# Run tests matching a pattern
npx playwright test --grep "Rectangle"The test helper launches Electron and exposes (window as any).__debugApp for direct access to the Application instance. This lets you programmatically create geometry, check state, and verify results.
- TypeScript strict mode
// @archigraph <node-id>comments at the top of files that implement a specific node- One tool per file in
src/tools/ - All keyboard shortcuts handled in one place (
App.tsx) - Use
event.hitEntityIdfrom the raycast pipeline (don't do your own raycasting in tools)
| Layer | Components | Key Files |
|---|---|---|
| Electron | Main process, IPC, file dialogs | src/main/main.ts, preload.ts |
| React UI | Toolbars, panels, context menu | src/renderer/components/ |
| Application | Orchestrator, tool registration | src/renderer/Application.ts |
| Three.js | Renderer, camera, viewport | src/renderer/WebGL*.ts, Viewport.ts |
| Scene Bridge | Geometry→Three.js sync, snap | src/renderer/SceneBridge.ts |
| Tools | 23 drawing/modify/navigate tools | src/tools/ |
| Geometry | B-Rep kernel, half-edge mesh | src/engine/geometry/ |
| Data | Document, scene, history, selection | src/data/ |
- Create
src/tools/MyTool.tsextendingBaseTool - Implement
onMouseDown/Move/Up,getPreview(),getVCBLabel() - Register in
src/renderer/Application.ts→registerTools() - Add keyboard shortcut in
src/renderer/App.tsx - Add button in
src/renderer/components/DrawingToolbar.tsx - Write a Playwright test
- Write a failing test using
page.evaluate()to create geometry directly - Trace through
GeometryEngine.tsandHalfEdgeMesh.ts - Fix the logic
- Verify the test passes
- Run the full test suite
- Check if the issue is data (geometry engine) or visual (Three.js)
- Use
page.evaluate()to inspect mesh state vs Three.js scene objects - Common causes: stale camera matrices, edge z-fighting, highlight material not restored
- The overlay scene (edges) renders separately from the main scene (faces)