aether-garden / ui /assets.py
kavyabhand's picture
Deploy Aether Garden application
781b9f7 verified
Raw
History Blame Contribute Delete
4.67 kB
"""Central registry for image assets and Gradio-version-safe asset URLs.
Gradio 5+ serves user files under ``/gradio_api/file=``; Gradio 4 used
``/file=``. We build the prefix dynamically so the same code works on the
local install (6.x) and on older Hugging Face Space runtimes.
"""
from __future__ import annotations
from pathlib import Path
import gradio as gr
ASSET_DIR = Path(__file__).resolve().parent.parent / "assets"
_GRADIO_MAJOR = int(gr.__version__.split(".")[0])
_FILE_PREFIX = "/gradio_api/file=" if _GRADIO_MAJOR >= 5 else "/file="
def file_url(relative_path: str) -> str:
"""Return a servable URL for a file inside ``assets/``."""
return f"{_FILE_PREFIX}assets/{relative_path}"
def file_url_from_path(absolute_path: str) -> str:
"""Convert an absolute file path to a Gradio-servable URL."""
if not absolute_path:
return ""
return f"{_FILE_PREFIX}{absolute_path.lstrip('/')}"
def allowed_paths() -> list[str]:
return [str(ASSET_DIR), str(ASSET_DIR / "generated")]
# --- Image library -------------------------------------------------------
# Bespoke art generated for each sacred location, matching its specific lore
# in a single consistent painterly style (see scripts that produced loc_*.jpg).
LOCATION_IMAGES = {
"library": "loc_library.jpg", # infinite shelves, self-writing books
"sea": "loc_sea.jpg", # silver sea of drifting name-lanterns
"clock-forest": "loc_clock.jpg", # gear-trees with clock-face leaves
"moon-market": "loc_market.jpg", # lantern bazaar under a crescent moon
"valley": "loc_valley.jpg", # sleeping giants forming the hills
"crossroads": "loc_crossroads.jpg", # the eternal bonfire at the center
"mirror-bogs": "loc_bogs.jpg", # still black water, wrong reflections
"hollow-mountain": "loc_mountain.jpg", # vast hollow ancient stone interior
}
BANNER = "banner.png"
def location_image_url(slug: str | None) -> str | None:
if not slug:
return None
name = LOCATION_IMAGES.get(slug)
return file_url(name) if name else None
def banner_url() -> str:
return file_url(BANNER)
# --- Character sprites ---------------------------------------------------
# Bespoke, transparent-cutout art generated for each named seed soul (see
# scripts/cutout_sprites.py). These are the "souls" that wander the 3D
# diorama and appear as portraits — purpose-painted for this world, not the
# stock reference plates that used to stand in for them.
NAMED_SPRITES = {
"Crystal Tree": "char_crystal_tree.png",
"Joke Dragon": "char_joke_dragon.png",
"Blind Cartographer": "char_blind_cartographer.png",
"Fog Merchant": "char_fog_merchant.png",
"Lantern Fox": "char_lantern_fox.png",
"Thirteen Sighs": "char_thirteen_sighs.png",
"Silent Gear": "char_silent_gear.png",
"Disagreeing Reflection": "char_disagreeing_reflection.png",
"Echo Counter": "char_echo_counter.png",
"Unfed Bonfire": "char_unfed_bonfire.png",
}
# Fallback pools for visitor-summoned souls, keyed by entity type. We reuse
# the bespoke cutouts so every soul — seeded or summoned — looks hand-made.
TYPE_SPRITES: dict[str, list[str]] = {
"character": [
"char_blind_cartographer.png",
"char_echo_counter.png",
"char_fog_merchant.png",
"char_disagreeing_reflection.png",
],
"creature": [
"char_lantern_fox.png",
"char_joke_dragon.png",
"char_crystal_tree.png",
],
"object": [
"char_silent_gear.png",
"char_thirteen_sighs.png",
],
"place": [
"char_unfed_bonfire.png",
"char_silent_gear.png",
],
}
_FALLBACK_SPRITE = "char_blind_cartographer.png"
def sprite_filename(entity: dict) -> str:
"""Stable sprite filename for an entity (named art, else type pool)."""
name = (entity.get("display_name") or "").strip()
if name in NAMED_SPRITES and (ASSET_DIR / NAMED_SPRITES[name]).exists():
return NAMED_SPRITES[name]
etype = entity.get("type", "character")
pool = TYPE_SPRITES.get(etype, TYPE_SPRITES["character"])
uid = entity.get("id") or name or "x"
chosen = pool[sum(ord(c) for c in uid) % len(pool)]
if (ASSET_DIR / chosen).exists():
return chosen
return _FALLBACK_SPRITE
def sprite_url(entity: dict) -> str:
"""Served URL for a diorama billboard sprite (HTML <img>)."""
return file_url(sprite_filename(entity))
def sprite_path(entity: dict) -> str:
"""Filesystem path for a sprite (gr.Gallery needs paths, not URLs)."""
return str(ASSET_DIR / sprite_filename(entity))