Skip to content

Commit a01e45f

Browse files
Add the FEBio Feature Manual as a third "Features" tab
Absorbs the standalone febiosoftware/febio-feature-manual repo into this site as a third navigation tab, alongside Theory and Studio. The feature manual is itself a generated site, not hand-authored Markdown, so rather than copying static output its source is vendored and its generator ported into this repo's pipeline: - source/feature-manual/ - febio_features.json (FEBio's feature database, exported from FEBio Studio) plus the 409 hand-authored per-feature description fragments in meta/. - tools/features2md.py - a port of the upstream build.py's content generation. Two deliberate differences: it does not write its own mkdocs.yml (build.py owns the site nav for all three manuals, so it writes a nested nav tree to its stats sidecar instead), and it creates output directories with exist_ok=True (upstream gitignores its generated docs/modules/*.md, leaving that directory absent in a fresh clone and crashing upstream's own build). build.py's MANUALS entries now carry a "kind" that selects the converter: "lyx" runs lyx2md.py as before, "features" runs features2md.py. "kind" also gates the figure-fetch step, since the feature manual's figures are vendored rather than fetched from upstream. Nav emission gained a recursive write_nav() for the feature manual's freely nested tree, with JSON-quoted titles so feature names carrying YAML-significant characters cannot corrupt mkdocs.yml. The upstream manual's own top-level tabs (Modules / Features / Output / febcode) become expandable sidebar sections under the one Features tab. Its home page is dropped in favor of a Preface matching the Theory and Studio tabs. Feature pages are written flat into docs/features/features/ with figs/ alongside them, exactly as upstream laid them out. That is why the path doubles up. The meta/ fragments contain 44 relative sibling links and 25 figure references that only resolve under that layout, so regrouping it would break authored prose rather than converter code; noted in both README.md and CLAUDE.md. Totals: 660 feature pages across 32 categories, 7 module pages, 262 plot and 419 log variables. 264 features still have no description fragment (inherited from upstream, listed in tools/_stats_features.json under needs_review.pages_without_description). Verified: build.py exits 0; mkdocs build --strict exits 0 with zero WARNINGs, so every one of the new pages, cross-page links, and figures resolves. mkdocs.yml's diff is additions only, with zero deletions, and nothing under docs/theory/ or docs/studio/ changed - the Theory and Studio nav is byte-identical. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U96z31ZadrrQ3YtU7br22M
1 parent c1a7ae1 commit a01e45f

1,115 files changed

Lines changed: 74629 additions & 67 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
site/
22
__pycache__/
33
*.pyc
4+
5+
# Local clone of the upstream feature-manual repo. Its source is vendored
6+
# into source/feature-manual/, so the clone itself is not part of this repo.
7+
febio-feature-manual/

CLAUDE.md

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,50 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## What this repo is
66

