Skip to content

Repository files navigation

SindriCAD

Parametric CAD for 3D printing. Runs on Linux, Windows and macOS.

Download the beta Linux, Windows, macOS AGPL-3.0

SindriCAD is a history-based solid modeler. You sketch, extrude, fillet, and pattern your way to a part, and every step stays editable in a feature tree. It is not a mesh editor, and it is not a geometry kernel of its own. It drives build123d on top of OpenCASCADE for the actual geometry, and puts a real modeling UI and a print workflow on top.

It began on Linux, where good parametric CAD has always been thin on the ground, and it runs natively on all three desktops now: Linux, Windows and macOS. It is built for 3D printing: color a multi-material model, export it as a ready-to-slice OrcaSlicer project set up for the Snapmaker U1, and send the sliced G-code to the printer over the LAN.

Named for Sindri, the dwarven smith of Norse myth.

A two-color part in SindriCAD: feature tree and palette on the left, a chamfered body with a knurled face in the viewport

Status: beta, in ongoing development. SindriCAD already builds real printed parts, but the feature set is still filling out and rough edges remain. Expect frequent releases, report what breaks, and keep backups of documents you care about.

Get it · What it does · Sketching · Textures · Measure · Import · Print pipeline · Document format
Install · Build and run · Architecture · Project layout · License · Support · Changelog

Get it

Installers for Linux, Windows and macOS are on the latest beta release, rebuilt automatically from every green main build. Free, no account needed, and everything is bundled including Python and the geometry engine. The builds are unsigned, so each platform asks you to confirm the first launch once: see Install for the exact steps, and note that macOS is the awkward one.

If SindriCAD looks useful, starring the repo helps other people find it.

What changed in each build is in CHANGELOG.md, and the same notes appear on the release itself.

What it does

  • Sketching with lines, arcs, circles, splines, rectangles, slots, polygons, and text in system fonts, plus associative patterns (bolt circles, grids, honeycomb) and a PlaneGCS constraint solver. Dimensions are entered on the canvas: type a value, press Tab to lock it, Enter to commit.
  • Parameters and expressions: name a value once, use it anywhere a number goes, and write arithmetic between parameters. Change one number and the whole part follows.
  • Features: Extrude (new body, join, cut, intersect, per region), Revolve, Loft, Sweep, Press/Pull (multi-face, and extrude up to a target surface), Fillet, Chamfer, Shell, Draft, Scale, Mirror, and patterns.
  • Offset Face and Thicken: push selected faces along their own normals with the surrounding walls following, or give surface geometry a wall. Thicken is what turns a non-watertight mesh import, which arrives as read-only reference geometry, into a solid you can actually model with.
  • Surface textures (see below).
  • Direct editing: Move with a live ghost preview, Split, Combine, Delete Face with automatic healing, and a cleanup pass for messy imported geometry.
  • Import STEP, BREP, STL, 3MF, OBJ, and GLB, with facet cleanup and STEP canonicalization, so imported parts come back as editable faces instead of a triangle soup. Export STEP, STL, 3MF, and GLB.
  • References that survive edits: geometry is picked by queryable descriptors (an axis, a face normal, the nearest point), never by a topology index. Change an upstream parameter and a downstream fillet still lands on the right edge.
  • Measure and section tools for checking a part before it prints.
  • A print pipeline for the Snapmaker U1 (see below).

Press ? in the app for the full keyboard shortcut list.

A part built up feature by feature: sketch, extrude, fillet, two cuts, then a surface texture
A part is its history: sketch, extrude, fillet, cut, texture, and every step stays editable.

Sketching

The SindriCAD sketcher: a dimensioned rectangle and two constrained circles, with the entity toolbar and sketch palette

Sketches are constraint-driven. Dimensions are entered on the canvas: type a value, Tab to lock it, Enter to commit. A PlaneGCS solver keeps the rest of the profile consistent as you edit. Equal, parallel, perpendicular, concentric and the usual family of constraints render as glyphs you can click, and a reference dimension measures without driving. Conflicting and over-defined constraints are called out rather than silently ignored.

Surface textures

Four cylinders with knurl, hexagon, rib, and Voronoi textures side by side

Textures turn a plain face into a tactile printed surface: knurling for grip, hexagon, rib or wave relief for looks, Voronoi and noise for organic breakup, or any grayscale image as a height map. Pick faces (or a whole body), set depth, scale, and angle, and the pattern is applied as real displaced geometry, not a shader trick: what you see is what the slicer gets.

