"""
Self-contained SVG isometric studio scene for Gradio — zero external dependencies.
No Three.js, no CDN. Pure SVG + HTML + vanilla JS.
"""
import json
from pathlib import Path
def _load_characters_js() -> str:
p = Path(__file__).parent / "sandbox_cache" / "characters.js"
return p.read_text() if p.exists() else ""
_CHARACTERS_JS = _load_characters_js()
# ---------------------------------------------------------------------------
# Isometric helpers
# ---------------------------------------------------------------------------
def _pts(pairs, ox=0, oy=0):
return " ".join(f"{x+ox},{y+oy}" for x, y in pairs)
def _darken(hex_color: str, factor: float = 0.65) -> str:
h = hex_color.lstrip("#")
if len(h) != 6:
return hex_color
r, g, b = int(h[:2], 16), int(h[2:4], 16), int(h[4:], 16)
return f"#{int(r*factor):02x}{int(g*factor):02x}{int(b*factor):02x}"
# Base desk polygon coordinates (desk slot 0, no offset)
_DESK_TABLETOP = [(148,268),(240,220),(306,252),(214,300)]
_DESK_LEFT = [(148,268),(148,288),(214,320),(214,300)]
_DESK_RIGHT = [(214,300),(214,320),(306,270),(306,252)]
_DESK_MAT = [(158,262),(238,218),(298,248),(218,292)]
_MON_BACK = [(196,208),(218,198),(242,210),(220,220)]
_MON_SCREEN = [(200,210),(218,202),(238,212),(220,220)]
_MON_LINES = [(200,211,228,203),(200,215,224,207),(200,219,230,211)]
# Base character polygons — head anchor at (174, 264) relative to slot 0
_CHAR_HEAD_TOP = [(174,264),(192,255),(202,259),(184,268)]
_CHAR_HEAD_SIDE = [(184,268),(202,259),(203,261),(185,270)]
_CHAR_BODY_TOP = [(176,276),(196,267),(204,271),(184,280)]
_CHAR_BODY_SIDE = [(184,280),(202,271),(204,273),(186,282)]
_CHAR_LEG_L = [(177,288),(185,284),(189,286),(181,290)]
_CHAR_LEG_R = [(184,285),(192,281),(196,283),(188,287)]
_CHAR_ARM_L = (186,270, 174,264)
_CHAR_ARM_R = (196,266, 210,260)
_CHAR_EYE_L = (178,258)
_CHAR_EYE_R = (189,255)
# Five desk slot offsets (ox, oy)
_SLOTS = [
(0, 0), # back-left
(188, 34), # back-center
(350, 2), # back-right
(0, 95), # front-left
(188, 129), # front-center
]
def _svg_desk(ox: int, oy: int) -> str:
lines = "".join(
f'