7-
A MkDocs site that converts FEBio's LyX-authored manuals to Markdown, mirroring the conventions of the
8-
sibling `febio-feature-manual` repo (Material for MkDocs theme, indigo palette, `pymdownx.arithmatex` +
9-
MathJax for equations, footnote-based citations). The site has two `navigation.tabs`, each a separately
10-
converted manual, orchestrated by `build.py`'s `MANUALS` list:
11-
12-
- **Theory** (`source/FEBio_Theory_Manual.lyx``docs/theory/`) — all 9 chapters (1–8 plus Appendix A)
13-
are converted.
14-
- **Studio** (`source/FEBioStudio_User_Manual.lyx``docs/studio/`) — all 22 chapters (1–20 plus
15-
Appendices A and B) are converted.
16-
17-
`source/` is vendored/checked-in for both manuals, so the repo builds standalone from a bare clone.
18-
19-
**`docs/theory/` and `docs/studio/` (except their `index.md` files) are generated output, not
20-
hand-authored content.** They're regenerated from each manual's `.lyx` source by `tools/lyx2md.py` on
21-
every build. Do not hand-edit generated chapter/section files expecting them to persist — fix the
22-
converter (`tools/lyx2md.py`) instead, or edit the relevant `source/*.lyx` file if the manual content
23-
itself is wrong. `docs/index.md` (site-root landing page, not in `nav:`), `docs/theory/index.md` and
24-
`docs/studio/index.md` (each manual's Preface), and `docs/js/mathjax_config.js` are hand-authored
25-
exceptions.
7+
A MkDocs site that generates all of FEBio's manuals into one site (Material for MkDocs theme, indigo
8+
palette, `pymdownx.arithmatex` + MathJax for equations, footnote-based citations). The site has three
9+
`navigation.tabs`, each a separately generated manual, orchestrated by `build.py`'s `MANUALS` list. Each
10+
entry has a `"kind"` selecting its converter:
11+
12+
- **Theory** (`kind: "lyx"`, `source/FEBio_Theory_Manual.lyx``docs/theory/`) — all 9 chapters (1–8
13+
plus Appendix A) are converted.
14+
- **Studio** (`kind: "lyx"`, `source/FEBioStudio_User_Manual.lyx``docs/studio/`) — all 22 chapters
15+
(1–20 plus Appendices A and B) are converted.
16+
- **Features** (`kind: "features"`, `source/feature-manual/``docs/features/`) — the FEBio Feature
17+
Manual, absorbed from the standalone `febio-feature-manual` repo. Generated by `tools/features2md.py`
18+
(not `lyx2md.py`) from `febio_features.json` plus per-feature description fragments in `meta/`.
19+
660 feature pages, 7 module pages, plot/log variable tables, and the hand-authored febcode page.
20+
21+
`source/` is vendored/checked-in for all three manuals, so the repo builds standalone from a bare clone.
22+
23+
**`docs/theory/`, `docs/studio/`, and `docs/features/` are generated output, not hand-authored
24+
content.** They're regenerated on every build. Do not hand-edit generated pages expecting them to
25+
persist — fix the converter instead, or edit the relevant file under `source/` if the manual content
26+
itself is wrong. For a missing/incorrect *feature description* specifically, the file to edit is
27+
`source/feature-manual/meta/<page-name>.md` — it is spliced verbatim into that page.
28+
29+
Hand-authored exceptions that survive a rebuild: `docs/index.md` (site-root landing page, not in `nav:`),
30+
each manual's Preface (`docs/theory/index.md`, `docs/studio/index.md`, `docs/features/index.md`),
31+
`docs/features/febcode.md` + `febcode.png`, `docs/features/features/figs/`, and
32+
`docs/js/mathjax_config.js`.
33+
34+
A local clone of the upstream `febio-feature-manual` repo may sit at `febio-feature-manual/` inside the
35+
working tree; it is gitignored and is *not* the build's source — `source/feature-manual/` is.
2636

2737
## Commands
2838

2939
```
3040
pip install mkdocs mkdocs-material # prerequisites
3141
32-
python3 build.py # runs tools/lyx2md.py once per manual, (re)writes docs/**/*.md and mkdocs.yml
33-
python3 build.py -v # verbose (streams lyx2md.py's own stdout instead of buffering it)
42+
python3 build.py # runs each manual's converter, (re)writes docs/**/*.md and mkdocs.yml
43+
python3 build.py -v # verbose (streams each converter's own stdout instead of buffering it)
3444
mkdocs serve # preview at http://127.0.0.1:8000
3545
mkdocs build --strict # validate the full build; must exit 0 with zero WARNINGs
3646
mkdocs gh-deploy --force # manually publish site/ to the gh-pages branch (needs push access)
3747
38-
# tools/lyx2md.py is generic across manuals via CLI flags (build.py passes these per MANUALS entry):
48+
# Both converters are generic via CLI flags (build.py passes these per MANUALS entry):
3949
python3 tools/lyx2md.py --lyx PATH --bib PATH --docs-root DIR --nav-root PREFIX --stats-out PATH --chapters "1,2|all"
50+
python3 tools/features2md.py --features-json PATH --meta-dir DIR --docs-root DIR --nav-root PREFIX --stats-out PATH
4051
```
4152

