Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions ASSETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,22 @@ The Block DNA batch-one reference establishes harbor, transit-market, canal, and
| Matching vertical vehicle loadout plate | Original OpenAI GPT Image 2.5 generation; no found artwork incorporated | `art-src/generated/environments/street/block_slide_car_loadout_mobile_v001.png` (1440×2560) | `generated.environments.street.block_slide_car_loadout_mobile_v001` → `/assets/runtime/generated/environments/street/block_slide_car_loadout_mobile_v001.webp` | 1080×1920, 201,184 bytes |

Both sources were imported using the processor's exact-source `--only` option after #198, not by hand-editing the manifest. The global runtime package is 7.70 MB against the 20 MB limit. These plates are **decorative only**: four seat buttons, selection/status text, stats, cargo, and the launch action remain accessible DOM. Fictional demo members have only a clearly labeled role-art fallback; a verified personal likeness depends on a real member photo and the separate #195 generation-provider gate. The loadout excludes the driver from passenger-shooter seats and post-mission shooter XP, but the legacy mini-game does not yet attribute shots to named passengers (#201).

## Nightfall tactical presentation reuse — 2026-10-09

`UnifiedEncounterScene` now consumes the existing `worldActorResolver` topdown idle/downed role art for crew and fictional opposition. Opposition borrows the registered shooter kit for presentation only; named identity, engine role, team, position and combat authority are preserved. URL-derived texture keys keep resolver aliases on the same loaded image. No generated art, asset import, manifest change, dependency or acquisition was added.

| Registered asset ID | Runtime file under `/assets/runtime/generated/characters/topdown/` | Existing source under `art-src/generated/characters/topdown/` | Bytes |
|---|---|---|---:|
| `generated.characters.topdown.character_dealer_male_blacktee_topdown_idle_v001` | `character_dealer_male_blacktee_topdown_idle_v001.webp` | `character_dealer_male_blacktee_topdown_idle_v001.png` | 12,014 |
| `generated.characters.topdown.character_dealer_male_topdown_downed_v001` | `character_dealer_male_topdown_downed_v001.webp` | `character_dealer_male_topdown_downed_v001.png` | 19,238 |
| `generated.characters.topdown.character_shooter_male_topdown_idle_v001` | `character_shooter_male_topdown_idle_v001.webp` | `character_shooter_male_topdown_idle_v001.png` | 11,120 |
| `generated.characters.topdown.character_shooter_male_topdown_downed_v001` | `character_shooter_male_topdown_downed_v001.webp` | `character_shooter_male_topdown_downed_v001.png` | 21,134 |

These are previously registered repository assets with their existing provenance, not newly acquired art or member likenesses. All four are 384×384 with alpha and resolver pivot `(0.5,0.5)`. The scene uses resolver pivots and the existing `0.32` sprite scale (122.88 world pixels; approximately 49.92 CSS pixels at 390px width).

**State/fallback contract:** preload idle/downed URLs once; use registered downed art when available. Missing actor images retain team-colored geometric markers and named labels. Aim/fire/hit/reload pose art is not available in this kit: idle is intentional while existing tracers/impacts and snapshot HUD communicate combat. No pose animation is claimed. The existing Las Olas `preparation.backgroundUrl` remains the plate; increased plate visibility and lighter passable-cell tint preserve cover/extraction readability. Missing plate retains the existing terrain/background fallback.

**Projection/budget:** 960×600 world, 8×8 terrain, 120×55.25 cells, top 86/bottom 72 and engine hit cells are unchanged. Phaser FIT owns canvas sizing/centering; CSS does not stretch it. Preloading the two already-shipped downed images adds at most 40,372 bytes of requests for the demonstrated dealer/shooter pair; shipped asset budget delta is zero. Audit remained 112 assets / 7.70 MB of 20 MB / no errors or warnings, with 5 valid packages and 4 schemas.