The faceted patterns are built as exact lattices. Mesh vertices land on the pattern's own crease lines, so a knurl prints as crisp diamonds and a hexagon pattern as flat-topped cells with sharp walls, instead of the rounded mush a sampled height field gives. Patterns wrap around cylinders and cones: ribs and waves close on themselves at any angle, and the 2D lattices (knurl, hexagon) close at multiples of 90 degrees, which is geometry rather than a limitation to fix. Textures can also cut inward instead of embossing outward, and a two-tone mode prints the textured faces in a different palette color than the rest of the body.

Orbiting a cylinder wrapped in a hexagon relief texture
Patterns wrap a full turn and meet themselves at the seam.

Inspect and measure

A section plane cutting a shelled box, revealing the interior walls

A section plane cuts the model live, so a shelled or hollow part can be checked from the inside before it prints. Drag the arrow along the axis, or type an exact offset.

Measuring between two edges of a plate: the readout shows distance, axis deltas, centre distance and angle

Measure reports the true shortest distance between two faces or edges, not just their centres, along with the per-axis deltas, the centre-to-centre distance, and the angle between them.

Import and round-trip

A STEP file imported back into SindriCAD, with its top face and four bores selected

STEP, BREP, STL, 3MF, OBJ, and GLB come in; STEP, STL, 3MF, and GLB go out. A STEP import arrives as real B-rep geometry. The faces above are ordinary selections on a body that was exported to STEP and read straight back in, so imported parts can be measured, sectioned, textured, and used as sketch planes instead of arriving as a triangle soup. Mesh formats are cleaned up on the way in, and STEP is canonicalized so its faces come back in a form the selectors can address.

Snapmaker U1 print pipeline

SindriCAD carries print prep for the Snapmaker U1 multi-material printer from model to machine, so a colored parametric part reaches a print without a manual export dance.

A white nameplate with red extruded sketch text reading SINDRI
Sketch text, extruded and mapped to its own filament slot.

  • Multi-material and multi-color 3MF: assign palette colors to bodies and export an OrcaSlicer project 3MF with per-object extruder (tool) mapping for the U1's tool changer (sidecar/project3mf.py).
  • Slicer handoff: "Open in OrcaSlicer" binds the U1 preset with your tuned process and filament, so you land ready to slice.
  • Direct device layer: a Rust Moonraker client (src-tauri/src/printer.rs) uploads G-code to the printer over the LAN with a filament-mapping dialog, reads the palette back from the printer, and monitors the running print.

U1 support will keep growing: I add features as I come up with them and have time for them.

Document format

A .sindri file is JSON: a parameter table and an ordered list of features.

{
  "parameters": { "width": 40, "height": 20, "thickness": 5 },
  "features": [
    { "id": "f1", "type": "sketch", "plane": "XY",
      "entities": [{ "type": "rectangle", "width": "width", "height": "height" }] },
    { "id": "f2", "type": "extrude", "sketch": "f1", "distance": "thickness", "operation": "new" },
    { "id": "f3", "type": "fillet", "edges": { "kind": "edge", "by": "axis", "axis": "Z" }, "radius": 2 }
  ]
}

Any numeric field is either a literal (5) or the name of a parameter ("width").

Changing width and boss radius parameters while the part rebuilds live
Change a parameter, the whole part follows, and the corner fillets stay on their edges.

Install

Everything is bundled, including Python and the geometry engine, so there is nothing else to install. The builds are unsigned for now, so each platform asks you to confirm the first launch once. Open the section for your platform:

Windows (.exe or .msi, self-updating)
  1. Download SindriCAD_<version>_x64-setup.exe (or the .msi) from the latest beta.
  2. The build is unsigned, so SmartScreen will warn "Windows protected your PC". Click "More info", then "Run anyway".

SindriCAD needs Microsoft Edge WebView2, which Windows 10 and 11 already ship; the setup exe fetches it automatically if it is missing. Once installed, SindriCAD updates itself: it checks the beta release at startup and offers a one-click restart-and-update.

Linux (.AppImage, .deb or .rpm)

Grab the .AppImage (chmod +x, runs on any distro, updates itself in place), or the .deb / .rpm (sudo dpkg -i / sudo rpm -i; updates come from your package manager workflow, not in-app).

macOS (.dmg, needs a right-click to open)

The .dmg is unsigned: right-click the app, choose Open, then confirm. Apple code signing is planned.

3Dconnexion SpaceMouse (optional, one udev rule on Linux)

SindriCAD reads a SpaceMouse natively for 6DOF camera navigation, with the two buttons mapped to Fit and Home/ISO. Plug it in: no driver or configuration needed. Sensitivity and axis inversion live in Settings.

On Linux the device node (/dev/hidrawN) is root-only until a udev rule grants the logged-in user access. The .deb and .rpm packages install that rule for you and reload udev, so a packaged install just works.

The AppImage cannot install system files, so it needs the rule once, by hand:

