From a09d2ce582aa7105661385e12bdcf64f314415a8 Mon Sep 17 00:00:00 2001
From: Anthony Sligar
Date: Sat, 6 Jun 2026 07:21:02 -0400
Subject: [PATCH] docs: add compose & theme-scaling graphics, surface both in
README (0.23.2)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Two new diagrams for the GitHub/PyPI page, matching the existing dark asset
style (all values verified against the engine):
- assets/compose.svg — lego-style components snapping onto the ruleset via
typed set/add/union contributions; one snap-in cascades downstream.
- assets/theme-scaling.svg — one computation graph re-skinned per setting via
ThemeScalingLayer (input_overrides, lookup_overrides, display-only
flavor_renames); same plate node -> AC 18/18/19/19 across themes.
README gains a "Composable" section and a "Re-skin for any setting — theme
scaling" section (theme scaling was previously undocumented in the README),
each with a verified runnable snippet, plus a feature-table row. Docs-only
patch release so the graphics reach the (per-version-frozen) PyPI page.
Co-Authored-By: Claude Opus 4.8 (1M context)
---
CHANGELOG.md | 16 ++++-
README.md | 38 ++++++++++++
assets/compose.svg | 121 ++++++++++++++++++++++++++++++++++++++
assets/theme-scaling.svg | 107 +++++++++++++++++++++++++++++++++
pyproject.toml | 2 +-
src/dndwright/__init__.py | 2 +-
6 files changed, 283 insertions(+), 3 deletions(-)
create mode 100644 assets/compose.svg
create mode 100644 assets/theme-scaling.svg
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 76ade01..a8b7395 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,19 @@ breaking changes; these will always be noted here.
## [Unreleased]
+## [0.23.2] — 2026-06-06
+
+### Documentation
+- **Two new README/PyPI diagrams.** `assets/compose.svg` shows lego-style components snapping
+ onto the ruleset — typed `set`/`add`/`union` contributions that keep the target node's id, so
+ one snap-in recomputes the whole downstream subtree. `assets/theme-scaling.svg` shows one
+ computation graph re-skinned per setting via `ThemeScalingLayer`: the same `plate` node emerges
+ as AC 18 (traditional / modern, re-flavored) or AC 19 (sci-fi / steampunk) through
+ `input_overrides`, `lookup_overrides`, and display-only `flavor_renames`.
+- **New README sections** — "Composable — snap mini-graphs onto the ruleset" and "Re-skin for
+ any setting — theme scaling" (theme scaling was previously undocumented in the README), plus a
+ `apply_theme_scaling` / `ThemeScalingLayer` row in the feature table. Docs-only; no code change.
+
## [0.23.1] — 2026-06-06
### Fixed
@@ -441,7 +454,8 @@ from a working application.
Pure (pydantic + stdlib); no application/framework coupling. Rules content derives
from the SRD 5.2 (CC-BY-4.0); see NOTICE.
-[Unreleased]: https://github.com/sligara7/dndwright/compare/v0.23.1...HEAD
+[Unreleased]: https://github.com/sligara7/dndwright/compare/v0.23.2...HEAD
+[0.23.2]: https://github.com/sligara7/dndwright/compare/v0.23.1...v0.23.2
[0.23.1]: https://github.com/sligara7/dndwright/compare/v0.23.0...v0.23.1
[0.23.0]: https://github.com/sligara7/dndwright/compare/v0.22.0...v0.23.0
[0.22.0]: https://github.com/sligara7/dndwright/compare/v0.21.0...v0.22.0
diff --git a/README.md b/README.md
index 35b1d96..30dda90 100644
--- a/README.md
+++ b/README.md
@@ -128,6 +128,43 @@ and serialisable — not buried in imperative code. `DND_5E_2024_RULESET` is a 1
+### Composable — snap mini-graphs onto the ruleset
+
+Items, feats and species traits are themselves tiny graphs. `compose()` merges a
+`Component`'s nodes and contributions onto a base ruleset and returns a new, larger
+`Ruleset` — the base is never mutated. Because each contribution keeps its target node's
+**id**, every existing edge downstream re-derives for free: a `set`/`add`/`union` on one
+node ripples out to every modifier, save, skill and attack that depends on it.
+
+
+
+
+
+```python
+from dndwright import DND_5E_2024_RULESET, compose, modifier
+ring = modifier("ring_of_protection", target="armor_class", amount=1)
+rs = compose(DND_5E_2024_RULESET, ring) # base untouched; AC now aggregates the +1
+```
+
+### Re-skin for any setting — theme scaling
+
+The same engine runs sci-fi, modern-warfare, steampunk or cosmic-horror. A `ThemeScalingLayer`
+folds three kinds of override onto a ruleset via `apply_theme_scaling()` (pure, like `compose`):
+`input_overrides` re-baseline a node's default value, `lookup_overrides` deep-merge into the
+lookup tables (so `plate` armour can read AC 19 instead of 18), and `flavor_renames` relabel
+terms for display **without ever changing a computed value**. The graph's shape never changes —
+only its numbers and names.
+
+
+
+
+
+```python
+from dndwright import DND_5E_2024_RULESET, apply_theme_scaling, get_theme_scaling
+rs = apply_theme_scaling(DND_5E_2024_RULESET, get_theme_scaling("sci_fi"))
+rs.lookup_tables["armor_base_ac"]["plate"] # 19 (base is still 18, untouched)
+```
+
## What's inside
| Component | What it does |
@@ -139,6 +176,7 @@ and serialisable — not buried in imperative code. `DND_5E_2024_RULESET` is a 1
| `validate_ruleset` / `assert_valid_ruleset` | Static integrity check for a ruleset (unknown ops, cycles, dangling refs) — catch authoring errors before evaluation. |
| `compose` / `modifier` / `Component` | Snap mini-graphs (items/feats/traits) onto a ruleset; downstream values cascade. |
| `component_from_content` | Build a `Component` from a bundled item/feat's `component` field — magic items & feats as data that snap onto a character (constant, dynamic, player-chosen, or *conditional* effects). |
+| `apply_theme_scaling` / `ThemeScalingLayer` / `get_theme_scaling` | Re-skin the ruleset for any setting (sci-fi, modern, steampunk, …): override node defaults & lookup tables and re-flavor names, same graph shape. `PREDEFINED_THEME_SCALING` ships ready-made themes. |
| `to_mermaid` / `to_dot` | Render the computation DAG as Mermaid or Graphviz DOT — *see* the dependency graph. |
| `dndwright.dice` | Typed dice engine: parse/roll 5e expressions, attacks, saves, damage, stat arrays. |
| `dndwright.combat` | Pure combat rules over a frozen `CombatantState`: damage, temp HP, healing, death saves. |
diff --git a/assets/compose.svg b/assets/compose.svg
new file mode 100644
index 0000000..9734371
--- /dev/null
+++ b/assets/compose.svg
@@ -0,0 +1,121 @@
+
diff --git a/assets/theme-scaling.svg b/assets/theme-scaling.svg
new file mode 100644
index 0000000..c2bdd77
--- /dev/null
+++ b/assets/theme-scaling.svg
@@ -0,0 +1,107 @@
+
diff --git a/pyproject.toml b/pyproject.toml
index 9e2e23e..dff9fa3 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "dndwright"
-version = "0.23.1"
+version = "0.23.2"
description = "Domain-neutral D&D 5e (2024) rules & character-sheet computation engine: a data-driven DAG of formulas (ability mods, proficiency, spell DC/slots, HP, AC)."
readme = "README.md"
requires-python = ">=3.10"
diff --git a/src/dndwright/__init__.py b/src/dndwright/__init__.py
index 2277d7e..20b8cef 100644
--- a/src/dndwright/__init__.py
+++ b/src/dndwright/__init__.py
@@ -100,7 +100,7 @@
validate_ruleset,
)
-__version__ = "0.23.1"
+__version__ = "0.23.2"
__all__ = [
# high-level (dict in -> computed sheet out)