Phone/desktop and actor-image-failure checks completed before the final DOM health/ammo/reload HUD addition. Final HUD recapture and screenshot upload are pending after a workspace outage; see `docs/evidence/2026-10-09-nightfall-presentation/README.md`. This narrow reuse fix does not complete #190's full hero-package/style approval or its missing pose inventory.
11 changes: 11 additions & 0 deletions docs/PROJECT_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,17 @@ Payments/monetization P0s are separately listed in `docs/MVP_STATUS_AND_DEV_PLAN

## Log

### 2026-10-09 — Nightfall reuse and touch geometry, draft handoff (#190)

- **Base/branch:** `9eef5aac28a82275d7a2e1596e8658b167953ed7` / `fix/190-tactical-role-art`. Reservations: #190 comments 6086504547 and 6087048558. Reuse existing resources before creating code/assets.
- **Player change:** registered idle/downed role art now renders named fictional rivals; resolver aliases share URL texture keys; distinct team rings and backed labels improve readability. Existing engine events render once even when same-tick IDs collide. Reveal the registered plate without changing cover/extraction geometry.
- **Input repair:** remove forced canvas CSS dimensions so existing Phaser FIT keeps taps aligned. Put full-screen combat above the rival banner; close control minimum becomes 44px. No camera, cell, hitbox, engine command, economy or result-writer change.
- **HUD:** expose existing crew snapshot HP/ammo/reload/down state in the existing DOM stats row. No parallel selection/state or new service.
- **Regression/gates before HUD:** scene suite 4 failed / 1 passed on base, then 5 passed. Full frontend 1,038 passed / 4 skipped / 92 files; typecheck/build pass; lint 200 baseline warnings / 0 errors / no new warnings; asset audit 112 / 7.70 MB of 20 MB / no errors or warnings; packages 5 / schemas 4. HUD regression failed on the base UI; final local preflight completion is unknown after the workspace disconnected.
- **Built-game proof before HUD:** real 390×844 touch and 1440×900 pointer path Strip → named Nightfall → actual cell movement → fire/reload → registered downed rival → retreat → apply once → strategy → reload. Both happy paths had no page/console errors and one unchanged local receipt. Reinjecting old canvas CSS reproduced wrong destination cells at both sizes. Phone actor-image failure retained playable labels/controls/result/reload (0 page errors; 16 expected resource errors).
- **Draft hold:** GitHub CI checks the published final source; final HUD phone/desktop/failure recapture and screenshot upload remain pending because the workspace went offline. Evidence summary and exact limits: `docs/evidence/2026-10-09-nightfall-presentation/`. Do not claim final HUD manual proof or authenticated receipt durability.
- **Integration/limits:** independent of #204 ATTACK response; both append this log and require append-only reconciliation on integration. No #169 resolver/member-identity, #201 DRIVE, #175 staging, migrations, secrets, Supabase or deployment edits. Role-art provenance/fallback/budget recorded in ASSETS.md. Full #190 hero approval/missing poses, phone Diorama hit-area overlap and #175 authenticated recovery remain open.

### 2026-10-01 — Backend timestamps are timezone-aware UTC (#170)

- Replaced all 17 `datetime.utcnow()` call sites in the live backend runtime with one shared helper, `backend/python/utils/utc.py` (`utc_now`, `to_iso_utc`, `utc_now_iso`). Python 3.12 deprecates `utcnow()` and the required CI runs the full backend suite, so the debt was visible on every run: the audited baseline emitted 153 warnings, all of them this single warning. The suite now runs with 0 warnings.
Expand Down
34 changes: 34 additions & 0 deletions docs/evidence/2026-10-09-nightfall-presentation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Nightfall presentation verification — 2026-10-09

This is a partial evidence handoff for issue #190. The scene/CSS fix passed local gates and real built-game checks before the final crew-condition HUD addition. The workspace disconnected during the final HUD preflight. **Keep the PR draft until the final HUD browser check and capture handoff are complete.**

## Regression and automated gates

- Against unchanged base `9eef5aa`, the new scene suite failed four cases and passed one. The corrected scene passed all five.
- Before the HUD addition: full frontend suite **1,038 passed / 4 skipped / 92 files**; typecheck and production build passed; lint **200 baseline warnings / 0 errors / 0 new warnings**.
- Asset audit: **112 assets / 7.70 MB of 20 MB / 0 errors / 0 warnings**. Package validation: **5 packages / 4 schemas**.
- The crew-condition HUD regression failed on the unchanged UI as expected. Its final local preflight started but its completion is unknown. GitHub CI verifies the published final source separately; consult the PR checks.
- Existing build warnings include large chunks and legacy logo/menu/drive-by background references. No new asset or dependency was introduced.

## Real player path completed before the HUD addition

At **390×844** with real touchscreen taps and **1440×900** with pointer input: age gate → Run the Block → lock Dre/Rome → place/assign through the existing Legal board → Close Deal → Defend Block → named Nightfall encounter → move → fire/reload → down a named rival → retreat → apply result once → return → reload.

Actual session cells matched the rendered destinations: Dre `(0,2)`, Rome `(4,4)`. A registered shooter downed texture appeared on the named Nightfall lookout. Both happy paths produced **0 page errors and 0 console errors**. One local receipt survived reload unchanged.

As a controlled reproduction, reinjecting only the old canvas sizing rule into the same build made Dre land at `(0,3)` on phone and `(1,2)` on desktop when the intended rendered cell was `(0,2)`. Removing forced CSS dimensions lets existing Phaser FIT own the canvas geometry; world projection and hit cells remain unchanged.

On phone, aborting registered topdown actor images left named fallback markers, fire/reload/retreat, result application, return and reload playable: **0 page errors**, with **16 expected failed-resource console errors**.

The demo used the real built game and commands, with a read-only observer for session/texture inspection. Built files were delivered through a hermetic static handler; unavailable web fonts used the system fallback. Game state, engine commands and result application were not stubbed. These are local demo checks, not authenticated Supabase receipt proof.

## Evidence gap and release hold

`verification-summary.json` records the checks inspected during the session. It is a summary, not a replacement for raw browser reports or screenshots. Local screenshots and browser reports were produced and inspected, but the disconnected workspace prevented their upload. No unavailable capture is presented as attached evidence.

Before making the PR ready for review:
1. Repeat phone/desktop movement, crew HP/ammo/reload HUD, fire/downed/retreat/apply/return/reload on the final commit.
2. Repeat actor-image failure and confirm labels, controls, HUD and one receipt remain intact.
3. Attach before/after and failure captures, confirm no clipping or cell offset after the extra HUD row, and record the final CI results.

This uses existing topdown role art and preserves the historical tactical plane. It does not complete the full #190 hero-package/style approval or missing aim/fire/hit/reload poses. The Legal board was used because Diorama hit areas overlap on phone; that separate overlap remains. Authenticated durability/recovery stays with #175.
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
{
"schemaVersion": 1,
"date": "2026-10-09",
"repository": "BrandDead/slide",
"baseCommit": "9eef5aac28a82275d7a2e1596e8658b167953ed7",
"scope": "Nightfall presentation and Phaser FIT correction",
"recordType": "Summary of locally completed and inspected checks; not raw Playwright output",
"verifiedSourceBlobs": {
"scene": "60feef55e8ff462e77aa6abea3a5c04d8ff8ada0",
"css": "67b2e6c7468d3235c5f50e1558a304db0e69d483"
},
"timing": {
"localAutomatedChecks": "Before the final DOM crew-condition HUD addition",
"browserChecks": "Before the final DOM crew-condition HUD addition",
"finalHudLocalPreflight": "Started, completion unknown: workspace environment disconnected",
"finalHudBrowserCheck": "Pending",
"screenshotUpload": "Blocked by workspace outage; no screenshot files are included in this summary"
},
"regressionFirst": {
"sceneBase": {
"passed": 1,
"failed": 4
},
"sceneAfter": {
"passed": 5,
"failed": 0
},
"hudBase": {
"passed": 1,
"failed": 1,
"expectedFailure": "Scout condition label absent"
}
},
"preHudLocalGates": {
"frontend": {
"passed": 1038,
"skipped": 4,
"files": 92
},
"lint": {
"warnings": 200,
"errors": 0,
"newWarnings": 0
},
"typecheck": "passed",
"build": "passed",
"assets": {
"count": 112,
"runtimeMB": 7.7,
"budgetMB": 20,
"errors": 0,
"warnings": 0
},
"packages": {
"count": 5,
"schemas": 4
}
},
"browserMethod": {
"build": "Existing demo mode built after normal validation, with demo Supabase configuration",
"runtime": "Real built React/Phaser game; real controls, commands and result application",
"delivery": "Hermetic static delivery of built files and system font fallback",
"inspection": "Read-only Phaser boot observer inspected actual session cells and sprite texture URLs",
"route": [
"Age gate",
"Run the Block",
"Lock Dre and Rome",
"Place Dre",
"Legal board",
"Storefront at (4,3)",
"Assign Rome",
"Close Deal",
"Defend Block",
"Named Nightfall encounter"
],
"persistenceBoundary": "Local demo receipt and reload; authenticated server receipt not exercised"
},
"happyPaths": [
{
"viewport": {
"width": 390,
"height": 844
},
"input": "Real touchscreen taps at rendered cell centers",
"intendedDestinations": {
"Dre": {
"x": 0,
"y": 2
},
"Rome": {
"x": 4,
"y": 4
}
},
"observedDestinations": {
"Dre": {
"x": 0,
"y": 2
},
"Rome": {
"x": 4,
"y": 4
}
},
"fireReload": "completed",
"downedRival": "Nightfall lookout used registered shooter downed texture",
"outcome": "retreated",
"appliedReceiptCount": 1,
"reloadLedgerUnchanged": true,
"pageErrors": 0,
"consoleErrors": 0
},
{
"viewport": {
"width": 1440,
"height": 900
},
"input": "Real pointer clicks at rendered cell centers",
"intendedDestinations": {
"Dre": {
"x": 0,
"y": 2
},
"Rome": {
"x": 4,
"y": 4
}
},
"observedDestinations": {
"Dre": {
"x": 0,
"y": 2
},
"Rome": {
"x": 4,
"y": 4
}
},
"fireReload": "completed",
"downedRival": "Nightfall lookout used registered shooter downed texture",
"outcome": "retreated",
"appliedReceiptCount": 1,
"reloadLedgerUnchanged": true,
"pageErrors": 0,
"consoleErrors": 0
}
],
"sizingRegression": {
"method": "Reinjected base canvas CSS into the otherwise unchanged presentation build",
"phone": {
"intendedDre": {
"x": 0,
"y": 2
},
"actualDre": {
"x": 0,
"y": 3
},
"correctCells": false
},
"desktop": {
"intendedDre": {
"x": 0,
"y": 2
},
"actualDre": {
"x": 1,
"y": 2
},
"correctCells": false
},
"geometry": {
"worldWidth": 960,
"worldHeight": 600,
"gridCols": 8,
"gridRows": 8,
"cellWidth": 120,
"cellHeight": 55.25,
"playfieldTop": 86,
"playfieldBottom": 72
}
},
"imageFailure": {
"viewport": {
"width": 390,
"height": 844
},
"method": "Abort registered character/topdown image requests",
"labelsAndMarkers": "visible",
"fireReloadRetreat": "playable",
"appliedReceiptCount": 1,
"reloadLedgerUnchanged": true,
"pageErrors": 0,
"expectedFailedResourceConsoleErrors": 16
},
"observedLocalReceipt": {
"key": "encounter-demo-block-las-olas-m36lx4:retreated",
"money": 13256,
"playerHeat": 9,
"blockMorale": 66
},
"remaining": [
"Repeat final HUD phone/desktop happy and image-failure paths and attach captures",
"Complete #190 hero package/style approval and missing aim/fire/hit/reload pose inventory",
"Authenticated result durability and recovery remain under #175",
"Legal-board fallback was used; mobile Diorama hit-area overlap is not fixed here"
]
}
8 changes: 5 additions & 3 deletions frontend/src/components/encounter/UnifiedEncounter.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.unified-encounter {
position: fixed;
inset: 0;
z-index: 2000;
z-index: 10000;
width: 100vw;
height: 100dvh;
margin: 0;
Expand Down Expand Up @@ -82,7 +82,9 @@
.ue-stage-shell { position: relative; min-height: 0; background: #07111d; overflow: hidden; }
.ue-stage { width: 100%; height: 100%; min-height: 0; opacity: 0; transition: opacity 220ms ease; }
.ue-stage--ready { opacity: 1; }
.ue-stage canvas { display: block; width: 100% !important; height: 100% !important; object-fit: contain; }
/* Phaser FIT owns canvas dimensions and centering. Stretching this element
offsets pointer coordinates from the visible letterboxed cells. */
.ue-stage canvas { display: block; }

.ue-loading {
position: absolute;
Expand Down Expand Up @@ -134,7 +136,7 @@
.ue-briefing { align-items: center; flex-direction: row; padding: 8px 10px; gap: 8px; }
.ue-briefing p { max-width: 230px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ue-kicker { display: none; }
.ue-close { min-height: 40px; padding-inline: 10px; }
.ue-close { min-height: 44px; padding-inline: 10px; }
.ue-modifiers { padding: 6px 10px; }
.ue-modifiers span { max-width: 220px; padding: 5px 7px; font-size: 10px; }
.ue-controls { grid-template-columns: 1fr; padding: 8px 10px; }
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/components/encounter/UnifiedEncounter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ export const UnifiedEncounter: React.FC<UnifiedEncounterProps> = ({
<span><strong>{activeCrew}</strong> crew active</span>
<span><strong>{opposition}</strong> opposition visible</span>
<span><strong>{snapshot.objective.progress}/{snapshot.objective.target}</strong> secure exits</span>
{snapshot.combatants.filter(actor => actor.team === 'crew').map(actor => (
<span key={actor.id} aria-label={`${actor.name} condition`}>
<strong>{actor.name}</strong> · {actor.isDown ? 'DOWN' : `${actor.health} HP`} · {actor.ammo}/{actor.maxAmmo} ammo{actor.reloadUntilTick !== null && !actor.isDown ? ' · reloading' : ''}
</span>
))}
</div>
<div className="ue-action-row">
<button type="button" disabled={!isReady || snapshot.phase !== 'active'} onClick={() => sceneRef.current?.fireNearestSelected()}>Fire nearest</button>
Expand Down
Loading
Loading