Commit Graph
296 Commits
Author SHA1 Message Date
jyvikoandClaude Opus 5.5 ed9ec7748d App: send usage batches to PostHog Cloud EU from a background thread (#238)
ureq over rustls (ring) with the OS certificate verifier. The project key
is the build-time FIELDCRAFT_POSTHOG_KEY; without it nothing is asked or
sent. FIELDCRAFT_TELEMETRY=0 turns it off; --control and CI runs only with
FIELDCRAFT_TELEMETRY=1. A failed post drops its batch.

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 79d583ea0f UI: ask once about anonymous usage; Help › Settings › Privacy (#238)
The first run asks whether to share anonymous usage (only when the host
says this run may), the answer and a random install id are kept in the
preferences, and Help › Settings… changes it. Commands are counted by
where they came from (ui, palette, script; mcp when the MCP server says
so), and cancelled forms and clicks on commands that cannot run yet are
recorded. The preferences go through a PrefsStore (a file, or the
browser's storage). Control channel: ui.settings, ui.prompt answers.

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 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 54f50f9518 Gallery: every example image captured again on the current build
All six docs/media/examples images at 1400 x 860 in the light theme, the
solved sample in the home view (the crank mirror from below, as its text
says), with the wireframe symbols, no SETUP card and the crank's planes
hidden; the Start card thumbnails cropped to the model from them.

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 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 b19277ae7a Docs: crash reports, the log file, Report a Bug and privacy (#107)
docs/crash-reports.md: what is kept where, what a bug report carries
(and only when ticked), the CLI and commands for agents; README's
privacy note; the control protocol's new prompt answers.

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 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 cb7e3a2711 CLI: fieldcraft-cli crashes [list|show|replay|dir|clear] (#107)
Lists, shows, replays and deletes the crash reports the desktop app
wrote. A replay opens the report's model, runs its commands with writes
confined to a scratch folder, and says whether the same internal error
happens again. Adapted from SolidCraft's solidcraft-cli crashes.

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 3d51bde9dd io: the app's data folder, and confining writes alone
recovery::data_dir() names the per-user data folder (the temporary
fieldcraft-automation folder in automated runs) that the recovery, crash
and log folders live in. Roots::writes_within lets reads go anywhere
while writes stay in one folder, for replaying a crash report safely.

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 d3ed8ffb05 Start card: every sample as a card with its thumbnail, flagship first, scrolling (#245)
The Start card and File › Samples show a grid of sample cards (thumbnail, name,
one-line description, the full text on hover) in a scroll area with a solid
scrollbar; Help › Samples keeps rows in the same order. The card stays clear of
the view cube and the navigation bar.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 00:06:20 -04:00
jyvikoandClaude Opus 5.5 072139353f Samples: 320 px thumbnails cropped from the gallery captures
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-15 00:06:20 -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 fbaba5fecd Geometry: a face's area centroid and a point a fraction along an edge
Shape::face_centre and Edge::point_at place datum points on a design's
named faces and edges.

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 0bf150633c Model: datum points, drawn as a small cross; each definition's users are public
Datum::Point joins planes and axes (checked like them, refused by
partitions with the kind named). The users each remove_* refuses with
(sets, materials, boundary conditions, loads, reference points, fluid
domains, datums) are public functions, so a caller can list them before
deleting.

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 c1fd58c6ce release: version 0.5.8
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
v0.5.8
2026-10-14 23:33:11 -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 73987bdbae Mesh: the triangle primitive for three-cornered sweep regions
A cross-section region with three corners (a fillet's quarter disk, a
pocket corner cut off by a partition) was left to the free all-quad
mesher. It now gets midpoint subdivision's triangle primitive (Tam and
Armstrong 1991; Li, Armstrong, McKeag 1997): lines from a centre to a
node on each side split it into three mapped blocks, the interior then
smoothed and every quadrilateral checked (a fold falls back to free).
Interval assignment gains dominance constraints (a side shorter than
the other two together) so the split always exists.

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 7df37d4b15 README: the setup symbols screenshot redrawn with the wireframe symbols
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 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 1fcc7acf84 render: lines drawn on top, any number of overlay layers, length per pixel
A scene's `on_top` lines are drawn after every depth-tested layer, over the
model, so a concentrated load at a point inside the part can be seen from any
side (#78). `render_layers` takes a list of overlays (the setup's symbols and
the selection highlight become separate layers), and draws every layer's
labels. `Camera::length_per_pixel` is the model length a pixel spans at the
target: the scale symbols of a fixed screen size are drawn at.

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 3aab588b8b Navigation: orbit about the point under the cursor, zoom toward it, presets in the display menu
An orbit turns about the model point under the press (the pick ray's
first hit on the plot, the mesh or the design), or the centre of what is
drawn when it starts on empty space, keeps that point still on screen and
marks it while orbiting. The wheel and a pinch zoom toward the point
under the cursor; the wheel's delta is read as it arrives, so a notch
zooms in full in orthographic and perspective views alike (#273).

Mouse presets and reverse zoom come from SolidCraft (prefs.rs NavPreset,
NAV_PRESETS; MIT OR Apache-2.0): FieldCraft's own (left drag per the
navigation bar) stays the default, Ctrl + left drag from empty space
orbits in every preset. They are chosen in the display menu, settable
with ui.set and kept in prefs.json beside recent.json (the browser build
keeps them for the page's run); an older prefs.json still loads.

Fixes #262, fixes #273.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 23:02:34 -04:00
jyvikoandClaude Opus 5.5 f074e10442 Render: Camera::orbit_about turns the view about a pivot that keeps its place on screen
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 23:02:34 -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 012119e2c2 Remove the SETUP card: the browser tree shows the progress
The setup checklist card (#265), its show_setup view setting, the View
menu checkbox and the preferences file that only remembered it go; the
tree's marks and ghost rows replace them. Session::progress and
model.check's progress stay for agents. An old prefs.json is no longer
read.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:49:07 -04:00
jyvikoandClaude Opus 5.5 f5a84f5f74 Browser: setup state marks and ghost rows on the tree
Each top-level node that is a setup stage carries a mark at the right
of its row beside its count (done, next, blocked) with the reason and
place in its hover, and a node still lacking what its stage needs shows
a ghost row that starts the providing command. ui.inspect reports each
node's state as browser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-14 22:49:07 -04:00
jyvikoandClaude Opus 5.5 910d437819 App: ask before a mesher replaces a body's mesh
The form's OK on a mesher whose body already has a mesh opens a Replace
mesh prompt ("CrankArm already has a mesh (7,274 hex20). Replace it?"),
naming sets that list the old labels and results that will be cleared.
Replace runs the form; Cancel leaves it open. The control channel's
ui.dialog submit is the OK button, ui.prompt answers replace or cancel.
Programmatic calls never ask. Fixes #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 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 ed2541170a Model: remove one body's mesh, and list the sets that named its labels
Model::remove_body_mesh drops the elements that fill a body and the nodes no
other element uses, with their tags; Model::sets_using names the sets that
listed any of them by label. The base of per-body remeshing (#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 ad84a52ed2 Viewport: one framing rule for open, results, fit, home and standard views
Every fit frames what is drawn (the deformed shape and the setup's symbols
included) with Camera::fit_in in the part of the viewport the overlays
leave free: the results legend, the selection bar, the gizmo and the
navigation bar (framing::free_part). Standard views fit too, so a long
beam's front view keeps both ends (#147); fit and home leave the legend
clear (#76). The view frames itself in the home view when another model,
sample or design is opened (Session::opened; the same design opened again
after an edit keeps the camera) (#233), and when results come up with part
of the model out of sight (#223). ui.inspect's layout reports the legend.

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 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 6bb3b04e60 App: a --control run keeps its autosaves out of the user's recovery folder
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 b1180bf987 IO: automated runs autosave into a temporary folder; stale entries prune themselves
Runs driven by automation (use_automation_dir) and CI use fieldcraft-automation/recovery in the
temporary folder unless FIELDCRAFT_RECOVERY_DIR is set. Taking a slot deletes left-behind
entries older than 14 days and those whose model was saved since.

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 786121c21a UI: a setup checklist at the top of the browser
Once a model has geometry or a mesh, the browser shows the analysis stages from the engine's
checklist, each ticked, next, dashed (optional) or open; a click starts the stage's command and a
blocked stage's hover says what it waits for. The × hides it and View › Setup checklist shows it
again; the choice is kept in the per-user prefs.json.

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 e223a6256a MCP: check_model describes the setup checklist it returns
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 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