#!/usr/bin/env python3 """ generate_stack_margin_figures.py Writes the HTML margin stack figure (images/svg/margin_stack.svg) for every chapter in all four volumes. The PDF draws the stack with a TikZ macro inside the chapter's Purpose marginfigure (\\mlsysstack, \\mlfleetstack, \\mlagentstack, \\mlphysicalstackfull). That macro call stays the single source of truth: this script reads its weights from the .qmd and draws a compact native SVG sized for the HTML margin column, with real text and a transparent background. Dark mode inverts it in CSS (`_dark-mode-base.scss`), so only the light palette is drawn here. The chapter .qmd files are read, never written. The HTML block that displays the SVG already sits next to each Purpose marginfigure. Usage: python3 tools/generate_stack_margin_figures.py # all volumes python3 tools/generate_stack_margin_figures.py vol1 vol3 # some volumes """ import glob import re import sys from pathlib import Path from xml.sax.saxutils import escape REPO_ROOT = Path(__file__).resolve().parents[1] BOOKS_DIR = REPO_ROOT / "books" FONT = "Inter, 'Helvetica Neue', Helvetica, Arial, sans-serif" WIDTH = 220 ROW_H = 22 GAP = 3 INK_MUTED = "#6B7280" # Layer order is top to bottom, as drawn. `args` maps each layer to its # position in the PDF macro's argument list (0-based). VOLUMES = { "vol1": { "macro": "mlsysstack", "accent": "#A51C30", "alt": "Machine Learning Systems Architecture Stack", "layers": ["Applications", "Operations", "Serving", "Training", "Models", "Frameworks", "Hardware"], "args": [6, 5, 4, 3, 2, 1, 0], "rail": {"label": "DATA", "arg": 7}, }, "vol2": { "macro": "mlfleetstack", "accent": "#1F407A", "alt": "Fleet Machine Learning Systems Stack", "layers": ["Governance", "Assurance", "Operations", "Serving", "Control", "Execution", "Fabric", "Facility"], "args": [7, 6, 5, 4, 3, 2, 1, 0], "parts": ["IV", "IV", "III", "III", "II", "II", "I", "I"], }, "vol3": { "macro": "mlagentstack", "accent": "#581C87", "alt": "Agentic Machine Learning Systems Stack", "layers": ["Distributed Fleet", "Trajectory Learning", "Agent Runtime", "Tool Actuation", "Context Memory", "Foundation Model"], "tags": ["Network", "Compiler", "OS", "I/O", "Memory", "Processor"], "args": [0, 1, 2, 3, 4, 5], "rail": {"label": "TRAJECTORY", "arg": None}, }, "vol4": { "macro": "mlphysicalstackfull", "accent": "#065F46", "alt": "Physical AI Systems Stack", "layers": ["Brain", "Nervous System", "Body", "Boundary", "Physical World"], "tags": ["1–50 Hz", "1 kHz", "10–25 kHz", "event", "continuous"], "args": [0, 1, 2, 3, 4], # Dashed rule after the first layer: above proposes, below commands. "divider_after": 0, }, } def hex_rgb(h): h = h.lstrip("#") return tuple(int(h[i:i + 2], 16) for i in (0, 2, 4)) def tint(w): """Fill opacity for weight w in [0, 100]. Tiles are the accent at partial opacity over a transparent background, so the dark-mode invert turns them into light-on-dark tints instead of tiles darker than the page. """ return 0.10 + 0.90 * (max(0, min(100, w)) / 100.0) def text(x, y, s, size, fill, weight=600, anchor="start", extra=""): return (f'' f'{escape(s)}') def render(vol, weights): spec = VOLUMES[vol] accent = spec["accent"] layers = spec["layers"] n = len(layers) vals = [weights[i] for i in spec["args"]] # A chapter that weights every layer equally has no focus; show it flat. flat = len(set(vals)) == 1 rail_arg = spec.get("rail", {}).get("arg") top = max(vals + ([weights[rail_arg]] if rail_arg is not None else [])) left = 26 if "parts" in spec else 0 rail_w = 18 if "rail" in spec else 0 right = WIDTH - (rail_w + 6 if rail_w else 0) height = n * ROW_H + (n - 1) * GAP if "divider_after" in spec: height += 8 out = [] y = 0.0 rows = [] for i, (name, w) in enumerate(zip(layers, vals)): focus = (not flat) and w == top and w >= 50 level = 22 if flat else w alpha = 1.0 if focus else tint(level * 0.55) ink = "#FFFFFF" if focus else accent out.append(f'') out.append(text(left + 9, y + ROW_H / 2, name, 11.5, ink, 700 if focus else 600)) if "tags" in spec: out.append(text(right - 8, y + ROW_H / 2, spec["tags"][i], 9.5, "#FFFFFF" if focus else INK_MUTED, 500, "end", ' opacity="0.9"' if focus else "")) rows.append((y, y + ROW_H)) y += ROW_H + GAP if spec.get("divider_after") == i: out.append(f'') y += 8 if "parts" in spec: parts = spec["parts"] i = 0 while i < n: j = i while j + 1 < n and parts[j + 1] == parts[i]: j += 1 y0, y1 = rows[i][0], rows[j][1] out.append(f'') cy = (y0 + y1) / 2 out.append(text(left - 12, cy, parts[i], 8, accent, 700, "end", ' opacity="0.8"')) i = j + 1 if "rail" in spec: rail = spec["rail"] x0 = WIDTH - rail_w w = weights[rail["arg"]] if rail["arg"] is not None else 100 focus = (not flat) and rail["arg"] is not None and w == top and w >= 50 if rail["arg"] is None: alpha, ink = tint(30), accent else: alpha = 1.0 if focus else tint((22 if flat else w) * 0.55) ink = "#FFFFFF" if focus else accent out.append(f'') cx, cy = x0 + rail_w / 2, height / 2 out.append(text(cx, cy, rail["label"], 9, ink, 700, "middle", f' letter-spacing="1.2" transform="rotate(-90 {cx:.1f} {cy:.1f})"')) if rail["arg"] is None: # Trajectory runs upward through the stack. out.append(f'') body = "\n".join(out) return (f'\n' f'{escape(spec["alt"])}\n{body}\n\n') MACRO_RE = re.compile(r"\\(ml[a-z]+)((?:\{[^}]*\})+)") def chapter_weights(qmd_text, macro): m = re.search(r"## Purpose.*?\\begin\{marginfigure\}(.*?)\\end\{marginfigure\}", qmd_text, re.DOTALL) if not m: return None for name, args in MACRO_RE.findall(m.group(1)): if name == macro: return [int(float(a)) for a in re.findall(r"\{([^}]*)\}", args)] return None def main(vols): written, skipped = 0, [] for vol in vols: spec = VOLUMES[vol] for f in sorted(glob.glob(str(BOOKS_DIR / vol / "*" / "*.qmd"))): if not re.search(r"/\d\d_", f): continue svg_path = Path(f).parent / "images" / "svg" / "margin_stack.svg" content = Path(f).read_text(encoding="utf-8") if "images/svg/margin_stack.svg" not in content: continue weights = chapter_weights(content, spec["macro"]) if weights is None: skipped.append(f) continue svg_path.parent.mkdir(parents=True, exist_ok=True) svg_path.write_text(render(vol, weights), encoding="utf-8") written += 1 print(f"Wrote {written} margin stack SVGs.") for f in skipped: print(f"⚠️ No {VOLUMES[Path(f).parts[-3]]['macro']} call in Purpose: {f}") return 1 if skipped else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:] or list(VOLUMES)))