Files
ashen-realms/docs/verification/first-visible-slice-fidelity.md
Bastian Wagner ec6c34e341 test: verify first visible vertical slice
Drives the full world/travel flow in Chromium via Playwright against the
live API and seeded Postgres, capturing the three required desktop
viewports and comparing them against the accepted design reference.

Fixes two evidenced defects found during verification:
- world-page scene sizing overflowed the viewport at all three required
  desktop sizes, pushing the footer (and, at 1440x900/1366x768, the travel
  button) below the fold; scene height now accounts for surrounding chrome
  so nothing is clipped.
- the generic HTTP-failure fallback message was hardcoded in English while
  the rest of the UI is German; now uses a matching German string.

Adds Playwright as a web devDependency for this and future browser
verification passes (no product-code dependency).
2026-08-19 10:13:40 +02:00

10 KiB
Raw Blame History

First Visible Vertical Slice — Fidelity Ledger

Reference: docs/references/world-travel-screen.png (concept mock, Graufurt hub with full RPG chrome: currencies, mail/friends/settings icons, "Shop" nav item, region detail panel with encounters/rewards, "Gebiet erkunden" action).

Renders (this task, post-fix): docs/verification/first-visible-slice-1920x1080.png, docs/verification/first-visible-slice-1440x900.png, docs/verification/first-visible-slice-1366x768.png. All three captured with Playwright/Chromium at http://localhost:4200/world, live API + seeded Postgres, with Verbrannte Straße selected as the travel target (matches the reference's state: travel panel populated).

Scope reminder: the reference is a full-game concept mock. This slice implements only the demo character, two locations, and travel — currencies, mail/social, settings, Shop, encounters/rewards, and "Gebiet erkunden" exploration are out of scope by design (see Task 110 rulings) and are recorded below as deliberate deviations, not defects.

Comparison points

1. Shell proportions and persistent regions

  • Reference: top bar (portrait, name/level, HP bar, currencies, icon row) + left icon nav (Karte/Jagd/Quests/Inventar/Charakter/Shop) + center map + right context panel + footer (chat/system line, world/online/time).
  • Render: top bar (portrait, name/level, HP bar, brand wordmark) + left nav (Karte enabled; Jagd/Quests/Inventar/Charakter present but disabled, aria-label="… ist noch nicht verfügbar") + center map + right "Gebietsinfo" panel + footer (status dot + text, ornament, region name).
  • Result: structural grid matches (top bar / nav+main+context / footer). Currency row, mail/friends/settings/logout icons, and "Shop" nav item are absent — deliberate, no such systems exist yet. No fix needed.

2. Artwork dominance and crop

  • Reference: large painterly Graufurt gate artwork fills the map region, background-size: cover-style dominant visual, quiet areas reserved for path/nodes/panel.
  • Render: .world-page__scene uses the project's own generated Südtor/Aschenstraße artwork (/images/backgrounds/Suedtor.png / Aschestrasse.png), background-size: cover, same compositional role. Visible and readable at all three captured sizes.
  • Result: matches intent. Different concrete artwork (project-specific, generated per the style guide) is expected, not a defect.

3. Typography hierarchy and control typography

  • Reference: large serif location title overlaid top-left of the map, green safety subtitle, short descriptive paragraph in the same overlay; serif headers in the side panel.
  • Render: serif (Georgia) location title top-left of the map (.world-page__location-title); description/safety/level facts live in the right "Gebietsinfo" panel instead of a second overlay block on the map. Control typography (buttons, dl labels) uses the app's sans body font with small-caps-style eyebrows ("REISEN", "GEBIETSINFO").
  • Result: title hierarchy matches (serif, large, top-left). The map-overlay vs. side-panel placement of description text is an established information-architecture choice from earlier tasks (Task 8/9), not a regression introduced here — left as a recorded deviation, not fixed, since re-architecting panel content is outside this task's evidenced-defect scope.

4. Dark palette, bronze borders, and blue/current state

  • Reference: anthracite/black panels, bronze/gold hairline borders, blue ring on the current-location node, gold ring + gold path on selected/target.
  • Render: --ar-bg/--ar-panel dark palette, --ar-border/ --ar-border-highlight bronze/gold borders on top bar, panels, and travel box; .location-node--current renders a blue marker ring (confirmed in all three captures, "Aktueller Ort" label green), selected/target node renders gold ring + gold dashed path (confirmed, "Ausgewähltes Ziel" label gold).
  • Result: matches the style guide's colour semantics (blue = current/active navigation, gold = selection/important action). No fix needed.

5. Node/path legibility

  • Reference: node names + short state label beneath each node, dashed gold connecting path.
  • Render: same pattern — location-node__name + location-node__state ("Aktueller Ort" / "Ausgewähltes Ziel" / "Erreichbar"), dashed gold SVG path between the two nodes. Legible with sufficient text-shadow contrast against the background artwork at all three captured sizes.
  • Result: matches. No fix needed.

6. Travel panel placement and action prominence

  • Reference: travel panel overlays the bottom edge of the map itself, as a floating box, with a full-width primary blue button.
  • Render: .world-page__travel-panel is a separate block directly beneath the map (not overlaid on top of it), centered, min(29rem, 100%) wide, with a full-width primary button (Reise beginnen / Zur Verbrannte Straße reisen?) using the gold-bordered, blue-tinted button style.
  • Result: placement differs (below vs. overlaid on the map) — an established layout choice from earlier tasks, not introduced or regressed by this task. Action prominence (full-width primary button, clear label, disabled state while travelling) matches reference intent. Not treated as a material mismatch requiring a redesign in this verification-only task.

7. Context-panel information density

  • Reference: region title, recommended level, "Mögliche Begegnungen" icon row, description, "Mögliche Belohnungen" icon row, "Gebiet erkunden" button.
  • Render: "GEBIETSINFO" eyebrow, location name, selected-target note, artwork thumbnail, description paragraph, facts list (recommended level / safety / hunting availability).
  • Result: reduced density is intentional — encounters, rewards, and area exploration are later-gameplay systems explicitly out of scope for this slice (per the plan's deliberate limitations). Not a defect.

8. Responsive behaviour at all three sizes

  • Evidence (pre-fix): measured via a Playwright DOM probe — document.documentElement.scrollHeight vs. window.innerHeight:
    • 1920×1080: docHeight 1098 vs. viewport 1080 (18px overflow; footer's bottom 18px clipped below the fold).
    • 1440×900: docHeight 997 vs. viewport 900 (97px overflow; travel button and footer entirely below the fold).
    • 1366×768: docHeight 909 vs. viewport 768 (141px overflow; travel button and footer entirely below the fold, ~half the travel panel cut off).
    • Root cause: .world-page__scene { min-block-size: clamp(30rem, 67vh, 44rem); } sized the map purely off viewport height without accounting for the fixed chrome around it (top bar + paddings + travel panel + footer ≈ 395px), so the three required desktop sizes all overflowed the viewport and pushed the footer (and, at the two smaller sizes, the travel button) out of view without scrolling.
    • Fixed in apps/web/src/app/features/world/world-page.component.scss: changed to min-block-size: clamp(20rem, calc(100dvh - 25rem), 44rem), which sizes the map to the remaining space after the known chrome height (with a small safety margin), while keeping the existing 2044rem floor and ceiling.
    • Evidence (post-fix), same probe: 1920×1080 → 1080 vs. 1080 (0 overflow); 1440×900 → 900 vs. 900 (0 overflow); 1366×768 → 768 vs. 768 (0 overflow). Re-captured screenshots (see paths above) show the top bar, nav, map with both nodes, full travel panel including the primary button, context panel, and footer all fully visible with no clipping at all three sizes.
  • Result: material mismatch found and fixed.

Above-the-fold copy diff

Every visible string across all three renders was checked against the brief's allowed-copy categories (API content, requested navigation labels, travel labels, restrained system/footer text):

Text Source Category
"Aric Duskwalker", "Stufe 1", "100 / 100" API (/api/characters/me) API content
"Südtor von Graufurt", "Verbrannte Straße", description paragraph, "11", "Sicherer Ort", "Keine Jagd" API (/api/world/current-location) API content
"Verbrannte Straße", "00:00:10", "Niedrig" API (/api/world/current-location connections) API content
"Karte", "Jagd", "Quests", "Inventar", "Charakter" side nav requested navigation labels
"REISEN", "Zur … reisen?", "Ziel", "Reisezeit", "Gefahr", "Reise beginnen", "Ankunft in", "REISE LÄUFT", "Reise läuft", "Wähle einen erreichbaren Ort auf der Karte." travel panel travel labels
"GEBIETSINFO", "Ausgewähltes Ziel: …", "Empfohlene Stufe", "Sicherheit", "Jagd", "Aktueller Ort", "Ausgewähltes Ziel", "Erreichbar" context panel / node labels restrained system text
"Verbindung bereit", "Aschenfelder", "Ashen Realms" footer / top bar restrained system/footer text
"Weltzustand wird geladen…", "Weltkarte wird vorbereitet.", "Erneut versuchen" loading/empty states restrained system text
"Unable to load world state." error fallback (world.store.ts) violation — English string in an otherwise fully German UI

Fixed: apps/web/src/app/features/world/world.store.ts, toErrorMessage() fallback changed from 'Unable to load world state.' to 'Weltzustand konnte nicht geladen werden.', matching the German tone/case used everywhere else in the app (e.g. "Weltzustand wird geladen…"). Verified live: killed the API process, reloaded /world, confirmed the in-shell error box now reads "Weltzustand konnte nicht geladen werden." with no window.alert() dialog fired (Playwright page.on('dialog', …) listener recorded zero dialogs across every step of the verification pass).

No invented, promotional, or placeholder copy was found anywhere in the above-the-fold content.

Summary

One functional/visual defect found and fixed (responsive overflow/clipping at all three required desktop sizes — item 8). One copy defect found and fixed (English fallback error string — copy diff table above). All other comparison points either matched the reference's visual language directly, or reflect deliberate, already-ruled-on scope reductions from earlier tasks (no currencies/social/settings/Shop, reduced context-panel density, no map-overlay description block, travel panel placed below rather than over the map) that this verification-only task did not redesign.