4253
There is no test suite. Validation is: `python3 build.py && mkdocs build --strict` exits 0 with no
@@ -47,10 +58,13 @@ below), plus a leftover-artifact grep across both manuals' output:
4758
grep -rn '\begin_\|\end_inset\|\begin_inset\|SpecialChar\|\lang ' docs/ # must be zero matches
4859
```
4960

50-
Each manual's stats sidecar (`tools/_stats.json` for Theory, `tools/_stats_studio.json` for Studio,
51-
written by `lyx2md.py`) reports per-chapter/per-section formula, citation, and figure counts —
52-
reconcile these against the source when validating a chapter (see `CONVERSION_NOTES.md` /
53-
`CONVERSION_NOTES_STUDIO.md` for the established methodology and known small discrepancies).
61+
Each manual's stats sidecar reports what it produced. `tools/_stats.json` (Theory) and
62+
`tools/_stats_studio.json` (Studio), written by `lyx2md.py`, report per-chapter/per-section formula,
63+
citation, and figure counts — reconcile these against the source when validating a chapter (see
64+
`CONVERSION_NOTES.md` / `CONVERSION_NOTES_STUDIO.md` for the established methodology and known small
65+
discrepancies). `tools/_stats_features.json`, written by `features2md.py`, instead holds the nav tree,
66+
totals, and `needs_review.pages_without_description` — the list of features still lacking a `meta/`
67+
fragment (264 of 660 as of the port; not a build failure, just unwritten prose).
5468

5569
CI (`.github/workflows/deploy.yml`) runs `python3 build.py` then `mkdocs build --strict` on every push
5670
to `main`, then `mkdocs gh-deploy --force`. **The live site is served from the `gh-pages` branch, not
@@ -61,12 +75,23 @@ triggers the workflow that does.
6175

6276
### Pipeline
6377

64-
For each manual in `build.py`'s `MANUALS` list: `source/<manual>.lyx``tools/lyx2md.py` (invoked as a
65-
separate subprocess per manual, with `--lyx`/`--bib`/`--docs-root`/`--nav-root`/`--stats-out`/`--chapters`)
66-
`docs/<nav_root>/chapter<N>/<N>.M-slug.md` + that manual's stats JSON → `build.py` reads all manuals'
67-
stats files and writes one `mkdocs.yml` whose `nav:` has one top-level tab per manual → `mkdocs build`.
68-
Running each manual as a separate subprocess means `lyx2md.py`'s module-level globals/label-registries
69-
never cross-contaminate between manuals — no in-process reset logic is needed.
78+
For each manual in `build.py`'s `MANUALS` list, `build.py` dispatches on `"kind"` to run that manual's
79+
converter as a separate subprocess, then reads back its stats JSON. Once all manuals are converted it
80+
writes one `mkdocs.yml` whose `nav:` has one top-level tab per manual → `mkdocs build`. Running each
81+
manual as a separate subprocess means `lyx2md.py`'s module-level globals/label-registries never
82+
cross-contaminate between manuals — no in-process reset logic is needed.
83+
84+
- `kind: "lyx"``source/<manual>.lyx``tools/lyx2md.py` (`--lyx`/`--bib`/`--docs-root`/`--nav-root`/
85+
`--stats-out`/`--chapters`) → `docs/<nav_root>/chapter<N>/<N>.M-slug.md` + stats JSON whose `chapters`
86+
key drives a fixed chapter → section nav shape.
87+
- `kind: "features"``source/feature-manual/``tools/features2md.py` (`--features-json`/`--meta-dir`/
88+
`--docs-root`/`--nav-root`/`--stats-out`) → `docs/features/{features,modules}/*.md` +
89+
`plotvars.md`/`logvars.md`, plus a stats JSON whose `nav` key is a *freely nested* tree that
90+
`build.py`'s `write_nav()` emits recursively. Nav titles are `json.dumps`-quoted so feature names
91+
carrying YAML-significant characters can't corrupt `mkdocs.yml`.
92+
93+
`"kind"` also gates the figure-fetching step (step 4): only `"lyx"` manuals fetch missing figures from
94+
upstream, since the Feature Manual's figures are vendored.
7095

7196
`tools/lyx2md.py` is a **stdlib-only, deterministic** parser for LyX's plain-text format — no LyX,
7297
Pandoc, or other external tool involved, and the parsing/rendering logic itself is identical regardless
@@ -123,6 +148,13 @@ copies).
123148
- `mkdocs.yml` is generated by `build.py` — don't hand-edit it; change the write logic in `build.py`
124149
instead (theme config and the `MANUALS` list live inline as `f.write(...)` calls / a module-level
125150
list at the top of the file).
151+
- **Don't rearrange the Feature Manual's output layout.** Its pages are written *flat* into
152+
`docs/features/features/` with `figs/` alongside them, exactly as the upstream repo laid them out,
153+
which is why the path doubles up (`features/features/...`) and why the "Features" nav section sits
154+
inside the "Features" tab. The `meta/` fragments contain 44 relative sibling links
155+
(`[x](other_page.md)`) and 25 figure references (`figs/Foo.png`) that only resolve under that layout;
156+
flattening or regrouping it would break them, and fixing that would mean rewriting authored prose
157+
rather than converter code. (`mkdocs build --strict` does catch it, at least.)
126158
- Merged table cells (colspan/rowspan) can't be represented in plain Markdown tables; `render_tabular()`
127159
flags these for manual review rather than guessing — check `CONVERSION_NOTES.md`/`needs_review` before
128160
assuming a table rendered correctly (occurs in Section 4.1's element-property tables).

0 commit comments

Comments
 (0)