Commit Graph
139 Commits
Author SHA1 Message Date
jyvikoandClaude Opus 5.5 5189554a6a model: suppress datums and partitions: kept, but left out of the model (#291)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 10:17:28 -04:00
jyvikoandClaude Opus 5.5 a0ae8b2111 model: rename a definition and every reference to it (model.rename, #290)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 10:17:28 -04:00
jyvikoandClaude Opus 5.5 1f36693c8f ui: one symbol-unit helper for the window, ui.render and headless renders (#285)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 10:17:28 -04:00
jyvikoandClaude Opus 5.5 750f5f5a61 model: geometry names up to 64 KiB everywhere, so long persistent face names mesh
Persistent names grow with a design's split history; opening accepted them but mesh tags, sets
and loads capped geometry names at 256 characters. One cap (64 KiB, against hostile input)
now holds for geometry references, partitions and saved views.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 10:09:04 -04:00
jyvikoandClaude Opus 5.5 91e8467e4f engine, render: hidden bodies hide their mesh and results; solve totals without round-off
- DisplayMesh::from_model_hiding leaves out a hidden body's elements (and the
  nodes only they use); Session::hidden_elements names them, so the viewport,
  probing and headless pictures skip hidden bodies (#365).
- A solve summary's applied and reaction totals set the round-off of
  cancelling sums to 0 (#319).
- results::principal for the probe's principal stresses (#329).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:36:54 -04:00
jyvikoandClaude Opus 5.5 0966dfa2a6 engine: result units, per-step staleness, step symbols, true-scale nonlinear results
- Quantity names the unit of every number the results show from the model's
  unit system (mm, MPa, N, N·mm, mJ, mW, °C or K); Field::title puts it in the
  legend title, and calls a mode shape normalised (#321).
- A solved step's result stays current through edits that leave what it reads
  alone (Model::step_inputs: other steps and what only they use), and comes
  back current on undo (#318).
- Session::step_glyphs: the symbols of what a solved step used, for drawing
  over its results; no load arrows on a frequency step's modes (#327).
- Nonlinear static steps open deformed at true scale like explicit ones, and
  their automatic scale is 1 (auto_scale, shared by the viewport and the
  headless pictures) (#326).
- results.reactions with an empty sets list sums the step's boundary-condition
  sets, as its form says (#328).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:36:54 -04:00
jyvikoandClaude Opus 5.5 1372094f8a engine: pick-driven points, cells' methods per cell, rigid walls as interactions
- geometry.bodies lists each body's vertices; geometry.datum.point by
  vertex takes the design's vertex names (labelled Vertex, not Mesh
  vertex) (#346).
- geometry.centre: the point for what is picked: a vertex, nodes, a
  hole's centre (cylindrical faces or circular edges), else a centroid
  (#351).
- mesh.cells' form: the cells first, and a method drop-down per cell
  (schema kind RefChoices) instead of JSON (#344).
- interaction.rigid_wall(.delete): rigid walls of an explicit step from
  the Interactions tab, no longer coming soon (#350).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:27:39 -04:00
jyvikoandClaude Opus 5.5 25dfbcce42 geometry: number the pieces of a split body by position (#349)
SolidCraft names the pieces of a split body by stacking suffixes
(Bracket (1) (1)' (1)). On opening a design, the pieces of one body are
named <body>.1 … <body>.N, ordered by centroid, so the tree, tooltips,
forms and picks read as one part with numbered cells.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:27:39 -04:00
jyvikoandClaude Opus 5.5 358ed2f54f geometry: a feature that fails to rebuild names the bodies it changes, and opening warns
The design file stores no measure to compare with, so the rebuild's own
failures are the guard: each failed feature lists the bodies it names (all of
them when it names none), and geometry.open replies with a warning per failure,
which the window shows with the open.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:23:40 -04:00
jyvikoandClaude Opus 5.5 4ee855bb27 ui: jobs with progress, refusals listed, datum preview, form filters and defaults
- A solve or a mesher runs as a job with one progress mechanism: the overlay
  shows the step, stage, count and elapsed time with a bar when bounded, OK
  waits while it runs, and the status sums it up (elements, smallest angle,
  time) (#322, #357).
- Over the control channel such a command is a job too: answered when it
  ends however long it runs, or at once with wait: false, then job.status,
  job.wait, job.cancel; ui.inspect gives job; MCP waits for it (#367).
- A command that cannot run yet lists what it misses in the context panel,
  each with a button to the command that provides it (#323).
- A cancelled or refused solve stays in its workspace (#324, test).
- A mesher form starts from the parameters of the mesh it would replace (#343).
- Seed Edges and edge/vertex/face datum points switch the selection filter
  while open and restore it (#341).
- Datum forms draw the datum live, the Partition form shows its datum, and
  new datums and partitions get the next free name (#347).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:14:34 -04:00
jyvikoandClaude Opus 5.5 3eaca26246 engine: a mesh made before its seeds changed is out of date; a remesh names a type change
The setup checklist marks the mesh Outdated (a warm ⚠ in the browser, with
what changed and where to remesh) when seeds, partitions or datum planes
changed after the last mesher ran, and model.check warns (#342). Replacing
a mesh asks with the element type change it makes, such as tet10 → tet4 (#343).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:14:34 -04:00
jyvikoandClaude Opus 5.5 464a4d50c1 solver: heat flow through each heat load, and the imbalance (#362)
solve.heat's reply and the results report give heat_flows: each convection,
flux and source load's heat into the body, the prescribed temperatures'
total and their sum; the results panel lists them for a heat step.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:14:34 -04:00
jyvikoandClaude Opus 5.5 0e0d8bd114 model: progress of long commands, reported by the solvers and the tet mesher
fieldcraft_model::progress: a host installs a Progress on the worker thread
and reads its snapshot from another; the engine names the step being solved,
the nonlinear solver its load factor, the explicit solver its time, the
fluid solver its steps, transient heat its increments and the tet mesher its
stage and pass. Without one installed every report is a no-op (#322, #357).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:14:34 -04:00
jyvikoandClaude Opus 5.5 c2ad804fed ui: Mesh Block under Structured Hex, Mirror Mesh its own Edit entry (#348)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:14:34 -04:00
jyvikoandClaude Opus 5.5 7dd4043afe engine: refuse unknown command parameters, suggest a valid name, document heat loads and thermal materials
Every command with a schema now refuses a top-level key it does not take,
naming the key and the accepted ones (#316). A bad definition name's error
suggests the nearest valid one (#320). The load and material params docs list
the heat loads and the thermal block.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 09:14:34 -04:00
jyvikoandClaude Opus 5.5 b65f1696b2 ui: name a sample's document after it until saved (#334); "Solve cancelled"
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 08:55:25 -04:00
jyvikoandClaude Opus 5.5 8819ff787c engine: a prescribed displacement or temperature satisfies the loads stage (#356)
The setup checklist asked for a load on rubber-seal, driven only by a
prescribed displacement, while model.check called it ready.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 08:55:25 -04:00
jyvikoandClaude Opus 5.5 491b3f6212 engine: the heated-bracket guard checks its element count, not wall time
The 60 s limit failed on the Linux CI heavy job (106 s in the test profile) while the
mesh was within its band; the count is what #303's blow-up changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 02:37:31 -04:00
jyvikoandClaude Opus 5.5 111a6f1a94 Mesh: a face edge split that encroaches a feature edge splits the feature edge
Delaunay refinement split a boundary face edge at its midpoint even when that
midpoint lay inside the diametral sphere of a feature edge beside it. Each such
split halves the face vertices' distance to the curve, so they piled up against
it (the heated bracket grew face vertices 0.016 mm from a 4 mm-sized edge), the
improvement schedule could not lift the tetrahedra there to its target, and
inserted vertex after vertex around them: 29257 elements and about two minutes
to open instead of 23641 and 6 s. The SolidCraft pin move (4c91f9b) added one
interior vertex to the bracket's end faces, which changed the CDT enough to
expose it.

Following Shewchuk (1998), an encroaching midpoint now splits the encroached
feature edge instead.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 02:17:00 -04:00
jyvikoandClaude Opus 5.5 43e2144090 Docs: the crank's one-datum workflow, its gallery images and the Decompose status
examples.md and mcp.md tell the one-datum workflow and its numbers; the
crank gallery captures and Start card thumbnails are taken again on this
build; ROADMAP marks the automatic blocks of extruded cross-sections done,
and features.md's Decompose entry says what is left (3D parts).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 01:50:49 -04:00
jyvikoandClaude Opus 5.5 8e45f2c275 Samples: the crank meshed from one datum, its half extruded in automatic blocks
crank-arm and crank-mirror now take one datum (Sym) and its partition:
mesh.hex.generate extrudes the half CrankArm/a, cutting its cross-section
into blocks itself, with no seeds, and mesh.mirror reflects it. 8 664
hex20, scaled Jacobian min 0.371; root sigma_xx -62.44/+62.44 MPa against
M/Z 62.6 (0.25 %), spindle reaction 1500 N. The seven partitions and
eleven exact seeds go.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 01:50:49 -04:00
jyvikoandClaude Opus 5.5 12487794a3 Engine: app.update.check reports whether a newer release is published (#231)
The same check as the app's Help › Check for Updates and fieldcraft-cli update --check: the
latest release, whether it is newer, its page, whether it is signed and the asset this install
would download. It only reports. Checking reaches the network, so only the desktop app and the
CLI switch it on; tests, scratch sessions and the browser build refuse without asking.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 01:48:30 -04:00
jyvikoandClaude Opus 5.5 4c18322a34 Engine: the half crank extrudes in blocks through mesh.hex.generate and mesh.cells
The extrusion's automatic cross-section blocks reach both commands; the
half crank arm, cut only on its symmetry plane, meshes all-structured
(sJ >= 0.37) with no seeds either way, and mesh.hex.generate's
description says so.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 01:26:30 -04:00
jyvikoandClaude Opus 5.5 162bb421f1 Engine: anonymous usage events, counted in Session::execute (#238)
fieldcraft_engine::usage holds the events docs/privacy.md lists, typed so
that only registry names (command ids, sample names, requirements) and
durations can go in them, a bounded queue that records nothing until the
host enables it, and the PostHog batch body. Session::execute counts each
top-level command of a session with an origin (ui, palette, script, mcp):
its id, kind, duration and error class, and the funnel's milestones and
opened samples. Nothing here touches the network.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 01:07:28 -04:00
jyvikoandClaude Opus 5.5 a0d11f1c22 Partitions hide their datum plane
geometry.partition hides the plane it cuts by (view state, saved with the
model): the cut shows as edges on the cells. The eye or selecting it in
the browser shows it again. The crank samples so open without their
planes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 01:01:43 -04:00
jyvikoandClaude Opus 5.5 dddb2d0584 Datums: drawn at the model's extent, never framed, the selected one shown
A datum plane is drawn as the model's extent within it (where it cuts the
model's box, in the plane's axes) plus a 5 % margin, a datum axis along the
model's extent plus the margin, instead of squares 1.2 diagonals wide.
Fit, Home, the standard views and headless pictures frame the model
without the datums (they stay inside the clipping radius). The datum
selected in the browser is drawn highlighted and on top, even when hidden.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 01:01:43 -04:00
jyvikoandClaude Opus 5.5 e06c85eb9e App: crash reports and a log file; Help › Report a Bug (#107)
The desktop app installs the crash reporter and a log file at start
(both in a temporary folder in --control and CI runs, #266), journals
the window's commands (background jobs included) and every control
request's method, and ends the journal on a clean exit. A start after a
crash asks: "FieldCraft closed unexpectedly", Report It… or Not Now.

Help › Report a Bug (also Tools › Help and ui.start
diagnostics.bug_report) shows exactly what the GitHub bug form will be
filled with: the version, the OS, the last error, and for a crash where
it happened. Share my session adds the replayable commands, Include the
model file the model. Open GitHub Issue opens the form in the browser
through the system's opener; files to attach are saved to
bug-reports/<time>/ and a long session goes on the clipboard. Nothing is
sent without that click and the user's submit on GitHub.

The control channel answers the new prompts (crashed: report, close;
report_bug: set, close) and ui.inspect shows the draft; it never opens
the browser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 00:36:18 -04:00
jyvikoandClaude Opus 5.5 080ff048c6 Engine: crash reports, a log file and bug report drafts (#107)
crash: a panic hook and a locked per-run command journal (adapted from
SolidCraft's crash reports). A panic in a command becomes a report with
the model from before it and the command; one outside commands, or an
unclean exit found at the next start (abort, segfault, a crash in a
graphics driver, a kill: what #248 needs), a report with the model the
journal starts from (autosave, file or a copy) and the commands since,
the last control request and the dead run's log lines. Reports are
bounded, deduplicated by signature and replayable (crash::replay, with
writes confined to a scratch folder). The crash folder follows the
automation temp area in --control and CI runs.

logfile: a small size-rotated file logger behind the log facade.

bug_report: GitHub bug-form drafts. Version, OS and what happened by
default, home folder shown as ~; the command journal only with Share my
session, the model only with Include the model as well; a session too
long for the link becomes a file to attach and the clipboard text.

Commands: diagnostics.crash_reports, diagnostics.crash_report,
diagnostics.bug_report (Tools › Help, with its icon) and
diagnostics.crash_test (FIELDCRAFT_CRASH_TEST=1 only).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 00:36:18 -04:00
jyvikoandClaude Opus 5.5 08f669acad Browser and viewport: item menu, per-item eyes, Delete key with confirmation
Right-click on any browser item (body, surface, datum, partition, set,
material, section, step, boundary condition, load, reference point,
coupling, contact, fluid domain) opens its menu: Edit…, Hide/Show,
Isolate, Show All, Active in step (boundary conditions and loads) and
Delete…. A right click on a datum or a partition's cut face in the
viewport opens the same menu. Each item the viewport draws on its own
has an eye; hidden items are neither drawn nor picked. Datums and
partitions are selectable with properties. Delete… and the Delete key
ask first (the prompt lists what uses the item: a datum's partitions
are deleted with it, other definitions in use are refused); ui.prompt
answers it. Every entry runs the same command as the ribbon and forms.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 23:51:01 -04:00
jyvikoandClaude Opus 5.5 d7ec7f486a View state: hide, show and isolate viewport items, saved with the model
view.hide, view.show, view.isolate and view.show_all change which
bodies, surfaces, datums, boundary conditions, loads, reference points
and couplings the viewport draws. The hidden items are view state: the
manifest's `view` keeps them, a change marks the model unsaved, but it
is neither journalled nor undone and leaves results current. Items that
go away are forgotten. Headless pictures leave hidden items out; the
glyph builders take a filter. Tools > View > Show All claims the
commands.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 23:51:01 -04:00
jyvikoandClaude Opus 5.5 d9824de4a5 Engine: geometry.datum.point; planes and axes through datum points; datum edits and cascading delete
A datum point by coordinates, at a mesh vertex, a fraction along a
design edge, at a face's centre, or where a datum axis crosses a datum
plane. Datum planes take three datum points or a normal to a datum axis;
axes take two datum points. geometry.datum.edit, .axis.edit and
.point.edit redefine a datum of their kind (partitions cut again);
geometry.datum.delete with cascade also deletes the partitions that cut
by it. The ribbon shows Datum Plane, Datum Axis, Datum Point and
Partition, each with its own icon; edit and delete leave the ribbon
(still commands, claimed by their entries).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 23:51:01 -04:00
jyvikoandClaude Opus 5.5 90948833e0 Samples: the crank arm meshed structured from a partitioned half
crank-arm (and crank-mirror, kept as the same model under the name of
its mirror workflow) now cut the crank on its symmetry plane and the
half into seven cells: across the arm at x = 30, 60, 110 and 148, and on
two diagonals radial to the pocket's corner fillets. Every cell's
cross-section maps (four-sided blocks, the half O-grids round the bores,
triangle primitives at the pocket's corners); exact edge seeds give each
cut the same divisions on both sides, so mesh.cells merges all six cuts
and mesh.mirror reflects the half: 7 710 hex20, scaled Jacobian min 0.37
(was 0.17, and 0.009 for the swept mirrored half), edge ratio at most
7.0. Root σxx ±62.43 MPa against M/Z 62.6 MPa, the spindle carries the
1500 N. The test asserts the quality floor. Gallery images regenerated.

Fixes #247

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 23:17:20 -04:00
jyvikoandClaude Opus 5.5 52c12e2ad7 Setup symbols: wireframe glyphs per held degree of freedom, a constant size on screen
Boundary condition, load and interaction symbols are wireframes (thin lines,
no shaded cones), so they never hide the mesh or a contour plot:

- a crossed wire triangle per constrained translation, tip on the node,
  coming from outside the part where the set's faces say which side that is;
  a held rotation adds a smaller triangle behind it (the double mark); fixed
  shows all three axes, a symmetry plane only its normal;
- forces as open-headed arrows ending on the node, as long as four support
  units at one place and 2.5 over a set, so loads and supports stay in
  proportion (#78); moments as an axis line and a right-handed curved arrow
  (#79); contact and tie surfaces as small squares on their faces;
- a constant size on screen at any zoom (#80): the symbol unit is the size
  setting (View > Symbol size, `ui.set {symbol_size}`, 14 pt by default)
  times the model length a pixel spans, rounded to a quarter of a doubling;
- spread evenly on a grid a few symbol units across, so their density follows
  the screen, never more than 400 per definition;
- a layer of their own on the desktop (GPU and CPU): zooming rebuilds and
  uploads the symbols only, never the mesh's scene; framing leaves them out;
- colour per kind from the theme's tokens (a new contact colour), and the
  definition selected in the browser drawn in the selection colour, wider;
- depth-tested against the model with the line bias that keeps them on their
  own surface; a load at a reference point or a single node and a reference
  point's cross are drawn over the part (#78).

Headless pictures (MCP screenshot, `ui.render`) frame the camera first and
draw the symbols at the default size for it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 23:14:40 -04:00
jyvikoandClaude Opus 5.5 05abcec6c2 engine: the crank-arm conformity test checks all-hex20, not a platform-dependent count
The tet-free sweep gives 7274 hex20 on macOS and 7334 on Linux (#115), so the exact
count failed develop's CI after #272.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:49:31 -04:00
jyvikoandClaude Opus 5.5 0e4ea5e099 Meshers replace the mesh of the bodies they mesh, and only theirs
mesh.tet.generate and mesh.planar stacked a second mesh on a meshed body;
mesh.hex.*, mesh.hex.octree and mesh.cells wiped every body's mesh. All of
them, and mesh.mirror for its image bodies, now go through replace::clear:
the body's old elements and the nodes only they use go, other bodies stay.
The reply reports replaced {body, elements, nodes}, stale_sets (sets that
listed the old labels) and results_cleared; the command is one undo step.
replace::MESHERS names the bodies each mesher fills, and replacement()
says what a run would replace, for the app to ask first. mesh.block stays
additive: a body is built from several blocks. Refs #267.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:45:24 -04:00
jyvikoandClaude Opus 5.5 0bbdd463ea Cells: the blocks refusal names its problem as a schema Problem
develop did not build: #277's new refusal in mesh.cells passed text to
EngineError::param, which #276 changed to take a ProblemKind.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:45:24 -04:00
jyvikoandClaude Opus 5.5 65fb1112ab Engine: EngineError::Param carries the schema Problem at its field's path
The ~40 parameter checks give a ProblemKind instead of text; Session::execute looks the problem
up in the command's form (a group's missing field becomes that field's own path). Replies still
name keys; forms phrase the same problem by label. A test refuses every field of every form and
checks each refusal names a field of that form.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:42:19 -04:00
jyvikoandClaude Opus 5.5 de8b7b6321 Schema: one phrasing of a problem, by key or by label; Required by field kind
Problem::phrase serves both for_agents and for_form. A required name says "enter a name", a
path "enter a path", anything else "required" (no more "Autosave: enter an autosave"). New
kinds for what commands check (positive, range, list, name, path, invalid), and refine() to
look a command's problem up in its form.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:42:19 -04:00
jyvikoandClaude Opus 5.5 70c5c9b26f Ribbon: Hex Mesh and Partitioned Mesh replace the duplicate hex entries (#270)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:35:17 -04:00
jyvikoandClaude Opus 5.5 f4b6d1dbff mesh.cells: "default": "blocks" runs mesh.hex.blocks; labels Hex Mesh, Partitioned Mesh
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:35:17 -04:00
jyvikoandClaude Opus 5.5 2d5dfb2137 Forms: a one-line note per choice; the hex Method says what each needs
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:35:17 -04:00
jyvikoandClaude Opus 5.5 5758dc7911 Results: a static step first shows its contours undeformed
The first look at a solved static step draws the von Mises contours on the
true geometry; the deformed shape comes when asked for (Deformed,
results.deformed, results.animate), at the automatic scale. Frequency steps
still open on mode 1 deformed and explicit steps at true scale, as the
owner's notes in #77 ask; a 0.24 mm deflection drawn as 10 mm no longer
reads as a failed part.

Fixes #77

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:29:44 -04:00
jyvikoandClaude Opus 5.5 29af2aef91 Camera::fit_in frames a box's corners in part of the view
The distance and the target follow from the eight corners' exact
projections, for orthographic and perspective cameras and any direction of
view, so a long beam seen side on fills the width instead of a sphere
around it the height (#147). The free part is given as fractions of the
view, so overlays can be left out (#76); a margin is kept on each side.
Camera::fit is fit_in over the whole of a square view, and the headless
renderer fits to the picture's aspect.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:29:44 -04:00
jyvikoandClaude Opus 5.5 696b64c30f Session::opened identifies the open document
It changes when file.open, file.recover or file.sample replaces the session
and when geometry.open opens another design file or starts a new model; an
edit, a solve or reopening the same design keep it. The desktop app frames
the view on that change (#233).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:29:44 -04:00
jyvikoandClaude Opus 5.5 a0f48c7207 render: quadratic elements draw through their mid-side nodes; geometry edges over the mesh follow it
Zoomed in on the hex20 crank arm, the element edges and the shaded faces
did not meet (#260). The mesh is conforming; the display drew each hex20
face and edge as straight chords between corners while the mid-side
nodes lie on the curved surface (up to 0.44 mm off the chord at 3 mm),
and drew the geometry's face boundaries from the design tessellation,
off both.

Now a quadratic face is cut into triangles whose vertices are its
corners and mid-side nodes, each edge is drawn as its two halves, and
over the mesh the geometry's edges (and a hovered design edge) are drawn
as the element edges on geometry edges (`DisplayEdge::feature`), so
faces, edges, feature lines and the highlight share their vertices.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:13:15 -04:00
jyvikoandClaude Opus 5.5 9e38fe866d mesh: conformity check finds cracks (free faces, open edges, duplicate nodes, mid-side mismatches)
`quality::conformity` checks a solid mesh for cracks: the free faces must
close up (every corner edge on exactly two), no two distinct nodes may
coincide, and every element edge has one mid-side node. The hex tests
assert it for every method, hex20 included, and the crank arm sample's
7274 hex20 is conforming (#260: the disjoint lines are a display issue).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:13:15 -04:00
jyvikoandClaude Opus 5.5 c26b142630 Recover: each entry's age, and Discard all
file.recovery.list gives each entry's age; File › Recover shows name, age and counts, newest
first, with Discard all. docs/formats/fieldcraft.md states the folder and pruning rules.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:11:13 -04:00
jyvikoandClaude Opus 5.5 fe557054ef Engine: the setup checklist (Session::progress), returned by model.check
The analysis stages in order (geometry, seeds & partitions, mesh, material, section, sets,
boundary conditions, loads, step, solve, results), each done, next, todo, blocked or optional,
with the command that does it. Built on the command requirements; Solve also reads the model
check's first error.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 21:46:33 -04:00
jyvikoandClaude Opus 5.5 6b9e669c7e Engine: every form field says what it means, and shows its unit or dimension
Field gains `help`: one or two sentences of our own wording with a
typical value (yield stress: the initial yield, 276 MPa for 6061-T6,
250 MPa for mild steel; hardening modulus explained; and so on), set
next to each field in cmd/forms.rs. Dim::name gives the dimension
("stress"), Field::unit_label the unit or, with no unit system, the
dimension in brackets, and Field::help_text the tooltip with the unit or
where to set the unit system. The JSON Schema description carries the
help too. A test checks every form field has help and every dimensioned
field shows a unit or dimension in every system.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 21:29:07 -04:00
jyvikoandClaude Opus 5.5 eb66b86e26 Engine: the meshing commands pass the design's edge seeds to the meshers
mesh.tet.generate, mesh.hex.*, mesh.hex.blocks and mesh.cells give every
seed on the open design to their meshers, which match them to their own
curves by position, so a seed on an edge two cells share holds in both. The
tet reply gives, per seed, the mesh edges along it. Docs and the roadmap
say what is honoured where.

Fixes #230.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 21:23:05 -04:00