"""Trace Personality Bulletin — HTML rendering.
The bulletin is a self-contained HTML document with embedded CSS, base64 assets,
and an html2canvas-driven 'Save as PNG' button that screenshots the card
client-side in the browser. No server-side image rendering, so the app deploys
to a Hugging Face Space with zero extra system dependencies.
Design adapted from the Anthropic Design handoff `Personality Report.html`
(1080×1440 portrait, retro bulletin aesthetic).
"""
import base64
import html as html_mod
from pathlib import Path
_ASSETS = Path(__file__).parent / "assets"
def _data_url(path: Path, mime: str = "image/png") -> str:
return f"data:{mime};base64,{base64.b64encode(path.read_bytes()).decode()}"
_SEAL_URL = _data_url(_ASSETS / "seal_small.png")
_GRAIN_URL = _data_url(_ASSETS / "grain_small.png")
_ROMAN = ["I", "II", "III", "IV", "V"]
_NBSP = " "
# --- Palette (Retro · Cream from the handoff) ---
_INK = "#353E60" # hf-blue-deep (navy)
_INK_SOFT = "rgba(53,62,96,0.7)"
_SURFACE = "#FFF8DE" # hf-cream
_ACCENT = "#00704A" # Starbucks-style green
_ACCENT2 = "#FF9D00" # hf-orange
_SUNBURST = "rgba(255,157,0,0.35)"
_SINS_BG = "#353E60"
_SINS_INK = "#FFF8DE"
_SINS_ACCENT = "#FF9D00"
_SINS_DOTS = "rgba(255,157,0,0.18)"
_RED = "#DB3328" # hf-red — second offset on the title shadow
_YELLOW = "#FFD21E"
# --- Fonts (Google Fonts CDN) ---
_FONTS_LINK = (
''
)
def _sunburst_svg(rays: int = 32, color: str = _SUNBURST) -> str:
parts = []
for i in range(rays):
a = (i * 360) / rays
parts.append(
f'
{e(str(sin.get("title") or ""))}
' f'' "{tagline}
{drop_cap}{body_rest}