Open source version of fusion 360
  • C++ 99%
  • CMake 0.8%
  • Shell 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
James 52c87b8cf2 feat(construct): offset, angled and mid datum planes, and sketches placed on them
The CONSTRUCT panel's first three commands are live: Offset Plane, Plane at
Angle and Midplane. Built so a loft can be tried on something other than the
three origin planes.

DatumPlaneFeature (datum_plane) resolves to a SketchPlane and builds to no
shape. Offset moves the base along its normal by a distance; angle turns it
about a world axis through its origin or about a straight edge of the base's
body; midplane sits halfway between two parallel faces of one body or two
datums. The base is an origin plane, a planar face, or another datum, and
each fails with ErrorCode::Unresolved rather than a guess when what it
references is gone. An axis perpendicular to the plane, non-parallel faces
for a midplane, and a curved edge as an axis are refused with the reason.

Enum-like settings now live on Feature as named text options with a declared
value list, serialised generically under "options", cloned with the rest of
the state, and refused on load when out of range. showsInput() lets a feature
hide inputs and options that do not apply to how it is configured, so an
offset plane's dialog offers a distance and nothing else.

BuildContext::planeOf and Feature::datumPlane() are how a sketch on a datum
finds its plane (SketchFeature::PlaneKind::Datum, serialised as "datum");
Feature::isConstruction() keeps datums out of Document::isBody, the body
list, the scene and the boolean host search. The face-plane resolution a
face-mounted sketch used is now planeOfReferencedFace, shared with datums.
kernel::edgeEndpoints gives a plane at an angle its hinge.

The sketch plane picker doubles as the datum base picker: it draws the origin
planes (when there are no bodies, or the browser shows them) and every built
datum as targets, and answers whichever asked -- Create Sketch or the dialog's
From field. Datums draw as translucent labelled quads sized to the model, the
dialog's draft in the accent colour, and the browser's Construction node
lists them with an eye, a Create Sketch item and the usual context menu. The
dialog gains SelectionKind::Plane, options drawn as dropdowns, and OK keyed
off the build succeeding rather than a preview shape existing, since
construction has none.

Not built: Tangent Plane, the two-edge and three-point planes, and the axis
and point constructors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Jaxmn8nH523Vpz4S9iadP
2026-09-13 12:34:57 -04:00
core feat(construct): offset, angled and mid datum planes, and sketches placed on them 2026-09-13 12:34:57 -04:00
docs feat(construct): offset, angled and mid datum planes, and sketches placed on them 2026-09-13 12:34:57 -04:00
packaging build: add CMake project, presets and vendored Dear ImGui 2026-08-29 22:59:22 -04:00
scripts fix(scripts): format untracked files too 2026-08-30 00:19:26 -04:00
tests feat(construct): offset, angled and mid datum planes, and sketches placed on them 2026-09-13 12:34:57 -04:00
third_party feat(ui): wire M2-M5 into the application, and fix a leak on every solve 2026-08-30 01:29:41 -04:00
ui feat(construct): offset, angled and mid datum planes, and sketches placed on them 2026-09-13 12:34:57 -04:00
.clang-format chore: add licence, formatting and editor configuration 2026-08-29 22:59:22 -04:00
.editorconfig chore: add licence, formatting and editor configuration 2026-08-29 22:59:22 -04:00
.gitignore fix(ui): stop drawing a sketch's profile face as a body 2026-08-30 18:23:32 -04:00
.gitmodules feat(core): add the sketch model and the SolveSpace constraint solver 2026-08-30 00:46:14 -04:00
ANVIL_PROFILE_LEAK_BUG.md feat(ui): face the sketch plane on selection, and default the grid off 2026-08-30 18:30:57 -04:00
CLAUDE.md feat(loft): skin a solid through profiles on two or more sketches 2026-09-13 12:10:54 -04:00
CMakeLists.txt feat(loft): skin a solid through profiles on two or more sketches 2026-09-13 12:10:54 -04:00
CMakePresets.json build: add CMake project, presets and vendored Dear ImGui 2026-08-29 22:59:22 -04:00
imgui.ini feat(extrude): add the two-sided direction and the to-object extent 2026-08-31 23:02:15 -04:00
LICENSE chore: add licence, formatting and editor configuration 2026-08-29 22:59:22 -04:00
PLAN.md docs: add project brief and M0 pre-flight plan 2026-08-29 22:59:22 -04:00
PROGRESS.md feat(construct): offset, angled and mid datum planes, and sketches placed on them 2026-09-13 12:34:57 -04:00
README.md fix(ui): make the keyboard a view onto the command registry 2026-08-30 10:47:12 -04:00

Anvil

A lightweight parametric CAD application for Linux, built for 3D printing.

Anvil is a native parametric solid modeller aimed at people who design parts for their own printer: brackets, enclosures, adapters, jigs, replacement parts. The reference experience is Fusion 360's sketch → extrude → modify workflow, without the cloud, the licensing or the bloat.

It is not a mesh editor, a slicer, or a general-purpose FreeCAD clone.

Status: M0–M5, plus the interface described in CLAUDE.md §10. Constraint-solved sketches drawn in the viewport with inferred constraints, extrude and revolve, fillet, chamfer, shell, patterns and mirror, a persistent topological naming scheme that survives parametric edits, and import/export for 3MF, STEP and STL.

Of the 159 commands the toolbar lists, 63 do something; the rest are greyed with a tooltip saying where they stand. The largest gaps are construction geometry (datum planes, axes, points), the hole feature, and the sketch modify tools — trim, extend and offset. PROGRESS.md lists exactly what is and is not built.

