`` - paragraphs split on blank lines """ import re def _inline(line: str) -> str: out = _md_safe(line) out = re.sub(r"\*\*([^*]+)\*\*", r"\1", out) out = re.sub(r"(?\1", out) return out blocks: list[str] = [] for raw_block in raw.split("\n\n"): block = raw_block.strip() if not block: continue if block.startswith(">"): quote = "\n".join( ln[1:].lstrip() if ln.startswith(">") else ln for ln in block.splitlines() ) blocks.append(f"
{_inline(quote)}") else: blocks.append(f"
{_inline(' '.join(block.split()))}
") return "".join(blocks) def _grimoire_left_html(state: GameState) -> str: """Render the left page: wizard's text for the current inscribe step, with hero/village placeholders substituted, the step marker in the corner, and the step-themed pixel sigil tucked into the bottom-inner corner. Cached by (lang, inscribe_step, hero_name, village_name). All four determine the output exactly; nothing else does. On grimoire spread transitions, only ``inscribe_step`` changes, so the cache stays warm. """ lang_code = state.lang or "en" cache_key = ( lang_code, state.inscribe_step, state.hero_name or "Tobin", state.village_name or "the Hollow", ) if cache_key in _GRIMOIRE_LEFT_CACHE: return _GRIMOIRE_LEFT_CACHE[cache_key] raw = _wizard_text_for(lang_code, state.inscribe_step) raw = (raw .replace("{hero_name}", state.hero_name or "Tobin") .replace("{village_name}", state.village_name or "the Hollow")) body = _grimoire_render_markdown(raw) step = state.inscribe_step + 1 lang = _tlang(state) marker_text = _t("grimoire_step_marker", lang).format( step=step, GRIMOIRE_NUM_STEPS=_GRIMOIRE_NUM_STEPS ) marker = f"{oracle}"
"modal run oracles_app/modal_backend/modal_klein_oracles.py)"
"