Kernel extend(body, edges, distance) moves the picked straight edges of a
planar surface outward in its plane, with neighbours meeting them. Doc
feature SurfaceExtend, engine FusionExtendCommand. Tests: 10x10 extended
by 5 past one edge gives 150, past two gives 225; the engine patch, trim,
extend and thicken gives 240.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
Kernel (surfaces):
- Bodies with an open shell are surface bodies (Body::is_surface).
- patch_region: a planar patch of a sketch region. patch_edges: a planar
patch filling a closed loop of a body's edges.
- copy_faces: faces copied out as a surface.
- stitch: sew surfaces along coinciding edges, turning faces to agree; the
result is a solid when it closes.
- trim: cut a surface by a plane or face and keep one side.
- thicken: offset planar and circular-cylindrical faces along their
normals (one side or symmetric) into a solid. Plane copies slide;
cylinder copies scale about the axis, exact for NURBS circles. Free
edges get ruled walls. Faces meeting at a sharp edge are refused.
Doc features Patch, Stitch, Thicken (with operations) and SurfaceTrim;
engine commands FusionSurfacePatchCommand, FusionSurfaceStitchCommand,
FusionSurfaceThickenCommand and FusionSurfaceTrimCommand.
Tests (volumes):
- A 10x10 patch thickened by 2 gives 200, also symmetric.
- Half a cylinder side thickened outward gives half a ring; both halves
inward give the full ring.
- Six faces of a box stitched back give 6000; an open box with its top
patched from the edges, stitched, gives 6000.
- Trim keeps 30 or 70 of 100.
- Engine: patch, trim, thicken gives 140.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
The Split feature takes an optional face tool (FaceAt, the face through a
point on a named body) and splits with kernel split_body, the tool's
surface extended; otherwise the plane as before. Engine test: a box split
by a cylinder's side into the core and the rest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
What a component holds moves with its occurrence, and picks in the world land in the
component's frame:
- Sketches and construction planes show where their component is placed (free move, joint
drive, Capture Position); sketch.inspect reports sketch points in the world.
- frames.rs maps a command's world picks into the frame of the body they lie on (through the
inverse of its placement: a moved component or a pasted instance), points that make new
geometry into the active component's frame, and directions with them; instance body names
("Body1 (Pin:2)") become the component's body. Fillet/chamfer edges, shell/offset/draft
faces, face extrude/revolve, sketch on face, holes, sheet metal and plastic picks, primitives,
appearance faces, analyses. Once per command (not again for commands run by commands); the
active-frame fallback stays for commands without a table. Nothing changes while every
placement is the identity.
- component.move_bodies keeps a body where it is in the world (Document.body_offsets: from the
new component's frame to the one it was made in; renames and deleted components follow).
- The UI reads the placed model (Session::world_state) for display, picking, sketch editing and
dialogs; live previews use it once anything is placed.
Tests (engine): sketches and construction planes move (and turn) with the component; world
picks fillet, sketch, hole and make boxes in a moved component; a pick on a pasted instance;
move_bodies keeps the world place there and back; a sketch on a face follows a Move feature.
QA's s34 now runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
- Bodies carry a Paint for export (opacity, per-face colours), set by
Document::painted from the appearance model. The paint comes from a
face appearance, a body/component appearance's opacity or a material
look (Glass), and falls back to the paint the body was imported with.
- STEP: faces with colours of their own get a STYLED_ITEM on their
ADVANCED_FACE. See-through looks add SURFACE_STYLE_TRANSPARENT.
Differently coloured pieces are not merged into one face.
- STEP import reads face styles and transparency. The reader tracks the
file face of each kernel face (bands split in two keep it), so imported
face colours land on the right faces; the design shows them through
face_colors.
- 3MF: per-triangle colours (pid/p1 into the base materials, carried
through welding) and the object's alpha (#RRGGBBAA).
- Tests: a blue half-transparent cube with a red top exports, re-imports
with its opacity and the red top face, and keeps it when opened and
exported again. 3MF writes the alpha and the face entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
- Bodies export (STEP, 3MF) in the colour they are shown in: an appearance,
else the physical material's look, else the colour the body was imported
with (Document::body_color / painted). Physical materials used to export
no colour at all.
- AppearanceCommand (Modify): a colour per body ("#rrggbb" or [r, g, b];
null follows the material again), kept in the design and across renames.
- Material looks move to solvecraft-doc (material_color); the viewport draws
appearance, material or imported colour, as exported.
- Engine test: brass and red ABS bodies export, re-import with their RGB, and
keep it through open and export again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
Export: ExportCommand/CLI --out/MCP export with .3mf write a 3MF Core package
([Content_Types].xml, _rels/.rels, 3D/3dmodel.model; millimetres), one
mesh object and build item per body, named after it, vertices shared and
welded watertight (T-junctions between faces split), base-material colours
when bodies carry one (STEP colours now ride on bodies). Tessellation as
for STL. File > Export 3MF.
Import: doc.open/drag-drop/CLI/MCP open accept .3mf and .stl; Insert Mesh
(ParaMeshInsertAlignCommand) adds them to a design as a MeshImport feature.
Kernel mesh bodies render, measure exactly, move and export; solid
features refuse them with a clear error. 3MF reading flattens components
and build transforms, converts units, reads colours; sizes, entries,
nesting and element counts are capped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
Import base feature (FeatureKind::Import, timeline type BaseFeature) holding
the STEP text and the file's product tree; bodies named from the file.
doc.open accepts .step/.stp (any case) as a new design; Insert STEP
(FusionImportCommandFromToolbar) adds one to the current design; File menu,
SOLID > INSERT, drag-and-drop (insert into a non-empty design, else open),
'solvecraft part.step', MCP open. Features (fillet, hole, sketch-on-face
cut, shell) work on imported bodies. Imports are cached so a file is read
once per command. Measure tightens its chord tolerance for small radii.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
The kernel moved from monstertruck to truck: truck's booleans handle blind
holes, pockets and bosses that monstertruck's did not (see the ADR). Fillets
and chamfers on straight convex edges between planar faces are our own exact
local B-rep operation. The document holds parameters with unit-aware
expressions and a timeline that re-evaluates incrementally.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>