A snapshot of 15 October 2026; line counts are from that day.

CadCraft · architecture

CadCraft Fork Map

How CadCraft 0.5 is built today, and what changes in a Rust fork and a C++ fork. Each fork is shown under two designs: the one 0.5 uses (web first, one build everywhere) and the one The Terminator described on Discord (native, Rust, built to match the desktop push/pull modeller many people learned on).

ProjectCadCraft
SheetFork map
Base0.5 dev builds
Date2026-10-15
Colour = language JavaScript Rust C++ PHP C / other, compiled to WASM
8apps, plus CadCraft Studio as the desktop host
328klines of JS in the eight dev/ builds
≈86kof those are byte-identical copies (dwg, ifc, m3d, shapes, skp, render)
18sync scripts that keep the copies in step
69%of app JS is in files that never touch the DOM, canvas or three.js
8klines of Rust in the Studio shell (Tauri 2), the Live server included
18klines of PHP in the site's service layer (67 classes)

Counted with wc -l on 2026-10-15. Compiled help files and language files are left out. "Touches the DOM" means the file mentions document., window., addEventListener, getContext( or THREE., so the 69% is a rough line between logic and UI.

Sheet 1 · as built

CadCraft 0.5, layer by layer

One JavaScript build runs in the browser at /use and /lab, and inside Studio's web view on Windows, macOS, Linux, Android and iPad. Heavy work that we didn't write ourselves comes in as WebAssembly, and most of it is C or C++ already.

Site and services

getcadcraft.com, server rendered

Service layerAccounts, licenses, Stripe, storage, library, downloads
core/classes · 67
Sync and device APICloud saves, device sign-in, connection keys
api/v1/sync/*
Help compilerMarkdown help compiled to each build's help.js
Help.php

Desktop host

CadCraft Studio, the only desktop download from 0.5

Tauri 2 shellWindows, files, account, updates, control channel, mobile
desktop-shell/src-tauri · 8k
Live session serverLAN co-editing, SPAKE2 handshake, ChaCha20 frames
studio_live.rs, live/
Live relayWAN invite links
relay/server.mjs (Node)
Studio hubLauncher page and suite packer
studio/hub

App shell

Shared by every app, switched on per build by its manifest

Frameapp-shell, settings, panels, phone and touch, screen modes
InputMenu styles, custom keys, menus and mouse
host.jsOpen, save and launch, plus the assistant (MCP) control core
RuntimeAutosave, add-on loader, i18n, help panel, offline service worker, live client

Eight apps

Lines per dev/ build

Our engines

Canonical in lib/ or one app, copied into the others

cc-dwgDWG reader and writer, clean room
lib/dwg · 11.7k · 5 copies
cc-ifcIFC engine, STEP, geometry
lib/ifc · 6.3k · 2 copies
m3d kernelPush/pull modeller, ModelCraft canonical
3 copies
cc-skpSketchUp reader, OpenSKP as the map
lib/skp · 2.5k
Shapes, render, entourageSteel sections, standard parts, renderer
lib/shapes · modelcraft/render
LanguagesAutoLISP interpreter, CraftScript VM
cadcraft/lisp · partcraft cs-*

Vendor engines

Pinned under assets/vendor/<lib>/<ver>; dashed = old releases only

ManifoldMesh booleans
manifold-3d 3.5.4 · wasm
laz-perfLAZ point clouds
0.0.7 · wasm
SQLiteGeoPackage
sql.js 1.14.2 · wasm
CPython, Lua, HDF5Script runtimes
cpython-wasi · wasmoon · h5wasm
rvtRevit to IFC, lab only
rvt 0.4.0 · wasm-bindgen
three.js3D, plus the GPU path tracer and BVH
three 0.186.1 · WebGL
pdf.js, pdf-libPDF render and write
pdfjs 6.3.289 (+ C decoders in wasm)
GISproj4, geotiff, delaunator
JS
OpenCascadeLGPL, releases 0.1–0.3
replicad-opencascadejs
web-ifcMPL, older releases and test oracle
LibreDWGGPL, releases ≤ 0.2

Drawing surface

What puts pixels on screen

Canvas 2DCadCraft, MarkupCraft, TakeoffCraft, 2D sheets
WebGL via three.js3D in every app except MarkupCraft
DOMToolbars, panels, dialogs, command line, help

Sheet 2 · patterns

The patterns, and what each one becomes

These are the habits the whole codebase follows. Each card shows how 0.5 does it today in JavaScript, then what it turns into in each fork. Most patterns port as ideas. A few disappear, and a few become real decisions.

Structure

Logic apart from the UI

Every app keeps its model, geometry, file formats and commands in DOM-free modules. Only a few files per app draw or handle events.

JS
About 225k lines of logic, 103k of UI. Node tests run the logic without a browser.
Rust
The logic becomes crates. This is where a port starts, and the parity tests come along with it.
C++
The logic becomes static libraries behind a C or C++ API. Same split, with headers and an ABI to look after.

Sharing

Byte-identical copies

An app's build never imports another app's folder, so shared code is copied in and checked by sync scripts.

JS
About 86k copied lines and 18 sync scripts with --check. Each app test fails on drift.
Rust
Disappears. A single Cargo workspace lets every app depend on cc-dwg, cc-ifc and m3d once.
C++
Disappears too, through one CMake tree of libraries. Pinning moves to vcpkg or Conan.

Editing

One edit, one undo step

doc.change(label, fn), store.change, model.change: every edit, including assistant and LISP edits, is one labelled transaction.

JS
Closures over mutable maps. Ops remember their map, so undo works across spaces.
Rust
Ports well, but as explicit op records, because closures that mutate shared state fight the borrow checker. That shape also suits Live merging.
C++
Ports almost as written, using a command pattern with std::function. The risk is dangling references into containers after an edit.

Commands

Commands that ask questions

The CadCraft engine runs commands as async functions that wait on c.point(), c.distance() and c.select(). LISP's (command …) drives the same path.

JS
async/await on the main thread. Each prompt is a promise the UI resolves.
Rust
An async state machine per command, or a small executor in the UI loop. egui and iced are frame or message driven, so it needs a deliberate bridge.
C++
C++20 coroutines fit this closely. Without them, every command becomes a hand-written state machine.

Safety

Every file is untrusted

DWG, IFC, SKP, PDF, the clipboard, .ccinput.json, add-ons and library items are all validated on read. The browser sandbox is the outer wall.

JS
A bad parse throws or returns garbage, but can't corrupt memory. The sandbox contains the rest.
Rust
Memory safe by default, so parsers can be fuzzed for panics only. A native build loses the browser's outer wall.
C++
The biggest new cost. Binary parsers that take strangers' files need fuzzing, ASan and UBSan in CI, and bounds-checked readers.

Concurrency

Workers for heavy work

DWG reads, IFC scans, LISP, CraftScript, auto count and RVT each run in a module Worker built from the library's own files.

JS
Message passing. Data is copied or transferred, and import graphs must stay a tree for blob linking.
Rust
Real threads with rayon. Natively, shared read-only models need no copies. WASM threads need cross-origin isolation headers.
C++
std::thread or TBB. Emscripten pthreads in the browser need the same isolation headers.

Versions

Versioned builds and pinned vendors

A frozen x.y folder per release, a current symlink, and an import map that pins every vendor URL.

JS
Old releases keep loading their own vendor folders, and a rollback is a symlink swap.
Rust
Cargo.lock plus tagged binaries. The web edition keeps the folder pattern for its .wasm files.
C++
A vcpkg or Conan lockfile plus tagged binaries. Reproducible builds take more work across five platforms.

Shell

Shared shell, switched on by the manifest

Panels, phone layout, touch, input profiles, help panel, offline and settings tabs come free to any build with the right markup.

JS
Found by shape: <main>'s role=toolbar, aside panels, the "phone" key.
Rust
Becomes one app-frame crate over egui or iced. Phone layout and offline save are new work, or are dropped.
C++
Becomes a Qt or Dear ImGui frame. Qt brings docking and accessibility, under an LGPL or commercial license.

Words

Words and help as data

Every string goes through t() keys from lang/*.json. Help is Markdown, compiled per build with trademark checks.

JS
The browser does the text shaping, bidi and IME for free.
Rust
Keeps the same JSON catalogs. Text shaping and IME come from cosmic-text or the toolkit, and are weaker than the browser for non-Latin input.
C++
Keeps the same catalogs. Qt handles shaping and IME well. ImGui needs HarfBuzz added.

Extending

Scripts, add-ons, assistants

AutoLISP, CraftScript, Lua, Python and MCP tools are all sealed: no network and no files. Add-ons are JS loaded at runtime.

JS
Sealed by running in workers, with no capabilities handed in.
Rust
Native add-ons would be arbitrary code. Use WASM plugins (wasmtime) to keep the seal. Lua through mlua, Python through embedded CPython, which is harder to seal.
C++
Same choice. The CAD habit of DLL plugins is the easy path and the unsafe one. Use wasmtime or wasmer for a sealed plugin model.

Proof

Tests with outside oracles

Known answers, plus second readers (ezdxf, LibreDWG, ODA, web-ifc, OpenSKP's TS package) and Playwright runs of each app.

JS
Node unit suites and browser suites per app, with a public fixture corpus.
Rust
Unit tests and oracles carry over, and the corpus becomes the parity gate between the JS and Rust engines. Browser suites only survive in the web design.
C++
Same carry-over, plus a sanitizer build of every suite. Native UI tests need a new harness.

Sheet 3 · designs

Two designs: 0.5 and The Terminator's

The language and the design are separate choices. The 0.5 design is about reach: one build in every browser and every Studio. The Terminator's design is about feel: a native modeller that matches SketchUp, fast on big files.

Original 0.5The Terminator
GoalEight apps for drafting, BIM, models, PDFs, takeoff, civil, steel and parts, under one licenseOne modeller that matches the SketchUp desktop workflow exactly
Where it runsBrowser (/use), Studio on Windows, macOS and Linux, Android, iPadNative desktop
UIDOMCanvas 2DShared shell, menu styles, touch and phone layoutsiced or egui, a native window
3Dthree.js / WebGLgpu path tracer"High performance 3D", which in Rust means wgpu
Enginesown JSManifold wasm Rust→WASM planned for 0.7 (Track RS), benchmark firstRust throughout
.skp filescc-skp reads .skp (2.5k lines of JS, OpenSKP as the map). Doesn't write."OpenSKP being ready to go". It reads and writes, in Python, TS, .NET, Dart and C++. There is no Rust package.
Starting pointThis codebaseA fork of Ingetrazo (we haven't looked at it)
StrengthZero install, one build everywhere, tablets and phones, Live co-editing, eight apps sharing enginesSpeed and feel on big models, one language from kernel to pixels
CostJS speed limit on very large files (the Discord "razor" file). The DOM doesn't feel native.No browser, a full UI rewrite, one app instead of eight. Text input, IME and accessibility are harder.
Sketchup isn't a program that's good because it has crazy features. it's good because it's entirely about a certain workflow
ModelCraft is built on that idea already: push/pull, inference markers, axis locks on the arrow keys, typed lengths, G for a component. Still listed as not built in its map: follow-me, offset, intersect faces, sections, tags.
high performance 3d, in rust
This is the Rust fork under his design. Track RS gets part of the way inside the 0.5 design.
openSKP being ready to go
True for reading and writing, but its C++ package suits the C++ fork, not Rust. A Rust fork ports our cc-skp or binds OpenSKP's C++.
rewrite in rust with iced or egui
That is the top-right cell of the matrix below, and it rewrites the whole UI.

Sheet 4 · the forks

Two languages, two designs

Each fork can keep the 0.5 design (the engines move, the UI stays JS in a web view) or take The Terminator's (everything native). The bars show the language mix of our own code at the end of each fork, by lines. They are rough: vendor libraries aren't counted, copies count once, and a rewritten UI is assumed to be about as long as today's.

Keep the 0.5 design

Engines move, the JS UI stays in the browser and Studio's web view

Take The Terminator's design

Native UI and native 3D, desktop first

Rust

Engines to Rust, compiled twice

Track RS, carried all the way

Keeps
  • All 103k lines of UI, the shell, help, phones, tablets, /use and offline
  • The Tauri shell, which is Rust already and can call the crates natively, so the desktop skips WASM
Rewrites
  • cc-dwg, cc-ifc, m3d, cc-skp, geometry and solver cores as crates, wasm-bindgen for the web
  • Each engine switches only when it is faster and matches on the corpus, as Track RS already requires
New risk
  • JS↔WASM boundary costs when meshes are copied across
  • wasm32's 4 GB memory ceiling in the browser
  • Two call paths (WASM and native) to keep identical

All Rust, iced or egui on wgpu

What The Terminator asked for

Keeps
  • File formats, known answers, the test corpus and the oracles
  • Lang JSON catalogs and help Markdown, as data
Rewrites
  • Everything: UI, shell, three.js scenes, the path tracer and Canvas 2D drawing, which moves to wgpu or vello
  • PDF rendering for MarkupCraft and TakeoffCraft. There's no mature pure-Rust renderer, so in practice it binds PDFium (C++)
New risk
  • The browser goes, unless eframe or iced's web target is good enough
  • Accessibility, IME and right-to-left text are weaker than the DOM
  • Add-ons need a WASM plugin host
C++

Engines to C++ with Emscripten

The way Manifold ships today

Keeps
  • The JS UI, the shell and every web surface
  • Manifold, laz-perf and SQLite become plain native links on the desktop
Rewrites
  • Engines as C++ libraries, with Emscripten builds for the web
  • The Studio shell is Rust, so the libraries need a bridge (the cxx crate) or a new C++ host (Qt WebEngine, CEF or a webview library)
New risk
  • Memory safety in parsers that read untrusted DWG, IFC and SKP files
  • A license pull toward LGPL or GPL CAD libraries (see below)

All C++, Qt or Dear ImGui

The FreeCAD-shaped route

Keeps
  • Formats, corpus, oracles and catalogs, as in the Rust cell
  • OpenSKP's C++ package for reading and writing SketchUp
Rewrites
  • Everything, with Qt or ImGui for the UI and Vulkan, OpenGL or bgfx for drawing. PDFium for PDFs
  • The Rust shell and Live server get replaced, or kept and bridged
New risk
  • The richest CAD ecosystem (OCCT, IfcOpenShell, LibreDWG) is LGPL or GPL, the code 0.4 removed to stay Apache-2.0
  • Build complexity across Windows, macOS, Linux, Android and iPad

Sheet 5 · what comes into view

Changes that show up once you refactor

RustC++

The copies collapse

About 86k copied lines and 18 sync scripts become one library each. That is the clearest win in both languages and both designs, and it removes a whole class of drift bugs.

JS

The UI is the real rewrite

Under the 0.5 design the 103k lines of UI stay. Under The Terminator's they all go. That one choice decides most of the cost, more than the language does.

JSRustC++

The browser is the fork in the road

/use, the lab, phones, tablets, offline save and LAN browser joiners for Live all depend on the web build. Keeping them means compiling the engines to WASM in either language.

pdf.jsPDFium

PDF apps change the most

MarkupCraft and TakeoffCraft are built on pdf.js rendering, text and annotations. A native fork in either language ends up on PDFium, which is C++.

three.jswgpuVulkan/GL

3D drawing gets rebuilt

three.js scenes, edges, sections, the view cube and the GPU path tracer all need replacing under the native designs. Under the 0.5 design they stay.

C++

License pressure lands on C++

Our Apache-2.0 rule (no GPL, LGPL or MPL outside Pyodide's folder) is easy to keep in Rust. C++'s strongest CAD libraries are the ones 0.4 removed.

Rust

The Studio shell already points at Rust

Tauri 2, the Live server and the control channel are 8k lines of Rust today. A Rust fork extends them. A C++ fork has to bridge to them or replace them.

RustC++

Add-ons need a sandbox

Runtime JS add-ons and sealed scripting don't survive the move to native code as they are. WASM plugins (wasmtime) keep the seal in both languages.

JSRustC++

Parity becomes the gate

The fixture corpus, known answers and outside oracles are already in place. Running the same suites against JS and each fork is how a fork proves itself, the rule Track RS set.

PHP

The site doesn't move

Accounts, licenses, cloud sync, the library and downloads are HTTP services. Every fork talks to the same API.

Decision in the way. The project rule today is to never promise a native app: CadCraft runs JS in the web view, and Rust is planned to arrive as WebAssembly under Track RS in 0.7, after the forks are tested. Both Terminator-design cells change that rule, and only the owner can change it.