Compare commits

..
185 Commits
Author SHA1 Message Date
jyvikoandClaude Opus 5.5 e1c7a13bb6 issue media: Pi 5 Base corner, current layout and a notched all-hex frame (#475)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
2026-10-16 08:06:51 -04:00
Irakli Kourtis 4c4fe5d764 media: ui-f-quality-worst.png 2026-10-15 11:01:10 -04:00
Irakli Kourtis 3d5ce92ea5 media: ui-f-quality-panel.png 2026-10-15 11:01:08 -04:00
Irakli Kourtis 2cc6cbe52e media: ui-f-probe-form.png 2026-10-15 11:01:06 -04:00
Irakli Kourtis 54df16b4bc media: ui-f-probe-form-filled.png 2026-10-15 11:01:04 -04:00
Irakli Kourtis e84efab24b media: ui-f-legend-before.png 2026-10-15 11:01:02 -04:00
Irakli Kourtis be9f7e4113 media: ui-f-legend-after.png 2026-10-15 11:01:00 -04:00
Irakli Kourtis 00db48a872 media: ui-f-ibeam-solved.png 2026-10-15 11:00:59 -04:00
Irakli Kourtis 96f10074bd media: ui-f-crash-reports.png 2026-10-15 11:00:57 -04:00
Irakli Kourtis 6b8ebf85c0 media: ui-f-crash-reports-deleted.png 2026-10-15 11:00:55 -04:00
jyviko 4892e7f8eb media: before/after captures for the ui-older bundle 2026-10-15 10:15:41 -04:00
Irakli Kourtis 84f433f650 media: ui-picking/after-350-browser-crop.png 2026-10-15 09:23:44 -04:00
Irakli Kourtis a7c03b78cf media: ui-picking/after-350-rigid-wall.png 2026-10-15 09:23:43 -04:00
Irakli Kourtis 2f164db4dc media: ui-picking/before-350-interactions.png 2026-10-15 09:23:41 -04:00
Irakli Kourtis e5808eabf6 media: ui-picking/after-351-rp.png 2026-10-15 09:23:39 -04:00
Irakli Kourtis c11135569f media: ui-picking/before-351-rp.png 2026-10-15 09:23:38 -04:00
Irakli Kourtis 5dfdf5f077 media: ui-picking/after-346-datum.png 2026-10-15 09:23:37 -04:00
Irakli Kourtis 2180d816c6 media: ui-picking/before-346-datum.png 2026-10-15 09:23:35 -04:00
Irakli Kourtis 3f5c3b8bcc media: ui-picking/after-344-hover-s.png 2026-10-15 09:23:33 -04:00
Irakli Kourtis 5b0bd418b3 media: ui-picking/before-344-cells.png 2026-10-15 09:23:32 -04:00
Irakli Kourtis 3890086b26 media: ui-picking/after-338-edge.png 2026-10-15 09:23:30 -04:00
Irakli Kourtis 37ab0f0afa media: ui-picking/before-338-edge.png 2026-10-15 09:23:29 -04:00
Irakli Kourtis f28c55ba58 media: ui-forms menus 2026-10-15 09:13:54 -04:00
Irakli Kourtis 1f61fe16ea media: ui-forms after-362-crop 2026-10-15 09:12:13 -04:00
Irakli Kourtis e619c5644b media: ui-forms after-343-remesh-form-crop 2026-10-15 09:12:12 -04:00
Irakli Kourtis 12d0f5f25b media: ui-forms after-342-crop 2026-10-15 09:12:11 -04:00
Irakli Kourtis 7a9f5d1f6c media: ui-forms after-323-tet-refused 2026-10-15 09:12:09 -04:00
Irakli Kourtis f70fe23c28 media: ui-forms after-323-solve-refused 2026-10-15 09:12:08 -04:00
Irakli Kourtis aa568b2938 media: ui-forms after-357-mesh-progress 2026-10-15 09:12:06 -04:00
Irakli Kourtis d7cbee38a1 media: ui-forms after-322-solve-progress 2026-10-15 09:12:05 -04:00
Irakli Kourtis 4ce89c2a40 media: ui-forms after-341-seed-filter 2026-10-15 09:12:04 -04:00
Irakli Kourtis 361ff9a366 media: ui-forms after-347-partition 2026-10-15 09:12:02 -04:00
Irakli Kourtis cfc460fd99 media: ui-forms after-347-datum-preview 2026-10-15 09:12:00 -04:00
Irakli Kourtis f23dd670f1 media: ui-forms after-340-step-form 2026-10-15 09:11:59 -04:00
Irakli Kourtis 64993629a0 media: ui-forms after-353-tet-form 2026-10-15 09:11:57 -04:00
Irakli Kourtis ca83583dfe media: ui-forms after-339-load-form 2026-10-15 09:11:56 -04:00
Irakli Kourtis a64e321ccd media: remove x.png 2026-10-15 09:00:31 -04:00
Irakli Kourtis f90d48644d media: remove top.png 2026-10-15 09:00:31 -04:00
Irakli Kourtis 53bfc8e0c4 media: remove top-s.png 2026-10-15 09:00:30 -04:00
Irakli Kourtis 5e501897cd media: remove tm.png 2026-10-15 09:00:29 -04:00
Irakli Kourtis 7fa8e34eef media: remove thumbs.png 2026-10-15 09:00:28 -04:00
Irakli Kourtis 8bd0b2dcb7 media: remove t-s.png 2026-10-15 09:00:27 -04:00
Irakli Kourtis 094d36a2e1 media: remove symbols-out.png 2026-10-15 09:00:26 -04:00
Irakli Kourtis 4a9696f661 media: remove symbols-in.png 2026-10-15 09:00:25 -04:00
Irakli Kourtis 47774ddbd5 media: remove symbols-home.png 2026-10-15 09:00:24 -04:00
Irakli Kourtis 34382cc8ab media: remove start.png 2026-10-15 09:00:23 -04:00
Irakli Kourtis 0dbab730e5 media: remove solved.png 2026-10-15 09:00:22 -04:00
Irakli Kourtis 68d25ea9df media: remove solved-fit.png 2026-10-15 09:00:20 -04:00
Irakli Kourtis 7c876b0027 media: remove setup.png 2026-10-15 09:00:19 -04:00
Irakli Kourtis 201f6ec696 media: remove rp-inside.png 2026-10-15 09:00:18 -04:00
Irakli Kourtis 94eeeea8a1 media: remove rp-inside-crop.png 2026-10-15 09:00:18 -04:00
Irakli Kourtis 7b91f4ec07 media: remove rp-behind.png 2026-10-15 09:00:17 -04:00
Irakli Kourtis 1c4d71f18e media: remove rp-behind-crop.png 2026-10-15 09:00:16 -04:00
Irakli Kourtis ca69f66184 media: remove pocket.png 2026-10-15 09:00:15 -04:00
Irakli Kourtis 3501852e5d media: remove pocket-s.png 2026-10-15 09:00:13 -04:00
Irakli Kourtis c2a923590f media: remove pocket-end.png 2026-10-15 09:00:12 -04:00
Irakli Kourtis 2814496028 media: remove pedalb.png 2026-10-15 09:00:11 -04:00
Irakli Kourtis 0628dfee0d media: remove pedal.png 2026-10-15 09:00:10 -04:00
Irakli Kourtis 7ef841e964 media: remove g-mirror.png 2026-10-15 09:00:09 -04:00
Irakli Kourtis 79025d97e3 media: remove g-arm.png 2026-10-15 09:00:08 -04:00
Irakli Kourtis 23bdf25cd6 media: remove crank-mirror.png 2026-10-15 09:00:07 -04:00
Irakli Kourtis d07b07f8e2 media: remove crank-mirror-s.png 2026-10-15 09:00:05 -04:00
Irakli Kourtis 1ce2de8546 media: remove crank-iso.png 2026-10-15 09:00:04 -04:00
Irakli Kourtis a453b36afa media: remove crank-arm.png 2026-10-15 09:00:03 -04:00
Irakli Kourtis 6f48f22848 media: remove crank-arm-s.png 2026-10-15 09:00:02 -04:00
Irakli Kourtis ab87e63830 media: remove cmp2.png 2026-10-15 09:00:01 -04:00
Irakli Kourtis e78f051957 media: remove cmp1.png 2026-10-15 09:00:00 -04:00
Irakli Kourtis 280192e203 media: remove cmp.png 2026-10-15 08:59:59 -04:00
Irakli Kourtis 72b3079867 media: remove closeups.png 2026-10-15 08:59:58 -04:00
Irakli Kourtis 9edde6f70c media: remove bore.png 2026-10-15 08:59:57 -04:00
Irakli Kourtis 8d702688bb media: remove b-s.png 2026-10-15 08:59:56 -04:00
Irakli Kourtis 3637a0b3fe media: ui-results x.png 2026-10-15 08:59:50 -04:00
Irakli Kourtis 69be8c1e56 media: ui-results top.png 2026-10-15 08:59:48 -04:00
Irakli Kourtis 251c9d5017 media: ui-results top-s.png 2026-10-15 08:59:47 -04:00
Irakli Kourtis 8c505bc6ca media: ui-results tm.png 2026-10-15 08:59:45 -04:00
Irakli Kourtis 446a33be09 media: ui-results thumbs.png 2026-10-15 08:59:44 -04:00
Irakli Kourtis 0c7570c034 media: ui-results t-s.png 2026-10-15 08:59:42 -04:00
Irakli Kourtis e023ec70b5 media: ui-results symbols-out.png 2026-10-15 08:59:41 -04:00
Irakli Kourtis 4b7134de02 media: ui-results symbols-in.png 2026-10-15 08:59:40 -04:00
Irakli Kourtis fae9258f87 media: ui-results symbols-home.png 2026-10-15 08:59:38 -04:00
Irakli Kourtis 6f4fdafed0 media: ui-results start.png 2026-10-15 08:59:37 -04:00
Irakli Kourtis cebf244f38 media: ui-results solved.png 2026-10-15 08:59:36 -04:00
Irakli Kourtis 6e307795f6 media: ui-results solved-fit.png 2026-10-15 08:59:34 -04:00
Irakli Kourtis 875bd6d15d media: ui-results setup.png 2026-10-15 08:59:33 -04:00
Irakli Kourtis b1906ab393 media: ui-results rp-inside.png 2026-10-15 08:59:31 -04:00
Irakli Kourtis 0ba476691f media: ui-results rp-inside-crop.png 2026-10-15 08:59:30 -04:00
Irakli Kourtis f3c2b282c6 media: ui-results rp-behind.png 2026-10-15 08:59:29 -04:00
Irakli Kourtis 464992a215 media: ui-results rp-behind-crop.png 2026-10-15 08:59:28 -04:00
Irakli Kourtis 5bb8554cb2 media: ui-results pocket.png 2026-10-15 08:59:26 -04:00
Irakli Kourtis 1f27e5d1dd media: ui-results pocket-s.png 2026-10-15 08:59:24 -04:00
Irakli Kourtis d9d3b7ce26 media: ui-results pocket-end.png 2026-10-15 08:59:23 -04:00
Irakli Kourtis 800dacc7c4 media: ui-results pedalb.png 2026-10-15 08:59:21 -04:00
Irakli Kourtis aa08a9a136 media: ui-results pedal.png 2026-10-15 08:59:20 -04:00
Irakli Kourtis 13c8b43211 media: ui-results g-mirror.png 2026-10-15 08:59:19 -04:00
Irakli Kourtis e7bb94b2e3 media: ui-results g-arm.png 2026-10-15 08:59:17 -04:00
Irakli Kourtis b194f2c0d4 media: ui-results crank-mirror.png 2026-10-15 08:59:15 -04:00
Irakli Kourtis 2da4e0af74 media: ui-results crank-mirror-s.png 2026-10-15 08:59:14 -04:00
Irakli Kourtis 3d603bfb73 media: ui-results crank-iso.png 2026-10-15 08:59:12 -04:00
Irakli Kourtis dbe7656ebb media: ui-results crank-arm.png 2026-10-15 08:59:10 -04:00
Irakli Kourtis 79f36c1ba0 media: ui-results crank-arm-s.png 2026-10-15 08:59:09 -04:00
Irakli Kourtis 8e613fdcf2 media: ui-results cmp2.png 2026-10-15 08:59:07 -04:00
Irakli Kourtis fad676d789 media: ui-results cmp1.png 2026-10-15 08:59:05 -04:00
Irakli Kourtis a0ecddcd59 media: ui-results cmp.png 2026-10-15 08:59:04 -04:00
Irakli Kourtis 06d9ecc386 media: ui-results closeups.png 2026-10-15 08:59:02 -04:00
Irakli Kourtis 9dfc78fe36 media: ui-results bore.png 2026-10-15 08:59:01 -04:00
Irakli Kourtis 4c8b14127c media: ui-results before-stale.png 2026-10-15 08:58:59 -04:00
Irakli Kourtis 94eeb7c0cf media: ui-results before-seal.png 2026-10-15 08:58:58 -04:00
Irakli Kourtis 855c6acfb1 media: ui-results before-seal-auto.png 2026-10-15 08:58:55 -04:00
Irakli Kourtis fbd222dd9b media: ui-results before-reactions.png 2026-10-15 08:58:54 -04:00
Irakli Kourtis 1770fd9fb1 media: ui-results before-probe.png 2026-10-15 08:58:52 -04:00
Irakli Kourtis 2c00b1f611 media: ui-results before-isolate.png 2026-10-15 08:58:51 -04:00
Irakli Kourtis 1337edc9bf media: ui-results before-drop.png 2026-10-15 08:58:49 -04:00
Irakli Kourtis 681beec6da media: ui-results before-cantilever-mode2.png 2026-10-15 08:58:48 -04:00
Irakli Kourtis dc7ae39f39 media: ui-results before-cantilever-load.png 2026-10-15 08:58:46 -04:00
Irakli Kourtis 773a97e212 media: ui-results before-bracket.png 2026-10-15 08:58:45 -04:00
Irakli Kourtis c1d4ebb282 media: ui-results before-bracket-solve-panel.png 2026-10-15 08:58:43 -04:00
Irakli Kourtis d0a9cdf1bd media: ui-results before-bracket-nomesh.png 2026-10-15 08:58:41 -04:00
Irakli Kourtis 538c8b760b media: ui-results b-s.png 2026-10-15 08:58:40 -04:00
Irakli Kourtis 86fafc7853 media: ui-results after-stale.png 2026-10-15 08:58:39 -04:00
Irakli Kourtis 7db56f4911 media: ui-results after-seal.png 2026-10-15 08:58:37 -04:00
Irakli Kourtis b798cdbdf8 media: ui-results after-probe-reactions.png 2026-10-15 08:58:35 -04:00
Irakli Kourtis 3c177ddd07 media: ui-results after-isolate.png 2026-10-15 08:58:34 -04:00
Irakli Kourtis 02afff31b5 media: ui-results after-drop.png 2026-10-15 08:58:32 -04:00
Irakli Kourtis 2c13977776 media: ui-results after-cantilever-mode2.png 2026-10-15 08:58:30 -04:00
Irakli Kourtis 967077d365 media: ui-results after-cantilever-load.png 2026-10-15 08:58:29 -04:00
Irakli Kourtis e1a9e19787 media: ui-results after-bracket-solve-panel.png 2026-10-15 08:58:27 -04:00
Irakli Kourtis 3c2494f295 media: ui-results after-bracket-nomesh.png 2026-10-15 08:58:26 -04:00
Irakli Kourtis 530d00b36e media: after-cantilever-tie-status.png 2026-10-15 08:45:50 -04:00
Irakli Kourtis cbfde06153 media: after-journal-crop.png 2026-10-15 08:45:49 -04:00
Irakli Kourtis 198715fdf0 media: after-us.png 2026-10-15 08:45:48 -04:00
Irakli Kourtis cffe894b91 media: after-seed-selected.png 2026-10-15 08:45:46 -04:00
Irakli Kourtis 91ac2e0097 media: after-trees.png 2026-10-15 08:45:45 -04:00
Irakli Kourtis 1b4e8acbaf media: after-crank-bodies.png 2026-10-15 08:45:43 -04:00
Irakli Kourtis 063a7beb2d media: after-bracket-set-stack.png 2026-10-15 08:45:42 -04:00
Irakli Kourtis 432b14d90c media: after-heated-heater.png 2026-10-15 08:45:40 -04:00
Irakli Kourtis 24dd11f04d media: after-rubber-seal-press.png 2026-10-15 08:45:38 -04:00
Irakli Kourtis 1f14b83820 media: before-crank-bodies.png 2026-10-15 08:45:37 -04:00
Irakli Kourtis b2ccdd0e5e media: before-bracket-set-stack.png 2026-10-15 08:45:35 -04:00
Irakli Kourtis 465b1db5e0 media: before-heated-heater.png 2026-10-15 08:45:34 -04:00
Irakli Kourtis 9c5d13c4f6 media: before-rubber-seal-press.png 2026-10-15 08:45:32 -04:00
Irakli Kourtis 04b46be8fe audit 2026-10-15 08:11:51 -04:00
Irakli Kourtis 06a5b622ef audit: a-seed-browser.png 2026-10-15 08:10:46 -04:00
Irakli Kourtis 67e7d833f8 audit: a-edit-menu-mirror.png 2026-10-15 08:10:45 -04:00
Irakli Kourtis 1ee9733d5e audit: a-bodies-panel.png 2026-10-15 08:10:44 -04:00
Irakli Kourtis 445b215a78 audit: a-partitioned-mesh-form.png 2026-10-15 08:10:42 -04:00
Irakli Kourtis 8e7f5d7864 audit: a-edge-sel-nomesh.png 2026-10-15 08:10:41 -04:00
Irakli Kourtis d1a4756924 audit: a-edge-sel-mesh.png 2026-10-15 08:10:39 -04:00
Irakli Kourtis 08b479461b audit 2026-10-15 08:10:30 -04:00
Irakli Kourtis 70b9776b33 audit: up-step-defaults.png 2026-10-15 08:10:23 -04:00
Irakli Kourtis 50a0054735 audit: up-set-json.png 2026-10-15 08:10:22 -04:00
Irakli Kourtis 4bea7855fb audit: up-press.png 2026-10-15 08:10:21 -04:00
Irakli Kourtis eb21b58220 audit: up-orphan.png 2026-10-15 08:10:20 -04:00
Irakli Kourtis f0e1f58938 audit: up-load-clip.png 2026-10-15 08:10:18 -04:00
Irakli Kourtis 45e5ad15e1 audit: up-journal.png 2026-10-15 08:10:17 -04:00
Irakli Kourtis 25ecc1bae3 audit: up-heater.png 2026-10-15 08:10:16 -04:00
Irakli Kourtis 7d86283c37 audit: up-bodies.png 2026-10-15 08:10:14 -04:00
Irakli Kourtis c5bdb16887 audit screenshot k1 2026-10-15 08:09:16 -04:00
Irakli Kourtis 4a8ad35f85 audit screenshot c5 2026-10-15 08:09:15 -04:00
Irakli Kourtis d46423546e audit screenshot s1 2026-10-15 08:09:14 -04:00
Irakli Kourtis f2fb6242bb audit screenshot r1 2026-10-15 08:09:12 -04:00
Irakli Kourtis 5b4599d17b audit screenshot p1 2026-10-15 08:09:11 -04:00
Irakli Kourtis 52339fa4b6 audit screenshot d2 2026-10-15 08:09:09 -04:00
Irakli Kourtis b090f213c7 audit screenshot c8 2026-10-15 08:09:08 -04:00
Irakli Kourtis 9678a8305a audit screenshot r5 2026-10-15 08:09:06 -04:00
Irakli Kourtis c0bf38efc2 audit screenshot c3 2026-10-15 08:09:05 -04:00
Irakli Kourtis 9345dea731 audit: tree status marks 2026-10-15 08:05:47 -04:00
Irakli Kourtis 297e96d145 media: releases/0.5.8/fieldcraft-0.5.8-setup-tree.png 2026-10-15 00:10:09 -04:00
Irakli Kourtis 12bb39d6f9 media: releases/0.5.8/fieldcraft-0.5.8-structured-hex.png 2026-10-15 00:10:07 -04:00
Irakli Kourtis 857a02b50f media: views framing 5-cantilever-solved-fit 2026-10-14 22:29:22 -04:00
Irakli Kourtis ce5d81f410 media: views framing 4-cantilever-front 2026-10-14 22:29:21 -04:00
Irakli Kourtis ad93e22d53 media: views framing 3-bracket-after-crank 2026-10-14 22:29:20 -04:00
Irakli Kourtis 035b23b395 media: views framing 2-crank-solved 2026-10-14 22:29:19 -04:00
Irakli Kourtis 353ed4be93 issue media: uiaudit-results-offscreen.png 2026-10-14 18:07:24 -04:00
Irakli Kourtis 2849f2d870 issue media: uiaudit-plasticity-no-material.png 2026-10-14 18:07:23 -04:00
Irakli Kourtis c82332054c issue media: uiaudit-plasticity-empty.png 2026-10-14 18:07:21 -04:00
Irakli Kourtis dc3d4c62b0 issue media: uiaudit-plasticity-carryover.png 2026-10-14 18:07:20 -04:00
Irakli Kourtis b647232433 issue media: uiaudit-narrow-plasticity.png 2026-10-14 18:07:18 -04:00
Irakli Kourtis 21fc85786f issue media: uiaudit-light-form-fields.png 2026-10-14 18:07:17 -04:00
Irakli Kourtis 25f7270d5a issue media: uiaudit-commandline-truncated.png 2026-10-14 18:07:15 -04:00
Irakli Kourtis 4457bd4646 issue media: uiaudit-check-json-status.png 2026-10-14 18:07:14 -04:00
jyvikoandClaude Opus 5.5 41fc6c23a0 issue media: Cook's membrane sketch (#83), octree over-refinement on thin parts (#85)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
2026-10-14 08:15:27 -04:00
jyvikoandClaude Opus 5.5 8086a108fd issue media: a force at a reference point on the cantilever's end face, buried in the part
Captured from FieldCraft 0.1.0 (f1253b4) with ui.capture: iso view and the opposite side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
2026-10-14 08:02:51 -04:00
jyvikoandClaude Opus 5.5 0d06b956c0 issue media: Lamé cylinder path through the wall (#96), NAFEMS LE1 oracle case (#97)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
2026-10-14 07:59:22 -04:00
jyvikoandClaude Opus 5.5 aaf64f7c0d issue media: start screen, results after solve, setup symbols at three zooms, demo tip load
Captured from FieldCraft 0.1.0 (f1253b4) with ui.capture; the tip-load crop is from docs/media/ibeam-analysis.gif.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
2026-10-14 07:58:56 -04:00
jyvikoandClaude Opus 5.5 deae8f77bd issue media: screenshots referenced from issues
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm
2026-10-14 07:51:30 -04:00
1015 changed files with 60 additions and 114407 deletions

No files matched your search

-2
View File
@@ -1,2 +0,0 @@
[alias]
xtask = "run --package xtask --"
-90
View File
@@ -1,90 +0,0 @@
name: CI
# CI runs once per merge, on main (AGENTS.md, "Workflow for every change"): pull requests are
# checked locally on the crates they touch and merged; a red main is fixed forward.
on:
push:
branches: [main]
# A merge that only touches prose starts no run. The generated pages are checked by the jobs
# (features.md by `cargo xtask ci`, oracle.md by the oracle job), so they still count.
# (Later patterns override earlier ones.)
paths:
- '**'
- '!**/*.md'
- '!docs/**'
- 'docs/features.md'
- 'docs/oracle.md'
schedule:
# Nightly: the heavy tests on main.
- cron: '23 3 * * *'
workflow_dispatch:
permissions:
contents: read
# A newer merge cancels the run still going for the one before it, so a burst of merges is tested
# once, at the tip. Nightly and manual runs are grouped apart and never cancelled by a merge.
concurrency:
group: ci-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: ${{ github.event_name == 'push' }}
env:
CARGO_TERM_COLOR: always
jobs:
ci:
name: cargo xtask ci
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- run: cargo xtask ci
heavy:
# The heavy verification and corpus tests (#[ignore]d) and the doc tests.
name: cargo xtask test --heavy
runs-on: ubuntu-24.04
timeout-minutes: 60
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
- run: cargo xtask test --heavy
oracle:
# Verification and validation (docs/verification.md): every case against its reference and
# its fixture, and docs/oracle.md must be the table the cases produce. Cases marked `slow`
# run here too while the whole set stays within a few minutes; `--quick` skips them.
name: cargo xtask oracle
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
key: oracle
save-if: ${{ github.ref == 'refs/heads/main' }}
- run: cargo xtask oracle
- name: docs/oracle.md is current
run: git diff --exit-code docs/oracle.md
advisories:
name: Dependency advisories and sources
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: dtolnay/rust-toolchain@stable
- name: Install cargo-deny
run: cargo install cargo-deny --version 0.20.2 --locked
- run: cargo deny --locked check --warn unmaintained advisories bans sources
-9
View File
@@ -1,9 +0,0 @@
/target*/
/plan/
/dist/
/.agent-files/
/worktrees/
*~
.DS_Store
*.swp
__pycache__/
-151
View File
@@ -1,151 +0,0 @@
# FieldCraft — instructions for agents
FieldCraft is a clean-room, open-source, pure-Rust CAE modeling application: it turns geometry
into analysis-ready finite element models (volume meshes, materials, sections, boundary
conditions, loads and steps), writes them as Abaqus input, Nastran bulk data and LS-DYNA keyword
decks, and solves linear static and modal problems with its own solver. It targets the
pre-processing done today in Abaqus/CAE, Nastran pre-processors and LS-PrePost, and aims to beat
them on meshing robustness, speed, openness and agent control.
Siblings with the same conventions: `../solidcraft` (parametric CAD, Fusion-class), and the
storytold Craft apps (`storytold/cadcraft`, `vectorcraft`, `photocraft`, …). Code adapted from
them (MIT OR Apache-2.0) is noted in ATTRIBUTION.md.
## Product name
FieldCraft everywhere: crates `fieldcraft-*`, binaries `fieldcraft` and `fieldcraft-cli`,
`.fieldcraft` models, `FIELDCRAFT_*` environment variables, docs, CI and packaging.
## Start every session here
1. Read `ROADMAP.md` (milestones, what is next) and your task.
2. `docs/architecture.md`: crates, layers, the meshing pipeline.
3. `docs/adr/`: library decisions (what we may depend on, what is rejected for licence reasons).
4. Meshing work: `docs/meshing/literature.md` (the papers each algorithm comes from).
## Never crash
People trust FieldCraft with their models; a crash loses their work. **This outranks feature work.**
- **No panics in non-test code:** no `unwrap()`, `expect()`, `panic!`, `unreachable!`, `todo!`,
`unimplemented!`; no `unsafe` (`unsafe_code = "forbid"`).
- **Errors are `Result<T, E>`** through the crate's error type and `?`. An unfinished feature
returns an error ("not supported yet: …"); it never panics.
- **Input-derived numbers are hostile** (command parameters, model files, solver decks,
control-channel input): `get()` not `[i]`, finite checks, caps on sizes and loop counts.
- **Bound every iterative algorithm.** Mesh refinement, smoothing, untangling and solver
iterations have explicit iteration and element-count caps and report when they stop early.
- **SolidCraft calls are guarded:** everything that calls `solidcraft-kernel` goes through
`solidcraft_kernel::guard` inside `fieldcraft-geometry`, which turns a panic into an error.
- **Last-resort guard:** `Session::execute` runs every command under `catch_unwind`; an error or
an escaped panic restores the model and reports `EngineError`.
- **Prove it:** every crash fix lands with a regression test (see `hostile_params_never_panic`).
- Every production crate root carries
`#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]`.
## Non-negotiables
- **Independent.** Behaviour is designed from public documentation, published papers, general
CAE conventions and user feedback. Never copy another product's code, icons, artwork, help
text, element or material libraries, templates or examples.
- **No commercial CAE products.** Agents must not drive, script, automate or extract data from
commercial CAE or meshing products (Abaqus, MSC/NX/Simcenter Nastran, LS-DYNA, LS-PrePost,
HyperMesh, ANSA, Femap, Patran, ANSYS, …): no test data, measurements, decks, results or ids
produced with them. Deck formats come from the vendors' publicly available reference manuals;
we write our own descriptions and our own examples, never copy manual text or example decks.
- **Verification and validation (docs/verification.md).** Every solver capability is checked
three ways, each case in `tests/oracle/` tagged with its source: **theory** (closed-form
solutions, patch tests, mesh invariants), **experiment** (measurements published in papers and
reports) and **published benchmarks** (reference results published by benchmark bodies and by
solver vendors' benchmark and verification manuals, e.g. NAFEMS, Abaqus). Owner decision
2026-10-13: published vendor results may be used as reference values, cited per case. We never
run a commercial product, never copy its input files, text or figures: each case is our own
model built from the published description, and only the published numbers are used. Once our
result matches its reference within the stated tolerance, it is frozen as a **fixture**
(`fixture.json`), so any later change that moves it fails CI (fidelity never drifts silently).
- **Algorithms come from papers.** Meshing and solver methods are implemented from published
papers and theses, cited in the module docs and in `docs/meshing/literature.md`.
- **Never read, copy or link GPL/LGPL/AGPL code**: TetGen, CGAL, Gmsh, Netgen, CalculiX,
Code_Aster, OpenRadioss, Elmer, deal.II, FreeFEM, Salome, OpenFOAM — don't even read their
sources. Permissively licensed code (MIT, BSD, Apache-2.0, MPL-2.0) may be read for reference;
anything adapted is noted in ATTRIBUTION.md with its licence.
- **Assets — absolutely essential.** FieldCraft contains **no iconography, images, fonts or
artwork from commercial CAE products — ever.** Icons are original artwork made with VectorCraft:
commit the editable `.vectorcraft` source beside the exported SVG/PNG. Any file asset must be
original or openly licensed and **must have a row in ATTRIBUTION.md** (`cargo xtask assets`
enforces it). Screenshots of commercial software are never committed.
- **Test geometry is our own.** Meshing and solver test parts are built with SolidCraft and
committed as recipes (scripts or designs) that regenerate them; analytic shapes are generated in
code. No public CAD datasets (ABC, MAMBO, Thingi10K, GrabCAD) and nothing made in a commercial
CAD or CAE product.
- **Everything is a command.** User-visible behaviour = a command in `crates/engine/src/cmd/*`
(`CommandSpec`: our own dotted, lower-case id `<area>.<thing>[.<variant>]` such as
`mesh.node.add` or `mesh.tet.generate`, never another product's keyword; label; params doc;
JSON `run`) + tests. The UI, scripts, CLI and control channel all reach the same commands.
- **Programmatic calls never open dialogs.**
- **Layering** is enforced by `cargo xtask layers` (`docs/architecture.md`): L0 `model` → L1
`geometry`, `mesh`, `fem`, `decks`, `render` → L2 solvers (`solver`, `lbm`; `explicit` later) →
L3 `fsi` (later) → L4 `doc` → L5 `io` → L6 `engine` → L7 `ui-egui`, `mcp` → apps. Nothing below
L7 depends on egui/eframe/winit/wgpu/rfd. **Only
`crates/geometry` may use `solidcraft-*`.**
- **Determinism.** The same input gives the same mesh, deck and CPU solver result, bit for bit, on
every platform: no hash-order iteration into output, no thread-count-dependent results (threads
go through `fieldcraft-parallel`: fixed blocks, sums in a fixed order, docs/adr/0001). GPU
solver backends (wgpu, f32) are the one exception: deterministic per device, and checked against
the CPU reference within a stated tolerance.
- **Robust geometry.** Meshing decisions (orientation, in-sphere, intersection) use exact or
adaptive-precision predicates, never a bare floating-point sign.
- **Units.** The model is unit-consistent and never converts (the user picks e.g. mm, t, s, N,
MPa); geometry from SolidCraft is in millimetres. Z is up.
- **Rust only.** **Never break wasm**: everything below the apps builds for
`wasm32-unknown-unknown` (`cargo xtask wasm`, part of `cargo xtask ci`).
- **Workflow for every change** (this section overrides any other instruction an agent carries,
such as a parent repository's CLAUDE.md or a task runner's "run tests and linters" step):
1. Work in your own worktree on a branch, with your own `CARGO_TARGET_DIR`. While you work:
`cargo check` and the tests of the crates you touch (`cargo test -p <crate>`). Commit after
each working step (a layer that compiles with its tests passing), not one big commit per PR.
Every commit lands on `main` as it is, so each one must build and pass its tests and say
what it does: `git bisect` walks them one by one.
2. When the change is done: review it once with `/simplify`, then `cargo fmt --all` and
`cargo clippy -p <crate> --all-targets -- -D warnings` for each crate you touched, once.
Regenerate what your change affects: `docs/features.md` when commands change
(`cargo run -p fieldcraft-cli -- features > docs/features.md`), `docs/oracle.md` when
oracle cases or solver numerics change (`cargo xtask oracle`).
3. Fold every fix into the commit it fixes, never a separate "fmt", "clippy", "review fixes" or
"regenerate features.md" commit: `git commit --fixup <sha>`, then
`git rebase -i --autosquash origin/main` (`GIT_SEQUENCE_EDITOR=true` keeps it
non-interactive). A regenerated page goes into the commit that changed what it lists.
4. Rebase onto the latest `origin/main` (never merge `main` into a branch), rerun the tests of
the touched crates, push, open the PR and merge it yourself with a rebase merge, which keeps
`main` linear and every commit bisectable: `gh pr merge <N> --rebase --delete-branch`, run as
its own command. Never squash. Then remove your worktree and delete your local branch.
5. Never run the full gate locally: no `cargo xtask ci`, no `cargo clippy --workspace`, no
`cargo xtask wasm` or `oracle` unless step 2 calls for it. Never watch CI. GitHub CI runs
`cargo xtask ci` (fmt, assets, licences, layers, clippy -D warnings, tests, wasm), the
oracle, the heavy tests and the advisories once per merge on `main`; the coordinator
watches it and sends a failure back to the change that caused it, which is fixed forward
at once.
- **Keep the main gate fast** (under ~3 minutes on CI). A test that takes more than a few seconds
(convergence studies, the whole corpus, cross-checks between solvers) is
`#[ignore = "heavy: cargo xtask test --heavy (CI heavy job)"]`, with a fast representative
test left in the main gate. The `heavy` CI job runs `cargo xtask test --heavy` (every ignored
test, benchmarks included, and the doc tests) on every merge to `main`, nightly and on
demand (`gh workflow run CI --ref <branch>`). Hostile-input tests run commands on sessions with small
work caps (`Session::limits`) so refusals are instant; never lower the production caps for a
test.
- **Publishing**: `origin` is github.com/jyviko/fieldcraft. Changes land through pull requests
as the workflow above describes; the coordinator reads every merged diff and sends findings
back as fix-forward work. Never force-push `main`. Never commit `plan/`, `.agent-files/`,
`worktrees/` or `target*/`; check `git ls-files` before pushing.
## Running
- `cargo run -p fieldcraft-cli -- commands` lists every command with its parameters.
- `cargo run -p fieldcraft-cli -- run script.json` runs a script (a JSON array of
`{"command", "params"}`) and prints the model summary.
- `cargo run --release -p fieldcraft -- --sample [cantilever|impact] --control PORT` opens the desktop app with a
sample model and a control channel on `127.0.0.1:PORT` (docs/control-protocol.md). For UI work,
look at the result: `ui.capture {path}` (the whole window drawn offscreen; works with the
screen locked), `ui.screenshot {path}` (a presented frame) or `ui.render {path}` (the model
only), then read the PNG.
- `cargo run -p fieldcraft-cli -- mcp [--connect 127.0.0.1:PORT]` serves MCP on stdio (docs/mcp.md):
the same commands as tools, headless or bridged to the running app.
- Build with `CARGO_TARGET_DIR=<repo>/target`. Parallel agents: separate target dirs, one
worktree each.
## Roadmap
`ROADMAP.md` (committed) tracks milestones. Update it whenever a milestone task lands.
-180
View File
@@ -1,180 +0,0 @@
# Attribution
Every non-code asset in this repository (images, icons, fonts, example geometry) is listed here
with its author, source and licence. `cargo xtask assets` (part of `cargo xtask ci`) fails if an
asset file is missing from this table.
**Policy (mandatory):** FieldCraft contains **no iconography, images, artwork, fonts, templates,
example decks or help text from commercial CAE products.** Every asset is original work by
FieldCraft contributors or third-party material under an open licence. Screenshots of commercial
software are never committed. Icons are made with VectorCraft; each icon's `.vectorcraft` source
is committed and listed here with its exports.
## Files
| File | Author | Source | Licence |
|---|---|---|---|
| docs/media/ibeam-analysis.mp4, docs/media/ibeam-analysis.gif | FieldCraft contributors | Original: the FieldCraft window captured during an MCP session, generated by `tools/demo-video/make.py` | MIT OR Apache-2.0 |
| crates/decks/tests/golden/nastran/*.bdf | FieldCraft contributors | Written by our Nastran writer from our own test models (crates/decks/tests/nastran.rs) | MIT OR Apache-2.0 |
| assets/icons/assembly.instance.svg, assets/icons/assembly.instance.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/assembly.instance.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/deck.read.svg, assets/icons/deck.read.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/deck.read.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/deck.write.abaqus.svg, assets/icons/deck.write.abaqus.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/deck.write.abaqus.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/deck.write.lsdyna.svg, assets/icons/deck.write.lsdyna.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/deck.write.lsdyna.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/deck.write.nastran.svg, assets/icons/deck.write.nastran.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/deck.write.nastran.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/edit.redo.svg, assets/icons/edit.redo.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/edit.redo.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/edit.undo.svg, assets/icons/edit.undo.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/edit.undo.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/file.open.svg, assets/icons/file.open.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/file.open.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/file.recover.svg, assets/icons/file.recover.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/file.recover.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/file.save_as.svg, assets/icons/file.save_as.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/file.save_as.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/file.save.svg, assets/icons/file.save.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/file.save.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/geometry.bodies.svg, assets/icons/geometry.bodies.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.bodies.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/geometry.datum.svg, assets/icons/geometry.datum.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.datum.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/geometry.import.mesh.svg, assets/icons/geometry.import.mesh.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.import.mesh.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/geometry.midsurface.svg, assets/icons/geometry.midsurface.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.midsurface.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/geometry.open.svg, assets/icons/geometry.open.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.open.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/geometry.partition.svg, assets/icons/geometry.partition.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.partition.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/geometry.tessellate.svg, assets/icons/geometry.tessellate.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.tessellate.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.bolt.svg, assets/icons/interaction.bolt.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.bolt.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.connector.svg, assets/icons/interaction.connector.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.connector.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.contact.find.svg, assets/icons/interaction.contact.find.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.contact.find.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.contact.general.svg, assets/icons/interaction.contact.general.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.contact.general.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.contact.pair.svg, assets/icons/interaction.contact.pair.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.contact.pair.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.fsi.svg, assets/icons/interaction.fsi.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.fsi.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.mass.create.svg, assets/icons/model.mass.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.mass.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.rigid_wall.svg, assets/icons/interaction.rigid_wall.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.rigid_wall.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.spring.create.svg, assets/icons/model.spring.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.spring.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/interaction.tie.svg, assets/icons/interaction.tie.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.tie.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.delaunay.points.svg, assets/icons/mesh.delaunay.points.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.delaunay.points.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.element.add.svg, assets/icons/mesh.element.add.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.element.add.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.hex.decompose.svg, assets/icons/mesh.hex.decompose.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.hex.decompose.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.hex.dominant.svg, assets/icons/mesh.hex.dominant.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.hex.dominant.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.hex.mapped.svg, assets/icons/mesh.hex.mapped.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.hex.mapped.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.hex.octree.svg, assets/icons/mesh.hex.octree.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.hex.octree.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.hex.polycube.svg, assets/icons/mesh.hex.polycube.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.hex.polycube.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.hex.sweep.svg, assets/icons/mesh.hex.sweep.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.hex.sweep.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.import.orphan.svg, assets/icons/mesh.import.orphan.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.import.orphan.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.layers.svg, assets/icons/mesh.layers.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.layers.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.node.add.svg, assets/icons/mesh.node.add.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.node.add.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.node.merge.svg, assets/icons/mesh.node.merge.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.node.merge.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.order.quadratic.svg, assets/icons/mesh.order.quadratic.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.order.quadratic.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.quad.faces.svg, assets/icons/mesh.quad.faces.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.quad.faces.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.quality.svg, assets/icons/mesh.quality.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.quality.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.region.remesh.svg, assets/icons/mesh.region.remesh.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.region.remesh.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.size.adapt.svg, assets/icons/mesh.size.adapt.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.size.adapt.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.size.global.svg, assets/icons/mesh.size.global.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.size.global.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.size.seed.svg, assets/icons/mesh.size.seed.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.size.seed.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.smooth.svg, assets/icons/mesh.smooth.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.smooth.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.surface.check.svg, assets/icons/mesh.surface.check.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.surface.check.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.tag.svg, assets/icons/mesh.tag.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.tag.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.tet.generate.svg, assets/icons/mesh.tet.generate.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.tet.generate.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.planar.svg, assets/icons/mesh.planar.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.planar.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.transition.svg, assets/icons/mesh.transition.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.transition.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.untangle.svg, assets/icons/mesh.untangle.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.untangle.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/mesh.verify.svg, assets/icons/mesh.verify.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.verify.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.activity.svg, assets/icons/model.activity.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.activity.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.amplitude.svg, assets/icons/model.amplitude.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.amplitude.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.boundary_condition.create.svg, assets/icons/model.boundary_condition.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.boundary_condition.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.check.svg, assets/icons/model.check.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.check.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.coupling.create.svg, assets/icons/model.coupling.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.coupling.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.fluid_domain.boundary.svg, assets/icons/model.fluid_domain.boundary.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.fluid_domain.boundary.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.fluid_domain.create.svg, assets/icons/model.fluid_domain.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.fluid_domain.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.info.svg, assets/icons/model.info.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.info.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.load.create.svg, assets/icons/model.load.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.load.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.material.create.svg, assets/icons/model.material.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.material.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.material.damage.svg, assets/icons/model.material.damage.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.material.damage.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.material.eos.svg, assets/icons/model.material.eos.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.material.eos.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.material.hyperelastic.svg, assets/icons/model.material.hyperelastic.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.material.hyperelastic.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.material.plasticity.svg, assets/icons/model.material.plasticity.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.material.plasticity.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.material.thermal.svg, assets/icons/model.material.thermal.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.material.thermal.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.orientation.svg, assets/icons/model.orientation.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.orientation.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.reference_point.create.svg, assets/icons/model.reference_point.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.reference_point.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.section.composite.svg, assets/icons/model.section.composite.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.section.composite.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.section.create.svg, assets/icons/model.section.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.section.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.set.create.svg, assets/icons/model.set.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.set.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.step.activate.svg, assets/icons/model.step.activate.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.step.activate.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.step.create.svg, assets/icons/model.step.create.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.step.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.step.explicit.svg, assets/icons/model.step.explicit.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.step.explicit.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.step.heat.svg, assets/icons/model.step.heat.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.step.heat.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.step.nonlinear.svg, assets/icons/model.step.nonlinear.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.step.nonlinear.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/model.units.svg, assets/icons/model.units.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.units.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.animate.svg, assets/icons/results.animate.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.animate.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.contour.svg, assets/icons/results.contour.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.contour.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.convergence.svg, assets/icons/results.convergence.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.convergence.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.cut.svg, assets/icons/results.cut.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.cut.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.deformed.svg, assets/icons/results.deformed.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.deformed.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.display_group.svg, assets/icons/results.display_group.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.display_group.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.free_body.svg, assets/icons/results.free_body.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.free_body.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.modes.svg, assets/icons/results.modes.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.modes.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.path.svg, assets/icons/results.path.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.path.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.probe.svg, assets/icons/solve.probe.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.probe.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.reactions.svg, assets/icons/results.reactions.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.reactions.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.read.svg, assets/icons/results.read.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.read.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.streamlines.svg, assets/icons/results.streamlines.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.streamlines.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/results.xy.svg, assets/icons/results.xy.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/results.xy.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.blast.svg, assets/icons/solve.blast.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.blast.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.explicit.svg, assets/icons/solve.explicit.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.explicit.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.fluid.svg, assets/icons/solve.fluid.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.fluid.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.frequency.svg, assets/icons/solve.frequency.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.frequency.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.fsi.svg, assets/icons/solve.fsi.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.fsi.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.static.svg, assets/icons/solve.static.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.static.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/solve.run.svg, assets/icons/solve.run.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.run.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/file.sample.svg, assets/icons/file.sample.vectorcraft | FieldCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/file.sample.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.eye.svg, assets/icons/ui.eye.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.eye.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.fit.svg, assets/icons/ui.fit.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.fit.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.help.svg, assets/icons/ui.help.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.help.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.home.svg, assets/icons/ui.home.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.home.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.moon.svg, assets/icons/ui.moon.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.moon.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.orbit.svg, assets/icons/ui.orbit.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.orbit.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.pan.svg, assets/icons/ui.pan.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.pan.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.perspective.svg, assets/icons/ui.perspective.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.perspective.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.search.svg, assets/icons/ui.search.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.search.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.style.svg, assets/icons/ui.style.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.style.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.sun.svg, assets/icons/ui.sun.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.sun.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.views.svg, assets/icons/ui.views.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.views.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/icons/ui.zoom.svg, assets/icons/ui.zoom.vectorcraft | FieldCraft contributors | Original interface icon (navigation bar, title bar, browser) drawn with VectorCraft from `assets/icons/src/ui.zoom.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
| assets/app-icon/icon.vectorcraft, assets/app-icon/icon.svg, assets/app-icon/icon.png | FieldCraft contributors | Original application icon (an L bracket with a bolt hole under a structured hexahedral mesh, on a rounded-square backdrop), drawn with VectorCraft by `cargo xtask app-icon` (xtask/src/app_icon.rs); editable source, SVG and 1024 × 1024 PNG export | MIT OR Apache-2.0 |
| assets/app-icon/icon-small.vectorcraft, assets/app-icon/icon-small.svg, assets/app-icon/icon-small.png | FieldCraft contributors | Original simplified application icon for 16–32 px (no mesh or floor grid), drawn with VectorCraft by `cargo xtask app-icon` (xtask/src/app_icon.rs) | MIT OR Apache-2.0 |
| assets/app-icon/layers/01-floor.vectorcraft, assets/app-icon/FieldCraft.icon/Assets/01-floor.svg | FieldCraft contributors | Original isometric floor grid with a radial fade (Default appearance), drawn with VectorCraft by `cargo xtask app-icon` (xtask/src/app_icon.rs) | MIT OR Apache-2.0 |
| assets/app-icon/layers/01-floor-dark.vectorcraft, assets/app-icon/FieldCraft.icon/Assets/01-floor-dark.svg | FieldCraft contributors | Original isometric floor grid with a radial fade (Dark appearance), drawn with VectorCraft by `cargo xtask app-icon` (xtask/src/app_icon.rs) | MIT OR Apache-2.0 |
| assets/app-icon/layers/02-part.vectorcraft, assets/app-icon/FieldCraft.icon/Assets/02-part.svg | FieldCraft contributors | Original bracket faces with transparent gaps at the shared edges, drawn with VectorCraft by `cargo xtask app-icon` (xtask/src/app_icon.rs) | MIT OR Apache-2.0 |
| assets/app-icon/layers/03-mesh.vectorcraft, assets/app-icon/FieldCraft.icon/Assets/03-mesh.svg | FieldCraft contributors | Original hexahedral mesh lines (O-grid around the hole) clipped to the bracket's faces, drawn with VectorCraft by `cargo xtask app-icon` (xtask/src/app_icon.rs) | MIT OR Apache-2.0 |
| assets/app-icon/FieldCraft.icon/icon.json | FieldCraft contributors | Icon Composer composition of the layers above (Default and Dark floor grid), written by `cargo xtask app-icon` (xtask/src/app_icon.rs) | MIT OR Apache-2.0 |
| assets/app-icon/Assets.car | FieldCraft contributors | Apple actool compilation of assets/app-icon/FieldCraft.icon; contains original artwork only | MIT OR Apache-2.0 |
| assets/app-icon/icon.icns | FieldCraft contributors | iconutil compilation of assets/app-icon/icon.iconset | MIT OR Apache-2.0 |
| assets/app-icon/icon.ico | FieldCraft contributors | ImageMagick compilation (16–256 px) of sips exports of assets/app-icon/icon-small.png (≤ 32 px) and assets/app-icon/icon.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_16x16.png | FieldCraft contributors | sips export (16 px) of assets/app-icon/icon-small.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_16x16@2x.png | FieldCraft contributors | sips export (32 px) of assets/app-icon/icon-small.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_32x32.png | FieldCraft contributors | sips export (32 px) of assets/app-icon/icon-small.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_32x32@2x.png | FieldCraft contributors | sips export (64 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_128x128.png | FieldCraft contributors | sips export (128 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_128x128@2x.png | FieldCraft contributors | sips export (256 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_256x256.png | FieldCraft contributors | sips export (256 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_256x256@2x.png | FieldCraft contributors | sips export (512 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_512x512.png | FieldCraft contributors | sips export (512 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
| assets/app-icon/icon.iconset/icon_512x512@2x.png | FieldCraft contributors | sips export (1024 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
| crates/ui-egui/fonts/Inter-SemiBold.ttf | The Inter Project Authors | https://github.com/rsms/inter release v4.1 (Inter-4.1.zip, extras/ttf/Inter-SemiBold.ttf), unmodified; licence text in crates/ui-egui/fonts/OFL.txt; the interface's caps labels (theme::LABEL_FAMILY) | SIL OFL 1.1 |
## Adapted code
| File | Adapted from | Licence |
|---|---|---|
| xtask/src/layers.rs | SolidCraft `xtask/src/layers.rs` (itself adapted from CADCraft's xtask) | MIT OR Apache-2.0 |
| xtask/src/assets.rs, xtask/src/licences.rs, xtask/src/test.rs, xtask/src/main.rs | SolidCraft `xtask/src/` | MIT OR Apache-2.0 |
| clippy.toml, rustfmt.toml | SolidCraft | MIT OR Apache-2.0 |
| crates/geometry/src/tagged_mesh.rs (package and part reading, transforms, units, caps) | SolidCraft `crates/io/src/threemf.rs` | MIT OR Apache-2.0 |
| crates/render/src/camera.rs, crates/render/src/raster.rs | SolidCraft `crates/render/src/camera.rs`, `raster.rs` | MIT OR Apache-2.0 |
| crates/ui-egui/src/gpu.rs, crates/ui-egui/src/theme.rs (tokens and their values), crates/ui-egui/src/control.rs, crates/ui-egui/src/lib.rs (input injection, screenshots), crates/ui-egui/src/toolbar.rs (workspace switcher, tabs, panels with drop-downs, fitting), crates/ui-egui/src/appbar.rs (application bar; the mark is drawn from assets/app-icon/icon-small.svg's coordinates), crates/ui-egui/src/titlebar.rs (caption buttons, drag and resize zones; SolidCraft took it from VectorCraft), crates/ui-egui/src/frame.rs (windows, heading bands), crates/ui-egui/src/browser.rs (row drawing), crates/ui-egui/src/palette.rs (command line and search), crates/ui-egui/src/timeline.rs (timeline strip, transport), crates/ui-egui/src/viewport.rs (navigation bar, orientation gizmo), crates/ui-egui/src/files.rs (background opening, file pickers as host services) | SolidCraft `crates/ui-egui/src/` (titlebar.rs also VectorCraft `crates/ui-egui/src/titlebar.rs`) | MIT OR Apache-2.0 |
| crates/io/src/fs.rs (atomic writes) | SolidCraft `crates/io/src/safe_write.rs` | MIT OR Apache-2.0 |
| crates/io/src/recovery.rs (recovery folder, entries, locks) | SolidCraft `crates/engine/src/recovery.rs` | MIT OR Apache-2.0 |
| apps/fieldcraft/src/control_server.rs | SolidCraft `apps/solidcraft/src/control_server.rs` | MIT OR Apache-2.0 |
| crates/mcp/src/ (JSON-RPC framing, MCP lifecycle, tool schema checks, the control-channel backend, base64) | SolidCraft `crates/mcp/src/` | MIT OR Apache-2.0 |
| crates/io/src/roots.rs (the rules of read and write roots) | VectorCraft's automation roots (docs/mcp.md there) | MIT OR Apache-2.0 |
## Test oracles
Used only by tests (dev-dependencies, not shipped); no code from them is copied or adapted.
| Used in | Oracle | Licence |
|---|---|---|
| crates/mesh/src/predicates/tests.rs, crates/mesh/tests/predicates_bench.rs | `robust` (georust), a port of Shewchuk's public-domain `predicates.c` | MIT OR Apache-2.0 |
| crates/mesh/src/predicates/tests.rs, crates/mesh/src/predicates/dyadic.rs (tests) | `num-bigint`, `num-rational`, `num-traits` (exact rationals) | MIT OR Apache-2.0 |
-1
View File
@@ -1 +0,0 @@
@AGENTS.md
-14
View File
@@ -1,14 +0,0 @@
# Contributing
Thanks for helping. Read [AGENTS.md](AGENTS.md) first: it holds the rules every change follows,
whether a person or an agent writes it.
1. Branch from `main`, keep a pull request to one topic.
2. Run `cargo xtask ci` before pushing; CI runs the same gates.
3. User-visible behaviour is a command (`crates/engine/src/cmd/`) with tests, including hostile
parameters.
4. Meshing and solver algorithms cite the paper they come from in the module docs.
5. Never contribute code, text or data from GPL-family projects or commercial CAE products
(see [docs/adr/0001-libraries.md](docs/adr/0001-libraries.md)).
By contributing you agree your work is licensed under MIT OR Apache-2.0.
Generated
-5047
View File
File diff suppressed because it is too large. Load diff
-123
View File
@@ -1,123 +0,0 @@
[workspace]
resolver = "3"
members = ["crates/*", "apps/*", "xtask"]
[workspace.package]
version = "0.1.0"
edition = "2024"
license = "MIT OR Apache-2.0"
rust-version = "1.95"
authors = ["FieldCraft contributors"]
repository = "https://github.com/jyviko/fieldcraft"
[workspace.dependencies]
# internal
fieldcraft-model = { path = "crates/model" }
fieldcraft-parallel = { path = "crates/parallel" }
fieldcraft-geometry = { path = "crates/geometry" }
fieldcraft-mesh = { path = "crates/mesh" }
fieldcraft-decks = { path = "crates/decks" }
fieldcraft-io = { path = "crates/io" }
fieldcraft-fem = { path = "crates/fem" }
fieldcraft-solver = { path = "crates/solver" }
fieldcraft-explicit = { path = "crates/explicit" }
fieldcraft-lbm = { path = "crates/lbm" }
fieldcraft-engine = { path = "crates/engine" }
fieldcraft-testkit = { path = "crates/testkit" }
fieldcraft-render = { path = "crates/render" }
fieldcraft-ui-egui = { path = "crates/ui-egui" }
fieldcraft-mcp = { path = "crates/mcp" }
# foundation
thiserror = "2"
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["float_roundtrip"] }
log = "0.4"
# 3MF packages (docs/formats/tagged-mesh.md): the same versions SolidCraft uses.
zip = { version = "3", default-features = false, features = ["deflate"] }
quick-xml = "0.41"
# content hashes and part checksums of .fieldcraft files (the version SolidCraft uses)
sha2 = "0.10"
# images (PNG snapshots and screenshots)
png = "0.18"
# SVG toolbar icons rasterised in the UI (no text, fonts or raster images in icons)
resvg = { version = "0.48", default-features = false }
# ui: the same egui/eframe/egui-wgpu line as SolidCraft
egui = "0.36"
eframe = { version = "0.36", default-features = false }
egui-wgpu = "0.36"
# Shared Craft-family egui components (icon buttons, tabs, widget palette); the same rev as
# VectorCraft. MIT OR Apache-2.0.
craft-ui = { git = "https://github.com/storytold/craft-libs", rev = "5c874d51eeb3de70e735c8ce87a59a7dedd47675" }
# native file pickers (the desktop app only; the UI crate takes them as services)
rfd = "0.17"
# Geometry: SolidCraft's B-rep kernel (MIT OR Apache-2.0), pinned. Only crates/geometry uses it
# (plan/adr/0001-libraries.md).
solidcraft-geom = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
solidcraft-kernel = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
solidcraft-doc = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
solidcraft-io = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
# Runs SolidCraft command scripts (the test corpus recipes); only behind fieldcraft-geometry's
# `scripts` feature.
solidcraft-engine = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
[workspace.lints.rust]
unsafe_code = "forbid"
[workspace.lints.clippy]
dbg_macro = "warn"
todo = "warn"
too_many_arguments = "allow"
type_complexity = "allow"
# `!(x > tol)` is our idiom for "not a usable number" (NaN-safe).
neg_cmp_op_on_partial_ord = "allow"
[profile.dev.package."*"]
opt-level = 2
[profile.dev]
opt-level = 1
# The lattice Boltzmann kernels are compute loops over millions of cells; their verification
# runs (tests) need them optimised.
[profile.dev.package.fieldcraft-lbm]
opt-level = 3
# Tests and lints (`cargo xtask ci`, GitHub CI). Debug assertions are off because truck's
# debug-only checks reject valid geometry (SolidCraft builds its tests the same way).
[profile.ci]
inherits = "dev"
opt-level = 1
debug = "line-tables-only"
debug-assertions = false
overflow-checks = true
incremental = false
[profile.ci.package."*"]
opt-level = 2
[profile.ci.package.fieldcraft-lbm]
opt-level = 3
[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 16
debug = "line-tables-only"
# SolidCraft builds truck and egui-wgpu with local fixes (its vendor/ directory). Patches don't
# reach a dependent workspace, so FieldCraft applies the same ones from the same pinned commit;
# keep this list and the rev in step with SolidCraft's [patch.crates-io].
[patch.crates-io]
truck-shapeops = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
truck-stepio = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
truck-meshalgo = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
matext4cgmath = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
# egui-wgpu with SolidCraft's fixes (vendor/egui-wgpu there): MSAA clamped to what the device
# supports and 1x on OpenGL adapters, so the requested 4x never fails pipeline validation at start.
egui-wgpu = { git = "https://github.com/bherbruck/solidcraft", rev = "de1479029dd6821cffd28b70688a58e7f61f0cfd" }
-177
View File
@@ -1,177 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2026 FieldCraft contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-19
View File
@@ -1,19 +0,0 @@
FieldCraft
Copyright (c) 2026 FieldCraft contributors.
Licensed under the MIT License or the Apache License, Version 2.0, at your option
(LICENSE-MIT, LICENSE-APACHE).
Third-party material
Software dependencies are listed in Cargo.lock; their licences are in THIRD-PARTY-LICENSES.txt
(`cargo xtask licences`). Geometry comes from SolidCraft (https://github.com/bherbruck/solidcraft,
MIT OR Apache-2.0), which builds on the truck crates (https://github.com/ricosjp/truck, Apache-2.0,
Copyright (c) RICOS Co. Ltd.), some with SolidCraft's modifications.
Some code is adapted from sibling projects (SolidCraft, CADCraft), licensed MIT OR Apache-2.0;
ATTRIBUTION.md lists the files.
FieldCraft is an independent project and is not affiliated with, sponsored by or endorsed by
Dassault Systèmes, MSC Software, Siemens Digital Industries Software or Ansys, Inc. Abaqus,
Nastran, MSC Nastran, Simcenter Nastran and LS-DYNA are trademarks of their respective owners;
they are used here only to describe file compatibility.
+2 -76
View File
@@ -1,77 +1,3 @@
# FieldCraft
# Issue media
An open-source, clean-room CAE application in pure Rust: from a parametric SolidCraft part to a
verified finite element analysis, with tetrahedral and hexahedral meshing, its own implicit,
explicit, thermal and lattice Boltzmann solvers, and decks for Abaqus, Nastran and LS-DYNA. The
desktop app, the command line and AI agents (over MCP) drive the same commands.
**Status:** early but working end to end — open a part, mesh it, define the analysis, solve,
see the results. Hex meshing is the centre of gravity; the next large step is the nonlinear
implicit solver that contact, elastomers and composites need. See [ROADMAP.md](ROADMAP.md).
![An AI agent analyses an I-beam cantilever in FieldCraft over MCP: open, hex mesh, steel, clamp and tip load, solve, von Mises contours, the deformed shape and an orbit round it](docs/media/ibeam-analysis.gif)
An AI agent drives FieldCraft over [MCP](docs/mcp.md), each stage captioned with the tool it
calls: it opens an I-beam, hex meshes it, defines the material, the clamp and a 1000 N tip load,
solves, and shows the von Mises stress and the deformed shape (tip deflection 0.176 mm; beam
theory with shear 0.177 mm).
[MP4](docs/media/ibeam-analysis.mp4) · regenerated by [tools/demo-video](tools/demo-video/README.md).
## What it does today
- **Geometry in:** SolidCraft designs (`.solidcraft`) with persistent face, edge and body names,
and face-tagged 3MF meshes; surface checks (weld, manifold, orientation, self-intersection).
- **Meshing:** constrained Delaunay tetrahedra (tet4, tet10) with exact predicates and a
certified validity gate; structured hex by sweeping, revolving and mapping (hex8, hex20; 16 of
the 21 corpus parts mesh all-hex); 2D quad and tri meshes; quality metrics per element and set.
- **Elements:** solids (tet4, tet10, wedge6, hex8 with incompatible modes, hex20 full and
reduced, hybrid u–p for near-incompressible materials), plane stress, plane strain and
axisymmetric, trusses, Timoshenko beams, MITC3/MITC4 shells, springs, dashpots and point masses.
- **Model:** sets bound to geometry names, so they survive remeshing; isotropic and orthotropic
elasticity, J2 plasticity, Johnson–Cook damage, thermal properties; fixed, displacement,
symmetry and temperature conditions; forces, moments, pressure, gravity, centrifugal and heat
loads; reference points with kinematic and distributing couplings; undo, redo and a
text-diffable `.fieldcraft` file.
- **Solvers:** linear static and frequency (supernodal Cholesky, block Lanczos); steady and
transient heat transfer and coupled thermal stress; explicit dynamics with plasticity, damage,
erosion and rigid walls; D3Q19 lattice Boltzmann flow with forces on the part's faces. Results
never depend on the thread count.
- **Decks:** Abaqus, Nastran and LS-DYNA writers, each refusing by name what it cannot express.
- **Results:** contours of stress, strain and displacement with a legend, deformed shapes, mode
shapes, explicit frames, probes and reaction sums; the analysis setup drawn in the viewport.
- **Verification:** every capability is checked against closed forms and published benchmarks
(NAFEMS, MacNeal–Harder, Scordelis–Lo) in [`tests/oracle`](tests/oracle), with results frozen
so they cannot drift: [docs/oracle.md](docs/oracle.md).
- **Driving it:** a desktop app in the Craft family's layout, a CLI, a JSON control channel and an
MCP server; every capability is a command ([docs/features.md](docs/features.md)).
## Build
```sh
cargo xtask ci # fmt, assets, licences, layers, clippy, tests, wasm
cargo xtask test --heavy # the heavy (ignored) tests and the doc tests
cargo run -p fieldcraft-cli -- commands # every command and its parameters
cargo run -p fieldcraft-cli -- run script.json # run a command script
cargo run -p fieldcraft-cli -- mcp # MCP server on stdio for AI agents (docs/mcp.md)
```
Rust 1.95 or later, with the `wasm32-unknown-unknown` target for `cargo xtask ci`.
## Documentation
- [Architecture](docs/architecture.md): crates, layers and the meshing pipeline
- [Element library](docs/elements.md) and [verification and validation](docs/verification.md)
- [Capability checklist](docs/parity.md) and [roadmap](ROADMAP.md)
- [Libraries and licences](docs/adr/0001-libraries.md)
- [AI agents (MCP)](docs/mcp.md): `claude mcp add fieldcraft -- /path/to/fieldcraft-cli mcp`
- [Control protocol](docs/control-protocol.md): driving the desktop app
- [Contributing](CONTRIBUTING.md) and [agent instructions](AGENTS.md)
## License
Dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option. Notices
are in [NOTICE](NOTICE); third-party licences in [THIRD-PARTY-LICENSES.txt](THIRD-PARTY-LICENSES.txt).
FieldCraft is an independent project, not affiliated with, sponsored or endorsed by Dassault
Systèmes, MSC Software, Siemens or Ansys. Abaqus, Nastran, MSC Nastran, Simcenter Nastran and
LS-DYNA are trademarks of their owners and are named only to describe file compatibility.
Screenshots referenced from GitHub issues, kept off `main`. FieldCraft's own renders and captures (MIT OR Apache-2.0).
-87
View File
@@ -1,87 +0,0 @@
# Roadmap
FieldCraft's goal is CAE modeling on par with Abaqus/CAE, Nastran pre-processors and LS-PrePost,
with hexahedral meshing as the centre of gravity, plus its own linear solver. Abaqus/CAE is the
reference for scope (its documentation is excellent and its solver strong); its application is
where we aim to be clearly better: parametric geometry from SolidCraft, sets that survive
remeshing, automatic hex partitioning, undo, a text-diffable model and agent control.
The capability checklist is [docs/parity.md](docs/parity.md). Beyond the pre-processor and the
linear solver come our own explicit, CFD (lattice Boltzmann) and fluid–structure solvers (M10–M14;
methods and papers in [docs/solvers/literature.md](docs/solvers/literature.md)).
Order (revised 2026-10-13): one end-to-end slice first — *SolidCraft part → named faces → sets →
mesh → material and section → BCs and loads → static and frequency steps → Abaqus, Nastran and
LS-DYNA decks and our own solve → contour plot* — on tet meshes, so every hex mesher lands in a
pipeline that already produces solvable, verified models. Then hex: structured (sweep and mapped,
with partitions proposed automatically) before octree all-hex, because that is how analysts get
hex meshes today and it gives the best elements where stresses are read.
Revised 2026-10-14 after a gap review (below): the implicit side is linear today, and nearly
everything analysts ask for next — contact and friction, elastomers, viscoelasticity, creep,
adhesion, composite failure, tissues — needs a nonlinear implicit solver first. The nonlinear
core (M15) therefore comes right after automatic hex (M6) and before contact (M7). Every material
model is written once in `fieldcraft-fem` with its consistent tangent and serves the implicit and
explicit solvers alike; every coupled field (temperature, pressure, electric potential, pore
pressure) is a degree of freedom of the existing DOF framework, not a separate solver.
| Milestone | Scope | Status |
|---|---|---|
| M0 Foundation | Workspace, quality gates, FE model, command engine with rollback and panic guard, CLI, geometry boundary on SolidCraft | done |
| M1 Geometry in and surface preparation | Open `.solidcraft` designs with persistent face names, assemblies placed (done); face-tagged 3MF (done); test corpus, `cargo xtask corpus` (done); exact predicates (done); quality metrics and certified validity gate (done); weld, closed/manifold/orientation and self-intersection checks, feature edges (`fieldcraft-mesh::surface`, `mesh.surface.check`, done) | in progress |
| M2 Tet meshing and size field | Size field (global, per face and edge seeds, curvature and proximity; the `fieldcraft_mesh::size::SizeField` trait and edge-division helpers are in); Bowyer–Watson Delaunay (exact, symbolic perturbation, verified; `fieldcraft-mesh::delaunay`, done); robust CDT boundary recovery (Diazzi et al. 2023: implicit LNC Steiner points on segments, gift-wrapping facet recovery, inside/outside labelling, B-rep face tags on boundary tet faces, few-ulp rounding repair checked by the validity gate; `fieldcraft-mesh::cdt` and `mesh.tet.generate`, done: all 20 valid corpus parts); Delaunay refinement, ODT smoothing, sliver removal; tet4 and tet10 with mid-side nodes on the B-rep; mesh verify per set | in progress |
| M3 First deck | Sets and surfaces bound to SolidCraft face, edge, vertex and body names, resolved after meshing; materials (isotropic and orthotropic elastic, density) with a unit-system label and consistency check; sections (solid, shell, beam profiles) assigned by set; element formulation per region mapped to each solver; BCs (fixed, displacement, symmetry); loads (force and moment on reference points, pressure, gravity); reference points with kinematic and distributing coupling; steps (linear static, frequency) with explicit per-step load and BC tables and output presets; `model.check` naming every missing or bad item; `model.*` and `mesh.tag` commands (model definition: done); writers for Abaqus input (done: `deck.write`), Nastran SOL 101/103 (done: `deck.write`) and LS-DYNA implicit (done); the `.fieldcraft` file (text definition, binary mesh, geometry references reopened on load, journal; atomic saves, autosave and recovery; undo/redo on the journal: done) | in progress |
| M4 Own solver and first results | Element library per docs/elements.md (1D and 2D first); Linear static and modal solver (tet4/10, wedge6, hex8, hex20; sparse direct, Lanczos), verified against analytic solutions (solver: done — `fieldcraft-fem` kernels, `fieldcraft-solver` with nested dissection, sparse Cholesky and block Lanczos, `solve.static`/`solve.frequency`/`solve.probe`, patch, cantilever, Lamé, Kirsch and beam-frequency tests; reference points with kinematic and distributing couplings and moments by master–slave constraint elimination, verified by rigid motion, clamping, Saint-Venant tension, bending and tube torsion; 1D elements I: rod2/rod3 trusses, point masses, rotary inertia, springs and dashpots in both solvers and all three decks, verified by the method of joints, the three-bar truss, spring–mass, two-mass chain and torsional pendulum frequencies, and damped decay; 2D elements: plane stress, plane strain and axisymmetric tri3, tri6, quad4 (incompatible modes QM6), quad8 with two degrees of freedom per node, centrifugal loads, `mesh.planar` 2D meshes of polygons and planar faces, verified by patch tests, Kirsch, Lamé (plane strain and axisymmetric), rotating discs and cylinders, and a plane stress cantilever; deck mapping to Abaqus CPS/CPE/CAX, Nastran membranes, LS-DYNA ELFORM 12/13); shells and beams (done: quad4 MITC4 and tri3 MITC3 flat shells with a Hughes–Brezzi drilling rotation, two-node Timoshenko beams with profile properties and orientations, six degrees of freedom at shell and beam nodes shared with solids and trusses, section forces and surface stresses, verified by shell patch tests, Navier's plate, cantilever and portal-frame beams, and the Scordelis–Lo and pinched-cylinder benchmarks); results display (done: `results.*` commands, deformed shape to scale, banded contours of displacement, von Mises, principal and component stresses with a legend, mode shapes with their frequencies and animation, probing a node by clicking it, reaction force and moment sums per set, stale results marked after an edit; explicit steps: field frames by slider or animation with contours per frame, energy histories plotted) | started |
| M5 Structured hex | 2D quad meshing of faces (`fieldcraft-mesh::quad`: transfinite mapped meshes, free all-quad meshes of polygons with holes on prescribed boundary nodes, exact planar quad validity, shared `SizeField` and even edge divisions; done for planar faces); mapped hex of six-sided regions (trivariate TFI, curved faces) and sweep meshing (multi-level extrusions with imprinted cross-sections, revolutions, one-to-one sweeps through linking faces; interval assignment, hex8/hex20 on the geometry, B-rep face tags, `mesh.hex.generate`/`sweep`/`mapped`: done, 16 of 21 corpus parts all-hex); conforming interfaces and tet–hex transition; automatic decomposition into sweepable and mappable regions, proposed as SolidCraft splits | started |
| M6 Automatic hex | Octree/grid-dual all-hex for any part; hex-dominant by tet recombination; polycube for blocky parts; smoothing, untangling, boundary padding, layers through thin walls; mesh editing and orphan-mesh import | planned |
| M7 Assemblies, contact and friction | Needs M15. Part instances from SolidCraft occurrences; tie between non-matching meshes (mortar); implicit contact: surface-to-surface mortar and node-to-surface, penalty and augmented Lagrange, self-contact, automatic pair detection with a bounding-volume search shared with explicit contact; friction: Coulomb with stick–slip, static/kinetic, anisotropic, pressure-, rate- and temperature-dependent coefficients; contact output (pressure, slip, status); thermal contact conductance and frictional heating; wear (Archard); bolt pretension, connectors with behaviour (elastic, damped, stops, locks); amplitudes, multiple steps, restart; nonlinear steps in all three decks. Verified by Hertz (sphere and cylinder), the Cattaneo–Mindlin partial-slip problem, the sliding block, NAFEMS contact benchmarks | planned |
| M8 Materials, explicit, shells, composites | Plasticity, hyperelasticity, damage data per solver; explicit dynamics decks (Abaqus/Explicit, LS-DYNA); midsurface shells; composite layups and material orientations, continuum shells on swept hex; hybrid (mixed u–p) hex8/hex20/tet10 for nearly incompressible materials (done); heat transfer (solids done: steady and θ-method transient conduction with flux, convection and sources, thermal strain in static steps (solids and 2D) and explicit dynamics (with plasticity), coupled temperature–displacement, `solve.heat`; deck output, 2D/shell/beam conduction planned) | started |
| M9 Post-processing and deck readers | Results readers for public formats (Nastran OP2, LS-DYNA d3plot, Abaqus `.fil`); XY and path plots, cuts, display groups, free-body forces; deck readers that keep unknown keywords; mesh convergence studies | planned |
| M10 Explicit dynamics | Shared element and material kernels with the implicit solver (`fem`); central-difference solver with lumped mass, stable time step, one-point hex8 with hourglass control and nodal-pressure tet4, bulk viscosity, energy accounting (X1 core: done — `fieldcraft-explicit`, `explicit_dynamic` steps with initial velocities, prescribed motion and planar rigid walls, `solve.explicit`/`solve.history`, small-strain linear elastic; bar wave, rigid-wall impact, energy balance and cantilever-period tests); large-deformation materials (X2: done — updated Lagrangian elements, Jaumann/Hughes–Winget and Green–Naghdi/Flanagan–Taylor rates, J2 bilinear/table plasticity, Johnson–Cook strength with heating and damage, erosion; materials gain `plastic`, `damage`, `erosion` with `model.material.plasticity`/`damage`; Dienes shear, rigid rotation, J2 uniaxial and Taylor-bar tests); contact (global search, penalty with friction, rigid walls); runs on hex and tet meshes | started |
| M11 Equations of state and shells | Polynomial, ideal-gas, Mie–Grüneisen, JWL with programmed burn, tabulated; energy coupling; shock verification (Rankine–Hugoniot, Sod, Noh, Sedov); Belytschko–Lin–Tsay shells with self-contact on quad meshes | planned |
| M12 CFD: lattice Boltzmann | D3Q19/D3Q27 on grids voxelised from the face-tagged surface; TRT, regularised and cumulant collision; interpolated walls, inlets and outlets; LES (Smagorinsky, WALE) with wall models; thermal LBM and conjugate heat transfer with the structure's thermal solver; non-Newtonian viscosity (power-law, Carreau–Yasuda, Cross, Herschel–Bulkley, Bingham) and temperature-dependent viscosity; porous media (Brinkman, Darcy–Forchheimer); multiphase and free surface (M13); validation by the lid-driven cavity, backward-facing step, cylinder wake (Strouhal) and turbulent channel; octree refinement shared with the hex mesher; wgpu backend (deterministic per device, checked against the CPU) (CPU core: done — `fieldcraft-lbm` with D3Q19 TRT and Guo forcing, halfway bounce-back and moving walls, slip and periodic faces, Zou–He velocity and pressure faces, exact voxelisation of obstacle bodies, momentum-exchange forces per face; fluid materials, fluid domains and fluid steps in the model; `model.fluid_domain.*`, `solve.fluid`; verified by Poiseuille channel and pipe, Couette, Taylor–Green decay, sphere-array Stokes drag and mass conservation; Schäfer–Turek 2D-1 as a benchmark) | started |
| M13 Fluid–structure interaction | Immersed-boundary coupling of the lattice Boltzmann fluid with the explicit or implicit structure; interface force transfer; sub-cycling; Aitken then interface quasi-Newton coupling; free-surface flow | planned |
| M14 Blast and impact fluids | EOS-driven fluids in the explicit solver: ALE multi-material or SPH, with fluid–structure contact | planned |
| M15 Nonlinear implicit core | Newton–Raphson with line search, automatic increments and cutbacks, convergence on force, displacement and energy; geometric nonlinearity (total and updated Lagrangian, large rotations for shells and beams, follower pressure); every `fem` material behind one interface with its consistent tangent (plasticity, damage and thermal strain from the explicit solver reused implicitly); arc-length (Riks) for snap-through; linear buckling (eigen) with preload stress stiffening, and imperfections from buckling modes; nonlinear stabilisation; restart. Verified by the elastica, Lee's frame, the snap-through arch, the hinged cylindrical shell and plastic collapse loads | planned |
| M16 Structural dynamics | Implicit transient (Newmark, HHT-α, generalised-α); modal superposition transient; steady-state harmonic (direct and modal), with Rayleigh, modal, structural and material damping; random vibration from PSDs and response spectrum (SRSS, CQC); complex eigenvalues with damping; rotating machinery (Campbell diagrams, gyroscopic terms); substructures (Craig–Bampton) | planned |
| M17 Constitutive library and material library | Elastic: transversely isotropic, fully anisotropic (21 constants), temperature-dependent. Elastomers: hyperelastic neo-Hookean, Mooney–Rivlin, Yeoh, Ogden, Arruda–Boyce, Gent, Marlow, with Mullins softening and finite-strain viscoelasticity (Prony series; parallel networks after Bergström–Boyce), foams. Viscoelasticity: small- and finite-strain Prony series, time–temperature superposition (WLF, Arrhenius), storage and loss moduli for harmonic steps. Viscoplasticity and creep: Norton power law, time and strain hardening, Perzyna, Anand, Chaboche combined hardening. Plasticity: Hill anisotropic, Drucker–Prager, Mohr–Coulomb, Cam-clay, crushable foam, concrete damaged plasticity, Gurson. Fluids: Newtonian and non-Newtonian viscosity shared with M12. Material library: curated, cited data sets (steels, aluminium and titanium alloys, polymers, elastomers, composites, tissues) with units and temperature dependence; calibration from test data (uniaxial, biaxial, shear, relaxation, DMA) by least squares with Drucker stability checks; user materials as a safe Rust trait | planned |
| M18 Composites and anisotropy | Material orientations (rectangular, cylindrical, spherical, from geometry edges and faces, per-element fields, draping of fibres over curved parts); layups on shells and continuum shells, ply stacks on swept hex; classical lamination theory checks; ply stresses and strains through the thickness; failure indices (Tsai–Wu, Tsai–Hill, Hashin, Puck, LaRC) and progressive damage; homogenisation (rule of mixtures, Mori–Tanaka, RVEs with periodic boundary conditions); delamination through M20's cohesive zones. Verified by laminate closed forms and the NAFEMS composite benchmarks | planned |
| M19 Coupled fields | On the DOF framework, each a degree of freedom beside the displacements: piezoelectricity (electric potential, d/e coupling and permittivity matrices, voltage and charge conditions, resonance and impedance through M16 harmonic steps); poroelasticity (Biot, u–p, Darcy flow, consolidation; Terzaghi and Mandel verification; soils and biphasic tissue); electro-thermal (Joule heating) and thermo-electro-mechanical coupling; acoustics (Helmholtz elements, structure–acoustic coupling, absorbing boundaries); low-frequency electromagnetics later | planned |
| M20 Damage, fracture, fatigue and adhesion | Continuum damage beyond Johnson–Cook (Lemaitre, ductile and shear criteria) for implicit and explicit; fracture mechanics (J-integral and stress intensity factors, crack-front meshes from the hex mesher; XFEM later); fatigue (S–N and ε–N with mean-stress corrections, rainflow counting, Paris crack growth); adhesion and debonding by cohesive zones (bilinear and exponential traction–separation, mixed mode with Benzeggagh–Kenane) as cohesive elements and cohesive contact; adhesive joints. Verified by DCB, ENF and MMB delamination tests and published fatigue data | planned |
| M21 Biomechanics and biomaterials | Soft tissue: Holzapfel–Gasser–Ogden fibre-reinforced hyperelasticity with dispersion, Fung, transversely isotropic models; biphasic and poro-hyperelastic cartilage (M19); active muscle (Hill-type); hydrogel swelling. Bone: density-dependent moduli from CT data, strain-energy-density remodelling (Huiskes, Beaupré). Growth and remodelling by kinematic growth (F = Fe·Fg). Implants and biomaterials (titanium, PEEK, UHMWPE) from the M17 library. Verified against published experiments with their tolerances | planned |
| M22 Design studies | Parameters of the SolidCraft design driven from FieldCraft: parametric sweeps, design of experiments, response surfaces and sensitivities; topology optimisation (SIMP with filters, manufacturing constraints); size and shape optimisation; submodelling (driven boundaries from a global model); uncertainty quantification | planned |
| M23 Wave propagation and ultrasound | Elastic, acoustic and coupled waves from the explicit solver's 1D bar today to guided and ultrasonic waves, by two methods. Finite differences first, for fast 2D (then 3D) ultrasound on regular grids: staggered-grid velocity–stress FDTD (Virieux) and the elastodynamic finite integration technique for solids, the rotated staggered grid for anisotropic media, a k-space pseudospectral scheme for weakly heterogeneous tissue and water, all on grids voxelised from the face-tagged geometry by the LBM's exact voxeliser, with heterogeneous, layered and fluid–solid media, CPML boundaries, threads and the GPU backend; staircased curved boundaries scatter spuriously, so the FD grid is checked against the finite elements on curved parts. Finite elements for curved geometry and coupling with structures: spectral elements (high-order Gauss–Lobatto–Legendre hexes with diagonal mass) on the hex meshes, and a mesh check in elements per wavelength with the dispersion error it implies; absorbing boundaries (convolutional PML, absorbing layers with increasing damping) and infinite media; tone-burst sources (Hann-windowed cycles), point, line and surface excitation, and piezoelectric transducers (M19); anisotropic media (composites, crystals) and viscoelastic, power-law-in-frequency attenuation; fluid–solid interfaces and fluid-loaded plates; ultrasound in water and tissue, nonlinear acoustics (Westervelt, KZK) for focused ultrasound. Guided waves: dispersion curves by semi-analytical finite elements (SAFE) for plates, pipes, rails and layered and anisotropic laminates — Lamb, Rayleigh, Love and SH modes — with phase and group velocities and mode shapes; mode-selective excitation. Output: A-scans and B-scans at sensors, wavefield snapshots, 2D FFT (frequency–wavenumber) for mode identification, and time–frequency diagrams of any signal — short-time Fourier spectrograms, continuous wavelet transforms (Morlet), reassigned spectrograms and smoothed pseudo Wigner–Ville — with the SAFE or Rayleigh–Lamb group-velocity curves overlaid as arrival times, and group velocities extracted from the ridges. GPU paths (M12's backend) for long runs. Verified by Lamb's problem (point load on a half-space), Rayleigh-wave speed, Rayleigh–Lamb dispersion, Love waves in a layer over a half-space, reflection and transmission at interfaces, and published guided-wave measurements | planned |
| Continuous: verification and validation | Every capability checked against theory (closed forms), experiments (published measurements) and published benchmarks (NAFEMS, vendor benchmark and verification manuals such as Abaqus's), each case our own model in `tests/oracle/` with its cited reference and tolerance; `cargo xtask oracle` runs them and writes docs/oracle.md; once a case matches, our result is frozen as a fixture so fidelity cannot regress (docs/verification.md). Runner, fixtures and CI job: done; 26 theory cases (patch tests of every solid element, cantilevers, Lamé in 3D, plane strain and axisymmetric, Kirsch in 3D and plane stress, rotating disc and cylinder, beam frequencies, couplings, explicit waves, impact and J2 plasticity, CDT invariants), 9 published benchmarks (MacNeal–Harder solid tests, Scordelis–Lo with solids, NAFEMS LE1 in 3D and 2D, LE10, FV32) and 9 pending cases with citations (shells, thermal, static plasticity, Taylor bar, CFD); `mesh.block` mapped blocks and 2D patches build their meshes | started |
| Continuous: performance | CPU first, deterministic: results never depend on the thread count (fixed partitions, sums in a fixed order; checked by hashing results on 1, 2 and 7 threads). Supernodal left-looking Cholesky (11–15× faster than the column solver on one thread), parallel element matrices, stresses and Lanczos products, explicit element updates and LBM cell blocks on rayon threads (done — `fieldcraft-parallel`, `threads` on the solve commands, `FIELDCRAFT_THREADS`); parallel forward/back substitution and explicit tet4 assembly; GPU paths later, within a stated tolerance of the CPU | started |
| Continuous: desktop and agents | Desktop app (viewport, model tree, commands, control channel, the open design drawn, `ui.capture` of the whole window offscreen: done; toolbar of every capability from the catalogue, ready or coming soon with its milestone, icons drawn with VectorCraft, docs/features.md: done; the Craft-family shell — title bar, workspaces and ribbon drop-downs, browser, context panel, command search, journal timeline, light and dark themes — native file pickers with background opening, drag and drop and recent files, samples and one-click Solve: done; MCP server over stdio, headless or bridged to the app, with read and write roots, docs/mcp.md: done; caps labels in Inter SemiBold; the README's analysis video recorded through MCP by `tools/demo-video`: done; support, load, reference-point and coupling symbols in the viewport and headless renders, with their browser toggles: done; a camera parameter for screenshots, a ribbon that follows the command being run: in progress), browser build, command schema as the public API | started |
## Next
In progress, in this order of landing:
1. Tet quality: sliver repair and Delaunay refinement to a size field, so curved and filleted parts
(the filleted bracket) solve on tets (M2).
2. Octree all-hex for any part (M6), the project's main meshing goal.
3. The analysis video regenerated with the setup's symbols (done: support, load, reference-point
and coupling symbols in the viewport and headless renders), captions and an orbit (screenshot
camera and the ribbon following the command: done).
4. A Scordelis–Lo refinement study (32×32×2, 64×64×4, hex20 full and reduced) separating
discretisation error from the solid-versus-shell model difference (−0.33 % today).
5. The nonlinear implicit core (M15), the gate for contact (M7), elastomers and viscoelasticity
(M17), composite failure (M18), adhesion (M20) and tissues (M21).
## Gap review (2026-10-14)
What exists and what is missing, by area; each gap is in a milestone above.
| Area | Today | Missing |
|---|---|---|
| Solution procedures | Linear static, frequency (Lanczos), steady and transient heat, coupled temperature–displacement, explicit dynamics, LBM flow | Nonlinear static and geometric nonlinearity, arc-length, buckling (M15); implicit, harmonic, random and spectrum dynamics (M16) |
| Contact, friction, adhesion | Explicit planar rigid walls (frictionless); couplings, springs, dashpots | Implicit and explicit deformable contact, tie, friction laws, thermal contact, wear (M7); cohesive adhesion and debonding (M20) |
| Materials | Isotropic and orthotropic elasticity, density, thermal, J2 plasticity (bilinear, table, Johnson–Cook), Johnson–Cook damage and erosion, Newtonian fluids | Hyperelastic and elastomers, viscoelasticity, viscoplasticity and creep, anisotropic and pressure-dependent plasticity, non-Newtonian viscosity, a cited material library and calibration (M17) |
| Composites and anisotropy | Orthotropic constants | Orientations, layups, ply results, failure criteria, homogenisation (M18) |
| Coupled fields | Thermal–structural (one way and coupled) | Piezoelectric, poroelastic, electro-thermal, acoustics (M19) |
| Failure | Johnson–Cook damage and element erosion (explicit) | Fracture mechanics, fatigue, cohesive zones, composite progressive damage (M18, M20) |
| Biomechanics | — | Tissue models, cartilage, muscle, bone remodelling, growth (M21) |
| Fluid dynamics | LBM D3Q19 TRT, walls, inlets/outlets, obstacle forces | Turbulence with wall models, thermal and conjugate heat transfer, non-Newtonian, porous media, multiphase, GPU (M12, M13) |
| Wave propagation | One-dimensional elastic waves and impact in the explicit solver (bar cases in the oracle) | A 2D/3D finite-difference ultrasound solver (velocity–stress FDTD, EFIT, k-space pseudospectral) on voxelised geometry, time–frequency diagrams (spectrogram, wavelet, Wigner–Ville) with dispersion overlays, spectral elements, absorbing boundaries, tone-burst and transducer sources, attenuation, Lamb/Rayleigh/Love guided waves and SAFE dispersion curves, ultrasound in fluids and tissue, nonlinear acoustics, A/B-scans and frequency–wavenumber analysis (M23) |
| Design | — | Parametric studies on SolidCraft parameters, optimisation, submodelling (M22) |
-11
View File
@@ -1,11 +0,0 @@
# Security policy
FieldCraft is young; only `main` and the latest release get fixes.
Please **don't open a public issue** for a security problem. Report it privately through the
repository's [Security tab](https://github.com/jyviko/fieldcraft/security/advisories/new) with
what you found, how to reproduce it (a model, deck or script), the version and platform, and the
impact you expect.
Reports are especially useful for opening untrusted models, decks or scripts (crashes, runaway
memory or CPU, path tricks) and for the control channel once it exists.
File diff suppressed because it is too large. Load diff
-15
View File
@@ -1,15 +0,0 @@
[package]
name = "fieldcraft-cli"
description = "FieldCraft from the command line: list commands, run scripts, serve MCP"
version.workspace = true
edition.workspace = true
license.workspace = true
[lints]
workspace = true
[dependencies]
fieldcraft-engine = { workspace = true }
fieldcraft-io = { workspace = true }
fieldcraft-mcp = { workspace = true }
serde_json = { workspace = true }
-156
View File
@@ -1,156 +0,0 @@
//! fieldcraft-cli commands
//! fieldcraft-cli run <script.json>
//! fieldcraft-cli features
//! fieldcraft-cli mcp [--connect ADDR | --headless] [--automation-read-root DIR] [--automation-write-root DIR]
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
#![forbid(unsafe_code)]
use std::path::Path;
use std::process::ExitCode;
use fieldcraft_engine::Session;
use serde_json::json;
const USAGE: &str = "\
usage:
fieldcraft-cli commands list every command with its parameters
fieldcraft-cli run <script.json> run a script (a JSON array of {\"command\", \"params\"})
and print the model summary
fieldcraft-cli features print docs/features.md (every capability, ready or
coming soon) from the capability catalogue
fieldcraft-cli mcp [options] serve the Model Context Protocol on stdin/stdout
(docs/mcp.md):
--headless an in-process session (the default)
--connect ADDR drive the app at ADDR (`fieldcraft --control PORT`);
headless when it cannot be reached
--automation-read-root DIR files may be read only inside DIR
--automation-write-root DIR files may be written only inside DIR (with either root,
the access a root left out is not granted)
";
/// Largest script accepted (bytes).
const MAX_SCRIPT_BYTES: u64 = 256 * 1024 * 1024;
fn main() -> ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
let result = match args.first().map(String::as_str) {
Some("commands") => {
for c in fieldcraft_engine::commands() {
println!("{:<24} {:<18} {}", c.id, c.label, c.params);
}
Ok(())
}
Some("features") => {
print!("{}", fieldcraft_engine::catalogue::features_page());
Ok(())
}
Some("mcp") => mcp(args.get(1..).unwrap_or(&[])),
Some("run") => args.get(1).ok_or_else(|| format!("run needs a script\n\n{USAGE}")).and_then(|p| run(p)),
Some("-h" | "--help" | "help") | None => {
print!("{USAGE}");
Ok(())
}
Some(other) => Err(format!("unknown command `{other}`\n\n{USAGE}")),
};
match result {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("error: {e}");
ExitCode::FAILURE
}
}
}
/// The `mcp` options: each given once, as `--flag value` or `--flag=value`.
fn mcp_options(args: &[String]) -> Result<fieldcraft_mcp::Options, String> {
let mut connect = None;
let mut headless = false;
let mut read = None;
let mut write = None;
let mut it = args.iter();
while let Some(arg) = it.next() {
let (flag, inline) = match arg.split_once('=') {
Some((f, v)) if f.starts_with("--") => (f, Some(v.to_string())),
_ => (arg.as_str(), None),
};
let mut value = || inline.clone().or_else(|| it.next().cloned()).filter(|v| !v.is_empty()).ok_or_else(|| format!("{flag} needs a value"));
let slot = match flag {
"--headless" if inline.is_none() => {
if std::mem::replace(&mut headless, true) {
return Err("--headless is given twice".into());
}
continue;
}
"--connect" => &mut connect,
"--automation-read-root" => &mut read,
"--automation-write-root" => &mut write,
other => return Err(format!("mcp: unknown option `{other}`\n\n{USAGE}")),
};
if slot.replace(value()?).is_some() {
return Err(format!("{flag} is given twice"));
}
}
if headless && connect.is_some() {
return Err("--connect and --headless exclude each other".into());
}
let roots = match (&read, &write) {
(None, None) => fieldcraft_io::roots::Roots::default(),
_ => fieldcraft_io::roots::Roots::new(read.as_deref().map(Path::new), write.as_deref().map(Path::new)).map_err(|e| e.to_string())?,
};
Ok(fieldcraft_mcp::Options { connect, roots })
}
fn mcp(args: &[String]) -> Result<(), String> {
let (backend, note) = fieldcraft_mcp::backend(mcp_options(args)?)?;
if let Some(note) = note {
eprintln!("fieldcraft-cli mcp: {note}");
}
let mut server = fieldcraft_mcp::Server::new(backend);
server.serve(std::io::stdin().lock(), std::io::stdout().lock()).map_err(|e| format!("mcp: {e}"))
}
fn run(path: &str) -> Result<(), String> {
let size = std::fs::metadata(path).map_err(|e| format!("{path}: {e}"))?.len();
if size > MAX_SCRIPT_BYTES {
return Err(format!("{path}: larger than {} MB", MAX_SCRIPT_BYTES / (1024 * 1024)));
}
let text = std::fs::read_to_string(path).map_err(|e| format!("{path}: {e}"))?;
let script: serde_json::Value = serde_json::from_str(&text).map_err(|e| format!("{path}: {e}"))?;
let mut session = Session::default();
session.run_script(&script).map_err(|e| e.to_string())?;
let info = session.execute("model.info", &json!({})).map_err(|e| e.to_string())?;
println!("{}", serde_json::to_string_pretty(&info).map_err(|e| e.to_string())?);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
fn opts(args: &[&str]) -> Result<fieldcraft_mcp::Options, String> {
mcp_options(&args.iter().map(|s| s.to_string()).collect::<Vec<_>>())
}
#[test]
fn mcp_options_are_checked() {
let dir = std::env::temp_dir();
let d = dir.to_string_lossy();
assert!(opts(&[]).unwrap().connect.is_none());
assert_eq!(opts(&["--connect", "127.0.0.1:7070"]).unwrap().connect.as_deref(), Some("127.0.0.1:7070"));
assert_eq!(opts(&["--connect=127.0.0.1:7070"]).unwrap().connect.as_deref(), Some("127.0.0.1:7070"));
assert!(opts(&["--automation-read-root", &d]).unwrap().roots.is_confined());
assert!(opts(&[&format!("--automation-write-root={d}")]).unwrap().roots.is_confined());
for bad in [
vec!["--connect"],
vec!["--connect", "a", "--connect", "b"],
vec!["--headless", "--headless"],
vec!["--headless", "--connect", "a"],
vec!["--automation-read-root", "/no/such/folder"],
vec!["--automation-read-root="],
vec!["--nope"],
vec!["--headless=yes"],
] {
assert!(opts(&bad).is_err(), "{bad:?}");
}
}
}
-20
View File
@@ -1,20 +0,0 @@
[package]
name = "fieldcraft"
description = "FieldCraft desktop app"
version.workspace = true
edition.workspace = true
license.workspace = true
publish = false
[lints]
workspace = true
[dependencies]
fieldcraft-engine = { workspace = true }
fieldcraft-ui-egui = { workspace = true }
fieldcraft-io = { workspace = true }
rfd = { workspace = true }
eframe = { workspace = true, features = ["default_fonts", "wgpu", "accesskit", "wayland", "x11"] }
egui = { workspace = true }
serde_json = { workspace = true }
log = { workspace = true }
-161
View File
@@ -1,161 +0,0 @@
//! Loopback JSON-lines control server: one request per line, one reply per line. Agents and
//! tests drive the app through it; the UI thread answers each request between frames
//! (`fieldcraft_ui_egui::control`).
//!
//! Adapted from SolidCraft's `apps/solidcraft/src/control_server.rs` (MIT OR Apache-2.0), see
//! ATTRIBUTION.md.
use std::io::{BufRead, BufReader, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{Receiver, Sender, channel};
use std::time::Duration;
use fieldcraft_ui_egui::ControlRequest;
use serde_json::{Value, json};
/// Longest request line (bytes).
const MAX_LINE: usize = 16 * 1024 * 1024;
/// Connections served at once. The channel has no authentication beyond being bound to
/// loopback, so a flood must not be able to spawn threads without end.
const MAX_CONNECTIONS: usize = 16;
/// Lines that are not JSON before the connection is closed, so garbage cannot loop forever.
const MAX_BAD_LINES: usize = 8;
/// How long a request waits for the UI thread.
const REPLY_TIMEOUT: Duration = Duration::from_secs(60);
static OPEN: AtomicUsize = AtomicUsize::new(0);
pub fn start(port: u16, ctx: egui::Context) -> Receiver<ControlRequest> {
let (tx, rx) = channel::<ControlRequest>();
let listener = match TcpListener::bind(("127.0.0.1", port)) {
Ok(l) => l,
Err(e) => {
eprintln!("fieldcraft: control server failed to bind 127.0.0.1:{port}: {e}");
return rx;
}
};
eprintln!("fieldcraft: control server listening on 127.0.0.1:{port}");
std::thread::spawn(move || {
for stream in listener.incoming().flatten() {
if OPEN.fetch_add(1, Ordering::Relaxed) >= MAX_CONNECTIONS {
OPEN.fetch_sub(1, Ordering::Relaxed);
let mut refused = stream;
let _ = writeln!(refused, "{}", json!({"ok": false, "error": "too many connections"}));
continue;
}
let tx = tx.clone();
let ctx = ctx.clone();
std::thread::spawn(move || {
serve(stream, tx, ctx);
OPEN.fetch_sub(1, Ordering::Relaxed);
});
}
});
rx
}
/// One line without its newline, or `None` at the end of the stream. A client that sends
/// gigabytes with no newline would otherwise make this thread allocate until the process is
/// killed, so the line is refused as soon as it passes `max`.
fn read_line(r: &mut impl BufRead, max: usize) -> std::io::Result<Option<Vec<u8>>> {
let mut line = Vec::new();
loop {
let (done, used) = {
let available = r.fill_buf()?;
if available.is_empty() {
return Ok((!line.is_empty()).then_some(line));
}
match available.iter().position(|b| *b == b'\n') {
Some(i) => {
line.extend_from_slice(available.get(..i).unwrap_or(&[]));
(true, i + 1)
}
None => {
line.extend_from_slice(available);
(false, available.len())
}
}
};
r.consume(used);
if line.len() > max {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "request too large"));
}
if done {
return Ok(Some(line));
}
}
}
fn serve(stream: TcpStream, tx: Sender<ControlRequest>, ctx: egui::Context) {
let Ok(read) = stream.try_clone() else { return };
let mut out = stream;
let mut reader = BufReader::new(read);
let mut bad = 0usize;
loop {
let line = match read_line(&mut reader, MAX_LINE) {
Ok(Some(l)) => String::from_utf8_lossy(&l).into_owned(),
Ok(None) => break,
Err(e) => {
let _ = writeln!(out, "{}", json!({"ok": false, "error": e.to_string()}));
break;
}
};
if line.trim().is_empty() {
continue;
}
let reply = match serde_json::from_str::<Value>(&line) {
Ok(msg) => {
let id = msg.get("id").cloned().unwrap_or(Value::Null);
let method = msg.get("method").and_then(Value::as_str).unwrap_or("").to_string();
let params = msg.get("params").cloned().unwrap_or(json!({}));
let (req, rrx) = ControlRequest::new(method, params);
if tx.send(req).is_err() {
break;
}
ctx.request_repaint();
let mut r = rrx.recv_timeout(REPLY_TIMEOUT).unwrap_or_else(|_| json!({"ok": false, "error": "timeout"}));
if let Some(o) = r.as_object_mut() {
o.insert("id".into(), id);
}
r
}
Err(e) => {
bad += 1;
json!({"ok": false, "error": format!("bad JSON: {e}")})
}
};
if writeln!(out, "{reply}").is_err() || bad >= MAX_BAD_LINES {
break;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
/// A request longer than the cap is refused instead of allocated.
#[test]
fn lines_past_the_cap_are_refused() {
let flood = vec![b'A'; MAX_LINE + 2];
let mut r = BufReader::new(flood.as_slice());
let e = read_line(&mut r, MAX_LINE).unwrap_err();
assert_eq!(e.kind(), std::io::ErrorKind::InvalidData);
}
/// Lines split on newlines, blank lines kept, no trailing newline needed; a line spanning
/// several reads arrives whole.
#[test]
fn lines_split_on_newlines() {
let text = b"{\"a\":1}\n\n{\"b\":2}\nlast".to_vec();
let mut r = BufReader::with_capacity(3, text.as_slice());
let mut got = Vec::new();
while let Some(line) = read_line(&mut r, MAX_LINE).unwrap() {
got.push(String::from_utf8(line).unwrap());
}
assert_eq!(got, vec!["{\"a\":1}", "", "{\"b\":2}", "last"]);
let mut r = BufReader::with_capacity(4, b"0123456789\n".as_slice());
assert!(read_line(&mut r, 5).is_err());
}
}
-232
View File
@@ -1,232 +0,0 @@
//! FieldCraft desktop app.
//!
//! Usage: `fieldcraft [--sample [NAME]] [--control PORT] [FILE…]` (files open as if dropped on the
//! window; NAME is a sample of `fieldcraft_engine::sample`, `parts` by default)
//!
//! `--sample` opens a sample model (`fieldcraft_engine::sample`). `--control PORT` (or
//! `FIELDCRAFT_CONTROL_PORT`) starts a localhost JSON-lines control server:
//! `{"id":1,"method":"engine.execute","params":{"command":"model.info","params":{}}}`. See
//! `fieldcraft_ui_egui::control` and docs/control-protocol.md.
#![cfg_attr(all(target_os = "windows", not(debug_assertions)), windows_subsystem = "windows")]
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
#![forbid(unsafe_code)]
mod control_server;
use fieldcraft_engine::Session;
use fieldcraft_engine::autosave::{self, Autosaver};
use fieldcraft_ui_egui::{Filter, ModelApp, Services};
const USAGE: &str = "usage: fieldcraft [--sample [parts|cantilever|impact]] [--control PORT] [FILE…] (FILE: .fieldcraft, .solidcraft or .3mf)";
const DEPTH_BITS: u8 = 24;
/// The window draws its own caption buttons where the OS ones would sit apart from the app bar.
const CUSTOM_TITLEBAR: bool = !cfg!(target_os = "macos");
const MSAA: u16 = 4;
/// The window and Dock icon: the 256 px export of the application icon (assets/app-icon).
const ICON_PNG: &[u8] = include_bytes!("../../../assets/app-icon/icon.iconset/icon_128x128@2x.png");
/// The application icon for the window; eframe's default icon if the PNG cannot be decoded.
fn app_icon() -> egui::IconData {
eframe::icon_data::from_png_bytes(ICON_PNG).unwrap_or_else(|e| {
log::warn!("app icon: {e}");
egui::IconData::default()
})
}
/// How often unsaved changes are autosaved for recovery (seconds).
const AUTOSAVE_SECONDS: f64 = 30.0;
struct App {
app: ModelApp,
/// Autosave for crash recovery (`None` when the recovery folder is unavailable).
autosaver: Option<Autosaver>,
/// App time of the last autosave check.
autosaved_at: f64,
}
impl App {
fn autosave(&mut self) {
if let Some(a) = &mut self.autosaver
&& let Err(e) = a.save(&self.app.session)
{
log::warn!("autosave: {e}");
}
}
}
impl eframe::App for App {
fn logic(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
self.app.logic(ctx);
if self.app.now - self.autosaved_at >= AUTOSAVE_SECONDS {
self.autosaved_at = self.app.now;
self.autosave();
}
if self.autosaver.is_some() {
ctx.request_repaint_after(std::time::Duration::from_secs_f64(AUTOSAVE_SECONDS));
}
}
fn on_exit(&mut self) {
if let Some(a) = self.autosaver.take()
&& let Err(e) = a.close(&self.app.session)
{
log::warn!("autosave: {e}");
}
}
fn raw_input_hook(&mut self, _ctx: &egui::Context, raw: &mut egui::RawInput) {
self.app.raw_input_hook(raw);
}
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
self.app.ui(ui);
}
}
/// Native file pickers and the recent-files file, for the UI.
fn services() -> Services {
let dialog = |filters: &[Filter]| filters.iter().fold(rfd::FileDialog::new(), |d, f| d.add_filter(f.name, f.extensions));
Services {
pick_open: Some(Box::new(move |filters: &[Filter]| dialog(filters).pick_file().map(|p| p.to_string_lossy().to_string()))),
pick_save: Some(Box::new(move |name: &str, filters: &[Filter]| {
dialog(filters).set_file_name(name).save_file().map(|p| p.to_string_lossy().to_string())
})),
// Beside the recovery folder in the per-user data folder.
recent_path: fieldcraft_io::recovery::default_dir().and_then(|d| d.parent().map(|p| p.join("recent.json"))),
}
}
/// Command-line options.
#[derive(Debug, Default, PartialEq)]
struct Args {
/// The sample to open (`--sample [NAME]`).
sample: Option<String>,
control: Option<u16>,
/// Files to open (models, designs, tagged meshes).
files: Vec<String>,
}
fn parse_args(args: impl IntoIterator<Item = String>, env_port: Option<String>) -> Result<Option<Args>, String> {
let mut out = Args { control: env_port.and_then(|p| p.trim().parse().ok()), ..Default::default() };
let mut args = args.into_iter().peekable();
while let Some(a) = args.next() {
match a.as_str() {
"--sample" => {
// An optional sample name follows.
let name = args.peek().filter(|a| fieldcraft_engine::sample::find(a).is_some()).cloned();
if name.is_some() {
args.next();
}
out.sample = Some(name.unwrap_or_else(|| "parts".into()));
}
"--control" => {
let port = args.next().ok_or("--control needs a port")?;
out.control = Some(port.parse().map_err(|_| format!("--control: `{port}` is not a port number"))?);
}
"--version" | "-V" => {
println!("fieldcraft {}", fieldcraft_ui_egui::VERSION);
return Ok(None);
}
"--help" | "-h" => {
println!("{USAGE}");
return Ok(None);
}
other if other.starts_with('-') => return Err(format!("unknown argument `{other}`\n{USAGE}")),
file => out.files.push(file.to_string()),
}
}
Ok(Some(out))
}
fn main() -> eframe::Result {
let args = match parse_args(std::env::args().skip(1), std::env::var("FIELDCRAFT_CONTROL_PORT").ok()) {
Ok(Some(a)) => a,
Ok(None) => return Ok(()),
Err(e) => {
eprintln!("fieldcraft: {e}");
std::process::exit(2);
}
};
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_title("FieldCraft")
.with_icon(app_icon())
.with_inner_size([1400.0, 900.0])
.with_min_inner_size([960.0, 600.0])
.with_drag_and_drop(true)
// The app bar is the title bar (as in the other Craft apps): on macOS under the
// traffic lights, elsewhere with its own caption buttons and resize zones.
.with_decorations(!CUSTOM_TITLEBAR)
.with_fullsize_content_view(true)
.with_titlebar_shown(false)
.with_title_shown(false),
depth_buffer: DEPTH_BITS,
multisampling: MSAA,
..Default::default()
};
eframe::run_native(
"FieldCraft",
options,
Box::new(move |cc| {
let mut app = ModelApp::new(Session::default()).with_services(services());
app.custom_titlebar = CUSTOM_TITLEBAR;
app.integrated_titlebar = cfg!(target_os = "macos");
if let Some(rs) = &cc.wgpu_render_state {
let info = rs.adapter.get_info();
eprintln!("fieldcraft: graphics {:?} {}, MSAA {}x (requested {MSAA}x)", info.backend, info.name, rs.msaa_samples);
app.set_wgpu(rs, DEPTH_BITS, rs.msaa_samples, &cc.egui_ctx);
}
if let Some(port) = args.control {
app = app.with_control(control_server::start(port, cc.egui_ctx.clone()));
}
if let Some(name) = &args.sample {
app.open_sample(name);
}
for f in &args.files {
app.open_path(f);
}
let autosaver = autosave::default_dir().and_then(|dir| {
let listed = app.session.execute("file.recovery.list", &serde_json::json!({"dir": dir}));
let recoverable = listed.ok().and_then(|v| v.as_array().map(Vec::len)).unwrap_or(0);
if recoverable > 0 {
app.set_status(format!("{recoverable} autosaved model(s) can be recovered: File › Recover…"), false);
}
Autosaver::new(&dir).map_err(|e| log::warn!("autosave unavailable: {e}")).ok()
});
Ok(Box::new(App { app, autosaver, autosaved_at: 0.0 }))
}),
)
}
#[cfg(test)]
mod tests {
#[test]
fn the_app_icon_decodes() {
let icon = super::app_icon();
assert_eq!((icon.width, icon.height), (256, 256));
assert_eq!(icon.rgba.len(), 256 * 256 * 4);
}
use super::*;
fn parse(a: &[&str], env: Option<&str>) -> Result<Option<Args>, String> {
parse_args(a.iter().map(|s| s.to_string()), env.map(str::to_string))
}
#[test]
fn arguments() {
assert_eq!(parse(&[], None), Ok(Some(Args::default())));
assert_eq!(
parse(&["--sample", "--control", "7070"], None),
Ok(Some(Args { sample: Some("parts".into()), control: Some(7070), files: vec![] }))
);
assert_eq!(parse(&[], Some("9000")), Ok(Some(Args { control: Some(9000), ..Default::default() })));
assert_eq!(parse(&[], Some("nope")), Ok(Some(Args::default())));
assert!(parse(&["--control"], None).is_err());
assert!(parse(&["--control", "99999"], None).is_err());
assert!(parse(&["--frobnicate"], None).is_err());
assert_eq!(parse(&["--sample", "impact"], None).map(|a| a.and_then(|a| a.sample)), Ok(Some("impact".into())));
let a = parse(&["--sample", "x.fieldcraft"], None).unwrap().unwrap();
assert_eq!((a.sample.as_deref(), a.files), (Some("parts"), vec!["x.fieldcraft".to_string()]));
assert_eq!(parse(&["a.fieldcraft", "--sample"], None).map(|a| a.map(|a| a.files)), Ok(Some(vec!["a.fieldcraft".to_string()])));
assert_eq!(parse(&["--help"], None), Ok(None));
}
}
Binary file not shown.
@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<clipPath id="clip-path-1">
<path d="M320 100 L704 100 C854 100 924 170 924 320 L924 704 C924 854 854 924 704 924 L320 924 C170 924 100 854 100 704 L100 320 C100 170 170 100 320 100 Z"/>
</clipPath>
<radialGradient id="radial-gradient-1" cx="0" cy="0" r="578" gradientTransform="matrix(1 0 0 0.5 512 720)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#4f8a82"/>
<stop offset="0.3" stop-color="#4f8a82" stop-opacity="0.9"/>
<stop offset="0.65" stop-color="#4f8a82" stop-opacity="0.35"/>
<stop offset="1" stop-color="#4f8a82" stop-opacity="0"/>
</radialGradient>
</defs>
<title>FieldCraft icon floor grid (Dark)</title>
<g id="Floor_grid" data-name="Floor grid" clip-path="url(#clip-path-1)">
<path id="floor_grid" data-name="floor grid" d="M154.62 100 L100 131.53 M869.38 100 L924 131.53 M368.82 100 L100 255.2 M655.18 100 L924 255.2 M583.01 100 L100 378.87 M440.99 100 L924 378.87 M797.21 100 L100 502.53 M226.79 100 L924 502.53 M924 150.47 L100 626.2 M100 150.47 L924 626.2 M924 274.13 L100 749.87 M100 274.13 L924 749.87 M924 397.8 L100 873.53 M100 397.8 L924 873.53 M924 521.47 L226.79 924 M100 521.47 L797.21 924 M924 645.13 L440.99 924 M100 645.13 L583.01 924 M924 768.8 L655.18 924 M100 768.8 L368.82 924 M924 892.47 L869.38 924 M100 892.47 L154.62 924" fill="none" stroke="url(#radial-gradient-1)" stroke-width="3" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<clipPath id="clip-path-1">
<path d="M320 100 L704 100 C854 100 924 170 924 320 L924 704 C924 854 854 924 704 924 L320 924 C170 924 100 854 100 704 L100 320 C100 170 170 100 320 100 Z"/>
</clipPath>
<radialGradient id="radial-gradient-1" cx="0" cy="0" r="578" gradientTransform="matrix(1 0 0 0.5 512 720)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#7fa8a2"/>
<stop offset="0.3" stop-color="#7fa8a2" stop-opacity="0.9"/>
<stop offset="0.65" stop-color="#7fa8a2" stop-opacity="0.35"/>
<stop offset="1" stop-color="#7fa8a2" stop-opacity="0"/>
</radialGradient>
</defs>
<title>FieldCraft icon floor grid</title>
<g id="Floor_grid" data-name="Floor grid" clip-path="url(#clip-path-1)">
<path id="floor_grid" data-name="floor grid" d="M154.62 100 L100 131.53 M869.38 100 L924 131.53 M368.82 100 L100 255.2 M655.18 100 L924 255.2 M583.01 100 L100 378.87 M440.99 100 L924 378.87 M797.21 100 L100 502.53 M226.79 100 L924 502.53 M924 150.47 L100 626.2 M100 150.47 L924 626.2 M924 274.13 L100 749.87 M100 274.13 L924 749.87 M924 397.8 L100 873.53 M100 397.8 L924 873.53 M924 521.47 L226.79 924 M100 521.47 L797.21 924 M924 645.13 L440.99 924 M100 645.13 L583.01 924 M924 768.8 L655.18 924 M100 768.8 L368.82 924 M924 892.47 L869.38 924 M100 892.47 L154.62 924" fill="none" stroke="url(#radial-gradient-1)" stroke-width="3" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<linearGradient id="linear-gradient-1" x1="512" y1="141" x2="512" y2="376.622" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#86e3d3"/>
<stop offset="1" stop-color="#4cc4b1"/>
</linearGradient>
<linearGradient id="linear-gradient-2" x1="512" y1="457.259" x2="512" y2="755.042" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#86e3d3"/>
<stop offset="1" stop-color="#4cc4b1"/>
</linearGradient>
<linearGradient id="linear-gradient-3" x1="512" y1="209.598" x2="512" y2="624.284" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#20b39f"/>
<stop offset="1" stop-color="#118c7c"/>
</linearGradient>
<linearGradient id="linear-gradient-4" x1="512" y1="588.018" x2="512" y2="878.381" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#20b39f"/>
<stop offset="1" stop-color="#118c7c"/>
</linearGradient>
<linearGradient id="linear-gradient-5" x1="512" y1="335.738" x2="512" y2="878.381" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#0f786d"/>
<stop offset="1" stop-color="#0a544e"/>
</linearGradient>
<linearGradient id="linear-gradient-6" x1="512" y1="558.616" x2="512" y2="658.304" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#0b665e"/>
<stop offset="1" stop-color="#04302c"/>
</linearGradient>
</defs>
<title>FieldCraft icon part</title>
<g id="Part">
<path id="wall_top" data-name="wall top" d="M512 141 L825.3 321.88 L730.48 376.62 L417.19 195.74 Z" fill="url(#linear-gradient-1)"/>
<path id="base_top" data-name="base top" d="M401.19 457.26 L714.48 638.14 L512 755.04 L198.7 574.16 Z M521.64 643.71 C555.35 624.24 555.35 592.68 521.64 573.22 C487.92 553.75 433.26 553.75 399.55 573.22 C365.83 592.68 365.83 624.24 399.55 643.71 C433.26 663.17 487.92 663.17 521.64 643.71 Z" fill="url(#linear-gradient-2)"/>
<path id="wall_front" data-name="wall front" d="M409.19 209.6 L722.48 390.48 L722.48 624.28 L409.19 443.4 Z" fill="url(#linear-gradient-3)"/>
<path id="base_front" data-name="base front" d="M190.7 588.02 L504 768.9 L504 878.38 L190.7 697.5 Z" fill="url(#linear-gradient-4)"/>
<path id="end" d="M833.3 697.5 L520 878.38 L520 768.9 L738.48 642.76 L738.48 390.48 L833.3 335.74 Z" fill="url(#linear-gradient-5)"/>
<path id="bolt_hole" data-name="bolt hole" d="M521.64 643.71 C487.92 663.17 433.26 663.17 399.55 643.71 C365.83 624.24 365.83 592.68 399.55 573.22 C433.26 553.75 487.92 553.75 521.64 573.22 C555.35 592.68 555.35 624.24 521.64 643.71 Z" fill="url(#linear-gradient-6)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<clipPath id="clip-path-1">
<path d="M512 141 L825.3 321.88 L730.48 376.62 L417.19 195.74 Z M401.19 457.26 L714.48 638.14 L512 755.04 L198.7 574.16 Z M521.64 643.71 C555.35 624.24 555.35 592.68 521.64 573.22 C487.92 553.75 433.26 553.75 399.55 573.22 C365.83 592.68 365.83 624.24 399.55 643.71 C433.26 663.17 487.92 663.17 521.64 643.71 Z M409.19 209.6 L722.48 390.48 L722.48 624.28 L409.19 443.4 Z M190.7 588.02 L504 768.9 L504 878.38 L190.7 697.5 Z M833.3 697.5 L520 878.38 L520 768.9 L738.48 642.76 L738.48 390.48 L833.3 335.74 Z"/>
</clipPath>
</defs>
<title>FieldCraft icon mesh</title>
<g id="Mesh" clip-path="url(#clip-path-1)">
<path id="hexahedral_mesh" data-name="hexahedral mesh" d="M460.59 482.32 L242.11 608.46 M679.07 608.46 L460.59 734.6 M354.57 484.18 L405.97 513.86 M624.45 640 L675.86 669.67 M299.95 515.71 L351.35 545.39 M569.83 671.53 L621.24 701.21 M245.32 547.25 L296.73 576.92 M515.21 703.07 L566.62 732.75 M460.59 482.32 L460.59 230.04 M563.41 170.68 L460.59 230.04 M515.21 513.86 L515.21 261.57 M618.03 202.22 L515.21 261.57 M569.83 545.39 L569.83 293.11 M672.65 233.75 L569.83 293.11 M624.45 576.93 L624.45 324.65 M727.27 265.29 L624.45 324.65 M679.07 608.46 L679.07 356.18 M781.89 296.82 L679.07 356.18 M409.19 389.57 L730.48 575.07 M409.19 326.5 L730.48 512 M409.19 263.43 L730.48 448.93 M460.59 170.68 L781.89 356.18 M242.11 727.18 L242.11 608.46 M296.73 758.72 L296.73 640 M351.35 790.25 L351.35 671.53 M405.97 821.79 L405.97 703.07 M460.59 853.32 L460.59 734.6 M190.7 638.14 L512 823.64 M781.89 727.18 L781.89 356.18 M730.48 756.86 L730.48 638.14 M675.86 788.39 L675.86 669.67 M621.24 819.93 L621.24 701.21 M566.62 851.47 L566.62 732.75 M833.3 638.14 L512 823.64 M833.3 578.78 L730.48 638.14 M833.3 515.71 L730.48 575.07 M833.3 452.64 L730.48 512 M833.3 389.57 L730.48 448.93 M460.59 558.62 L460.59 482.32 M433.29 561.17 L405.97 513.86 M399.55 573.22 L351.35 545.39 M378.69 592.7 L296.73 576.92 M374.26 608.46 L242.11 608.46 M487.89 561.17 L515.21 513.86 M378.69 624.22 L296.73 640 M521.64 573.22 L569.83 545.39 M399.55 643.71 L351.35 671.53 M542.49 592.7 L624.45 576.92 M433.29 655.75 L405.97 703.06 M546.92 608.46 L679.07 608.46 M542.49 624.22 L624.45 640 M521.64 643.71 L569.83 671.53 M487.89 655.75 L515.21 703.07 M460.59 658.3 L460.59 734.6 M545.74 657.62 L540.09 660.8 L534.3 663.92 L528.33 666.99 L522.16 670.03 L515.76 673.05 L509.11 676.08 L502.15 679.15 L494.85 682.27 L487.14 685.51 L478.94 688.9 L470.14 692.52 L460.59 696.45 L451.05 692.52 L442.25 688.9 L434.05 685.51 L426.34 682.27 L419.03 679.15 L412.08 676.08 L405.42 673.05 L399.02 670.03 L392.86 666.99 L386.89 663.92 L381.09 660.8 L375.45 657.62 L369.94 654.36 L364.54 651.01 L359.22 647.57 L353.95 644.01 L348.72 640.31 L343.47 636.47 L338.16 632.45 L332.74 628.24 L327.14 623.79 L321.26 619.05 L315 613.97 L308.19 608.46 L315 602.95 L321.26 597.87 L327.14 593.13 L332.74 588.68 L338.16 584.47 L343.47 580.45 L348.72 576.61 L353.95 572.91 L359.22 569.35 L364.54 565.91 L369.94 562.56 L375.45 559.3 L381.09 556.12 L386.89 553 L392.86 549.93 L399.02 546.89 L405.42 543.87 L412.08 540.84 L419.03 537.77 L426.34 534.65 L434.05 531.41 L442.25 528.02 L451.05 524.4 L460.59 520.47 L470.14 524.4 L478.94 528.02 L487.14 531.41 L494.85 534.65 L502.15 537.77 L509.11 540.84 L515.76 543.87 L522.16 546.89 L528.33 549.93 L534.3 553 L540.09 556.12 L545.74 559.3 L551.25 562.56 L556.65 565.91 L561.97 569.35 L567.23 572.91 L572.47 576.61 L577.72 580.45 L583.02 584.47 L588.44 588.68 L594.05 593.13 L599.92 597.87 L606.19 602.95 L613 608.46 L606.19 613.97 L599.92 619.05 L594.05 623.79 L588.44 628.24 L583.02 632.45 L577.72 636.47 L572.47 640.31 L567.23 644.01 L561.97 647.57 L556.65 651.01 L551.25 654.36 Z" fill="none" stroke="#ffffff" stroke-width="4.5" stroke-linejoin="round" opacity="0.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

-116
View File
@@ -1,116 +0,0 @@
{
"fill": "system-light",
"groups": [
{
"layers": [
{
"glass-specializations": [
{
"appearance": "tinted",
"value": true
}
],
"image-name": "03-mesh.svg",
"name": "03-mesh",
"position": {
"scale": 0.9,
"translation-in-points": [
0,
0
]
}
}
],
"name": "03 Mesh",
"shadow": {
"kind": "none",
"opacity": 0
},
"specular": false,
"translucency": {
"enabled": false,
"value": 0.3
}
},
{
"layers": [
{
"glass-specializations": [
{
"appearance": "tinted",
"value": true
}
],
"image-name": "02-part.svg",
"name": "02-part",
"position": {
"scale": 0.9,
"translation-in-points": [
0,
0
]
}
}
],
"name": "02 Part",
"shadow": {
"kind": "none",
"opacity": 0
},
"specular": true,
"translucency": {
"enabled": false,
"value": 0.3
}
},
{
"layers": [
{
"fill": "none",
"glass-specializations": [
{
"value": false
},
{
"appearance": "tinted",
"value": true
}
],
"image-name-specializations": [
{
"value": "01-floor.svg"
},
{
"appearance": "dark",
"value": "01-floor-dark.svg"
}
],
"name": "01-floor",
"position": {
"scale": 0.9,
"translation-in-points": [
0,
0
]
}
}
],
"name": "01 Floor",
"shadow": {
"kind": "none",
"opacity": 0
},
"specular": false,
"translucency": {
"enabled": false,
"value": 0.3
}
}
],
"supported-platforms": {
"circles": [
"watchOS"
],
"squares": "shared"
}
}
-27
View File
@@ -1,27 +0,0 @@
# FieldCraft application icon
FieldCraft's mark is an L-shaped bracket with a bolt hole, drawn in isometric view and covered
by a structured hexahedral mesh with an O-grid around the hole. Its faces are separated by
transparent gaps rather than painted edge lines, so the backdrop shows through them in every
appearance. It is original artwork, attributed in `ATTRIBUTION.md`, and shares the Craft
family's layout (rounded-square backdrop, isometric floor grid, lit top faces) in its own teal.
Everything here is generated by `cargo xtask app-icon` (`xtask/src/app_icon.rs`), which computes
the geometry and draws it with VectorCraft's command-line tool (`VECTORCRAFT_CLI`, else
`vectorcraft-cli` on the PATH). Change the recipe there and rerun it; do not edit the exports by
hand. It runs on macOS (sips, iconutil, `xcrun actool`) with ImageMagick (`magick`) installed.
| File | What it is |
|---|---|
| `icon.vectorcraft`, `icon.svg`, `icon.png` | The full icon on its backdrop, 1024 × 1024 |
| `icon-small.vectorcraft`, `icon-small.svg`, `icon-small.png` | Small-size artwork used at 16–32 px: no mesh or floor grid, faces edge to edge |
| `icon.iconset/`, `icon.icns` | macOS iconset (sips) and its iconutil compilation |
| `icon.ico` | Windows icon, 16–256 px |
| `FieldCraft.icon/` | Icon Composer document: floor grid (Default and Dark), part and mesh layers, each scaled to 90% |
| `layers/*.vectorcraft` | Editable sources of the Icon Composer layers |
| `Assets.car` | `actool` compilation of `FieldCraft.icon` for macOS 26 and later (needs Xcode 26 or later; the task skips it with a note otherwise) |
The desktop app embeds `icon.iconset/icon_128x128@2x.png` as its window and Dock icon
(`apps/fieldcraft/src/main.rs`). There is no macOS bundle yet; packaging will copy
`Assets.car` and `icon.icns` into `Contents/Resources` and name `FieldCraft` in
`CFBundleIconName` / `CFBundleIconFile`.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

-48
View File
@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<filter id="filter-1" filterUnits="userSpaceOnUse" x="67" y="67" width="890" height="890" data-vc-blend="multiply" color-interpolation-filters="sRGB"><feGaussianBlur in="SourceAlpha" stdDeviation="7"/><feOffset dx="0" dy="10" result="shadow"/><feFlood flood-color="#1d3b38" flood-opacity="0.22"/><feComposite in2="shadow" operator="in" result="paint"/><feMerge><feMergeNode in="paint"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<linearGradient id="linear-gradient-1" x1="512" y1="100" x2="512" y2="924" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fbfdfd"/>
<stop offset="1" stop-color="#dbe5e4"/>
</linearGradient>
<linearGradient id="linear-gradient-2" x1="512" y1="141" x2="512" y2="385.86" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#86e3d3"/>
<stop offset="1" stop-color="#4cc4b1"/>
</linearGradient>
<linearGradient id="linear-gradient-3" x1="512" y1="452.64" x2="512" y2="764.28" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#86e3d3"/>
<stop offset="1" stop-color="#4cc4b1"/>
</linearGradient>
<linearGradient id="linear-gradient-4" x1="512" y1="200.36" x2="512" y2="638.14" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#20b39f"/>
<stop offset="1" stop-color="#118c7c"/>
</linearGradient>
<linearGradient id="linear-gradient-5" x1="512" y1="578.78" x2="512" y2="883" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#20b39f"/>
<stop offset="1" stop-color="#118c7c"/>
</linearGradient>
<linearGradient id="linear-gradient-6" x1="512" y1="326.5" x2="512" y2="883" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#0f786d"/>
<stop offset="1" stop-color="#0a544e"/>
</linearGradient>
<linearGradient id="linear-gradient-7" x1="512" y1="558.616" x2="512" y2="658.304" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#0b665e"/>
<stop offset="1" stop-color="#04302c"/>
</linearGradient>
</defs>
<title>FieldCraft application icon, small sizes</title>
<g id="Backdrop">
<g filter="url(#filter-1)">
<path id="backdrop" d="M320 100 L704 100 C854 100 924 170 924 320 L924 704 C924 854 854 924 704 924 L320 924 C170 924 100 854 100 704 L100 320 C100 170 170 100 320 100 Z" fill="url(#linear-gradient-1)"/>
</g>
</g>
<g id="Part">
<path id="wall_top" data-name="wall top" d="M512 141 L833.3 326.5 L730.48 385.86 L409.19 200.36 Z" fill="url(#linear-gradient-2)"/>
<path id="base_top" data-name="base top" d="M409.19 452.64 L730.48 638.14 L512 764.28 L190.7 578.78 Z M521.64 643.71 C555.35 624.24 555.35 592.68 521.64 573.22 C487.92 553.75 433.26 553.75 399.55 573.22 C365.83 592.68 365.83 624.24 399.55 643.71 C433.26 663.17 487.92 663.17 521.64 643.71 Z" fill="url(#linear-gradient-3)"/>
<path id="wall_front" data-name="wall front" d="M409.19 200.36 L730.48 385.86 L730.48 638.14 L409.19 452.64 Z" fill="url(#linear-gradient-4)"/>
<path id="base_front" data-name="base front" d="M190.7 578.78 L512 764.28 L512 883 L190.7 697.5 Z" fill="url(#linear-gradient-5)"/>
<path id="end" d="M833.3 697.5 L512 883 L512 764.28 L730.48 638.14 L730.48 385.86 L833.3 326.5 Z" fill="url(#linear-gradient-6)"/>
<path id="bolt_hole" data-name="bolt hole" d="M521.64 643.71 C487.92 663.17 433.26 663.17 399.55 643.71 C365.83 624.24 365.83 592.68 399.55 573.22 C433.26 553.75 487.92 553.75 521.64 573.22 C555.35 592.68 555.35 624.24 521.64 643.71 Z" fill="url(#linear-gradient-7)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

-66
View File
@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="1024" viewBox="0 0 1024 1024">
<defs>
<filter id="filter-1" filterUnits="userSpaceOnUse" x="67" y="67" width="890" height="890" data-vc-blend="multiply" color-interpolation-filters="sRGB"><feGaussianBlur in="SourceAlpha" stdDeviation="7"/><feOffset dx="0" dy="10" result="shadow"/><feFlood flood-color="#1d3b38" flood-opacity="0.22"/><feComposite in2="shadow" operator="in" result="paint"/><feMerge><feMergeNode in="paint"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<linearGradient id="linear-gradient-1" x1="512" y1="100" x2="512" y2="924" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#fbfdfd"/>
<stop offset="1" stop-color="#dbe5e4"/>
</linearGradient>
<clipPath id="clip-path-1">
<path d="M320 100 L704 100 C854 100 924 170 924 320 L924 704 C924 854 854 924 704 924 L320 924 C170 924 100 854 100 704 L100 320 C100 170 170 100 320 100 Z"/>
</clipPath>
<radialGradient id="radial-gradient-1" cx="0" cy="0" r="578" gradientTransform="matrix(1 0 0 0.5 512 720)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#7fa8a2"/>
<stop offset="0.3" stop-color="#7fa8a2" stop-opacity="0.9"/>
<stop offset="0.65" stop-color="#7fa8a2" stop-opacity="0.35"/>
<stop offset="1" stop-color="#7fa8a2" stop-opacity="0"/>
</radialGradient>
<linearGradient id="linear-gradient-2" x1="512" y1="141" x2="512" y2="376.622" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#86e3d3"/>
<stop offset="1" stop-color="#4cc4b1"/>
</linearGradient>
<linearGradient id="linear-gradient-3" x1="512" y1="457.259" x2="512" y2="755.042" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#86e3d3"/>
<stop offset="1" stop-color="#4cc4b1"/>
</linearGradient>
<linearGradient id="linear-gradient-4" x1="512" y1="209.598" x2="512" y2="624.284" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#20b39f"/>
<stop offset="1" stop-color="#118c7c"/>
</linearGradient>
<linearGradient id="linear-gradient-5" x1="512" y1="588.018" x2="512" y2="878.381" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#20b39f"/>
<stop offset="1" stop-color="#118c7c"/>
</linearGradient>
<linearGradient id="linear-gradient-6" x1="512" y1="335.738" x2="512" y2="878.381" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#0f786d"/>
<stop offset="1" stop-color="#0a544e"/>
</linearGradient>
<linearGradient id="linear-gradient-7" x1="512" y1="558.616" x2="512" y2="658.304" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#0b665e"/>
<stop offset="1" stop-color="#04302c"/>
</linearGradient>
<clipPath id="clip-path-2">
<path d="M512 141 L825.3 321.88 L730.48 376.62 L417.19 195.74 Z M401.19 457.26 L714.48 638.14 L512 755.04 L198.7 574.16 Z M521.64 643.71 C555.35 624.24 555.35 592.68 521.64 573.22 C487.92 553.75 433.26 553.75 399.55 573.22 C365.83 592.68 365.83 624.24 399.55 643.71 C433.26 663.17 487.92 663.17 521.64 643.71 Z M409.19 209.6 L722.48 390.48 L722.48 624.28 L409.19 443.4 Z M190.7 588.02 L504 768.9 L504 878.38 L190.7 697.5 Z M833.3 697.5 L520 878.38 L520 768.9 L738.48 642.76 L738.48 390.48 L833.3 335.74 Z"/>
</clipPath>
</defs>
<title>FieldCraft application icon</title>
<g id="Backdrop">
<g filter="url(#filter-1)">
<path id="backdrop" d="M320 100 L704 100 C854 100 924 170 924 320 L924 704 C924 854 854 924 704 924 L320 924 C170 924 100 854 100 704 L100 320 C100 170 170 100 320 100 Z" fill="url(#linear-gradient-1)"/>
</g>
</g>
<g id="Floor_grid" data-name="Floor grid" clip-path="url(#clip-path-1)">
<path id="floor_grid" data-name="floor grid" d="M154.62 100 L100 131.53 M869.38 100 L924 131.53 M368.82 100 L100 255.2 M655.18 100 L924 255.2 M583.01 100 L100 378.87 M440.99 100 L924 378.87 M797.21 100 L100 502.53 M226.79 100 L924 502.53 M924 150.47 L100 626.2 M100 150.47 L924 626.2 M924 274.13 L100 749.87 M100 274.13 L924 749.87 M924 397.8 L100 873.53 M100 397.8 L924 873.53 M924 521.47 L226.79 924 M100 521.47 L797.21 924 M924 645.13 L440.99 924 M100 645.13 L583.01 924 M924 768.8 L655.18 924 M100 768.8 L368.82 924 M924 892.47 L869.38 924 M100 892.47 L154.62 924" fill="none" stroke="url(#radial-gradient-1)" stroke-width="3" stroke-linejoin="round"/>
</g>
<g id="Part">
<path id="wall_top" data-name="wall top" d="M512 141 L825.3 321.88 L730.48 376.62 L417.19 195.74 Z" fill="url(#linear-gradient-2)"/>
<path id="base_top" data-name="base top" d="M401.19 457.26 L714.48 638.14 L512 755.04 L198.7 574.16 Z M521.64 643.71 C555.35 624.24 555.35 592.68 521.64 573.22 C487.92 553.75 433.26 553.75 399.55 573.22 C365.83 592.68 365.83 624.24 399.55 643.71 C433.26 663.17 487.92 663.17 521.64 643.71 Z" fill="url(#linear-gradient-3)"/>
<path id="wall_front" data-name="wall front" d="M409.19 209.6 L722.48 390.48 L722.48 624.28 L409.19 443.4 Z" fill="url(#linear-gradient-4)"/>
<path id="base_front" data-name="base front" d="M190.7 588.02 L504 768.9 L504 878.38 L190.7 697.5 Z" fill="url(#linear-gradient-5)"/>
<path id="end" d="M833.3 697.5 L520 878.38 L520 768.9 L738.48 642.76 L738.48 390.48 L833.3 335.74 Z" fill="url(#linear-gradient-6)"/>
<path id="bolt_hole" data-name="bolt hole" d="M521.64 643.71 C487.92 663.17 433.26 663.17 399.55 643.71 C365.83 624.24 365.83 592.68 399.55 573.22 C433.26 553.75 487.92 553.75 521.64 573.22 C555.35 592.68 555.35 624.24 521.64 643.71 Z" fill="url(#linear-gradient-7)"/>
</g>
<g id="Mesh" clip-path="url(#clip-path-2)">
<path id="hexahedral_mesh" data-name="hexahedral mesh" d="M460.59 482.32 L242.11 608.46 M679.07 608.46 L460.59 734.6 M354.57 484.18 L405.97 513.86 M624.45 640 L675.86 669.67 M299.95 515.71 L351.35 545.39 M569.83 671.53 L621.24 701.21 M245.32 547.25 L296.73 576.92 M515.21 703.07 L566.62 732.75 M460.59 482.32 L460.59 230.04 M563.41 170.68 L460.59 230.04 M515.21 513.86 L515.21 261.57 M618.03 202.22 L515.21 261.57 M569.83 545.39 L569.83 293.11 M672.65 233.75 L569.83 293.11 M624.45 576.93 L624.45 324.65 M727.27 265.29 L624.45 324.65 M679.07 608.46 L679.07 356.18 M781.89 296.82 L679.07 356.18 M409.19 389.57 L730.48 575.07 M409.19 326.5 L730.48 512 M409.19 263.43 L730.48 448.93 M460.59 170.68 L781.89 356.18 M242.11 727.18 L242.11 608.46 M296.73 758.72 L296.73 640 M351.35 790.25 L351.35 671.53 M405.97 821.79 L405.97 703.07 M460.59 853.32 L460.59 734.6 M190.7 638.14 L512 823.64 M781.89 727.18 L781.89 356.18 M730.48 756.86 L730.48 638.14 M675.86 788.39 L675.86 669.67 M621.24 819.93 L621.24 701.21 M566.62 851.47 L566.62 732.75 M833.3 638.14 L512 823.64 M833.3 578.78 L730.48 638.14 M833.3 515.71 L730.48 575.07 M833.3 452.64 L730.48 512 M833.3 389.57 L730.48 448.93 M460.59 558.62 L460.59 482.32 M433.29 561.17 L405.97 513.86 M399.55 573.22 L351.35 545.39 M378.69 592.7 L296.73 576.92 M374.26 608.46 L242.11 608.46 M487.89 561.17 L515.21 513.86 M378.69 624.22 L296.73 640 M521.64 573.22 L569.83 545.39 M399.55 643.71 L351.35 671.53 M542.49 592.7 L624.45 576.92 M433.29 655.75 L405.97 703.06 M546.92 608.46 L679.07 608.46 M542.49 624.22 L624.45 640 M521.64 643.71 L569.83 671.53 M487.89 655.75 L515.21 703.07 M460.59 658.3 L460.59 734.6 M545.74 657.62 L540.09 660.8 L534.3 663.92 L528.33 666.99 L522.16 670.03 L515.76 673.05 L509.11 676.08 L502.15 679.15 L494.85 682.27 L487.14 685.51 L478.94 688.9 L470.14 692.52 L460.59 696.45 L451.05 692.52 L442.25 688.9 L434.05 685.51 L426.34 682.27 L419.03 679.15 L412.08 676.08 L405.42 673.05 L399.02 670.03 L392.86 666.99 L386.89 663.92 L381.09 660.8 L375.45 657.62 L369.94 654.36 L364.54 651.01 L359.22 647.57 L353.95 644.01 L348.72 640.31 L343.47 636.47 L338.16 632.45 L332.74 628.24 L327.14 623.79 L321.26 619.05 L315 613.97 L308.19 608.46 L315 602.95 L321.26 597.87 L327.14 593.13 L332.74 588.68 L338.16 584.47 L343.47 580.45 L348.72 576.61 L353.95 572.91 L359.22 569.35 L364.54 565.91 L369.94 562.56 L375.45 559.3 L381.09 556.12 L386.89 553 L392.86 549.93 L399.02 546.89 L405.42 543.87 L412.08 540.84 L419.03 537.77 L426.34 534.65 L434.05 531.41 L442.25 528.02 L451.05 524.4 L460.59 520.47 L470.14 524.4 L478.94 528.02 L487.14 531.41 L494.85 534.65 L502.15 537.77 L509.11 540.84 L515.76 543.87 L522.16 546.89 L528.33 549.93 L534.3 553 L540.09 556.12 L545.74 559.3 L551.25 562.56 L556.65 565.91 L561.97 569.35 L567.23 572.91 L572.47 576.61 L577.72 580.45 L583.02 584.47 L588.44 588.68 L594.05 593.13 L599.92 597.87 L606.19 602.95 L613 608.46 L606.19 613.97 L599.92 619.05 L594.05 623.79 L588.44 628.24 L583.02 632.45 L577.72 636.47 L572.47 640.31 L567.23 644.01 L561.97 647.57 L556.65 651.01 L551.25 654.36 Z" fill="none" stroke="#ffffff" stroke-width="4.5" stroke-linejoin="round" opacity="0.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>assembly.instance</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M8 10 L13 12.5 L13 17.5 L8 20 L3 17.5 L3 12.5 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 12.5 L8 15 L13 12.5 M8 15 L8 20" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 4 L21 6.5 L21 11.5 L16 14 L11 11.5 L11 6.5 Z" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11 6.5 L16 9 L21 6.5 M16 9 L16 14" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 8 L13.5 6 M12.19 8.13 L13.5 6 L11 6.05" fill="none" stroke="#dde2ea" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>deck.read</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M8 3 L16 3 L20 7 L20 21 L8 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 3 L16 7 L20 7" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11 10 L17 10 M11 13 L17 13 M11 16 L15 16" fill="none" stroke="#dde2ea" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 15 L9 15 M6.19 16.53 L9 15 L6.19 13.47" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 808 B

Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>deck.write.abaqus</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M4 3 L12 3 L16 7 L16 21 L4 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 3 L12 7 L16 7" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 10 L13 10 M7 13 L13 13 M7 16 L11 16" fill="none" stroke="#dde2ea" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 15 L21 15 M18.19 16.53 L21 15 L18.19 13.47" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 6 C16 4.619 17.119 3.5 18.5 3.5 C19.881 3.5 21 4.619 21 6 C21 7.381 19.881 8.5 18.5 8.5 C17.119 8.5 16 7.381 16 6 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>deck.write.lsdyna</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M4 3 L12 3 L16 7 L16 21 L4 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 3 L12 7 L16 7" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 10 L13 10 M7 13 L13 13 M7 16 L11 16" fill="none" stroke="#dde2ea" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 15 L21 15 M18.19 16.53 L21 15 L18.19 13.47" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.5 3 L21.3 8.2 L15.7 8.2 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 962 B

Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>deck.write.nastran</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M4 3 L12 3 L16 7 L16 21 L4 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 3 L12 7 L16 7" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 10 L13 10 M7 13 L13 13 M7 16 L11 16" fill="none" stroke="#dde2ea" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 15 L21 15 M18.19 16.53 L21 15 L18.19 13.47" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 3.5 L21 3.5 L21 8.5 L16 8.5 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 967 B

Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>edit.redo</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M19 9 L10 9 C7.239 9 5 11.239 5 14 C5 16.761 7.239 19 10 19 L16 19" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 5.5 L19.5 9 L16 12.5" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 562 B

Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>edit.undo</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M5 9 L14 9 C16.761 9 19 11.239 19 14 C19 16.761 16.761 19 14 19 L8 19" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 5.5 L4.5 9 L8 12.5" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 562 B

Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>file.open</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 5 L9 5 L11 7 L20 7 L20 19 L3 19 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 17 L12 10 M13.53 12.81 L12 10 L10.47 12.81" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 556 B

Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>file.recover</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M4.5 12 C4.505 15.538 6.981 18.591 10.442 19.327 C13.903 20.062 17.406 18.278 18.849 15.048 C20.291 11.817 19.279 8.018 16.421 5.932 C13.564 3.846 9.637 4.041 7 6.4" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.4 4.6 L7 6.4 L5.6 10.2" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 8 L12 12 L15 14" fill="none" stroke="#dde2ea" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 796 B

Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>file.sample</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 10 L11 6 L19 10 L19 18 L11 22 L3 18 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 10 L11 14 L19 10 M11 14 L11 22" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.5 1.5 L19.44 4.206 L22.304 4.264 L20.022 5.994 L20.851 8.736 L18.5 7.1 L16.149 8.736 L16.978 5.994 L14.696 4.264 L17.56 4.206 Z" fill="#f0b44a" stroke="#f0b44a" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 775 B

Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>file.save</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 14 L3 20 L21 20 L21 14" fill="none" stroke="#dde2ea" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 3 L12 15 M10.47 12.19 L12 15 L13.53 12.19" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 542 B

Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>file.save_as</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 14 L3 20 L21 20 L21 14" fill="none" stroke="#dde2ea" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 3 L9 15 M5.8 12 L9 15 L12.2 12" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 12 L19.5 6.5 L21.5 8.5 L16 14 L13.5 14.5 Z" fill="#2d4e70" stroke="#f0b44a" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 695 B

Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>geometry.bodies</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M9 8 L15 11 L15 18 L9 21 L3 18 L3 11 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 11 L9 14 L15 11 M9 14 L9 21" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 4 L19 6.5 L19 13 L16 14.5" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 4 L9 6.5 L9 7" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 817 B

Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>geometry.datum</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 15 L9 9 L21 9 L15 15 Z" fill="#2d4e70" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 12 L12 3 M13.53 5.81 L12 3 L10.47 5.81" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.5 12 C10.5 11.172 11.172 10.5 12 10.5 C12.828 10.5 13.5 11.172 13.5 12 C13.5 12.828 12.828 13.5 12 13.5 C11.172 13.5 10.5 12.828 10.5 12 Z" fill="#4f9ce8"/>
<path d="M12 15 L12 21" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.5 2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 869 B

Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>geometry.import.mesh</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 13 L12 9 L21 13 L12 17 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.5 11 L16.5 15 M7.5 15 L16.5 11 M12 9 L12 17" fill="none" stroke="#dde2ea" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 13 L3 16 L12 20 L21 16 L21 13" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 2 L12 8 M10.47 5.19 L12 8 L13.53 5.19" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 836 B

Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>geometry.midsurface</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 9 L9 4 L21 4 L15 9 Z" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 14 L9 9 L21 9 L15 14 Z" fill="#2d4e70" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 19 L9 14 L21 14 L15 19 Z" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 670 B

Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>geometry.open</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M13 6 L20 9.5 L20 17.5 L13 21 L6 17.5 L6 9.5 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 9.5 L13 13 L20 9.5 M13 13 L13 21" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 3 L9 9 M5.93 8.1 L9 9 L8.1 5.93" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 705 B

Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>geometry.partition</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M12 3 L20 7 L20 16 L12 20 L4 16 L4 7 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 7 L12 11 L20 7 M12 11 L12 20" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 5 L16 9 M16 9 L16 18 M16 9 L16 9" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 5 L8 14 L16 18" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 829 B

Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>geometry.tessellate</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 12 C3 7.029 7.029 3 12 3 C16.971 3 21 7.029 21 12 C21 16.971 16.971 21 12 21 C7.029 21 3 16.971 3 12 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 12 L19.79 16.5 M12 12 L12 21 M12 12 L4.21 16.5 M12 12 L4.21 7.5 M12 12 L12 3 M12 12 L19.79 7.5" fill="none" stroke="#4f9ce8" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.79 16.5 L12 21 L4.21 16.5 L4.21 7.5 L12 3 L19.79 7.5 Z" fill="none" stroke="#4f9ce8" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 818 B

Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>interaction.bolt</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M7 3 L17 3 L17 7 L7 7 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.5 7 L14.5 7 L14.5 21 L9.5 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.5 11 L14.5 12.5 M9.5 14 L14.5 15.5 M9.5 17 L14.5 18.5" fill="none" stroke="#dde2ea" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 13 L4 6 M5.2 8.19 L4 6 L2.8 8.19" fill="none" stroke="#f0b44a" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 13 L20 20 M18.8 17.81 L20 20 L21.2 17.81" fill="none" stroke="#f0b44a" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 991 B

Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>interaction.connector</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M2.2 18 C2.2 17.006 3.006 16.2 4 16.2 C4.994 16.2 5.8 17.006 5.8 18 C5.8 18.994 4.994 19.8 4 19.8 C3.006 19.8 2.2 18.994 2.2 18 Z" fill="#dde2ea"/>
<path d="M18.2 6 C18.2 5.006 19.006 4.2 20 4.2 C20.994 4.2 21.8 5.006 21.8 6 C21.8 6.994 20.994 7.8 20 7.8 C19.006 7.8 18.2 6.994 18.2 6 Z" fill="#dde2ea"/>
<path d="M4 18 L10 14 M14 10 L20 6" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.2 12 C9.2 10.454 10.454 9.2 12 9.2 C13.546 9.2 14.8 10.454 14.8 12 C14.8 13.546 13.546 14.8 12 14.8 C10.454 14.8 9.2 13.546 9.2 12 Z" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 965 B

Binary file not shown.
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>interaction.contact.find</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 8 C3 5.239 5.239 3 8 3 C10.761 3 13 5.239 13 8 C13 10.761 10.761 13 8 13 C5.239 13 3 10.761 3 8 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 13 L13 13 L13 21 L3 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 15 C12 12.791 13.791 11 16 11 C18.209 11 20 12.791 20 15 C20 17.209 18.209 19 16 19 C13.791 19 12 17.209 12 15 Z" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.83 17.83 L21.83 20.83" fill="none" stroke="#4f9ce8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 981 B

Binary file not shown.
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>interaction.contact.general</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 8 C3 5.239 5.239 3 8 3 C10.761 3 13 5.239 13 8 C13 10.761 10.761 13 8 13 C5.239 13 3 10.761 3 8 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 15 L21 15 L21 21 L3 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 3 L21 3 L21 10 L14 10 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.5 14.3 C7.476 14.607 8.524 14.607 9.5 14.3" fill="none" stroke="#4f9ce8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 6 L13 10" fill="none" stroke="#4f9ce8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>interaction.contact.pair</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M6 9 C6 5.686 8.686 3 12 3 C15.314 3 18 5.686 18 9 C18 12.314 15.314 15 12 15 C8.686 15 6 12.314 6 9 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 15 L21 15 L21 21 L3 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 15 L16 15" fill="none" stroke="#4f9ce8" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 745 B

Binary file not shown.
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<title>interaction.fsi</title>
<g id="Layer_1" data-name="Layer 1">
<path d="M3 7 L3.23 6.71 L3.46 6.43 L3.69 6.17 L3.92 5.94 L4.15 5.75 L4.38 5.61 L4.6 5.53 L4.83 5.5 L5.06 5.53 L5.29 5.61 L5.52 5.75 L5.75 5.94 L5.98 6.17 L6.21 6.43 L6.44 6.71 L6.67 7 L6.9 7.29 L7.12 7.57 L7.35 7.83 L7.58 8.06 L7.81 8.25 L8.04 8.39 L8.27 8.47 L8.5 8.5 L8.73 8.47 L8.96 8.39 L9.19 8.25 L9.42 8.06 L9.65 7.83 L9.88 7.57 L10.1 7.29 L10.33 7 L10.56 6.71 L10.79 6.43 L11.02 6.17 L11.25 5.94 L11.48 5.75 L11.71 5.61 L11.94 5.53 L12.17 5.5 L12.4 5.53 L12.62 5.61 L12.85 5.75 L13.08 5.94 L13.31 6.17 L13.54 6.43 L13.77 6.71 L14 7" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 12 L3.23 11.71 L3.46 11.43 L3.69 11.17 L3.92 10.94 L4.15 10.75 L4.38 10.61 L4.6 10.53 L4.83 10.5 L5.06 10.53 L5.29 10.61 L5.52 10.75 L5.75 10.94 L5.98 11.17 L6.21 11.43 L6.44 11.71 L6.67 12 L6.9 12.29 L7.12 12.57 L7.35 12.83 L7.58 13.06 L7.81 13.25 L8.04 13.39 L8.27 13.47 L8.5 13.5 L8.73 13.47 L8.96 13.39 L9.19 13.25 L9.42 13.06 L9.65 12.83 L9.88 12.57 L10.1 12.29 L10.33 12 L10.56 11.71 L10.79 11.43 L11.02 11.17 L11.25 10.94 L11.48 10.75 L11.71 10.61 L11.94 10.53 L12.17 10.5 L12.4 10.53 L12.62 10.61 L12.85 10.75 L13.08 10.94 L13.31 11.17 L13.54 11.43 L13.77 11.71 L14 12" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 17 L3.23 16.71 L3.46 16.43 L3.69 16.17 L3.92 15.94 L4.15 15.75 L4.38 15.61 L4.6 15.53 L4.83 15.5 L5.06 15.53 L5.29 15.61 L5.52 15.75 L5.75 15.94 L5.98 16.17 L6.21 16.43 L6.44 16.71 L6.67 17 L6.9 17.29 L7.12 17.57 L7.35 17.83 L7.58 18.06 L7.81 18.25 L8.04 18.39 L8.27 18.47 L8.5 18.5 L8.73 18.47 L8.96 18.39 L9.19 18.25 L9.42 18.06 L9.65 17.83 L9.88 17.57 L10.1 17.29 L10.33 17 L10.56 16.71 L10.79 16.43 L11.02 16.17 L11.25 15.94 L11.48 15.75 L11.71 15.61 L11.94 15.53 L12.17 15.5 L12.4 15.53 L12.62 15.61 L12.85 15.75 L13.08 15.94 L13.31 16.17 L13.54 16.43 L13.77 16.71 L14 17" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17 21 C17 15 18 9 20 3" fill="none" stroke="#dde2ea" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M15 21 L21 21" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.
Loaded 100 of 1015 files, more files were not shown because too many files have changed in this diff. Show more