Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ebb9f16dc | ||
|
|
0899587127 | ||
|
|
e900f41ce3 | ||
|
|
bf325bb234 | ||
|
|
29ae46ff84 | ||
|
|
6de6de13aa | ||
|
|
96c9992c92 | ||
|
|
84e81acf3a | ||
|
|
ca02c01e1f | ||
|
|
87d51a0afe | ||
|
|
6dda34e837 | ||
|
|
cbff230734 | ||
|
|
6d9452ad84 | ||
|
|
a3cb6d749b | ||
|
|
15a9ac9157 | ||
|
|
5e5a2ae251 | ||
|
|
7dc7a0e36d | ||
|
|
50764def18 | ||
|
|
4c0fcc80ad | ||
|
|
4e4d19b88c | ||
|
|
a17752a49f | ||
|
|
bd55abea7f | ||
|
|
c686cbd531 | ||
|
|
0e97f8dd1d | ||
|
|
1899ecbd2f | ||
|
|
6ca3cca1b8 | ||
|
|
de8c0e2700 | ||
|
|
aa68bbbcdf | ||
|
|
e688f6f934 | ||
|
|
d45a2da5b5 |
No files matched your search
@@ -4,6 +4,9 @@ on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
schedule:
|
||||
# Nightly: the heavy tests on main.
|
||||
- cron: '23 3 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -17,8 +20,45 @@ env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
# Pull requests that only touch Markdown or docs/ skip the build jobs (they still report, as
|
||||
# skipped). Pushes to main and manual runs always run everything.
|
||||
changes:
|
||||
name: Select checks
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
code: ${{ steps.paths.outputs.code }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- id: paths
|
||||
name: Detect code changes
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" != "pull_request" ]; then
|
||||
echo "code=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
changed=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA")
|
||||
code=false
|
||||
while IFS= read -r f; do
|
||||
case "$f" in
|
||||
docs/features.md|docs/oracle.md) code=true ;;
|
||||
*.md|docs/*) ;;
|
||||
"") ;;
|
||||
*) code=true ;;
|
||||
esac
|
||||
done <<< "$changed"
|
||||
echo "code=$code" >> "$GITHUB_OUTPUT"
|
||||
echo "code changes: $code"
|
||||
|
||||
ci:
|
||||
name: cargo xtask ci
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
@@ -28,10 +68,50 @@ jobs:
|
||||
components: rustfmt, clippy
|
||||
targets: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
|
||||
with:
|
||||
# Branches restore main's cache; saving their own would only evict it.
|
||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||
- run: cargo xtask ci
|
||||
|
||||
heavy:
|
||||
# The heavy verification and corpus tests (#[ignore]d) and the doc tests: on main, nightly
|
||||
# and on demand, not on every pull request.
|
||||
name: cargo xtask test --heavy
|
||||
if: contains(fromJSON('["push", "schedule", "workflow_dispatch"]'), github.event_name)
|
||||
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
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
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
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
|
||||
@@ -48,12 +48,16 @@ People trust ModelCraft with their models; a crash loses their work. **This outr
|
||||
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.
|
||||
- **Expected values are analytic.** Reference tests compare with closed-form solutions (patch
|
||||
tests, beams, plates, Lamé cylinders, Kirsch plates, natural frequencies, wave and shock
|
||||
solutions) and with mesh invariants (positive Jacobians, conserved volume, watertight
|
||||
boundaries). A separate **benchmark** suite may compare with reference values published in
|
||||
papers (lid-driven cavity, Schäfer–Turek, Turek–Hron, Taylor bar), each tagged with its source;
|
||||
the analytic suite is the gate. Never values produced with a commercial product.
|
||||
- **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,
|
||||
@@ -75,7 +79,7 @@ People trust ModelCraft with their models; a crash loses their work. **This outr
|
||||
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`; `explicit`, `lbm` later) →
|
||||
`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-*`.**
|
||||
@@ -93,19 +97,33 @@ People trust ModelCraft with their models; a crash loses their work. **This outr
|
||||
warnings, tests, wasm) on every PR; don't run the full gate locally. Before pushing: `cargo fmt
|
||||
--all`, `cargo check` the touched crates, and run the tests you added or changed. Commit after
|
||||
each working step (a layer that compiles with its tests passing), not one big commit per PR.
|
||||
- **Keep the PR 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 PR gate. The `heavy` CI job runs `cargo xtask test --heavy` (every ignored
|
||||
test, benchmarks included, and the doc tests) on pushes 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/modelcraft. Changes land through pull requests:
|
||||
branch, push, open a PR, let CI run, then `gh pr merge --squash` when green. Rebase onto `main`
|
||||
(never merge `main` into a branch); never force-push `main`. Never commit `plan/`,
|
||||
`.agent-files/`, `worktrees/` or `target*/`; check `git ls-files` before pushing.
|
||||
branch, **rebase onto the latest `origin/main` right before opening the PR and before every push
|
||||
that updates it** (never merge `main` into a branch), push, open a PR, let CI run. A PR merges
|
||||
(`gh pr merge --squash`) only after review and only when its green CI ran on top of current
|
||||
`main` (`mergeStateStatus` CLEAN; rebase again if `main` moved); after a merge, `main`'s own CI
|
||||
must pass. Never force-push `main`. Never commit `plan/`, `.agent-files/`, `worktrees/` or
|
||||
`target*/`; check `git ls-files` before pushing.
|
||||
|
||||
## Running
|
||||
- `cargo run -p modelcraft-cli -- commands` lists every command with its parameters.
|
||||
- `cargo run -p modelcraft-cli -- run script.json` runs a script (a JSON array of
|
||||
`{"command", "params"}`) and prints the model summary.
|
||||
- `cargo run --release -p modelcraft -- --sample --control PORT` opens the desktop app with the
|
||||
- `cargo run --release -p modelcraft -- --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.screenshot {path}` (needs a presented frame) or `ui.render {path}`
|
||||
(CPU render, no window needed), then read the PNG.
|
||||
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 modelcraft-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.
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@ is committed and listed here with its exports.
|
||||
| assets/icons/file.recover.svg, assets/icons/file.recover.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/file.save.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
| assets/icons/flow.boundary.svg, assets/icons/flow.boundary.vectorcraft | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/flow.boundary.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
| assets/icons/flow.domain.svg, assets/icons/flow.domain.vectorcraft | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/flow.domain.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
| assets/icons/geometry.bodies.svg, assets/icons/geometry.bodies.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/geometry.import.mesh.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
@@ -41,9 +39,9 @@ is committed and listed here with its exports.
|
||||
| assets/icons/interaction.contact.general.svg, assets/icons/interaction.contact.general.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.fsi.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
| assets/icons/interaction.mass.svg, assets/icons/interaction.mass.vectorcraft | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.mass.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
| assets/icons/model.mass.create.svg, assets/icons/model.mass.create.vectorcraft | ModelCraft 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 | ModelCraft 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/interaction.spring.svg, assets/icons/interaction.spring.vectorcraft | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/interaction.spring.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
| assets/icons/model.spring.create.svg, assets/icons/model.spring.create.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.element.add.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
@@ -68,6 +66,7 @@ is committed and listed here with its exports.
|
||||
| assets/icons/mesh.surface.check.svg, assets/icons/mesh.surface.check.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/mesh.verify.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
@@ -76,6 +75,8 @@ is committed and listed here with its exports.
|
||||
| assets/icons/model.boundary_condition.create.svg, assets/icons/model.boundary_condition.create.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/model.material.create.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
@@ -111,10 +112,46 @@ is committed and listed here with its exports.
|
||||
| assets/icons/results.xy.svg, assets/icons/results.xy.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft 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.flow.svg, assets/icons/solve.flow.vectorcraft | ModelCraft contributors | Original toolbar icon drawn with VectorCraft from `assets/icons/src/solve.flow.json` (`cargo xtask icons`) | MIT OR Apache-2.0 |
|
||||
| assets/icons/solve.fluid.svg, assets/icons/solve.fluid.vectorcraft | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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/ModelCraft.icon/Assets/01-floor.svg | ModelCraft 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/ModelCraft.icon/Assets/01-floor-dark.svg | ModelCraft 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/ModelCraft.icon/Assets/02-part.svg | ModelCraft 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/ModelCraft.icon/Assets/03-mesh.svg | ModelCraft 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/ModelCraft.icon/icon.json | ModelCraft 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 | ModelCraft contributors | Apple actool compilation of assets/app-icon/ModelCraft.icon; contains original artwork only | MIT OR Apache-2.0 |
|
||||
| assets/app-icon/icon.icns | ModelCraft contributors | iconutil compilation of assets/app-icon/icon.iconset | MIT OR Apache-2.0 |
|
||||
| assets/app-icon/icon.ico | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft 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 | ModelCraft contributors | sips export (64 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
|
||||
| assets/app-icon/icon.iconset/icon_128x128.png | ModelCraft 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 | ModelCraft contributors | sips export (256 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
|
||||
| assets/app-icon/icon.iconset/icon_256x256.png | ModelCraft 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 | ModelCraft contributors | sips export (512 px) of assets/app-icon/icon.png | MIT OR Apache-2.0 |
|
||||
| assets/app-icon/icon.iconset/icon_512x512.png | ModelCraft 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 | ModelCraft 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
|
||||
|
||||
@@ -125,10 +162,12 @@ is committed and listed here with its exports.
|
||||
| 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, crates/ui-egui/src/control.rs, crates/ui-egui/src/lib.rs (input injection, screenshots), crates/ui-egui/src/toolbar.rs (tabs of panels of buttons) | SolidCraft `crates/ui-egui/src/` | 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/modelcraft/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
|
||||
|
||||
|
||||
@@ -749,6 +749,14 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "craft-ui"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=5c874d51eeb3de70e735c8ce87a59a7dedd47675#5c874d51eeb3de70e735c8ce87a59a7dedd47675"
|
||||
dependencies = [
|
||||
"egui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.2"
|
||||
@@ -858,6 +866,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"block2 0.6.2",
|
||||
"libc",
|
||||
"objc2 0.6.5",
|
||||
]
|
||||
|
||||
@@ -924,7 +934,7 @@ dependencies = [
|
||||
"objc2-foundation 0.3.2",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"pollster",
|
||||
"pollster 1.0.1",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
"static_assertions",
|
||||
@@ -1853,7 +1863,9 @@ dependencies = [
|
||||
"egui",
|
||||
"log",
|
||||
"modelcraft-engine",
|
||||
"modelcraft-io",
|
||||
"modelcraft-ui-egui",
|
||||
"rfd",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
@@ -1862,6 +1874,8 @@ name = "modelcraft-cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"modelcraft-engine",
|
||||
"modelcraft-io",
|
||||
"modelcraft-mcp",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
@@ -1880,10 +1894,14 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"modelcraft-decks",
|
||||
"modelcraft-explicit",
|
||||
"modelcraft-fem",
|
||||
"modelcraft-geometry",
|
||||
"modelcraft-io",
|
||||
"modelcraft-lbm",
|
||||
"modelcraft-mesh",
|
||||
"modelcraft-model",
|
||||
"modelcraft-render",
|
||||
"modelcraft-solver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1891,6 +1909,16 @@ dependencies = [
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modelcraft-explicit"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"modelcraft-fem",
|
||||
"modelcraft-model",
|
||||
"serde",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modelcraft-fem"
|
||||
version = "0.1.0"
|
||||
@@ -1928,6 +1956,26 @@ dependencies = [
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modelcraft-lbm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"modelcraft-mesh",
|
||||
"modelcraft-model",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modelcraft-mcp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"modelcraft-engine",
|
||||
"modelcraft-io",
|
||||
"modelcraft-render",
|
||||
"modelcraft-testkit",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "modelcraft-mesh"
|
||||
version = "0.1.0"
|
||||
@@ -1973,6 +2021,7 @@ dependencies = [
|
||||
name = "modelcraft-testkit"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"modelcraft-engine",
|
||||
"modelcraft-geometry",
|
||||
"modelcraft-mesh",
|
||||
"serde_json",
|
||||
@@ -1983,10 +2032,14 @@ dependencies = [
|
||||
name = "modelcraft-ui-egui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"craft-ui",
|
||||
"egui",
|
||||
"egui-wgpu",
|
||||
"log",
|
||||
"modelcraft-decks",
|
||||
"modelcraft-engine",
|
||||
"modelcraft-explicit",
|
||||
"modelcraft-geometry",
|
||||
"modelcraft-model",
|
||||
"modelcraft-render",
|
||||
"resvg",
|
||||
@@ -2197,6 +2250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
|
||||
dependencies = [
|
||||
"bitflags 2.13.2",
|
||||
"block2 0.6.2",
|
||||
"objc2 0.6.5",
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
@@ -2667,6 +2721,12 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pollster"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
|
||||
|
||||
[[package]]
|
||||
name = "pollster"
|
||||
version = "1.0.1"
|
||||
@@ -2944,6 +3004,33 @@ dependencies = [
|
||||
"usvg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rfd"
|
||||
version = "0.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20dafead71c16a34e1ff357ddefc8afc11e7d51d6d2b9fbd07eaa48e3e540220"
|
||||
dependencies = [
|
||||
"block2 0.6.2",
|
||||
"dispatch2",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"objc2 0.6.5",
|
||||
"objc2-app-kit 0.3.2",
|
||||
"objc2-core-foundation",
|
||||
"objc2-foundation 0.3.2",
|
||||
"percent-encoding",
|
||||
"pollster 0.4.0",
|
||||
"raw-window-handle",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
"web-sys",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rgb"
|
||||
version = "0.8.53"
|
||||
|
||||
@@ -19,10 +19,13 @@ modelcraft-decks = { path = "crates/decks" }
|
||||
modelcraft-io = { path = "crates/io" }
|
||||
modelcraft-fem = { path = "crates/fem" }
|
||||
modelcraft-solver = { path = "crates/solver" }
|
||||
modelcraft-explicit = { path = "crates/explicit" }
|
||||
modelcraft-lbm = { path = "crates/lbm" }
|
||||
modelcraft-engine = { path = "crates/engine" }
|
||||
modelcraft-testkit = { path = "crates/testkit" }
|
||||
modelcraft-render = { path = "crates/render" }
|
||||
modelcraft-ui-egui = { path = "crates/ui-egui" }
|
||||
modelcraft-mcp = { path = "crates/mcp" }
|
||||
|
||||
# foundation
|
||||
thiserror = "2"
|
||||
@@ -46,6 +49,11 @@ resvg = { version = "0.48", default-features = false }
|
||||
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).
|
||||
@@ -74,6 +82,11 @@ 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.modelcraft-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]
|
||||
@@ -87,6 +100,9 @@ incremental = false
|
||||
[profile.ci.package."*"]
|
||||
opt-level = 2
|
||||
|
||||
[profile.ci.package.modelcraft-lbm]
|
||||
opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = "thin"
|
||||
|
||||
@@ -13,8 +13,10 @@ geometry boundary (SolidCraft's kernel and tessellator) are in place; meshing is
|
||||
|
||||
```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 modelcraft-cli -- commands # every command and its parameters
|
||||
cargo run -p modelcraft-cli -- run script.json # run a command script
|
||||
cargo run -p modelcraft-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`.
|
||||
@@ -23,6 +25,8 @@ Rust 1.95 or later, with the `wasm32-unknown-unknown` target for `cargo xtask ci
|
||||
|
||||
- [Architecture](docs/architecture.md): crates, layers and the meshing pipeline
|
||||
- [Libraries and licences](docs/adr/0001-libraries.md)
|
||||
- [AI agents (MCP)](docs/mcp.md): `claude mcp add modelcraft -- /path/to/modelcraft-cli mcp`
|
||||
- [Control protocol](docs/control-protocol.md): driving the desktop app
|
||||
- [Contributing](CONTRIBUTING.md) and [agent instructions](AGENTS.md)
|
||||
|
||||
## License
|
||||
|
||||
@@ -20,17 +20,18 @@ hex meshes today and it gives the best elements where stresses are read.
|
||||
|---|---|---|
|
||||
| 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 (`modelcraft-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 `modelcraft_mesh::size::SizeField` trait and edge-division helpers are in); Bowyer–Watson Delaunay (exact, symbolic perturbation, verified; `modelcraft-mesh::delaunay`, done); robust CDT boundary recovery (Diazzi et al. 2023); Delaunay refinement, ODT smoothing, sliver removal; tet4 and tet10 with mid-side nodes on the B-rep; mesh verify per set | in progress |
|
||||
| M2 Tet meshing and size field | Size field (global, per face and edge seeds, curvature and proximity; the `modelcraft_mesh::size::SizeField` trait and edge-division helpers are in); Bowyer–Watson Delaunay (exact, symbolic perturbation, verified; `modelcraft-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; `modelcraft-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 `.modelcraft` 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 | Linear static and modal solver (tet4/10, wedge6, hex8, hex20; sparse direct, Lanczos), verified against analytic solutions (solver: done — `modelcraft-fem` kernels, `modelcraft-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); deformed shape, contours, mode shapes, probes, reaction sums | started |
|
||||
| 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 — `modelcraft-fem` kernels, `modelcraft-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 (`modelcraft-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; sweep meshing; 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 and contact | Part instances from SolidCraft occurrences; tie between non-matching meshes; general and pairwise contact with automatic pair detection, friction; bolt pretension, springs, point masses; amplitudes, multiple steps; nonlinear static steps in decks | 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; heat transfer | planned |
|
||||
| M7 Assemblies and contact | Part instances from SolidCraft occurrences; tie between non-matching meshes; general and pairwise contact with automatic pair detection, friction; bolt pretension, connectors; amplitudes, multiple steps; nonlinear static steps in decks | 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; large-deformation materials (objective rates, J2, Johnson–Cook, damage, erosion); contact (global search, penalty with friction, rigid walls); runs on hex and tet meshes | 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 — `modelcraft-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; octree refinement shared with the hex mesher; wgpu backend (deterministic per device, checked against the CPU) | 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; octree refinement shared with the hex mesher; wgpu backend (deterministic per device, checked against the CPU) (CPU core: done — `modelcraft-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 |
|
||||
| Continuous: desktop and agents | Desktop app (viewport, model tree, commands, control channel: done; toolbar of every capability from the catalogue, ready or coming soon with its milestone, icons drawn with VectorCraft, docs/features.md: done), MCP server, browser build, command schema as the public API | started |
|
||||
| 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: 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), browser build, command schema as the public API | started |
|
||||
@@ -1,6 +1,6 @@
|
||||
Third-party software in ModelCraft
|
||||
|
||||
ModelCraft (the desktop app, modelcraft-cli and the web app) is built from the 441 crates below.
|
||||
ModelCraft (the desktop app, modelcraft-cli and the web app) is built from the 444 crates below.
|
||||
Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files.
|
||||
ModelCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE.
|
||||
|
||||
@@ -74,6 +74,7 @@ core-foundation-sys 0.8.7 (MIT OR Apache-2.0)
|
||||
core-graphics 0.23.2 (MIT OR Apache-2.0)
|
||||
core-graphics-types 0.1.3 (MIT OR Apache-2.0)
|
||||
cpufeatures 0.2.17 (MIT OR Apache-2.0)
|
||||
craft-ui 0.1.0 (MIT OR Apache-2.0)
|
||||
crc32fast 1.5.2 (MIT OR Apache-2.0)
|
||||
crossbeam-deque 0.8.8 (MIT OR Apache-2.0)
|
||||
crossbeam-epoch 0.9.21 (MIT OR Apache-2.0)
|
||||
@@ -238,6 +239,7 @@ piper 0.2.5 (MIT OR Apache-2.0)
|
||||
plain 0.2.3 (MIT/Apache-2.0)
|
||||
png 0.18.1 (MIT OR Apache-2.0)
|
||||
polling 3.11.0 (Apache-2.0 OR MIT)
|
||||
pollster 0.4.0 (Apache-2.0/MIT)
|
||||
pollster 1.0.1 (Apache-2.0/MIT)
|
||||
polycool 0.4.0 (MIT OR Apache-2.0)
|
||||
portable-atomic 1.15.0 (Apache-2.0 OR MIT)
|
||||
@@ -270,6 +272,7 @@ redox_syscall 0.5.18 (MIT)
|
||||
redox_syscall 0.9.4 (MIT)
|
||||
renderdoc-sys 1.1.0 (MIT OR Apache-2.0)
|
||||
resvg 0.48.1 (Apache-2.0 OR MIT)
|
||||
rfd 0.17.2 (MIT)
|
||||
rgb 0.8.53 (MIT)
|
||||
robust 1.2.0 (MIT OR Apache-2.0)
|
||||
roxmltree 0.21.1 (MIT OR Apache-2.0)
|
||||
@@ -753,10 +756,10 @@ flate2 1.1.10, futures-lite 2.6.1, gethostname 1.1.0, glow 0.17.0, hashbrown 0.1
|
||||
khronos-egl 6.0.0, linux-raw-sys 0.12.1, linux-raw-sys 0.4.15, lock_api 0.4.14, log 0.4.34,
|
||||
num-complex 0.4.6, num-traits 0.2.19, once_cell 1.21.4, ordered-stream 0.2.0, parking 2.2.1,
|
||||
parking_lot 0.12.5, parking_lot_core 0.9.12, percent-encoding 2.3.2, piper 0.2.5, plain 0.2.3, png
|
||||
0.18.1, polling 3.11.0, pollster 1.0.1, rayon 1.12.0, rayon-core 1.13.0, renderdoc-sys 1.1.0, robust
|
||||
1.2.0, roxmltree 0.21.1, rustc-hash 1.1.0, rustix 0.38.44, rustix 1.1.5, scoped-tls 1.0.1,
|
||||
scopeguard 1.2.0, signal-hook-registry 1.4.8, simd_cesu8 1.2.0, simplecss 0.2.2, smallvec 1.16.3,
|
||||
smol_str 0.2.2, svgtypes 0.16.1, syn 1.0.109, tempfile 3.27.0, ttf-parser 0.25.1,
|
||||
0.18.1, polling 3.11.0, pollster 0.4.0, pollster 1.0.1, rayon 1.12.0, rayon-core 1.13.0,
|
||||
renderdoc-sys 1.1.0, robust 1.2.0, roxmltree 0.21.1, rustc-hash 1.1.0, rustix 0.38.44, rustix 1.1.5,
|
||||
scoped-tls 1.0.1, scopeguard 1.2.0, signal-hook-registry 1.4.8, simd_cesu8 1.2.0, simplecss 0.2.2,
|
||||
smallvec 1.16.3, smol_str 0.2.2, svgtypes 0.16.1, syn 1.0.109, tempfile 3.27.0, ttf-parser 0.25.1,
|
||||
unicode-segmentation 1.13.3, unicode-width 0.2.2, uuid 1.28.0, wasi 0.11.1+wasi-snapshot-preview1,
|
||||
wasip2 1.0.4+wasi-0.2.12, wasm-bindgen 0.2.129, wasm-bindgen-futures 0.4.79, wasm-bindgen-macro
|
||||
0.2.129, wasm-bindgen-macro-support 0.2.129, wasm-bindgen-shared 0.2.129, web-sys 0.3.106, weezl
|
||||
@@ -8113,7 +8116,7 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
pollster 1.0.1
|
||||
pollster 0.4.0, pollster 1.0.1
|
||||
================================================================================
|
||||
|
||||
Copyright (c) 2020-2021 Joshua Barretto
|
||||
@@ -9338,6 +9341,32 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
rfd 0.17.2
|
||||
================================================================================
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Bartłomiej Maryńczak
|
||||
|
||||
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.
|
||||
|
||||
================================================================================
|
||||
rgb 0.8.53
|
||||
================================================================================
|
||||
@@ -13012,6 +13041,7 @@ block2 0.5.1: MIT (https://github.com/madsmtm/objc2)
|
||||
block2 0.6.2: MIT (https://github.com/madsmtm/objc2)
|
||||
clipboard-win 5.4.1: BSL-1.0 (https://github.com/DoumanAsh/clipboard-win)
|
||||
convert_case 0.4.0: MIT (https://github.com/rutrum/convert-case)
|
||||
craft-ui 0.1.0: MIT OR Apache-2.0 (https://github.com/storytold/craft-libs)
|
||||
dispatch 0.2.0: MIT (http://github.com/SSheldon/rust-dispatch)
|
||||
dispatch2 0.3.1: Zlib OR Apache-2.0 OR MIT (https://github.com/madsmtm/objc2)
|
||||
ecolor 0.36.2: MIT OR Apache-2.0 (https://github.com/emilk/egui)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "modelcraft-cli"
|
||||
description = "ModelCraft from the command line: list commands, run scripts"
|
||||
description = "ModelCraft from the command line: list commands, run scripts, serve MCP"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
@@ -10,4 +10,6 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
modelcraft-engine = { workspace = true }
|
||||
modelcraft-io = { workspace = true }
|
||||
modelcraft-mcp = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
@@ -1,9 +1,11 @@
|
||||
//! modelcraft-cli commands
|
||||
//! modelcraft-cli run <script.json>
|
||||
//! modelcraft-cli features
|
||||
//! modelcraft-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 modelcraft_engine::Session;
|
||||
@@ -16,6 +18,14 @@ usage:
|
||||
and print the model summary
|
||||
modelcraft-cli features print docs/features.md (every capability, ready or
|
||||
coming soon) from the capability catalogue
|
||||
modelcraft-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 (`modelcraft --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).
|
||||
@@ -34,6 +44,7 @@ fn main() -> ExitCode {
|
||||
print!("{}", modelcraft_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}");
|
||||
@@ -50,6 +61,54 @@ fn main() -> ExitCode {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `mcp` options: each given once, as `--flag value` or `--flag=value`.
|
||||
fn mcp_options(args: &[String]) -> Result<modelcraft_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) => modelcraft_io::roots::Roots::default(),
|
||||
_ => modelcraft_io::roots::Roots::new(read.as_deref().map(Path::new), write.as_deref().map(Path::new)).map_err(|e| e.to_string())?,
|
||||
};
|
||||
Ok(modelcraft_mcp::Options { connect, roots })
|
||||
}
|
||||
|
||||
fn mcp(args: &[String]) -> Result<(), String> {
|
||||
let (backend, note) = modelcraft_mcp::backend(mcp_options(args)?)?;
|
||||
if let Some(note) = note {
|
||||
eprintln!("modelcraft-cli mcp: {note}");
|
||||
}
|
||||
let mut server = modelcraft_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 {
|
||||
@@ -63,3 +122,35 @@ fn run(path: &str) -> Result<(), 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<modelcraft_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:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ workspace = true
|
||||
[dependencies]
|
||||
modelcraft-engine = { workspace = true }
|
||||
modelcraft-ui-egui = { workspace = true }
|
||||
modelcraft-io = { workspace = true }
|
||||
rfd = { workspace = true }
|
||||
eframe = { workspace = true, features = ["default_fonts", "wgpu", "accesskit", "wayland", "x11"] }
|
||||
egui = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! ModelCraft desktop app.
|
||||
//!
|
||||
//! Usage: `modelcraft [--sample] [--control PORT]`
|
||||
//! Usage: `modelcraft [--sample [NAME]] [--control PORT] [FILE…]` (files open as if dropped on the
|
||||
//! window; NAME is a sample of `modelcraft_engine::sample`, `parts` by default)
|
||||
//!
|
||||
//! `--sample` opens a sample model (`modelcraft_engine::sample`). `--control PORT` (or
|
||||
//! `MODELCRAFT_CONTROL_PORT`) starts a localhost JSON-lines control server:
|
||||
@@ -14,12 +15,25 @@ mod control_server;
|
||||
|
||||
use modelcraft_engine::Session;
|
||||
use modelcraft_engine::autosave::{self, Autosaver};
|
||||
use modelcraft_ui_egui::ModelApp;
|
||||
use modelcraft_ui_egui::{Filter, ModelApp, Services};
|
||||
|
||||
const USAGE: &str = "usage: modelcraft [--sample] [--control PORT]";
|
||||
const USAGE: &str = "usage: modelcraft [--sample [parts|cantilever|impact]] [--control PORT] [FILE…] (FILE: .modelcraft, .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;
|
||||
|
||||
@@ -67,19 +81,42 @@ impl eframe::App for App {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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: modelcraft_io::recovery::default_dir().and_then(|d| d.parent().map(|p| p.join("recent.json"))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Command-line options.
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
struct Args {
|
||||
sample: bool,
|
||||
/// 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();
|
||||
let mut args = args.into_iter().peekable();
|
||||
while let Some(a) = args.next() {
|
||||
match a.as_str() {
|
||||
"--sample" => out.sample = true,
|
||||
"--sample" => {
|
||||
// An optional sample name follows.
|
||||
let name = args.peek().filter(|a| modelcraft_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"))?);
|
||||
@@ -92,7 +129,8 @@ fn parse_args(args: impl IntoIterator<Item = String>, env_port: Option<String>)
|
||||
println!("{USAGE}");
|
||||
return Ok(None);
|
||||
}
|
||||
other => return Err(format!("unknown argument `{other}`\n{USAGE}")),
|
||||
other if other.starts_with('-') => return Err(format!("unknown argument `{other}`\n{USAGE}")),
|
||||
file => out.files.push(file.to_string()),
|
||||
}
|
||||
}
|
||||
Ok(Some(out))
|
||||
@@ -108,7 +146,18 @@ fn main() -> eframe::Result {
|
||||
}
|
||||
};
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_title("ModelCraft").with_inner_size([1400.0, 900.0]).with_min_inner_size([800.0, 500.0]),
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_title("ModelCraft")
|
||||
.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()
|
||||
@@ -117,7 +166,9 @@ fn main() -> eframe::Result {
|
||||
"ModelCraft",
|
||||
options,
|
||||
Box::new(move |cc| {
|
||||
let mut app = ModelApp::new(Session::default());
|
||||
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!("modelcraft: graphics {:?} {}, MSAA {}x (requested {MSAA}x)", info.backend, info.name, rs.msaa_samples);
|
||||
@@ -126,15 +177,17 @@ fn main() -> eframe::Result {
|
||||
if let Some(port) = args.control {
|
||||
app = app.with_control(control_server::start(port, cc.egui_ctx.clone()));
|
||||
}
|
||||
if args.sample {
|
||||
// The status bar reports a failure; the app still opens.
|
||||
let _ = app.run_script(&modelcraft_engine::sample::script());
|
||||
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.recovery.list, file.recover)"), false);
|
||||
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()
|
||||
});
|
||||
@@ -145,6 +198,13 @@ fn main() -> eframe::Result {
|
||||
|
||||
#[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> {
|
||||
@@ -154,12 +214,19 @@ mod tests {
|
||||
#[test]
|
||||
fn arguments() {
|
||||
assert_eq!(parse(&[], None), Ok(Some(Args::default())));
|
||||
assert_eq!(parse(&["--sample", "--control", "7070"], None), Ok(Some(Args { sample: true, control: Some(7070) })));
|
||||
assert_eq!(parse(&[], Some("9000")), Ok(Some(Args { sample: false, control: Some(9000) })));
|
||||
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.modelcraft"], None).unwrap().unwrap();
|
||||
assert_eq!((a.sample.as_deref(), a.files), (Some("parts"), vec!["x.modelcraft".to_string()]));
|
||||
assert_eq!(parse(&["a.modelcraft", "--sample"], None).map(|a| a.map(|a| a.files)), Ok(Some(vec!["a.modelcraft".to_string()])));
|
||||
assert_eq!(parse(&["--help"], None), Ok(None));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?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>ModelCraft 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>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,18 @@
|
||||
<?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>ModelCraft 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>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,38 @@
|
||||
<?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>ModelCraft 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>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,12 @@
|
||||
<?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>ModelCraft 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>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# ModelCraft application icon
|
||||
|
||||
ModelCraft'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 |
|
||||
| `ModelCraft.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 `ModelCraft.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/modelcraft/src/main.rs`). There is no macOS bundle yet; packaging will copy
|
||||
`Assets.car` and `icon.icns` into `Contents/Resources` and name `ModelCraft` in
|
||||
`CFBundleIconName` / `CFBundleIconFile`.
|
||||
|
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1,48 @@
|
||||
<?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>ModelCraft 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>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 364 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 166 KiB |
@@ -0,0 +1,66 @@
|
||||
<?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>ModelCraft 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>
|
||||
|
After Width: | Height: | Size: 8.7 KiB |
@@ -0,0 +1,9 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 775 B |
@@ -0,0 +1,8 @@
|
||||
<?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>mesh.planar</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M3 5 L21 5 L21 19 L3 19 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 5 L9 19 M15 5 L15 19 M3 12 L21 12" fill="none" stroke="#4f9ce8" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 537 B |
@@ -1,6 +1,6 @@
|
||||
<?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>flow.boundary</title>
|
||||
<title>model.fluid_domain.boundary</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M3 5 L21 5 M3 19 L21 19" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 9.5 L9 9.5 M6.19 11.03 L9 9.5 L6.19 7.97" fill="none" stroke="#f0b44a" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
Before Width: | Height: | Size: 857 B After Width: | Height: | Size: 871 B |
@@ -1,6 +1,6 @@
|
||||
<?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>flow.domain</title>
|
||||
<title>model.fluid_domain.create</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M3 3 L21 3 L21 21 L3 21 Z" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.5 3 L7.5 21 M3 7.5 L21 7.5 M12 3 L12 21 M3 12 L21 12 M16.5 3 L16.5 21 M3 16.5 L21 16.5" fill="none" stroke="#dde2ea" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
Before Width: | Height: | Size: 813 B After Width: | Height: | Size: 827 B |
@@ -1,6 +1,6 @@
|
||||
<?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.mass</title>
|
||||
<title>model.mass.create</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M5 21 L7 9 L17 9 L19 21 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 9 C9 7.343 10.343 6 12 6 C13.657 6 15 7.343 15 9" fill="none" stroke="#dde2ea" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
Before Width: | Height: | Size: 705 B After Width: | Height: | Size: 706 B |
@@ -1,6 +1,6 @@
|
||||
<?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.spring</title>
|
||||
<title>model.spring.create</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M1.2 12 C1.2 11.006 2.006 10.2 3 10.2 C3.994 10.2 4.8 11.006 4.8 12 C4.8 12.994 3.994 13.8 3 13.8 C2.006 13.8 1.2 12.994 1.2 12 Z" fill="#dde2ea"/>
|
||||
<path d="M19.2 12 C19.2 11.006 20.006 10.2 21 10.2 C21.994 10.2 22.8 11.006 22.8 12 C22.8 12.994 21.994 13.8 21 13.8 C20.006 13.8 19.2 12.994 19.2 12 Z" fill="#dde2ea"/>
|
||||
|
Before Width: | Height: | Size: 760 B After Width: | Height: | Size: 761 B |
@@ -1,6 +1,6 @@
|
||||
<?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>solve.flow</title>
|
||||
<title>solve.fluid</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M8.5 12 C8.5 10.067 10.067 8.5 12 8.5 C13.933 8.5 15.5 10.067 15.5 12 C15.5 13.933 13.933 15.5 12 15.5 C10.067 15.5 8.5 13.933 8.5 12 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 6 C8 6 9 4.5 12 4.5 C15 4.5 16 6 21 6" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
Before Width: | Height: | Size: 945 B After Width: | Height: | Size: 946 B |
@@ -0,0 +1,8 @@
|
||||
<?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>solve.run</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="M10 7.8 L16.4 12 L10 16.2 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 609 B |
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M3 10 L11 6 L19 10 L19 18 L11 22 L3 18 Z", "fill": "soft", "stroke": "line"}, {"d": "M3 10 L11 14 L19 10 M11 14 L11 22", "stroke": "line"}, {"star": [18.5, 5.5, 4, 1.6, 4], "fill": "warm", "stroke": "warm", "width": 1}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M3 5 L21 5 L21 19 L3 19 Z", "fill": "soft", "stroke": "line"}, {"d": "M9 5 L9 19 M15 5 L15 19 M3 12 L21 12", "stroke": "accent", "width": 1.25}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"circle": [12, 12, 9], "fill": "soft", "stroke": "line"}, {"d": "M10 7.8 L16.4 12 L10 16.2 Z", "fill": "accent", "stroke": "accent", "width": 1.25}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M2.5 12 C5.5 6.5 18.5 6.5 21.5 12 C18.5 17.5 5.5 17.5 2.5 12 Z", "fill": "soft", "stroke": "line"}, {"circle": [12, 12, 3], "fill": "accent", "stroke": "accent", "width": 1}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M3.5 8 L3.5 3.5 L8 3.5 M16 3.5 L20.5 3.5 L20.5 8 M20.5 16 L20.5 20.5 L16 20.5 M8 20.5 L3.5 20.5 L3.5 16", "stroke": "line"}, {"rect": [8, 8, 8, 8], "radius": 1, "fill": "soft", "stroke": "accent"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"circle": [12, 12, 9], "stroke": "line"}, {"d": "M9.4 9.6 C9.4 6.9 14.6 6.9 14.6 9.9 C14.6 12 12 12.1 12 14.3", "stroke": "accent", "width": 1.9}, {"circle": [12, 17.3, 0.7], "fill": "accent", "stroke": "accent", "width": 1.25}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M5.5 10 L5.5 20 L18.5 20 L18.5 10", "fill": "soft", "stroke": "line"}, {"d": "M3 11.5 L12 4 L21 11.5", "stroke": "line"}, {"rect": [10.25, 14, 3.5, 6], "fill": "accent", "stroke": "accent", "width": 1}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M15 3.5 C9 4 5.5 9 6.5 14 C7.5 19 13 21.5 18 19.5 C13.5 18.5 11 15 11 11 C11 7.5 12.5 5 15 3.5 Z", "fill": "soft", "stroke": "line"}, {"star": [18.5, 7.5, 2.4, 1, 4], "fill": "warm", "stroke": "warm", "width": 0.75}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M3 12 C3 8.2 21 8.2 21 12 C21 15.8 3 15.8 3 12 Z", "stroke": "line"}, {"d": "M16.5 7.6 L19.2 9.4 L16.4 10.8", "stroke": "accent", "width": 1.5}, {"circle": [12, 12, 3], "fill": "accent", "stroke": "accent", "width": 1}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M12 4 L12 20 M4 12 L20 12", "stroke": "line"}, {"d": "M9.5 6.5 L12 4 L14.5 6.5 M9.5 17.5 L12 20 L14.5 17.5 M6.5 9.5 L4 12 L6.5 14.5 M17.5 9.5 L20 12 L17.5 14.5", "stroke": "accent", "width": 1.75}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M3 19.5 L21 19.5 L16 6 L8 6 Z", "fill": "soft", "stroke": "line"}, {"d": "M12 19.5 L12 6 M5.6 12.5 L18.4 12.5", "stroke": "accent", "width": 1.25, "dash": [1.5, 1.5]}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"circle": [10.5, 10.5, 6.5], "stroke": "line"}, {"line": [15.3, 15.3, 20.5, 20.5], "stroke": "accent", "width": 2.25}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M12 3 L20 7.5 L20 16.5 L12 21 L4 16.5 L4 7.5 Z", "fill": "soft", "stroke": "line"}, {"d": "M12 12 L20 7.5 L20 16.5 L12 21 Z", "fill": "accent", "stroke": "line"}, {"d": "M4 7.5 L12 12 L12 21", "stroke": "line"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"circle": [12, 12, 4], "fill": "warm", "stroke": "warm"}, {"d": "M12 2.5 L12 4.5 M12 19.5 L12 21.5 M2.5 12 L4.5 12 M19.5 12 L21.5 12 M5.3 5.3 L6.7 6.7 M17.3 17.3 L18.7 18.7 M5.3 18.7 L6.7 17.3 M17.3 6.7 L18.7 5.3", "stroke": "line"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"d": "M12 3 L20 7.5 L20 16.5 L12 21 L4 16.5 L4 7.5 Z", "stroke": "line"}, {"d": "M4 7.5 L12 12 L20 7.5 M12 12 L12 21", "stroke": "line"}, {"d": "M12 3 L20 7.5 L12 12 L4 7.5 Z", "fill": "accent", "stroke": "line"}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"shapes": [{"circle": [10.5, 10.5, 6.5], "fill": "soft", "stroke": "line"}, {"line": [15.3, 15.3, 20.5, 20.5], "stroke": "line", "width": 2.25}, {"d": "M10.5 7.5 L10.5 13.5 M7.5 10.5 L13.5 10.5", "stroke": "accent", "width": 1.5}]}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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>ui.eye</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M2.5 12 C5.5 6.5 18.5 6.5 21.5 12 C18.5 17.5 5.5 17.5 2.5 12 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 12 C9 10.343 10.343 9 12 9 C13.657 9 15 10.343 15 12 C15 13.657 13.657 15 12 15 C10.343 15 9 13.657 9 12 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 625 B |
@@ -0,0 +1,8 @@
|
||||
<?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>ui.fit</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M3.5 8 L3.5 3.5 L8 3.5 M16 3.5 L20.5 3.5 L20.5 8 M20.5 16 L20.5 20.5 L16 20.5 M8 20.5 L3.5 20.5 L3.5 16" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 8 L15 8 C15.552 8 16 8.448 16 9 L16 15 C16 15.552 15.552 16 15 16 L9 16 C8.448 16 8 15.552 8 15 L8 9 C8 8.448 8.448 8 9 8 Z" fill="#2d4e70" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 699 B |
@@ -0,0 +1,9 @@
|
||||
<?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>ui.help</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="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.4 9.6 C9.4 6.9 14.6 6.9 14.6 9.9 C14.6 12 12 12.1 12 14.3" fill="none" stroke="#4f9ce8" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.3 17.3 C11.3 16.913 11.613 16.6 12 16.6 C12.387 16.6 12.7 16.913 12.7 17.3 C12.7 17.687 12.387 18 12 18 C11.613 18 11.3 17.687 11.3 17.3 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 891 B |
@@ -0,0 +1,9 @@
|
||||
<?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>ui.home</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M5.5 10 L5.5 20 L18.5 20 L18.5 10" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M3 11.5 L12 4 L21 11.5" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10.25 14 L13.75 14 L13.75 20 L10.25 20 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 663 B |
@@ -0,0 +1,8 @@
|
||||
<?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>ui.moon</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M15 3.5 C9 4 5.5 9 6.5 14 C7.5 19 13 21.5 18 19.5 C13.5 18.5 11 15 11 11 C11 7.5 12.5 5 15 3.5 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M18.5 5.1 L19.088 6.691 L20.783 6.758 L19.451 7.809 L19.911 9.442 L18.5 8.5 L17.089 9.442 L17.549 7.809 L16.217 6.758 L17.912 6.691 Z" fill="#f0b44a" stroke="#f0b44a" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 704 B |
@@ -0,0 +1,9 @@
|
||||
<?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>ui.orbit</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M3 12 C3 8.2 21 8.2 21 12 C21 15.8 3 15.8 3 12 Z" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M16.5 7.6 L19.2 9.4 L16.4 10.8" fill="none" stroke="#4f9ce8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 12 C9 10.343 10.343 9 12 9 C13.657 9 15 10.343 15 12 C15 13.657 13.657 15 12 15 C10.343 15 9 13.657 9 12 Z" fill="#4f9ce8" stroke="#4f9ce8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 752 B |
@@ -0,0 +1,8 @@
|
||||
<?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>ui.pan</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M12 4 L12 20 M4 12 L20 12" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.5 6.5 L12 4 L14.5 6.5 M9.5 17.5 L12 20 L14.5 17.5 M6.5 9.5 L4 12 L6.5 14.5 M17.5 9.5 L20 12 L17.5 14.5" fill="none" stroke="#4f9ce8" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 598 B |
@@ -0,0 +1,8 @@
|
||||
<?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>ui.perspective</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M3 19.5 L21 19.5 L16 6 L8 6 Z" fill="#2d4e70" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 19.5 L12 6 M5.6 12.5 L18.4 12.5" fill="none" stroke="#4f9ce8" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.5 1.5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 570 B |
@@ -0,0 +1,8 @@
|
||||
<?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>ui.search</title>
|
||||
<g id="Layer_1" data-name="Layer 1">
|
||||
<path d="M4 10.5 C4 6.91 6.91 4 10.5 4 C14.09 4 17 6.91 17 10.5 C17 14.09 14.09 17 10.5 17 C6.91 17 4 14.09 4 10.5 Z" fill="none" stroke="#dde2ea" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M15.3 15.3 L20.5 20.5" fill="none" stroke="#4f9ce8" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 599 B |