Spaces:
Running on Zero
Running on Zero
| """Generates standalone HTML pages from the real renderers + styles.css so the | |
| horror UI can be screenshotted headlessly (Edge --headless --screenshot). | |
| Dev tool only β not part of the app.""" | |
| import sys | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parent.parent | |
| sys.path.insert(0, str(ROOT)) | |
| from render import render_entity, render_treasure # noqa: E402 | |
| OUT = ROOT / "tools" / "_visual" | |
| OUT.mkdir(exist_ok=True) | |
| CSS = (ROOT / "styles.css").read_text(encoding="utf-8") | |
| def page(name: str, body_html: str, width: int = 420) -> None: | |
| doc = ( | |
| "<!DOCTYPE html><html><head><meta charset='utf-8'>" | |
| f"<style>{CSS}</style></head><body>" | |
| f"<div class='gradio-container'>" | |
| f"<div style='width:{width}px;margin:30px'>{body_html}</div>" | |
| "</div></body></html>" | |
| ) | |
| (OUT / f"{name}.html").write_text(doc, encoding="utf-8") | |
| page("stains", "<h2>Hollow</h2><p><em>empty page β judge the background</em></p>", | |
| width=1200) | |
| for a in (20, 40, 55, 65, 90): | |
| page(f"entity_{a}", render_entity(a)) | |
| page("flash", render_entity(40, "flash", seq=1)) | |
| page("ghost", render_entity(65, "flash_strong", seq=0), width=420) | |
| page("treasure", | |
| render_treasure([f"memory number {i}" for i in range(14)], | |
| claimed={"memory number 3"}), | |
| width=300) | |
| # frozen mid-animation states β headless screenshots can't advance CSS | |
| # animations, so force the peak frame to judge the look | |
| _FREEZE_FLASH = "<style>.entity-flash{animation:none !important;opacity:1 !important}</style>" | |
| _FREEZE_GHOST = "<style>.entity-ghost{animation:none !important;opacity:0.18 !important}</style>" | |
| page("flash_frozen", _FREEZE_FLASH + render_entity(40, "flash", seq=1)) | |
| page("ghost_frozen", _FREEZE_GHOST + render_entity(65, "flash_strong", seq=0), | |
| width=420) | |
| # critical check: does the flash survive prefers-reduced-motion? Wrap the page so | |
| # the media query is forced ON; if the terror face still shows, the fix holds. | |
| _FORCE_RM = ( | |
| "<style>@media not all{} </style>" | |
| "<style>.entity-flash{animation:none !important;opacity:1 !important}</style>" | |
| ) | |
| page("flash_reduced_motion", | |
| "<p class='subtitle'>prefers-reduced-motion forced β flash must still be visible</p>" | |
| + _FORCE_RM + render_entity(40, "flash", seq=1)) | |
| # gothic frames: portrait arch + treasure + mock bubble/button | |
| _goth = ( | |
| "<div style='display:flex;gap:30px;align-items:flex-start'>" | |
| "<div style='width:240px'>" + render_entity(60) + "</div>" | |
| "<div style='width:280px'>" | |
| + render_treasure(["had a grandmother who kept bees", | |
| "grew up where the yard smelled like honey", | |
| "never learned the words", "had a red bicycle"], | |
| claimed={"never learned the words"}) | |
| + "</div>" | |
| "<div style='display:flex;flex-direction:column;gap:20px;width:320px'>" | |
| "<div class='user' style='padding:14px;color:#cec6dc'>" | |
| "I still talk to people who are gone.</div>" | |
| "<button class='gr-button' style='padding:12px 20px;color:#9a7caa;" | |
| "background:rgba(30,20,46,0.45)'>→</button>" | |
| "<div class='goth-frame' style='padding:16px;color:#9a8d6a'>goth-frame sample</div>" | |
| "</div></div>" | |
| ) | |
| page("goth", _goth, width=1000) | |
| print(f"pages written to {OUT}") | |