hollow / tools /visual_check.py
Pabloler21's picture
feat: screamer flicker + gothic Fear & Hunger framing
9b82354
Raw
History Blame Contribute Delete
3.28 kB
"""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)'>&rarr;</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}")