sudo curl -fsSL https://raw.githubusercontent.com/MakerViking/sindricad/main/packaging/99-spacemouse.rules -o /usr/lib/udev/rules.d/99-sindricad-spacemouse.rules
sudo udevadm control --reload && sudo udevadm trigger --subsystem-match=hidraw

Building from a clone? Run sudo sh packaging/setup-spacemouse.sh instead. It installs the same rule and applies it to an already-connected device.

If SindriCAD can see the device but can't open it, it says so in a notification rather than failing silently. Two usual causes: the rule above is missing, or spacenavd / the official 3Dconnexion driver is already holding the device. Stop that service to let SindriCAD read it directly.

Build and run

Prerequisites: Node, a Rust toolchain, Python 3.12, uv, and WebKitGTK. See docs/PACKAGING.md for per-OS package names and known-good versions. A system OpenCASCADE install is not needed for the default build: the geometry sidecar ships its own OCCT inside its Python wheels. OCCT is only needed for the opt-in rust-geom Cargo feature (see docs/PACKAGING.md).

# 1. geometry sidecar (Python 3.12 via uv, locked versions from uv.lock)
cd sidecar
uv sync
uv run python test_smoke.py    # backend sanity (rebuild/export/error naming)
uv run python test_ws.py       # WebSocket transport sanity

# 2. the app, from the repo root. Tauri starts Vite and the sidecar for you.
npm install
npm run tauri dev

For frontend-only iteration you can run the two halves separately:

cd sidecar && uv run python server.py     # ws://127.0.0.1:8765
npm run dev                               # http://localhost:5173

Note: on Linux a standalone python server.py arms PR_SET_PDEATHSIG and dies with the shell that started it. To keep one alive across shells (or on other platforms), run it in a terminal you keep open, and kill it by hand when done or it will hold port 8765.

Architecture

┌─ Tauri shell (Rust) ──────────────────────────────────────┐
│  • native window, file dialogs                             │
│  • spawns and supervises the Python geometry sidecar       │
│  • kills the sidecar on app exit (process-group + PDEATHSIG)│
│                                                            │
│  ┌─ Frontend (TypeScript, in the webview) ──────────────┐  │
│  │  • Three.js viewport (orbit/pan/zoom, ViewCube,      │  │
│  │    picking, Z-up)                                    │  │
│  │  • UI: browser tree, timeline, parameters, toolbar   │  │
│  │  • owns the DOCUMENT (feature tree + parameters)     │  │
│  └──────────────────┬───────────────────────────────────┘  │
└─────────────────────┼──────────────────────────────────────┘
                      │  JSON over localhost WebSocket (ws://127.0.0.1:8765)
                      ▼
┌─ Geometry sidecar (Python + build123d + OCCT) ────────────┐
│  • rebuild(document) -> mesh + per-triangle faceIds + edges │
│  • export(document, format, path) -> STEP / STL / 3MF       │
│  • selector resolution (topological-naming mitigation)     │
└────────────────────────────────────────────────────────────┘

Design decisions worth knowing up front:

  • Geometry lives only in Python on the shipping path. Rust never touches it there. There is an experimental opt-in Rust geometry path on OpenCASCADE, gated behind VITE_GEOM=rust, but a 2026 feasibility study found a Rust kernel could not beat OCCT on robustness or speed, so the Python build123d sidecar stays the default and the source of truth.
  • Full rebuild on every change. The frontend sends the whole document, the sidecar rebuilds from scratch and returns a fresh mesh. There is no server-side state.
  • The parametric engine is the build123d tree, re-run. Nothing more exotic.
  • Selectors, not indices. Geometry is referenced by queryable descriptors so references survive edits that renumber the underlying topology.

See docs/ARCHITECTURE.md for the full invariant list and the rebuild pipeline, and docs/PROTOCOL.md for the sidecar's wire protocol.

Project layout

sidecar/      build123d geometry service (builder, geom_select, tessellate, exporters, server)
src/          frontend: viewport/, ui/, document/, geometry/, input/, io/, print/
src-tauri/    Rust shell: lib.rs (entry), sidecar.rs (lifecycle), printer.rs (U1 device layer)

License

SindriCAD is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only), see LICENSE. AGPL's network copyleft means any fork, or any modified version offered over a network, has to publish its source under the same terms.

Contributions are welcome under CONTRIBUTING.md, which includes a short contributor agreement so the project can stay open under the AGPL while the maintainer can also offer commercial terms to those who need them. Third-party components and their licenses are listed in NOTICE.md.

Support

SindriCAD is free and open source. If it earns a place in your workflow, you can back development on Patreon (MuninWorks). Patronage covers the servers, domains, and tooling behind this and my other projects.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages