- Fix Saga geometry so portraits and glyphs remain aligned during hover - Bound Cast and Legacy content with overflow and empty states - Prevent hidden camera beats from reserving Saga layout space - Add fixed-size regression coverage and document the UX contract
12 KiB
Life-saga roster
Dynamic top-10 cast of interesting lives (MCs). Owns the dossier rail and soft camera bias.
Chronicle stays a history book and never drives the camera.
Short combat/love/war arcs stay in StoryPlanner as chapter beats.
Durable observed facts live in LifeSagaMemory and survive roster churn.
The fixed-layout hover redesign is specified in the Saga UX redesign plan.
AFK caption is a character beat: Identity (who) + Beat (live tip) + Context (spine or stake).
CaptionComposer merges saga identity into the live caption without baking titles into InterestCandidate.Label.
SagaProse owns all player-facing relation/stake English.
Ownership
| Concern | Owner |
|---|---|
| Top-10 MCs, diversity, Prefer | LifeSagaRoster |
| Durable observed facts | LifeSagaMemory |
| Adaptive presentation model | LifeSagaPresentation |
| Player-facing saga/caption English | SagaProse |
| Identity + Beat + Context caption | CaptionComposer → WatchCaption |
| Hover Cast/Legacy depth | LifeSagaViewController + LifeSagaPanel |
| Rail icons / Prefer click | LifeSagaRail |
| Camera read-pause lease | InterestDirector |
| Short climax → aftermath → epilogue | StoryPlanner (thinned) |
Context spine (Kind · Phase) |
StoryPlanner.FormatSpineLabel (via ContextLine) |
| Full history | Chronicle / Lore |
Admission
Live discovery (no tip-string allowlists):
- Game favorite, king, city leader, kills/renown floors (
InterestScoring.IsNotable) - Pack alpha, clan chief, army captain, active plot author, founder, species singleton
Standing is recomputed from live roles each refill. Heat comes from chapter stamps / featured tips and decays with idle time. Each slot keeps its original admission reason even when its live role later changes. Hard-arc admissions also retain the arc kind and chapter context that brought the life onto the roster.
Dynamic top-10
- Cap stays 10; order follows Effective = Standing + Heat + pin bonuses.
- Prefer and WorldBox favorites are hard pins and fully count toward Cap.
- Admission-role units always compete on the periodic scan.
- Non-admission "nobodies" challenge Cap only via hard-arc chapter stamps (Combat / War / Plot / Love / Grief).
- Hard-arc admit heat escalates with climax age (re-stamped while the arc holds) so a prolonged stranger duel can displace dull Cap slots and light Active chrome.
- Soft
NoteFeaturedheats existing MCs only. - Newcomers need a small challenger margin over the weakest non-pin so the rail does not thrash.
Camera (soft)
- No rail camera lock. Prefer is a toggle soft-favorite for idle scoring.
- Score ladder: crisis ownership > active short-arc ownership > Prefer soft > MC soft > MC cast > CausalHeat.
nearTieEpsilon(8) picks #1 for ordinary gaps; Prefer/MC/cast may still win withinsagaNearTieEpsilon(28).- Soft ranks: Prefer > CrossMC (>1 roster MC) > MC > MC cast (lover/friend/kin/earned rival of a roster MC).
- Tips that touch two or more roster MCs get
sagaCrossMcBonus(~11); scoring touch inventory matches rail Involved ids. - Sticky combat/war/plot maintain heats both MCs early when two roster principals share the tip.
- Mid-fight follow uses Prefer/MC/cast soft weight in
CombatFocusWeight(spectacle floors can still win). - Ambient / character-fill yields immediately to Prefer/MC tips (not vs crisis/combat/short-arc holds).
- Soft-fill quiet still suppresses anonymous crumbs; Prefer/MC tips may break quiet.
- Glyph hover acquires a camera read-pause lease: feeds/story/roster continue, but selection and focus repair are deferred until release.
Character beat caption
Always-on AFK chrome (no Dossier/Saga tabs):
| Row | Source | MC | Nobody |
|---|---|---|---|
| Identity | CaptionComposer |
Name · Title (real roles only; else species/job) |
Name (Species/Job) |
| Beat | owned tip + SagaProse.BeatClause |
tip enriched with one relation clause | tip as today |
| Context | muted | spine if live short-arc; else unresolved stake hitch (omits kill/role/founding under love/rest tips; RoleChange that echoes Identity always omitted) | spine only |
Hard rule: saga titles and stake slogans never enter InterestCandidate.Label.
Selection/identity_filter stay event-first.
Beat other resolves RelatedId then PairPartnerId (no living-name parse).
Status banners still own/suppress Beat; Identity + Context keep updating.
Outside hover, caption Identity/Beat/Context track camera focus. During Saga hover, the
primary nametag temporarily binds to the hovered MC (species, name/title, sex, favorite),
while camera Beat/Context are hidden to prevent false attribution. Camera composition keeps
running underneath and restores immediately when hover ends.
Rail UX
- Up to 10 slots with unit-keyed inspect-UI portraits. Each character is captured on first display, refreshed while watched, and retains that latest unique frame after focus leaves.
- Egg forms and tiny/blank atlas crops fall back to the species icon (letter last).
- Active chrome = camera follow MC; Involved chrome = other tip-touched MCs (subject/related/follow/pair/short-arc cast only - not mass
ParticipantIds). - Prefer uses a star pip / distinct border.
- Click toggles saga Prefer only (does not mutate WorldBox unit favorite; does not pin a Saga subject).
- Rail sits at the top of caption chrome (no tabs).
- Hovering a glyph opens Cast/Legacy depth (
LifeSagaPanel) and pauses camera switching. - Leaving the glyph hides the panel, restores dossier body rows, and releases the pause lease.
- Hover temporarily swaps the primary nametag to the hovered life; it does not change camera focus.
- The orange camera Beat and Context are hidden during hover rather than attributed to the hovered life.
- Hover restores the hovered character's live stone-frame dossier portrait beside the panel (species fallback only when no living actor is available).
- Panel is Cast + Legacy only (the primary nametag owns hovered name/title; no duplicate identity row or stake chrome).
- Cast budget is 8 (two rows); Legacy prefers turning points over Cast-echo kin crumbs.
- No Evidence stats dump. No Open Lore button (press L).
- ParentChild is capped (one named beat, or a lineage summary when there are 3+ children).
- Living Cast lover/friend/kin are not repeated as Legacy relationship lines.
- Legacy lines may prefix the world date (
Month Year · beat). - Context spine (
Kind · Phase) is hidden when the orange beat already names the same kind and phase is Climax. - Never show live task/status/trait rows or call a live attack target a rival.
Saga prose
SagaProse is the single voice owner. Evidence drives copy; enum names never appear in UI.
Relation classes: Bond, Friend, Kin (Parent/Child/Heir/Packmate/Kin), Foe (Old Foe/War Enemy/Plot Enemy/Blood Foe), Plot Partner, Grief.
Ban list (player-facing): earned rival, Earned a rival, Rivalry with, saga hero, fellow saga hero, War foe, Plot ally, Likely successor, A life in motion on Identity, mood wallpaper stakes.
Capitalization:
- Identity titles / Cast labels: Title Case (
Pack Alpha,Old Foe,Best Friend) - Beat clauses after
·: lowercase start - Stake / Legacy: Sentence case
- Unit names and owned tip body: leave as-is
Opposition facts (memory)
Notable only:
- Living rematches (≥
sagaRivalEncounterThreshold, default 3) while both are alive (sticky combat hook; kill/death do not count). - Kin blood (
killed_kin/kin_slain). - War / plot opposition (opposing principals on the same war/plot tip).
- MC↔MC living rematches earn rivalry one encounter sooner; a single MC kill is crossover Legacy, not automatic RivalEarned.
- Cast shows living credible foes only; weak kill-cycle
repeated_encountersfacts are pruned. - Heir cast label only when a game-authored heir API probe succeeds (
Heir, notLikely successor). - Unresolved
WarJoin/PlotJoinOthers fill Cast asWar Enemy/Plot Partnerwhen still living. - Crown / Combat / Intrigue / Pack / Bond lenses fill remaining Cast slots with live family peers (
Packmatefor Pack,Kinotherwise) after lover/friend/parents/children/heir/foe.
Stake
- Primary stake: strongest unresolved war/plot/rival/role/founding/grief (and McCrossover beats of those kinds).
- Fallback stake when nothing stronger exists: unresolved
HardArcCombat, openBondFormed, or McCrossoverKill. - War/plot prose names the opposing principal and kingdom/plot display when known (
Still at war with…). - Role rises (king/leader/alpha/clan chief/army captain) emit
RoleChangefrom live roster deltas. - Current role/founding facts live in Identity and are omitted from Context, Legacy, and rail tooltip stakes when they would only repeat the title.
- Titleless MCs (hard-arc, no crown) keep species/job Identity; Context stake hitch is required when memory has unresolved facts.
Cross-MC moments
When subject and other are both roster MCs, facts are flagged McCrossover (named stake/legacy prose + heat on both).
Prose stays plain (Bound with X, Slew X) - no “saga hero” wording.
Both rail glyphs light (Active + Involved) when the current tip touches multiple MCs.
Soft-fill quiet (AFK hygiene)
After hard story/crisis closers, soft-fill quiet suppresses soft-life crumbs and short interrupt FX (stunned / invincible).
FamilyPack does not break quiet (ambient cluster fill).
Combat / war / plot / outbreak / earthquake / story beats / epic strength / Prefer/MC still cut in.
Quiet can refresh briefly when a soft crumb ends (bounded).
Performance (idle)
- Roster role refresh runs on the ~3.5s amortized scan (not every frame). Soft heat does not force a world Refill.
- Dirty Prefer / membership changes re-rank existing slots only; full world admission stays on the timed cadence.
- World admission walks ~260 units/frame, then BuildSlots only the best ~2× Cap challengers (skips when pins fill Cap).
- Dossier
Relayoutruns only when chrome geometry changes; leaving hover restores dossier rows once. - Live portrait tile refresh is ~5 Hz; rail live sprites are only for the watched glyph (others use species icons).
- Rail face animation refreshes the Active glyph ~1/s; other glyphs stay static between structure changes.
- Plot join memory records the joiner only; full member snapshots stay on create/finish/cancel.
- RelationEvidence caches invalidate on memory revision + live lover/friend change.
- Hitch probe: harness
hitch_probe/ load save viaload_save_slot(slot 2 = Box of Magic). Optional.harness/autoload_slot.
Session
StoryPlanner.Cleardoes not wipe the roster or saga memory.- Lore browse / brief idle-off keeps the roster and memory.
- World replacement, map load-complete (
MapBox.finishingUpLoading),clearWorld, harness batch end, andinterest_saga_clear/saga_session_resetwipe roster + memory (+CaptionComposer.Clear). - Bind key uses live
map_stats.name,current_world_seed_id,map_statsidentity,_load_counter, and map size - not world reference alone. - Same-map spectator re-enable does not clear when the bind key is unchanged.
- Read-only soak dumps use
soak_probe(orsnapshotwithvalue=preserve) and skip the batch-end wipe.
Harness
saga_roster_diversitysaga_camera_prefers_mcsaga_prefer_soft_biassaga_wins_moderate_gapsaga_combat_follow_mcsaga_cast_soft_biassaga_cross_mc_lightsaga_cross_mc_wins_gapsaga_cross_mc_killsaga_rival_not_single_killsaga_rival_rematchsaga_prefer_cuts_ambientsaga_hard_arc_escalatessaga_overview_has_mcsaga_adaptive_dossier(hover depth; no tabs / empty-pick)saga_memory_survivessaga_war_memory_both_sidessaga_plot_cast_memberssaga_cast_kin_non_pack_lenssaga_stake_from_role_livesaga_legacy_qualitysaga_session_resetsaga_hover_read_pausesaga_replace_on_deathsaga_admit_rolessaga_replace_weakersaga_rail_active_highlightsaga_rail_prefer_clicksaga_soft_fill_no_packcaption_character_beatcaption_prose_voice
See also: story-planner.md.