A parametric, feature-based mechanical CAD system for Windows, built on .NET 10.
Status: Phase 2 of 17 — the viewport. The kernel is real (OCCT 8.0.1 behind a C ABI shim), the application opens on shaded geometry with edges, and picking works. There is no document model, no sketcher and no file format yet. See
docs/plan.mdfor the full plan and what each phase still owes.
History-based parametric part modelling, a fully constrained 2D sketcher, assemblies with mates and an assembly-level solve, associative production drawings generated by hidden-line removal, STEP AP242 and other exchange formats, sheet metal, surfacing, and a stable public plugin API.
| Solution and layered project skeleton | ✅ P0-T04 |
| Layering enforced by architecture tests | ✅ P0-T05 |
Double-precision geometry primitives (OpenMCAD.Math) |
✅ P0-T13 |
| WPF shell that launches, with ribbon and docking | ✅ P0-T10 |
Headless CLI (omcad) |
✅ P0-T11 |
| Structured logging and DI composition root | ✅ P0-T09 |
| Native shim skeleton (CMake, C ABI, exception firewall) | ✅ P0-T06 — authored, not yet linked to OCCT |
| Kernel abstraction, single-threaded dispatcher, owning handles | ✅ P1-T01/02/07/08 |
FakeKernel — deterministic analytic mock |
✅ P1-T09 |
| Kernel contract battery | ✅ P1-T10 |
| C ABI generated from a single IDL (49 operations) | ✅ P1-T03 |
| Repro-bundle capture, regression corpus, determinism gate | ✅ P1-T13, P1-T14 |
| OCCT 8.0.1 built and verified (spike) | ✅ |
OCCT behind IGeometryKernel |
⬜ P1-T04/05/06 — next |
| Viewport | ⬜ Phase 2 |
| Documents, rebuild, topological naming | ⬜ Phase 3 |
| Sketcher | ⬜ Phase 4 |
Requirements:
- .NET 10 SDK (pinned in
global.json) - Visual Studio Build Tools with the C++ workload — only for the native shims. Without it the build skips them and everything managed still builds and runs.
- CMake 3.25+ — same condition.
./build.ps1 # Debug build, then tests
./build.ps1 -Configuration Release # Release
./build.ps1 -SkipTests # Build only
./build.ps1 -Clean # Clean firstOutputs land under artifacts/bin/:
OpenMCAD.Shell/<config>/OpenMCAD.exe— the applicationOpenMCAD.Cli/<config>/omcad.exe— the headless runner
./artifacts/bin/OpenMCAD.Cli/debug/omcad.exe versionLogs are written to %LOCALAPPDATA%\OpenMCAD\logs.
xunit.v3 runs on Microsoft.Testing.Platform, and each test project builds as its own executable
test host. build.ps1 invokes those hosts directly rather than using dotnet test; see
docs/notes/test-runner.md for why.
./artifacts/bin/OpenMCAD.Math.Tests/debug/OpenMCAD.Math.Tests.exedocs/ PLAN.md (the master plan) · adr/ · specs/ · notes/
native/ C ABI shims over OCCT and planegcs · vcpkg manifest · CMake
src/ one project per architectural layer; dependencies point downward only
tests/ unit · integration · regression corpus · fuzz · perf · arch
Layer order is declared in docs/PLAN.md section 4.1 and enforced by
tests/arch/OpenMCAD.Architecture.Tests, which checks both the compiled metadata and the project
graph. A reference that points sideways or upward fails the build.
Read docs/PLAN.md section 12 before starting. In short:
- Work phase by phase. Announce the task ID you are doing.
- Commit as
P<n>-T<nn>: <imperative summary>, and tick the box indocs/PLAN.mdin the same commit. - A geometry change without corpus coverage is not done. A naming regression is a P0.
- No new NuGet dependency without an ADR (
docs/adr/). - Do not improve the architecture opportunistically. Write an ADR proposal and stop.
OpenMCAD is an experiment in how far an AI coding agent can get building a system of this size,
working from docs/PLAN.md phase by phase under human direction. Essentially all
of the code here was written by Claude. That is the point of the repository, and it is stated
plainly rather than left to be inferred — judge the code accordingly.
MIT.
Third-party components keep their own licences; see
THIRD-PARTY-NOTICES.md. The geometry kernel (OCCT) and constraint
solver (planegcs) are LGPL-2.1 and are confined to separately replaceable dynamic libraries, which
is both the engineering design (ADR-0003, ADR-0006) and what the LGPL relinking condition asks for.
See ADR-0017 for the full reasoning.