Spaces:
Sleeping
Sleeping
| """Featured characters and living world showcase.""" | |
| from __future__ import annotations | |
| from ui import assets | |
| from world.entities import get_all_entities | |
| from world.locations import get_location_by_id | |
| from ui.avatars import render_avatar | |
| def _location_slug(entity: dict) -> str | None: | |
| loc = get_location_by_id(entity["location_id"]) | |
| return loc["slug"] if loc else None | |
| def render_featured_characters(limit: int = 6) -> str: | |
| entities = get_all_entities(limit=50) | |
| if not entities: | |
| return "" | |
| # Prioritize characters/creatures with memory and legendary/active status | |
| def score(e: dict) -> int: | |
| s = 0 | |
| if e["type"] in ("character", "creature"): | |
| s += 3 | |
| if e.get("memory_summary"): | |
| s += 2 | |
| if e["status"] == "legendary": | |
| s += 4 | |
| if e.get("tags"): | |
| s += 1 | |
| s += min(e["days_in_realm"], 10) | |
| return s | |
| featured = sorted(entities, key=score, reverse=True)[:limit] | |
| cards = [] | |
| for entity in featured: | |
| loc = get_location_by_id(entity["location_id"]) | |
| loc_name = loc["short_description"][:60] if loc else "" | |
| loc_short = loc["name"].replace("The ", "") if loc else "Unknown" | |
| slug = loc["slug"] if loc else None | |
| avatar = render_avatar(entity, size=72, location_slug=slug) | |
| status_class = f"featured-{entity['status']}" | |
| tag = entity["tags"][0] if entity.get("tags") else entity["type"] | |
| img = assets.location_image_url(slug) | |
| bg_style = f"background-image: url('{img}');" if img else "" | |
| cards.append(f""" | |
| <div class="featured-card {status_class}" data-entity-id="{entity['id']}" style="{bg_style}"> | |
| <div class="featured-card-scrim"></div> | |
| <div class="featured-portrait">{avatar}</div> | |
| <div class="featured-info"> | |
| <span class="featured-type">{tag}</span> | |
| <h3 class="featured-name">{entity['name']}</h3> | |
| <p class="featured-location">{loc_short}</p> | |
| <p class="featured-appearance">{entity['appearance'][:140]}…</p> | |
| <blockquote class="featured-greeting">"{entity['greeting'][:90]}{'…' if len(entity['greeting']) > 90 else ''}"</blockquote> | |
| {f'<p class="featured-memory">{entity["memory_summary"][:100]}…</p>' if entity.get("memory_summary") else ''} | |
| </div> | |
| </div> | |
| """) | |
| return f""" | |
| <div class="featured-section"> | |
| <div class="section-header"> | |
| <h2 class="section-title">Souls of the Garden</h2> | |
| <p class="section-desc">Real inhabitants — each with their own wants, fears, and memories</p> | |
| </div> | |
| <div class="featured-grid">{"".join(cards)}</div> | |
| </div> | |
| """ | |
| def render_world_vignette() -> str: | |
| from world.book_of_ages import get_entries | |
| from world.events import get_active_world_event | |
| event = get_active_world_event() | |
| if event: | |
| return f""" | |
| <div class="world-vignette"> | |
| <p class="vignette-label">The world right now</p> | |
| <h3 class="vignette-title">{event['title']}</h3> | |
| <p class="vignette-text">{event['description']}</p> | |
| </div> | |
| """ | |
| entries = get_entries(limit=1, entry_type="interaction") | |
| if entries: | |
| return f""" | |
| <div class="world-vignette"> | |
| <p class="vignette-label">Recently, in the Garden</p> | |
| <p class="vignette-text">{entries[0]['content']}</p> | |
| </div> | |
| """ | |
| return """ | |
| <div class="world-vignette"> | |
| <p class="vignette-label">You stand at the threshold</p> | |
| <p class="vignette-text">The lanterns are lit. Someone left footprints in the moss. | |
| The world has been waiting. Add something — and it will remember you.</p> | |
| </div> | |
| """ | |