diff --git a/README.md b/README.md
index 79d3d8b..e11e12d 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@
> models from LaTeX; don't hand-code what the compiler should generate.**
π **New here? Start with the [documentation](docs/index.md)** β
+[Installation](docs/installation.md) Β·
[Getting started](docs/mechdsl-core/getting-started.md) Β·
[Core concepts](docs/mechdsl-core/concepts.md) Β·
[LaTeX directive reference](docs/mechdsl-core/latex-directives.md) Β·
@@ -38,9 +39,17 @@ viscoplasticity, and Lemaitre continuum damage. Backends: Taichi (MVP-stable), M
[`mechdsl-workbench`](https://github.com/CEmM2/mechdsl-workbench) is a companion
browser workbench: LaTeX on the left, the compiled mechanics or transpiled
-algorithm on the right. It installs this repository's packages at a pinned
-release and is the fastest way to try the language before committing to the
-pipeline documentation.
+algorithm on the right. It is the fastest way to try the language before
+committing to the pipeline documentation.
+
+```bash
+pip install "mechdsl-workbench[mechdsl]" # workbench + the MechDSL engine
+mechdsl-workbench # then open http://127.0.0.1:8000
+```
+
+The `[mechdsl]` extra pulls `mechdsl-core[verify]` and `algo2code` from PyPI. The
+workbench pins Python 3.12 (`>=3.12,<3.13`), narrower than this repository's
+`>=3.11,<3.14`. See [the workbench docs page](docs/workbench.md).
## Installation
@@ -265,11 +274,14 @@ User-facing documentation lives in [`docs/`](docs/) and is built as a
| Page | What it covers |
|------|----------------|
| [Home](docs/index.md) | What MechDSL is and why to use it |
-| [Getting started](docs/mechdsl-core/getting-started.md) | Install with `uv`, first solver, `.tex` and energy-derived inputs |
+| [Installation](docs/installation.md) | Every package and extra on PyPI, plus the from-source `uv` workflow |
+| [Getting started](docs/mechdsl-core/getting-started.md) | `pip install`, first solver, `.tex` and energy-derived inputs |
| [Core concepts](docs/mechdsl-core/concepts.md) | LaTeX-first idea, six-layer pipeline, hyperelastic vs. dissipative, support tiers |
| [LaTeX directive reference](docs/mechdsl-core/latex-directives.md) | Every `% mechanics` directive with examples |
| [Constitutive models](docs/mechdsl-core/constitutive-models.md) | Model catalog with runnable snippets |
| [Algorithm transpiler (algo2code)](docs/algo2code/index.md) | How return-maps/PCG are transpiled from `algpseudocode` |
+| [ti-runtime](docs/ti-runtime/index.md) | The neutral Taichi runtime: seams, primitives, and the operator contract |
+| [Browser workbench](docs/workbench.md) | Installing and running the companion browser app |
| [Examples gallery](docs/mechdsl-core/examples.md) | Cantilever, Cook's membrane, necking bar, patch test, cyclic plasticity |
| [How it works](docs/reference/architecture.md) | Layers, IR discipline, determinism, verification |
| [FAQ & troubleshooting](docs/reference/faq.md) | Common questions and fixes |
diff --git a/docs/algo2code/getting-started.md b/docs/algo2code/getting-started.md
index 617c79e..cd73d46 100644
--- a/docs/algo2code/getting-started.md
+++ b/docs/algo2code/getting-started.md
@@ -1,27 +1,43 @@
# Getting started
-This page takes you from a fresh clone to a transpiled algorithm.
+This page takes you from an empty environment to a transpiled algorithm.
-## Prerequisites
+## Install
-`algo2code` is part of the MechDSL [uv](https://docs.astral.sh/uv/) workspace, so the
-simplest way to get it is the workspace install:
+`algo2code` is on PyPI and installs on its own β you do not need `mechdsl-core`, and
+you do not need the monorepo:
```bash
-git clone https://github.com/CEmM2/MechDSL.git
-cd MechDSL
-uv sync --all-packages --all-groups --all-extras
+pip install algo2code
```
+It requires Python 3.11, 3.12, or 3.13 (`requires-python = ">=3.11,<3.14"`) and
+nothing else.
+
!!! tip "Zero runtime dependencies"
- `algo2code` is **standard-library only** β it imports nothing at runtime beyond the
- Python stdlib, and it never imports `mechdsl`. That means the package directory
+ `algo2code` is **standard-library only** β its `dependencies` list is literally
+ empty, it imports nothing at runtime beyond the Python stdlib, and it never imports
+ `mechdsl`. That also means the package directory
(`packages/algo2code/src/algo2code/`) is self-contained and can be vendored into
another project by copying it, with no dependency footprint.
-!!! warning "Always go through `uv run`"
- Never call `python` or `pytest` directly inside the workspace β prefix every command
- with `uv run` so it uses the project's locked environment.
+`algo2code` also arrives automatically with `pip install "mechdsl-core[verify]"`, since
+the full engine uses it to generate the matrix-free PCG solver.
+
+??? note "Installing from source instead"
+ `algo2code` is one of the three packages in the MechDSL
+ [uv](https://docs.astral.sh/uv/) workspace. For the test suite or to contribute:
+
+ ```bash
+ git clone https://github.com/CEmM2/MechDSL.git
+ cd MechDSL
+ uv sync --all-packages --all-groups --all-extras
+ ```
+
+ Inside a source checkout, never call `python` or `pytest` directly β prefix every
+ command with `uv run` so it uses the project's locked environment.
+
+See [Installation](../installation.md) for the full matrix across all packages.
## Your first transpile
@@ -38,7 +54,7 @@ print(code) # Taichi-compatible Python source, as text
Run it:
```bash
-uv run python first_algo.py
+python first_algo.py
```
### What just happened
@@ -77,3 +93,5 @@ radial_return_j2 = ns["radial_return_j2"] # now a real callable
how the transpiled code is wired into the mechdsl-core solver.
- [Examples](examples.md) β runnable snippets for the J2 return-map family and the PCG
solver.
+- [Browser workbench](../workbench.md) β paste an `algorithmic` block into a pane and
+ read the generated Taichi next to it.
diff --git a/docs/algo2code/index.md b/docs/algo2code/index.md
index e376bb3..f1ed493 100644
--- a/docs/algo2code/index.md
+++ b/docs/algo2code/index.md
@@ -9,6 +9,12 @@ It is deliberately tiny: **zero runtime dependencies** (stdlib only), and it nev
`mechdsl`. The relationship is strict producer/consumer β mechdsl-core consumes
`algo2code`-generated artifacts, not the other way around.
+It is on PyPI under the MIT license and installs standalone β no `mechdsl-core` needed:
+
+```bash
+pip install algo2code
+```
+
---
## Why a separate package
@@ -47,7 +53,8 @@ The authoritative reference is `dev/design_docs/11-ALGO2CODE.md`.
-- :material-rocket-launch: **[Getting started](getting-started.md)** β install and transpile your first algorithm.
+- :material-download: **[Installation](../installation.md)** β every package, extra, and the from-source workflow.
+- :material-rocket-launch: **[Getting started](getting-started.md)** β `pip install`, then transpile your first algorithm.
- :material-code-tags: **[Usage](usage.md)** β the `transpile` API, the algorithm library, and the solver seam.
- :material-cards: **[Examples](examples.md)** β runnable transpile snippets for the J2 family and PCG.
diff --git a/docs/assets/mechdsl-banner.webp b/docs/assets/mechdsl-banner.webp
new file mode 100644
index 0000000..01878fa
Binary files /dev/null and b/docs/assets/mechdsl-banner.webp differ
diff --git a/docs/assets/mechdsl-mark.webp b/docs/assets/mechdsl-mark.webp
new file mode 100644
index 0000000..96f47e5
Binary files /dev/null and b/docs/assets/mechdsl-mark.webp differ
diff --git a/docs/index.md b/docs/index.md
index e0d2022..decbc84 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,11 +1,13 @@
# MechDSL
-**Write your mechanics in LaTeX. Get tested code back.**
+{ .hero-banner }
-MechDSL is a monorepo of two cooperating LaTeX-to-code compilers for computational solid
-mechanics. You describe the math β a boundary-value problem, a strain-energy function, a
-return-mapping algorithm β in an ordinary LaTeX document, and the toolchain emits
-deterministic, tested [Taichi](https://www.taichi-lang.org/) solver code.
+**Write your mechanics in LaTeX. Get a tested finite-element solver back.**
+
+MechDSL is a monorepo of LaTeX-to-code compilers for computational solid mechanics. You
+describe the math β a boundary-value problem, a strain-energy function, a return-mapping
+algorithm β in an ordinary LaTeX document, and the toolchain emits deterministic, tested
+[Taichi](https://www.taichi-lang.org/) solver code.
The same `.tex` file renders normally through `pdflatex` **and** is executable input to
the compiler. Your paper's source can be your simulation's source. The guiding principle:
@@ -14,7 +16,28 @@ the compiler. Your paper's source can be your simulation's source. The guiding p
---
-## The two packages
+## Install it
+
+Everything is on PyPI under the MIT license:
+
+```bash
+pip install mechdsl-core # the compiler: LaTeX -> emitted solver source (Taichi-free)
+pip install "mechdsl-core[verify]" # the full engine: run and verify solves
+```
+
+Or skip the scripting entirely and drive it from a browser:
+
+```bash
+pip install "mechdsl-workbench[mechdsl]"
+mechdsl-workbench # then open http://127.0.0.1:8000
+```
+
+See [Installation](installation.md) for every package, extra, and the from-source
+workflow.
+
+---
+
+## The packages
@@ -26,6 +49,8 @@ the compiler. Your paper's source can be your simulation's source. The guiding p
element kernels, deriving stress **S = βΞ¨/βE** and tangent **C = βΒ²Ξ¨/βEΒ²**
symbolically. Six-layer pipeline, Total Lagrangian, Hex8, Taichi backend.
+ `pip install mechdsl-core`
+
[:octicons-arrow-right-24: Introduction](mechdsl-core/index.md) Β·
[Getting started](mechdsl-core/getting-started.md)
@@ -37,15 +62,43 @@ the compiler. Your paper's source can be your simulation's source. The guiding p
the PCG solver β into executable code. Zero runtime dependencies. Consumed by
mechdsl-core for everything that *isn't* a closed-form expression.
+ `pip install algo2code`
+
[:octicons-arrow-right-24: Introduction](algo2code/index.md) Β·
[Getting started](algo2code/getting-started.md)
+- :material-chip: **[ti-runtime](ti-runtime/index.md)**
+
+ ---
+
+ The neutral Taichi runtime. Vector primitives, Tier-1 `@ti.func` tensor helpers, and
+ the injection seams that generated bodies plug into. Generated code depends on this,
+ never on the compiler that produced it.
+
+ `pip install ti-runtime`
+
+ [:octicons-arrow-right-24: Introduction](ti-runtime/index.md)
+
+- :material-application-brackets: **[mechdsl-workbench](workbench.md)**
+
+ ---
+
+ The companion browser app: LaTeX on the left, compiled mechanics or transpiled
+ algorithm on the right. Lives in its own repository; the fastest way to try the
+ language before committing to the pipeline.
+
+ `pip install "mechdsl-workbench[mechdsl]"`
+
+ [:octicons-arrow-right-24: Browser workbench](workbench.md)
+
-The relationship is strict producer/consumer: **mechdsl-core consumes algo2code-generated
-artifacts**; algo2code is runtime-free and never imports `mechdsl`. Together they cover
-both halves of a constitutive model β the closed-form energy (differentiated by
-mechdsl-core) and the iterative algorithm (transpiled by algo2code).
+The three monorepo packages have strict, one-way relationships. **mechdsl-core consumes
+algo2code-generated artifacts**; algo2code is runtime-free and never imports `mechdsl`;
+`ti-runtime` is what generated code lands on and never imports `mechdsl` either. Together
+they cover both halves of a constitutive model β the closed-form energy (differentiated
+by mechdsl-core) and the iterative algorithm (transpiled by algo2code) β plus the runtime
+floor they both emit against.
---
@@ -69,15 +122,20 @@ print(bundle.content_hash()) # deterministic β same input, same hash, ev
```
That call runs the full pipeline: parse the directives β build the Mechanics IR β
-localise to an Element IR β plan the tensor contractions β emit Taichi.
+localise to an Element IR β plan the tensor contractions β emit Taichi. It needs only the
+base `pip install mechdsl-core` β no Taichi required to emit.
---
## Where to go next
+- Just want it installed? **[Installation](installation.md)** covers PyPI, the extras,
+ and the `uv` source workflow.
- New here? Start with the **[mechdsl-core introduction](mechdsl-core/index.md)** β it's
the main package.
- Want to run something? **[Getting started](mechdsl-core/getting-started.md)** takes you
- from a fresh clone to a compiled solver bundle.
+ from a fresh install to a compiled solver bundle.
+- Prefer clicking to typing? The **[browser workbench](workbench.md)** runs the same
+ compiler behind a UI.
- Curious about the design? **[How it works](reference/architecture.md)** is a guided tour
of the six layers, and the **[FAQ](reference/faq.md)** answers the common questions.
diff --git a/docs/installation.md b/docs/installation.md
new file mode 100644
index 0000000..4935ba6
--- /dev/null
+++ b/docs/installation.md
@@ -0,0 +1,127 @@
+# Installation
+
+Every MechDSL package is published on PyPI under the MIT license, so the fastest way
+in is `pip install`. Installing from source with [uv](https://docs.astral.sh/uv/) is
+the path for contributors and for anyone who wants the runnable `examples/` tree.
+
+!!! tip "In a hurry?"
+ `pip install "mechdsl-workbench[mechdsl]"` then `mechdsl-workbench` gives you the
+ whole toolchain behind a browser UI β LaTeX in the left pane, generated Taichi in
+ the right. See [the workbench page](workbench.md).
+
+## What's on PyPI
+
+| Install | What it gives you |
+|---|---|
+| `pip install mechdsl-core` | The FEM compiler: LaTeX β emitted Taichi solver source. **Taichi-free.** ([PyPI](https://pypi.org/project/mechdsl-core/)) |
+| `pip install "mechdsl-core[verify]"` | The full engine β adds `taichi`, `ti-runtime`, and `algo2code` so you can *run* and *verify* solves |
+| `pip install algo2code` | The algorithm transpiler on its own. **Zero runtime dependencies**, stdlib only. ([PyPI](https://pypi.org/project/algo2code/)) |
+| `pip install ti-runtime` | The neutral Taichi runtime: vector primitives, Tier-1 `@ti.func` helpers, injection seams. ([PyPI](https://pypi.org/project/ti-runtime/)) |
+| `pip install "mechdsl-workbench[mechdsl]"` | The browser workbench plus the engine, in one command. ([PyPI](https://pypi.org/project/mechdsl-workbench/)) |
+
+All five are released together and currently sit at **0.2.1**.
+
+## Requirements
+
+- **Python 3.11β3.13** for `mechdsl-core`, `algo2code`, and `ti-runtime`
+ (`requires-python = ">=3.11,<3.14"`).
+- **Python 3.12** for `mechdsl-workbench`, which pins `>=3.12,<3.13`.
+- No compiler toolchain, no system FEM library. Taichi ships prebuilt wheels and
+ JIT-compiles to CPU or GPU at run time.
+
+## Install from PyPI
+
+### Just the compiler (lean, Taichi-free)
+
+```bash
+pip install mechdsl-core
+```
+
+This is everything you need to **emit** code: parse `% mechanics` directives, derive
+stress and tangent symbolically, plan contractions, and print Taichi source. It pulls
+only `sympy`, `numpy`, `scipy`, `opt-einsum`, `pyyaml`, and `nrpylatex` β no Taichi, so
+the install stays small and imports cleanly in Taichi-free environments.
+
+```python
+from mechdsl import compile_latex
+
+bundle = compile_latex("% mechanics dim 3\n% mechanics cell hex8\n"
+ "% mechanics formulation total_lagrangian\n"
+ "% mechanics material svk --E 200e3 --nu 0.3\n")
+print(bundle.content_hash())
+```
+
+### The full engine (run and verify solves)
+
+```bash
+pip install "mechdsl-core[verify]"
+```
+
+The `verify` extra adds `taichi`, `ti-runtime`, and `algo2code` β the complete
+installation. Expect a noticeably larger download; Taichi alone is around 170 MB.
+Take this one if you want to execute generated kernels, run the verification
+harness, or use the generated matrix-free PCG solver.
+
+!!! info "Why the split?"
+ Only `mechdsl.integration.verify()` ever touches Taichi, and it imports it lazily
+ at call time. The emit, transpile, `capabilities()`, and `model_catalog()`
+ surfaces are proven Taichi-free by the test suite, so downstream consumers can
+ depend on `mechdsl-core` for code generation without pulling Taichi into their
+ dependency closure.
+
+### The satellite packages alone
+
+```bash
+pip install algo2code # LaTeX algpseudocode -> executable code; stdlib-only
+pip install ti-runtime # Taichi primitives + injection seams for generated code
+```
+
+`algo2code` never imports `mechdsl`, and `ti-runtime` never imports `mechdsl` either β
+generated artifacts depend on `ti_runtime`, not on the compiler that produced them. Both
+are usable standalone.
+
+## Install from source
+
+Use this if you want the `examples/` scripts, the test suite, or you intend to
+contribute. The repository is a [uv](https://docs.astral.sh/uv/) workspace holding all
+three monorepo packages.
+
+```bash
+git clone https://github.com/CEmM2/MechDSL.git
+cd MechDSL
+uv sync --all-packages --all-groups --all-extras
+```
+
+Verify the install with the fast test tier:
+
+```bash
+uv run pytest -m "not slow and not gpu" -q
+```
+
+!!! warning "Inside the workspace, always go through `uv run`"
+ Never call `python`, `pytest`, `ruff`, or `mypy` directly in a source checkout β
+ they may not be on your PATH or may pick up the wrong environment. Prefix every
+ project command with `uv run`. (This applies to the source workflow only; a
+ `pip install`ed MechDSL is an ordinary package in whatever environment you put it.)
+
+## Command-line entry points
+
+`mechdsl-core` installs one console script:
+
+```bash
+mechdsl-lawgen --help # emit constitutive-law carriers for the ticonstit target
+mechdsl-lawgen compile law.yaml # ...with --dry-run to print the plan and write nothing
+```
+
+`mechdsl-workbench` installs its own launcher β see [the workbench page](workbench.md).
+
+## Where to next
+
+
+
+- :material-rocket-launch: **[mechdsl-core getting started](mechdsl-core/getting-started.md)** β compile your first solver bundle.
+- :material-cog-transfer: **[algo2code getting started](algo2code/getting-started.md)** β transpile your first algorithm.
+- :material-application-brackets: **[Browser workbench](workbench.md)** β try the language without writing a script.
+- :material-help-circle: **[FAQ & troubleshooting](reference/faq.md)** β when something doesn't install or run.
+
+
diff --git a/docs/mechdsl-core/examples.md b/docs/mechdsl-core/examples.md
index 83ee898..5214cad 100644
--- a/docs/mechdsl-core/examples.md
+++ b/docs/mechdsl-core/examples.md
@@ -68,9 +68,11 @@ The J2 kinematic and mixed hardening models (`mechdsl.lib.plasticity_kinematic`
`plasticity_mixed`) are exercised on a uniaxial **cyclic** load path
(loading β unloading β reverse) in the test suite. The kinematic/mixed models re-yield in
reverse *below* the forward yield magnitude β the Bauschinger effect β which the isotropic
-model cannot reproduce. See
-[`packages/mechdsl-core/tests/plan_tests/constitutive_latex/`](https://github.com/CEmM2/MechDSL/tree/main/packages/mechdsl-core/tests/plan_tests/constitutive_latex)
-for the cyclic differential tests and the reduction cross-checks, and the
+model cannot reproduce. The hand-written reference kernels that pin this behaviour are
+[`ref_j2_kinematic.py`](https://github.com/CEmM2/MechDSL/blob/main/packages/mechdsl-core/tests/ref/ref_j2_kinematic.py)
+and
+[`ref_j2_mixed.py`](https://github.com/CEmM2/MechDSL/blob/main/packages/mechdsl-core/tests/ref/ref_j2_mixed.py);
+see the
[constitutive model catalog](constitutive-models.md#j2-plasticity-kinematic-prager-hardening)
for the API.
diff --git a/docs/mechdsl-core/getting-started.md b/docs/mechdsl-core/getting-started.md
index 7c9a089..36ba5bd 100644
--- a/docs/mechdsl-core/getting-started.md
+++ b/docs/mechdsl-core/getting-started.md
@@ -1,35 +1,61 @@
# Getting started
-This page takes you from a fresh clone to a compiled solver bundle.
+This page takes you from an empty environment to a compiled solver bundle.
## Prerequisites
-- **Python 3.12** (the workspace pins `>=3.12,<3.13`).
-- **[uv](https://docs.astral.sh/uv/)** β the package/environment manager this project
- uses. Install it with `curl -LsSf https://astral.sh/uv/install.sh | sh` or `brew install uv`.
-
-!!! warning "Always go through `uv run`"
- Never call `python`, `pytest`, `ruff`, or `mypy` directly β they may not be on your
- PATH or may pick up the wrong environment. Prefix every project command with
- `uv run`.
+- **Python 3.11, 3.12, or 3.13** β `mechdsl-core` declares
+ `requires-python = ">=3.11,<3.14"`.
+- Nothing else. There is no compiler toolchain to set up and no system FEM library to
+ build; Taichi ships prebuilt wheels and is only needed if you want to *run* solves.
## Install
+`mechdsl-core` is on PyPI, so the quickest start is one command:
+
```bash
-git clone https://github.com/CEmM2/MechDSL.git
-cd MechDSL
-uv sync --all-packages --all-groups --all-extras
+pip install mechdsl-core
```
-`uv sync` installs both workspace packages (`mechdsl-core` and `algo2code`) and their
-dependencies into a local `.venv`.
+That is all you need for everything on this page: parsing directives, deriving
+stress and tangent, and emitting Taichi source. It pulls no Taichi, so the install
+stays small.
-Verify the install by running the fast test suite:
+If you want to **execute and verify** the code you generate, take the full engine
+instead β it adds `taichi`, `ti-runtime`, and `algo2code`:
```bash
-uv run pytest -m "not slow and not gpu" -q
+pip install "mechdsl-core[verify]"
```
+??? note "Installing from source instead"
+ If you want the runnable `examples/` tree, the test suite, or you intend to
+ contribute, clone the [uv](https://docs.astral.sh/uv/) workspace:
+
+ ```bash
+ git clone https://github.com/CEmM2/MechDSL.git
+ cd MechDSL
+ uv sync --all-packages --all-groups --all-extras
+ ```
+
+ `uv sync` installs all three workspace packages (`mechdsl-core`, `algo2code`, and
+ `ti-runtime`) and their dependencies into a local `.venv`. Inside a source
+ checkout, prefix **every** command with `uv run` β never call `python`, `pytest`,
+ `ruff`, or `mypy` directly, since they may not be on your PATH or may pick up the
+ wrong environment. Verify with the fast test tier:
+
+ ```bash
+ uv run pytest -m "not slow and not gpu" -q
+ ```
+
+The full install matrix β every package, every extra, the workbench β is on the
+[Installation](../installation.md) page.
+
+!!! tip "The commands below"
+ Snippets on this page are written for a `pip install`ed MechDSL, so they call
+ `python` directly. In a **source checkout**, prefix them with `uv run`
+ (`uv run python first_run.py`).
+
## Your first solver bundle
The canonical entry point is `compile_latex`. Create a file `first_run.py`:
@@ -54,11 +80,12 @@ print("content hash:", bundle.content_hash())
Run it:
```bash
-uv run python first_run.py
+python first_run.py
```
-A runnable copy of this lives at
-[`examples/run_compile_latex.py`](https://github.com/CEmM2/MechDSL/blob/main/examples/run_compile_latex.py):
+A runnable copy of this lives in the repository at
+[`examples/run_compile_latex.py`](https://github.com/CEmM2/MechDSL/blob/main/examples/run_compile_latex.py),
+so from a source checkout you can skip straight to:
```bash
uv run python examples/run_compile_latex.py
@@ -131,3 +158,5 @@ for the full list of derivable energies.
- [LaTeX directive reference](latex-directives.md) β the complete directive grammar.
- [Examples gallery](examples.md) β runnable benchmarks (Cook's membrane, necking bar,
patch test, cyclic plasticity).
+- [Browser workbench](../workbench.md) β the same compiler with a UI, if you'd rather
+ edit LaTeX in a pane than in a script.
diff --git a/docs/mechdsl-core/index.md b/docs/mechdsl-core/index.md
index 946831e..499d426 100644
--- a/docs/mechdsl-core/index.md
+++ b/docs/mechdsl-core/index.md
@@ -12,6 +12,13 @@ The same `.tex` file renders normally through `pdflatex` (the directives are LaT
comments) **and** is executable input to the compiler. Your paper's source can be your
simulation's source.
+It is published on PyPI under the MIT license:
+
+```bash
+pip install mechdsl-core # emit code β Taichi-free, small install
+pip install "mechdsl-core[verify]" # the full engine β run and verify solves
+```
+
---
## Why a colleague should care
@@ -74,11 +81,14 @@ See the full [constitutive model catalog](constitutive-models.md) and the
-- :material-rocket-launch: **[Getting started](getting-started.md)** β install with `uv`, run your first solver in a few minutes.
+- :material-download: **[Installation](../installation.md)** β every package, extra, and the from-source workflow.
+- :material-rocket-launch: **[Getting started](getting-started.md)** β `pip install`, then your first solver in a few minutes.
- :material-school: **[Core concepts](concepts.md)** β the LaTeX-first idea, the six-layer pipeline, and the support tiers.
- :material-code-tags: **[LaTeX directive reference](latex-directives.md)** β every `% mechanics` directive, with examples.
- :material-function-variant: **[Constitutive models](constitutive-models.md)** β the model catalog with runnable snippets.
- :material-cards: **[Examples gallery](examples.md)** β cantilever, Cook's membrane, necking bar, patch test, cyclic plasticity.
+- :material-chip: **[ti-runtime](../ti-runtime/index.md)** β the runtime the emitted kernels actually land on.
+- :material-application-brackets: **[Browser workbench](../workbench.md)** β the same compiler, driven from a UI.
- :material-help-circle: **[FAQ & troubleshooting](../reference/faq.md)** β common questions and fixes.
diff --git a/docs/reference/architecture.md b/docs/reference/architecture.md
index 25fdd05..d06c4a0 100644
--- a/docs/reference/architecture.md
+++ b/docs/reference/architecture.md
@@ -22,6 +22,12 @@ representation. Information only ever flows downward, through the IRs.
Supporting packages: `mechdsl.solver` (Newton driver + imported linear solver adapter)
and `mechdsl.lib` (the Tier-1 `@ti.func` library and plasticity orchestration).
+Beneath all of that sits [`ti-runtime`](../ti-runtime/index.md), the neutral Taichi
+runtime that **generated** code lands on β vector primitives, Tier-1 `@ti.func` tensor
+helpers, Hex8 shape gradients, and the injection seams. The direction matters: emitted
+artifacts import `ti_runtime`, never `mechdsl`, so a generated kernel outlives the
+compiler run that produced it.
+
```text
LaTeX βββΆ SymPy tensors βββΆ ProblemIR βββΆ ElementIR βββΆ EinsumIR βββΆ Taichi
frontend symbolic lowering optimiser codegen
@@ -70,6 +76,41 @@ The seam is the `LinearSolverInterface` protocol in `mechdsl.solver.import_adapt
the Newton driver calls through. See [the algo2code page](../algo2code/index.md) for the full
story, and `dev/design_docs/11-ALGO2CODE.md` for the authoritative reference.
+## `mechdsl.integration` β the public faΓ§ade { #integration-facade }
+
+Everything above describes the machinery. Tools that *consume* MechDSL β the
+[browser workbench](../workbench.md), downstream adapters, anything embedding the
+compiler β should not reach into it. They call `mechdsl.integration`, the stable,
+machine-readable Tier-1 surface, which is exactly five entry points:
+
+| Function | Returns | Needs Taichi? |
+|---|---|---|
+| `capabilities()` | A manifest: version, profiles, backends, actions, models | No |
+| `model_catalog()` | Every constitutive model with tier, dissipative flag, params, state variables | No |
+| `compile_from_sources(...)` | `{element_ir_summary, emitted_source, content_hash, derived_energy_present}` | No |
+| `transpile_algorithm(algpseudocode, backend)` | `{code, entry_point, line_count, valid_python}` | No |
+| `verify(kind, params)` | `{kind, passed, details}` | **Yes** |
+
+```python
+from mechdsl.integration import capabilities, compile_from_sources
+
+caps = capabilities()
+print(caps["taichi_required_for"]) # -> ["verify"]
+
+result = compile_from_sources(problem_source="% mechanics dim 3\n...")
+print(result["content_hash"]) # 64-char sha-256 hex digest
+```
+
+**The Taichi-required-for contract:** `capabilities()` declares
+`taichi_required_for: ["verify"]`. The other four entry points are guaranteed never to
+trigger `ti.init`, so importing `mechdsl.integration` and calling them is safe in a
+Taichi-free environment β which is why the base `pip install mechdsl-core` can leave
+Taichi out entirely (see [Installation](../installation.md)). Only `verify()` pays the
+Taichi cost, and it imports lazily at call time.
+
+This is a machine API contract, not a convenience library; entry points are not added to
+it without a deliberate design decision.
+
## Where to read more
| Topic | Design doc |
diff --git a/docs/reference/faq.md b/docs/reference/faq.md
index 0584bdf..02a8528 100644
--- a/docs/reference/faq.md
+++ b/docs/reference/faq.md
@@ -2,6 +2,44 @@
## Frequently asked
+### How do I install it? Is it on PyPI?
+
+Yes β every package is published on PyPI under the MIT license, so `pip install` is the
+normal way in:
+
+```bash
+pip install mechdsl-core # the compiler, Taichi-free
+pip install "mechdsl-core[verify]" # the full engine: run and verify solves
+pip install algo2code # the transpiler alone, stdlib-only
+pip install ti-runtime # the Taichi runtime alone
+pip install "mechdsl-workbench[mechdsl]" # the browser workbench plus the engine
+```
+
+You do **not** need to clone the repository or install `uv` unless you want the
+runnable `examples/` tree, the test suite, or to contribute. Full matrix on the
+[Installation](../installation.md) page.
+
+### Why does the base install not include Taichi?
+
+Because only one entry point needs it. Emission, transpilation, `capabilities()`, and
+`model_catalog()` are proven Taichi-free by the test suite; only
+`mechdsl.integration.verify()` imports Taichi, and it does so lazily at call time. That
+lets downstream consumers depend on `mechdsl-core` for code generation without pulling
+Taichi's ~170 MB into their dependency closure. `pip install "mechdsl-core[verify]"`
+when you actually want to run solves.
+
+### Which Python version do I need?
+
+`mechdsl-core`, `algo2code`, and `ti-runtime` accept **Python 3.11β3.13**
+(`>=3.11,<3.14`). The `mechdsl-workbench` companion is narrower and pins **Python 3.12**
+(`>=3.12,<3.13`).
+
+### Can I try it without writing any code?
+
+Yes. `pip install "mechdsl-workbench[mechdsl]"`, run `mechdsl-workbench`, and open
+
β LaTeX in the left pane, generated Taichi in the right. See
+[the workbench page](../workbench.md).
+
### Is this a replacement for Abaqus / ANSYS / a full FE package?
No. MechDSL is a **compiler** that generates solver code from a LaTeX description of a
@@ -58,13 +96,28 @@ numpy. See [the algo2code page](../algo2code/usage.md#how-the-j2-family-is-wired
### `command not found` / wrong package versions
-You're probably calling `python`/`pytest`/`ruff` directly. Always prefix with `uv run`.
-If the environment looks stale, re-sync:
+**In a source checkout:** you're probably calling `python`/`pytest`/`ruff` directly.
+Always prefix with `uv run`. If the environment looks stale, re-sync:
```bash
uv sync --all-packages --all-groups --all-extras
```
+**With a `pip install`ed MechDSL:** check you're in the environment you installed into
+(`python -c "import mechdsl; print(mechdsl.__file__)"`) and that the interpreter is
+3.11β3.13. A `pip install` puts MechDSL in whatever environment `pip` points at, so a
+virtualenv you forgot to activate is the usual culprit.
+
+### `ModuleNotFoundError: No module named 'taichi'`
+
+Expected on the base install β it is deliberately Taichi-free. Anything that *runs*
+generated code (`mechdsl.integration.verify()`, the solver path, the `slow`/`gpu` tests)
+needs the full engine:
+
+```bash
+pip install "mechdsl-core[verify]"
+```
+
### A construct raises "planned in phase ..."
That's intentional. Unsupported constructs raise explicitly with the plan phase that adds
diff --git a/docs/stylesheets/mechdsl.css b/docs/stylesheets/mechdsl.css
new file mode 100644
index 0000000..faa21ee
--- /dev/null
+++ b/docs/stylesheets/mechdsl.css
@@ -0,0 +1,744 @@
+/* ==========================================================================
+ MechDSL documentation theme
+ --------------------------------------------------------------------------
+ Ports the sosovski.group site's sketchbook look (paper ground, hand-drawn
+ borders, hard offset shadows, Baloo 2 / Patrick Hand / Cabin Sketch) onto
+ MkDocs Material. Token names and values mirror GroupWebSite's
+ src/styles/global.css so the docs read as part of the same site.
+ ========================================================================== */
+
+@import url('https://fonts.googleapis.com/css2?family=Cabin+Sketch:wght@700&family=Patrick+Hand&display=swap');
+
+/* --------------------------------------------------------------------------
+ 1. Tokens
+ -------------------------------------------------------------------------- */
+
+:root,
+[data-md-color-scheme="default"] {
+ --paper: #f7ead0;
+ --paper-2: #fff8e7;
+ --surface: #fffaf0;
+ --elev: #f0dfbd;
+ --ink: #2b2118;
+ --muted: #6d5b45;
+ --line: #9f744b;
+ --line-soft: rgba(159, 116, 75, 0.35);
+ --gold: #d8aa55;
+ --teal: #2f6f78;
+ --blue: #4e7d96;
+ --sage: #718a5d;
+ --rust: #a24d37;
+ --shadow: 5px 6px 0 rgba(43, 33, 24, 0.92);
+ --shadow-sm: 3px 4px 0 var(--ink);
+ --radius: 22px;
+ --font-hand: 'Patrick Hand', 'Baloo 2', system-ui, sans-serif;
+ --font-sketch: 'Cabin Sketch', 'Baloo 2', system-ui, sans-serif;
+
+ /* Material bindings */
+ --md-default-fg-color: var(--ink);
+ --md-default-fg-color--light: var(--muted);
+ --md-default-fg-color--lighter: rgba(109, 91, 69, 0.5);
+ --md-default-fg-color--lightest: var(--line-soft);
+ --md-default-bg-color: var(--paper-2);
+ --md-primary-fg-color: var(--paper);
+ --md-primary-bg-color: var(--ink);
+ --md-primary-bg-color--light: var(--muted);
+ --md-accent-fg-color: var(--rust);
+ --md-typeset-color: var(--ink);
+ --md-typeset-a-color: var(--teal);
+ --md-code-bg-color: #fdf3dd;
+ --md-code-fg-color: #3b2d20;
+ --md-footer-bg-color: var(--paper);
+ --md-footer-fg-color: var(--ink);
+ --md-shadow-z1: none;
+ --md-shadow-z2: none;
+ --md-shadow-z3: none;
+}
+
+/* Night-desk variant: the same palette, inked rather than papered. */
+[data-md-color-scheme="slate"] {
+ --paper: #241c15;
+ --paper-2: #2e251c;
+ --surface: #332a20;
+ --elev: #3d3226;
+ --ink: #f4e6cb;
+ --muted: #c3ad8d;
+ --line: #b9884f;
+ --line-soft: rgba(185, 136, 79, 0.4);
+ --gold: #e0b76a;
+ --teal: #79bfc7;
+ --blue: #8fb4c9;
+ --sage: #a7c08a;
+ --rust: #e08b6c;
+ --shadow: 5px 6px 0 rgba(0, 0, 0, 0.65);
+ --shadow-sm: 3px 4px 0 rgba(0, 0, 0, 0.65);
+
+ --md-default-fg-color: var(--ink);
+ --md-default-fg-color--light: var(--muted);
+ --md-default-fg-color--lighter: rgba(195, 173, 141, 0.5);
+ --md-default-fg-color--lightest: var(--line-soft);
+ --md-default-bg-color: var(--paper-2);
+ --md-primary-fg-color: var(--paper);
+ --md-primary-bg-color: var(--ink);
+ --md-accent-fg-color: var(--gold);
+ --md-typeset-color: var(--ink);
+ --md-typeset-a-color: var(--teal);
+ --md-code-bg-color: #2a2219;
+ --md-code-fg-color: #e8dcc2;
+ --md-footer-bg-color: var(--paper);
+ --md-footer-fg-color: var(--ink);
+}
+
+/* --------------------------------------------------------------------------
+ 2. Paper ground
+ -------------------------------------------------------------------------- */
+
+body {
+ background:
+ radial-gradient(circle at 1px 1px, rgba(159, 116, 75, 0.18) 1.2px, transparent 0) 0 0 / 28px 28px,
+ linear-gradient(135deg, #f4e2bd 0%, var(--paper) 45%, #ead2a7 100%);
+ background-attachment: fixed;
+ text-rendering: optimizeLegibility;
+}
+
+[data-md-color-scheme="slate"] body {
+ background:
+ radial-gradient(circle at 1px 1px, rgba(185, 136, 79, 0.14) 1.2px, transparent 0) 0 0 / 28px 28px,
+ linear-gradient(135deg, #1d1710 0%, var(--paper) 45%, #191410 100%);
+}
+
+.md-main__inner {
+ margin-top: 1.6rem;
+}
+
+/* The content sheet: a page of paper laid on the desk. */
+.md-content__inner {
+ background: var(--paper-2);
+ border: 3px solid var(--line);
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+ padding: 1.6rem clamp(1rem, 3vw, 2.4rem) 2.4rem;
+ margin-bottom: 2.4rem;
+}
+
+.md-content__inner::before {
+ height: 0;
+}
+
+/* --------------------------------------------------------------------------
+ 3. Header & navigation
+ -------------------------------------------------------------------------- */
+
+.md-header {
+ background: rgba(247, 234, 208, 0.92);
+ backdrop-filter: blur(10px);
+ border-bottom: 3px solid var(--line);
+ box-shadow: 0 4px 0 rgba(43, 33, 24, 0.12);
+ color: var(--ink);
+}
+
+[data-md-color-scheme="slate"] .md-header {
+ background: rgba(36, 28, 21, 0.92);
+}
+
+.md-header__title {
+ font: 800 1.25rem/1 var(--md-text-font-family);
+ letter-spacing: 0.02em;
+}
+
+.md-header__button.md-logo img {
+ width: 2rem;
+ height: 2rem;
+ border-radius: 8px;
+ border: 2px solid var(--line);
+ background: var(--paper-2);
+}
+
+.md-search__form {
+ background: var(--paper-2);
+ border: 2px solid var(--line);
+ border-radius: 999px;
+ box-shadow: 2px 3px 0 var(--ink);
+}
+
+.md-search__form:hover {
+ background: var(--surface);
+}
+
+.md-search__input::placeholder {
+ color: var(--muted);
+}
+
+.md-search__output {
+ border-radius: var(--radius);
+ border: 3px solid var(--line);
+ overflow: hidden;
+}
+
+/* Sidebar links styled like the group site's nav pills. */
+.md-nav {
+ font-size: 0.74rem;
+}
+
+.md-nav__title {
+ font: 800 0.78rem/1.2 var(--md-text-font-family);
+ color: var(--muted);
+ text-transform: uppercase;
+ letter-spacing: 0.06em;
+}
+
+.md-nav__link {
+ border: 2px solid transparent;
+ border-radius: 999px;
+ padding: 0.2rem 0.55rem;
+ font-weight: 700;
+ color: var(--ink);
+ transition: background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
+}
+
+.md-nav__link:focus,
+.md-nav__link:hover {
+ color: var(--rust);
+ border-color: var(--line-soft);
+ background: var(--paper-2);
+}
+
+.md-nav__link--active,
+.md-nav__item .md-nav__link--active {
+ color: var(--ink);
+ border-color: var(--line);
+ background: var(--paper-2);
+ box-shadow: 2px 3px 0 var(--ink);
+}
+
+.md-nav--secondary .md-nav__link--active {
+ box-shadow: none;
+ background: transparent;
+ border-color: transparent;
+ color: var(--rust);
+}
+
+/* --------------------------------------------------------------------------
+ 4. Typography
+ -------------------------------------------------------------------------- */
+
+.md-typeset {
+ font-size: 0.79rem;
+ line-height: 1.65;
+}
+
+.md-typeset h1 {
+ font-weight: 800;
+ font-size: clamp(2rem, 5vw, 2.9rem);
+ line-height: 0.98;
+ letter-spacing: -0.035em;
+ color: var(--ink);
+ margin-bottom: 0.6rem;
+}
+
+.md-typeset h2 {
+ font-weight: 800;
+ font-size: 1.65rem;
+ line-height: 1.05;
+ letter-spacing: -0.02em;
+ color: var(--ink);
+ margin-top: 2.2rem;
+ padding-bottom: 0.35rem;
+ border-bottom: 3px solid var(--line-soft);
+}
+
+.md-typeset h3 {
+ font-weight: 800;
+ font-size: 1.2rem;
+ letter-spacing: -0.01em;
+ color: var(--teal);
+}
+
+.md-typeset h4,
+.md-typeset h5 {
+ font-weight: 800;
+ color: var(--ink);
+}
+
+.md-typeset a {
+ text-decoration-thickness: 2px;
+ text-underline-offset: 0.18em;
+}
+
+.md-typeset a:hover {
+ color: var(--rust);
+}
+
+.md-typeset hr {
+ border-bottom: 3px dashed var(--line-soft);
+ margin: 2rem 0;
+}
+
+/* Material ships these under [dir=ltr], which outranks a bare .md-typeset
+ selector β match that specificity or the accent bar never lands. */
+.md-typeset blockquote,
+[dir="ltr"] .md-typeset blockquote {
+ border-left: 10px solid var(--teal);
+ border-right: none;
+ border-radius: 0 12px 12px 0;
+ background: rgba(255, 248, 231, 0.72);
+ color: var(--ink);
+ padding: 0.6rem 1rem;
+ margin-left: 0;
+}
+
+[data-md-color-scheme="slate"] .md-typeset blockquote {
+ background: rgba(51, 42, 32, 0.7);
+}
+
+.md-typeset blockquote strong {
+ color: var(--rust);
+}
+
+.md-typeset kbd {
+ background: var(--elev);
+ border: 2px solid var(--line);
+ border-radius: 8px;
+ box-shadow: 2px 3px 0 var(--ink);
+ color: var(--ink);
+}
+
+/* --------------------------------------------------------------------------
+ 5. Code
+ -------------------------------------------------------------------------- */
+
+.md-typeset code {
+ border: 1px solid var(--line-soft);
+ border-radius: 6px;
+ padding: 0.08em 0.35em;
+}
+
+.md-typeset pre > code {
+ border: none;
+ padding: 0.7rem 1rem;
+}
+
+.md-typeset .highlight,
+.md-typeset pre {
+ border-radius: 14px;
+}
+
+/* Border and shadow on the frame; the inner keeps Material's own
+ horizontal scroll, so wide lines stay reachable rather than clipped. */
+.md-typeset .highlight > pre,
+.md-typeset > pre {
+ border: 3px solid var(--line);
+ border-radius: 14px;
+ box-shadow: var(--shadow-sm);
+}
+
+.md-typeset .highlight > pre > code,
+.md-typeset > pre > code {
+ border-radius: 11px;
+}
+
+.md-typeset .highlight [data-linenos]::before {
+ background: var(--elev);
+ color: var(--muted);
+ box-shadow: none;
+}
+
+.md-clipboard {
+ color: var(--muted);
+}
+
+.md-clipboard:hover {
+ color: var(--rust);
+}
+
+/* Tabbed code blocks */
+.md-typeset .tabbed-set > input:checked + label {
+ color: var(--teal);
+ border-color: var(--teal);
+ font-weight: 800;
+}
+
+.md-typeset .tabbed-labels > label {
+ font-weight: 700;
+}
+
+/* --------------------------------------------------------------------------
+ 6. Tables
+ -------------------------------------------------------------------------- */
+
+.md-typeset table:not([class]) {
+ border: 3px solid var(--line);
+ border-radius: 14px;
+ box-shadow: var(--shadow-sm);
+ background: var(--surface);
+ overflow: hidden;
+ font-size: 0.72rem;
+}
+
+.md-typeset table:not([class]) th {
+ background: var(--elev);
+ color: var(--ink);
+ font-weight: 800;
+ border-bottom: 3px solid var(--line);
+}
+
+.md-typeset table:not([class]) td {
+ border-top: 1px solid var(--line-soft);
+}
+
+.md-typeset table:not([class]) tr:hover {
+ background: rgba(240, 223, 189, 0.35);
+}
+
+/* Code spans in tables wrap at token boundaries rather than mid-identifier. */
+.md-typeset table:not([class]) td code {
+ word-break: keep-all;
+ overflow-wrap: break-word;
+}
+
+/* --------------------------------------------------------------------------
+ 7. Admonitions β the group site's callout, colour-coded
+ -------------------------------------------------------------------------- */
+
+.md-typeset .admonition,
+.md-typeset details {
+ border: 3px dashed var(--line);
+ border-left-width: 3px;
+ border-radius: var(--radius);
+ background: rgba(255, 248, 231, 0.78);
+ box-shadow: none;
+ font-size: 0.76rem;
+}
+
+[data-md-color-scheme="slate"] .md-typeset .admonition,
+[data-md-color-scheme="slate"] .md-typeset details {
+ background: rgba(51, 42, 32, 0.75);
+}
+
+.md-typeset .admonition-title,
+.md-typeset summary,
+[dir="ltr"] .md-typeset .admonition-title,
+[dir="ltr"] .md-typeset summary {
+ background: transparent;
+ border: none;
+ border-left-width: 0;
+ border-radius: 0;
+ font-weight: 800;
+ font-size: 0.86rem;
+}
+
+/* Material tints each title bar with the type colour at 10% opacity, scoped
+ as `.md-typeset .tip>.admonition-title` (0,3,1). Match that to keep the
+ title flush with the callout body. */
+.md-typeset .admonition > .admonition-title,
+.md-typeset .admonition > summary,
+.md-typeset details > .admonition-title,
+.md-typeset details > summary {
+ background-color: transparent;
+}
+
+.md-typeset .admonition-title::before,
+.md-typeset summary::before {
+ top: 0.62rem;
+}
+
+/* Material scopes its per-type colours as `.md-typeset .admonition.tip`
+ (specificity 0,3,0), so a bare `.md-typeset .tip` never wins. Every rule
+ below matches that shape deliberately. */
+
+/* note / info / abstract -> teal */
+.md-typeset .admonition.note,
+.md-typeset details.note,
+.md-typeset .admonition.info,
+.md-typeset details.info,
+.md-typeset .admonition.abstract,
+.md-typeset details.abstract {
+ border-color: var(--teal);
+}
+
+.md-typeset .note > .admonition-title,
+.md-typeset .note > summary,
+.md-typeset .info > .admonition-title,
+.md-typeset .info > summary,
+.md-typeset .abstract > .admonition-title,
+.md-typeset .abstract > summary {
+ color: var(--teal);
+}
+
+.md-typeset .note > .admonition-title::before,
+.md-typeset .note > summary::before,
+.md-typeset .info > .admonition-title::before,
+.md-typeset .info > summary::before,
+.md-typeset .abstract > .admonition-title::before,
+.md-typeset .abstract > summary::before {
+ background-color: var(--teal);
+}
+
+/* tip / success / example -> sage */
+.md-typeset .admonition.tip,
+.md-typeset details.tip,
+.md-typeset .admonition.success,
+.md-typeset details.success,
+.md-typeset .admonition.example,
+.md-typeset details.example {
+ border-color: var(--sage);
+}
+
+.md-typeset .tip > .admonition-title,
+.md-typeset .tip > summary,
+.md-typeset .success > .admonition-title,
+.md-typeset .success > summary,
+.md-typeset .example > .admonition-title,
+.md-typeset .example > summary {
+ color: var(--sage);
+}
+
+.md-typeset .tip > .admonition-title::before,
+.md-typeset .tip > summary::before,
+.md-typeset .success > .admonition-title::before,
+.md-typeset .success > summary::before,
+.md-typeset .example > .admonition-title::before,
+.md-typeset .example > summary::before {
+ background-color: var(--sage);
+}
+
+/* warning / question -> gold (darkened for text contrast on cream) */
+.md-typeset .admonition.warning,
+.md-typeset details.warning,
+.md-typeset .admonition.question,
+.md-typeset details.question {
+ border-color: var(--gold);
+}
+
+.md-typeset .warning > .admonition-title,
+.md-typeset .warning > summary,
+.md-typeset .question > .admonition-title,
+.md-typeset .question > summary {
+ color: #8a6320;
+}
+
+[data-md-color-scheme="slate"] .md-typeset .warning > .admonition-title,
+[data-md-color-scheme="slate"] .md-typeset .warning > summary,
+[data-md-color-scheme="slate"] .md-typeset .question > .admonition-title,
+[data-md-color-scheme="slate"] .md-typeset .question > summary {
+ color: var(--gold);
+}
+
+.md-typeset .warning > .admonition-title::before,
+.md-typeset .warning > summary::before,
+.md-typeset .question > .admonition-title::before,
+.md-typeset .question > summary::before {
+ background-color: #8a6320;
+}
+
+/* danger / failure / bug -> rust */
+.md-typeset .admonition.danger,
+.md-typeset details.danger,
+.md-typeset .admonition.failure,
+.md-typeset details.failure,
+.md-typeset .admonition.bug,
+.md-typeset details.bug {
+ border-color: var(--rust);
+}
+
+.md-typeset .danger > .admonition-title,
+.md-typeset .danger > summary,
+.md-typeset .failure > .admonition-title,
+.md-typeset .failure > summary,
+.md-typeset .bug > .admonition-title,
+.md-typeset .bug > summary {
+ color: var(--rust);
+}
+
+.md-typeset .danger > .admonition-title::before,
+.md-typeset .danger > summary::before,
+.md-typeset .failure > .admonition-title::before,
+.md-typeset .failure > summary::before,
+.md-typeset .bug > .admonition-title::before,
+.md-typeset .bug > summary::before {
+ background-color: var(--rust);
+}
+
+/* --------------------------------------------------------------------------
+ 8. Cards, buttons, ornaments
+ -------------------------------------------------------------------------- */
+
+.md-typeset .grid.cards > ul > li,
+.md-typeset .grid > .card {
+ background: var(--surface);
+ border: 3px solid var(--line);
+ border-radius: var(--radius);
+ box-shadow: var(--shadow-sm);
+ padding: 1.05rem;
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
+}
+
+.md-typeset .grid.cards > ul > li:hover,
+.md-typeset .grid > .card:hover {
+ transform: translate(2px, 2px);
+ box-shadow: 1px 2px 0 var(--ink);
+ border-color: var(--teal);
+}
+
+.md-typeset .grid.cards > ul > li > hr {
+ border-bottom: 3px dashed var(--line-soft);
+ margin: 0.6rem 0;
+}
+
+.md-typeset .md-button {
+ border: 3px solid var(--ink);
+ border-radius: 999px;
+ padding: 0.55rem 1rem;
+ font-weight: 900;
+ color: var(--ink);
+ background: var(--gold);
+ box-shadow: var(--shadow-sm);
+ transition: transform 0.12s ease, box-shadow 0.12s ease;
+}
+
+.md-typeset .md-button:hover,
+.md-typeset .md-button:focus {
+ background: var(--gold);
+ border-color: var(--ink);
+ color: var(--ink);
+ transform: translate(2px, 2px);
+ box-shadow: 1px 2px 0 var(--ink);
+}
+
+.md-typeset .md-button--primary {
+ background: var(--teal);
+ color: var(--paper-2);
+ border-color: var(--ink);
+}
+
+.md-typeset .md-button--primary:hover,
+.md-typeset .md-button--primary:focus {
+ background: var(--teal);
+ color: var(--paper-2);
+}
+
+/* Hand-lettered aside, as on the group site. */
+.md-typeset .note-hand {
+ font-family: var(--font-hand);
+ font-size: 1.25rem;
+ line-height: 1.3;
+ color: var(--muted);
+ transform: rotate(-0.6deg);
+ display: block;
+ margin: 1.2rem 0;
+}
+
+/* Rotated sticker label. */
+.md-typeset .ribbon {
+ display: inline-block;
+ font-family: var(--font-sketch);
+ color: var(--ink);
+ background: var(--gold);
+ border: 3px solid var(--ink);
+ border-radius: 10px;
+ padding: 0.12rem 0.55rem;
+ transform: rotate(-1deg);
+ box-shadow: 2px 3px 0 var(--ink);
+}
+
+/* Pill tags for package/tier badges. */
+.md-typeset .tag-pill {
+ display: inline-block;
+ border: 2px solid var(--line-soft);
+ border-radius: 999px;
+ padding: 0.1rem 0.55rem;
+ color: var(--muted);
+ background: #fff4d8;
+ font-weight: 800;
+ font-size: 0.72rem;
+}
+
+[data-md-color-scheme="slate"] .md-typeset .tag-pill {
+ background: var(--elev);
+}
+
+/* Banner image on the landing page. */
+.md-typeset .hero-banner {
+ display: block;
+ width: 100%;
+ border: 3px solid var(--line);
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+ margin: 0 0 1.6rem;
+}
+
+.md-typeset figure img {
+ border: 3px solid var(--line);
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+}
+
+.md-typeset figcaption {
+ color: var(--muted);
+ font-style: italic;
+}
+
+/* --------------------------------------------------------------------------
+ 9. Footer
+ -------------------------------------------------------------------------- */
+
+.md-footer {
+ border-top: 3px solid var(--line);
+ background: rgba(247, 234, 208, 0.9);
+ color: var(--ink);
+}
+
+[data-md-color-scheme="slate"] .md-footer {
+ background: rgba(36, 28, 21, 0.9);
+}
+
+.md-footer-meta {
+ background: transparent;
+ border-top: 1px solid var(--line-soft);
+}
+
+.md-footer__link {
+ color: var(--ink);
+ font-weight: 800;
+ opacity: 1;
+}
+
+.md-footer__link:hover {
+ color: var(--rust);
+}
+
+.md-copyright,
+.md-copyright__highlight {
+ color: var(--muted);
+}
+
+.md-footer-nav__link,
+.md-social__link {
+ color: var(--ink);
+}
+
+/* --------------------------------------------------------------------------
+ 10. Small screens
+ -------------------------------------------------------------------------- */
+
+@media screen and (max-width: 76.1875em) {
+ .md-nav--primary .md-nav__title {
+ background: var(--paper);
+ color: var(--ink);
+ box-shadow: none;
+ border-bottom: 3px solid var(--line);
+ }
+
+ .md-nav--primary {
+ background: var(--paper-2);
+ }
+}
+
+@media screen and (max-width: 44.9375em) {
+ .md-content__inner {
+ border-width: 2px;
+ border-radius: 16px;
+ padding: 1.1rem 0.9rem 1.6rem;
+ box-shadow: 3px 4px 0 rgba(43, 33, 24, 0.9);
+ }
+}
diff --git a/docs/ti-runtime/index.md b/docs/ti-runtime/index.md
new file mode 100644
index 0000000..84bfece
--- /dev/null
+++ b/docs/ti-runtime/index.md
@@ -0,0 +1,88 @@
+# ti-runtime
+
+`ti-runtime` is the **neutral Taichi runtime** that MechDSL-generated code lands on. It
+holds seams and primitives β and nothing algorithmic. Where
+[mechdsl-core](../mechdsl-core/index.md) derives constitutive math from LaTeX and
+[algo2code](../algo2code/index.md) derives algorithms from LaTeX, `ti-runtime` is the
+stable floor both of them emit against.
+
+```bash
+pip install ti-runtime
+```
+
+It is a genuinely standalone package: it depends on `taichi` and nothing else, and it
+never imports `mechdsl`. It also arrives automatically with
+`pip install "mechdsl-core[verify]"`.
+
+---
+
+## Seams & Bodies
+
+The architecture has a one-line summary:
+
+> MechDSL owns the **seams and primitives** (this package); algo2code generates the
+> **bodies** β solvers, preconditioners, constitutive updates, time integrators β from
+> LaTeX, injected into those seams.
+
+The payoff is portability. Generated artifacts depend on `ti_runtime`, **never** on
+`mechdsl`, so an emitted kernel can be lifted out of the compiler that produced it and
+run wherever `ti-runtime` is installed.
+
+---
+
+## What's in it
+
+| Module | Contents |
+|---|---|
+| `vector_ops` | `@ti.kernel` vector primitives: `copy`, `axpy`, `xpay`, `scal`, `zero`, `dot`, `norm2`, `vec_add`, `ediv` |
+| `tensor_ti` | Tier-1 `@ti.func` helpers: `det3` / `inv3`, the FβCβEβJ kinematic chain, Voigt conversion, deviatoric split, von Mises |
+| `seams` | Injection plumbing: `Operator`, `PreconditionerBase` / `IdentityPreconditioner` / `DiagonalPreconditioner`, `Solver`, `LinearSolveContext`, `Integrator`, `TimeIntegrationContext`, `AccelSolve` |
+| `fields` | `ti.init` and field-allocation boilerplate |
+| `hex8` | Hex8 shape functions, natural-coordinate gradients, 2Γ2Γ2 Gauss quadrature |
+
+Everything above is re-exported from the package root:
+
+```python
+from ti_runtime import LinearSolveContext, DiagonalPreconditioner, axpy, dot, norm2
+```
+
+---
+
+## The operator / solver contract
+
+A matrix-free operator is an in-place callable `apply(out, x) -> None` computing
+`out = A @ x` over Taichi fields β typically a generated `@ti.kernel`. A preconditioner
+mirrors the same shape: `apply(z, r)` sets `z = Mβ»ΒΉ r`.
+
+```python
+from ti_runtime import LinearSolveContext, DiagonalPreconditioner
+
+ctx = LinearSolveContext()
+ctx.set_operator(my_tangent_matvec) # out = K(u) @ x, matrix-free @ti.kernel
+ctx.set_preconditioner(DiagonalPreconditioner(diag))
+# a generated PCG body then calls ctx.apply_A / ctx.apply_preconditioner + vector_ops
+```
+
+Because `LinearSolveContext` applies *whatever* operator, preconditioner, and solver were
+injected, the plumbing is algorithm-agnostic β swapping in a different generated solver
+body changes no runtime code.
+
+---
+
+## How mechdsl-core uses it
+
+The generated matrix-free SVK tangent kernel emits `from ti_runtime import ...` for the
+Tier-1 tensor helpers, the Hex8 shape gradients, and the `apply_A` injection seam. That
+is the `mechdsl-core β ti-runtime` production dependency edge. Since `ti-runtime` carries
+Taichi, it rides in the `verify` extra alongside it β keeping the base `mechdsl-core`
+install Taichi-free. See [Installation](../installation.md) for the split.
+
+---
+
+## Provenance & conventions
+
+- **One-time harvest.** Adapted from NumerixWeave (`libs/tisolvers`, `libs/ticonstit`,
+ `apps/tifem`) in a single pass; there is no ongoing sync.
+- **Conventions match the rest of MechDSL:** Voigt order `[xx, yy, zz, xy, xz, yz]`,
+ tensorial (unscaled shears), metric `diag(1, 1, 1, 2, 2, 2)`. See
+ [Core concepts β conventions](../mechdsl-core/concepts.md#conventions).
diff --git a/docs/workbench.md b/docs/workbench.md
new file mode 100644
index 0000000..d409d1f
--- /dev/null
+++ b/docs/workbench.md
@@ -0,0 +1,110 @@
+# Browser workbench
+
+[`mechdsl-workbench`](https://github.com/CEmM2/mechdsl-workbench) is a companion
+browser application for MechDSL: **LaTeX on the left, the compiled mechanics or
+transpiled algorithm on the right**. It is the fastest way to try the language before
+committing to the pipeline β no scripts, no `ProblemIR`, no local Taichi wrangling.
+
+It lives in its own repository, is published to PyPI, and is MIT-licensed like the rest
+of the toolchain.
+
+```text
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+β Mechanics | Algorithm Example βΎ Compile/Run β
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
+β LaTeX source β
+β β
+β % mechanics ... or % algorithm pcg β
+β \begin{algorithmic} ... β
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
+β Preview | Generated Taichi | Translation View | Diagnostics β
+βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+```
+
+## Install and run
+
+```bash
+pip install "mechdsl-workbench[mechdsl]" # workbench + the MechDSL engine, one command
+mechdsl-workbench
+```
+
+Then open .
+
+The `[mechdsl]` extra pulls `mechdsl-core[verify]` and `algo2code` from PyPI β the full
+engine including Taichi, so expect a large download. If you already have an engine
+installed (or want to point at a source checkout), take the workbench alone:
+
+```bash
+pip install mechdsl-workbench # bring your own mechdsl-core
+```
+
+!!! warning "Python 3.12"
+ The workbench pins `requires-python = ">=3.12,<3.13"`, which is narrower than the
+ `>=3.11,<3.14` range the three monorepo packages accept. Install it into a 3.12
+ environment.
+
+Common flags and the full environment-variable table (bind host and port, compile
+timeout, concurrency and payload limits, MathJax source) are documented in the
+[workbench README](https://github.com/CEmM2/mechdsl-workbench#run-options):
+
+```bash
+mechdsl-workbench --host 127.0.0.1 --port 8000
+mechdsl-workbench --reload
+```
+
+A Docker image is available too β `docker compose up` from the workbench repository.
+
+## The two modes
+
+### Mechanics mode
+
+Compile a `% mechanics` document through
+[`compile_from_sources()`](reference/architecture.md#integration-facade):
+
+- line-numbered LaTeX editor, with an optional separate constitutive-energy source;
+- MathJax preview and `% mechanics` directive cards;
+- the generated Taichi source;
+- the public Element IR summary, the semantic content hash, and whether a derived
+ energy was present;
+- bundled SVK Hex8, equation-bearing Hex8, and Tet4 examples.
+
+### Algorithm mode
+
+Transpile a LaTeX `algorithmic` block through `transpile_algorithm()`:
+
+- `% algorithm`, `% backend`, `% args`, and `% type` contract preview;
+- the generated Taichi/Python source;
+- entry-point name, line count, backend, and Python-validity result;
+- bundled J2 radial-return and PCG examples.
+
+Both modes share an explicit action button (or `Ctrl+Enter` / `Cmd+Enter`), copy and
+download actions for the source and the generated `.py`, and browser-local drafts kept
+separately per mode.
+
+## How it talks to the compiler
+
+The dependency direction is strictly one-way, and checked in the workbench's CI:
+
+```text
+mechdsl-workbench -> mechdsl.integration -> mechdsl-core / algo2code
+MechDSL -X-> mechdsl-workbench
+```
+
+The workbench only ever calls the five entry points of the `mechdsl.integration`
+faΓ§ade β the stable, machine-readable Tier-1 surface. It never imports `algo2code`
+directly and never reaches into the parser, IR, lowering, symbolic, or codegen
+internals. That is deliberate: the workbench is the reference consumer that proves the
+public integration surface is sufficient to build a real application on.
+
+!!! note "Nothing generated is executed"
+ Each translation runs in a short-lived worker subprocess with a hard timeout, and
+ the server terminates it if it overruns. The workbench **does not execute the code
+ it emits** β the preview is presentational, and the Translation View reports only
+ what the public integration result actually returned.
+
+## Where to next
+
+- [Installation](installation.md) β the full PyPI and source matrix for every package.
+- [LaTeX directive reference](mechdsl-core/latex-directives.md) β what to type into the
+ mechanics pane.
+- [algo2code usage](algo2code/usage.md) β what to type into the algorithm pane.
diff --git a/mkdocs.yml b/mkdocs.yml
index bf97a9a..d9f4a11 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -8,18 +8,23 @@ use_directory_urls: false
theme:
name: material
+ logo: assets/mechdsl-mark.webp
+ favicon: assets/mechdsl-mark.webp
+ font:
+ text: Baloo 2
+ code: JetBrains Mono
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
- primary: indigo
- accent: indigo
+ primary: custom
+ accent: custom
toggle:
icon: material/weather-night
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
- primary: indigo
- accent: indigo
+ primary: custom
+ accent: custom
toggle:
icon: material/weather-sunny
name: Switch to light mode
@@ -34,6 +39,9 @@ theme:
- search.suggest
- search.highlight
+extra_css:
+ - stylesheets/mechdsl.css
+
markdown_extensions:
- admonition
- attr_list
@@ -45,12 +53,17 @@ markdown_extensions:
anchor_linenums: true
- pymdownx.superfences
- pymdownx.inlinehilite
+ # Required for the :material-*: / :octicons-*: icon shortcodes used in the card grids.
+ - pymdownx.emoji:
+ emoji_index: !!python/name:material.extensions.emoji.twemoji
+ emoji_generator: !!python/name:material.extensions.emoji.to_svg
- pymdownx.tabbed:
alternate_style: true
- pymdownx.details
nav:
- Home: index.md
+ - Installation: installation.md
- mechdsl-core:
- Introduction: mechdsl-core/index.md
- Getting started: mechdsl-core/getting-started.md
@@ -63,6 +76,10 @@ nav:
- Getting started: algo2code/getting-started.md
- Usage: algo2code/usage.md
- Examples: algo2code/examples.md
+ - ti-runtime:
+ - Introduction: ti-runtime/index.md
+ - Workbench:
+ - Browser workbench: workbench.md
- Reference:
- How it works: reference/architecture.md
- FAQ & troubleshooting: reference/faq.md
@@ -71,3 +88,10 @@ extra:
social:
- icon: fontawesome/brands/github
link: https://github.com/CEmM2/MechDSL
+ name: MechDSL on GitHub
+ - icon: fontawesome/brands/python
+ link: https://pypi.org/project/mechdsl-core/
+ name: mechdsl-core on PyPI
+ - icon: fontawesome/solid/flask
+ link: https://sosovski.group/
+ name: The research group site