Building

Arch Linux (or CachyOS):

sudo pacman -S --needed cmake ninja gcc git clang doctest \
                        opencascade eigen nlohmann-json minizip-ng pugixml zlib
git clone --recurse-submodules <url> anvil && cd anvil

cmake --preset release
cmake --build --preset release
ctest --preset release

./build/release/bin/anvil

If you cloned without --recurse-submodules:

git submodule update --init --recursive

Presets

Preset Purpose
debug-asan Debug with ASan + UBSan. What you develop against.
debug Debug without sanitizers, for when you need the speed.
relwithdebinfo Optimised with symbols, for profiling.
release Optimised. The configuration the performance budgets are measured against.

scripts/ci.sh runs the full gate: formatting check, then debug-asan and release both built with -Werror and both running the test suite.

Usage

  anvil [options] [FILE.anvil]

  FILE.anvil           Open a document on startup.
  --inspect FILE       Dump a document's JSON to stdout and exit.
  --startup-timing     Print milliseconds from launch to the first drawn frame.
  --log-level LEVEL    trace, debug, info, warn, error or off.
  --width / --height   Initial window size.
  --no-vsync           Disable vertical sync.
  --gl-debug           Request a debug context and log driver diagnostics.

--inspect reads one entry straight out of the container without building the document, so it still works on a file this build cannot fully open:

anvil --inspect bracket.anvil | jq .parameters

Modelling

The parametric workflow:

  1. Create → Create Sketch (on XY, or on a selected planar face)
  2. Draw with L, R, C, A. The tool stays armed for the next shape; Esc puts it down. Constraints are inferred as you go — the glyph at the cursor is what you will get — and typing a number while dragging locks it as a driving dimension. The sketch palette counts the remaining degrees of freedom.
  3. Finish Sketch, then Create → Extrude (E)
  4. Switch to edge selection (R), click edges, Modify → Fillet (F)
  5. Change a parameter — everything downstream rebuilds, and the fillet stays on its edge

Every 3D feature opens a dialog at the right of the viewport with a live preview. Fields take expressions, so wall_thickness * 2 + 0.4 is a valid size; define named parameters in the Parameters panel and reference them from any field. Dragging the arrow in the viewport edits the same value. Enter commits, Esc cancels, and nothing reaches the document until you accept.

Selecting first pre-fills the dialog; running a command with nothing selected opens it waiting for a pick. Shift-click adds to a selection. Resting the cursor over crowded geometry offers a list of what is under it.

Right-click opens a marking menu — flick in a direction and release to fire that wedge without the menu ever drawing. S opens a fuzzy command search where any command can be pinned.

Everything goes through the undo stack — Ctrl+Z and Ctrl+Shift+Z, unlimited.

Shortcut
Ctrl+O / Ctrl+S Open / Save
Ctrl+Z / Ctrl+Shift+Z Undo / Redo
Ctrl+Q Quit
S Command search
Esc Back out one level
Del Delete the selected feature
E / F / Q Extrude / Fillet / Press Pull
B / G / R Select bodies / faces / edges
L / R / C / A In a sketch: line / rectangle / circle / arc
D In a sketch: dimension

Command keys come from the toolbar layout, so the key a tooltip shows is the key that fires. R is the edge filter outside a sketch and the rectangle tool inside one.

Viewport navigation

Matching Fusion 360's defaults, and rebindable under Preferences → Navigation if you prefer middle-drag to orbit.

Input Action
Middle drag Pan
Shift + middle drag Orbit
Scroll Zoom toward the cursor
H Home view
1–6 Front, back, left, right, top, bottom
F6 Fit to the build volume
O Toggle orthographic / perspective

Layout

core/
  base/       math, Result, logging, ids
  document/   expressions, parameters, features, commands, undo
  sketch/     2D entities, constraints, ISketchSolver
  features/   sketch, extrude, revolve, fillet, chamfer, shell, patterns
  kernel/     the ONLY place OpenCASCADE headers are included
  io/         .anvil container, JSON, STL, 3MF, STEP, PNG
ui/
  app/        window, main loop, session, navigation
  commands/   the command registry and the toolbar layout, which is data
  render/     GL loader, camera, grid, build plate, mesh and picking
  panels/     theme, docked panels, dialogs, sketch view, file dialog
tests/        doctest suites. anvil_core_tests links core alone, which keeps it headless;
              anvil_ui_tests drives panels through real ImGui frames with no window.
docs/         file format and the topological naming scheme.

core/ is testable without a GPU or a window, and OpenCASCADE types never escape core/kernel/ — the core test target compiles without OCCT's include path at all, which is what proves it. Both rules exist so the geometry kernel stays replaceable (CLAUDE.md §4).

The sketch solver sits behind ISketchSolver for the same reason. It is SolveSpace's, vendored under third_party/solvespace — see PROGRESS.md for why, and what that cost.

How a fillet survives a parametric edit

Change an extrude's height and OpenCASCADE renumbers the faces. A fillet storing "edge 7" would silently round a different corner. Anvil names a face after what produced it — an extrude's wall is seeded by the sketch entity that generated it, and sketch ids do not move when numbers do — and names an edge by the two faces meeting along it.

When a reference genuinely cannot be found, the feature errors rather than guessing. docs/topological-naming.md explains the whole scheme.

File format

.anvil is a ZIP with every entry stored uncompressed, so a saved model is greppable and diffable:

document.json    parameters, feature tree
metadata.json    app version, format version, timestamps
grep -a wall_thickness bracket.anvil    # works, by design

Licence

GPL-3.0-or-later. See LICENSE.