Sprint 16 — Visual Punch List (P0 + P1 + P2 template) - #104
Conversation
- AgeGate: bg_loading_screen_v001 behind the panel with legibility scrim - New SplashScreen component replaces the bare 'Loading...' div during auth check. Note: demo mode skips AgeGate; production flow shows both.
Registers block_lasolas_1208_001 in the environment manifest (street plates reuse stripplaza night/day until Las Olas street art lands).
The engine preloaded /assets/*.jpg which never existed (real files are /assets/runtime/*.webp) so every session fell back to the solid-color procedural background. Paths fixed, and the new in-car POV plate now draws cover-fit under targets/FX; procedural remains the no-asset fallback.
bg_os_wallpaper_v001 (portrait aerial plate) replaces the broken bg_desktop.jpg reference in OSShell and the six other screens that pointed at the same dead path (all rendered black).
Data-driven card: neon ring portrait, role chip, LEVEL hex, two segmented stat bars, SEND TO BLOCK / CALL BACK. ROLE_CARD_THEMES covers dealer, shooter, enforcer, lookout, k9, recruit — P2 role cards are the same template, one theme entry each. Stat mappings provisional until role-specific progression stats land.
Full-screen creation: starter attributes (heart/loyalty/speed/nerve/ potential) with reroll, role rail w/ recruit-promote ribbon (RECRUIT → DEALER or SHOOTER), name entry, fullbody sprite preview. Contacts: new first option in Add Member modal; active tab now renders RoleContactCard (open/backdoor preserved, send-to-block navigates to map, call back opens profile).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3b158af. Configure here.
| className={`mc-role${role === id ? ' mc-role-active' : ''}`} | ||
| style={{ ['--mc-role' as any]: accent }} | ||
| onClick={() => { setRole(id); setSpriteOk(true); }} | ||
| aria-pressed={role === id} |
There was a problem hiding this comment.
Stale sprite error clears preview
Medium Severity
Member preview uses one shared spriteOk flag and an onError handler that always sets it false. After switching roles, a late error from the previous role’s image request can flip spriteOk off while the current role’s sprite is valid, so the UI shows the icon fallback instead of the full-body art.
Reviewed by Cursor Bugbot for commit 3b158af. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3b158af1b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| message: `Pick a corner for ${contact.nickname || contact.name}`, | ||
| timestamp: new Date().toISOString(), | ||
| } as any); | ||
| navigateTo('map'); |
There was a problem hiding this comment.
Enter placement mode before routing to the map
For every active contact, SEND TO BLOCK only posts a “Pick a corner” notification and navigates to the map. It never calls useBlockStore.setPlacementMode with this member, while TopDownBlock only places a member when isPlacementMode and pendingPlacementMemberId are set, so tapping a corner after this action does nothing and the advertised deployment flow is nonfunctional.
Useful? React with 👍 / 👎.
| role?: string, | ||
| ): { label: string; value: number }[] { | ||
| const theme = getRoleCardTheme(role); | ||
| const read = (k: StatKey) => Math.max(0, Math.min(100, Number(member?.[k] ?? 50))); |
There was a problem hiding this comment.
Read card stats from the canonical member fields
Canonical GangMember records, including the demo seed and market hires, store combat attributes under member.stats and do not define top-level shooting, dealing, driving, heatResistance, or stealth. Reading member[k] therefore silently substitutes 50 for most role-specific bars—for example, every seeded shooter shows 50 shooting regardless of its actual stats—making the new contact cards display misleading progression data.
Useful? React with 👍 / 👎.
|
|
||
| // Sprint 16 (P0): in-car POV plate — storefront strip seen through the | ||
| // passenger window (matches the drive-by HUD concept art shot-for-shot). | ||
| const DRIVEBY_POV_BG = '/assets/runtime/generated/environments/street/bg_driveby_pov_v001.png'; |
There was a problem hiding this comment.
Ship the POV asset referenced by the drive-by engine
The reviewed Git tree has no bg_driveby_pov_v001.png anywhere (verified with a repo-wide tree search), so this URL always returns 404 and the naturalWidth > 0 drawing branch can never run. Consequently the newly advertised in-car POV backdrop is absent in every build and the engine continues rendering only its procedural/parallax fallback.
Useful? React with 👍 / 👎.
| name={contact.nickname || contact.name} | ||
| role={contact.role} | ||
| level={(member as any)?.level ?? 1} | ||
| avatarUrl={contact.customAvatarUrl} |
There was a problem hiding this comment.
Preserve legacy contact avatars on the new cards
For persisted contacts that use the valid Contact.avatar field rendered by the previous ContactCard, the replacement passes only customAvatarUrl, so their saved portrait is discarded and the card falls back to a letter. Pass contact.customAvatarUrl ?? contact.avatar so upgrading to this card does not regress existing contact images.
Useful? React with 👍 / 👎.
| accent: '#ff4d6d', glow: 'rgba(255, 77, 109, 0.45)', label: 'SOLDIER', | ||
| primary: { label: 'PRIMARY', statKey: 'shooting' }, | ||
| secondary: { label: 'SECONDARY', statKey: 'loyalty' }, |
There was a problem hiding this comment.
Add themes for every existing roster role
A driver hired from the existing Market is a valid active contact, but ROLE_CARD_THEMES has no driver entry, so this fallback labels that member SOLDIER and shows generic PRIMARY/SECONDARY bars instead of their actual role. The same regression affects other supported roles such as chemist, runner, and boss; the previous card displayed contact.role directly.
Useful? React with 👍 / 👎.
| role, | ||
| status: 'active', | ||
| level: 1, | ||
| xp: segmentsToStat(a.potential) - 35, // potential seeds a small XP head start |
There was a problem hiding this comment.
Seed the canonical experience field during creation
When potential grants a new member an XP head start, only the optional xp alias is populated. The progression panel, Slide rewards, and dealer game loop all read member.experience, so the member initially displays zero XP and the first normal reward is calculated from zero, discarding the promised 13–52 starting XP. Initialize experience consistently with xp here.
Useful? React with 👍 / 👎.


Sprint 16 — Visual Punch List (P0 + P1 + P2 template)
Closes out the remaining visual punch list against the reference art set
(18 mockups: role contact cards, member creation v2, Las Olas topdown,
drive-by POV + HUD concept, world-concept plate).
What landed
P0
bg_loading_screen_v001now sitsbehind the AgeGate panel (with a legibility scrim), and a new
SplashScreencomponent replaces the bareLoading...div during theauth check. Demo mode still skips AgeGate by design.
demoSeed.tsnow points atblock_lasolas_topdown_v001.webp;block_lasolas_1208_001isregistered in the environment manifest (street plates reuse stripplaza
night/day until Las Olas street art lands).
background: the engine preloaded four
/assets/*.jpgpaths that don'texist (real files are
/assets/runtime/*.webp), so it always fellback to procedural. Paths repaired, and the new in-car POV plate
(
bg_driveby_pov_v001) draws cover-fit under targets/FX — matches thedrive-by HUD concept art shot-for-shot. Procedural stays as the
no-asset fallback.
P1
bg_os_wallpaper_v001(portrait aerial) wiredinto
.os-shell::before— and into the six other stylesheets thatreferenced the same dead
bg_desktop.jpgpath (Contacts, Settings,Casino, AlchemyLab, App.css, theme.css). All of these rendered black
before.
name, role chip, LEVEL hex, two segmented stat bars, SEND TO BLOCK /
CALL BACK. Wired into the Contacts active tab; open-profile and
backdoor behavior preserved; send-to-block routes to the map with a
pick-a-corner notification.
attributes (heart / loyalty / speed / nerve / potential) with reroll,
role rail (dealer / shooter / enforcer / recruit / k9), the
"ONLY RECRUITS CAN PROMOTE → DEALER or SHOOTER" ribbon, name entry,
fullbody sprite preview. First option in the Add Member modal.
P2
Recruit) ship as theme entries in
ROLE_CARD_THEMES— one template,per-role neon + stat labels. Adding future roles is one entry.
Verification
tsc --noEmit: 0 new errors (5 pre-existing onmain-tL2525:BlockOverlay GeoJSON ×2, CanvasStreetRendererV3 role map, TrapApp
status comparison, assetResolver role map — the last two role-map ones
are
recruit/k9/policemissing fromRecord<MemberRole, string>mapsand are worth a small follow-up fix)
vitest run: 581/581 passnode scripts/assets/audit.mjs: PASSED — 5.35 MB / 20 MB budget;4 non-blocking
W_ORPHANwarnings for the new plates until mastersare registered via
assets:process(see APPLY notes)vite build: succeedsKnown gaps / fast-follows (not blocking)
the engine yet — good Sprint 17 candidate.
GangMember fields) until role-specific stats (hustle, talk game, bite
force…) land in progression.
remain the street fallback.
gifts, special gifts) from the v2 mockups are a natural next component
on top of
ROLE_CARD_THEMES.Note
Low Risk
Mostly presentational assets and new optional crew UI; member creation only extends existing
addMemberpaths with no auth or payment changes.Overview
Sprint 16 aligns the client with the reference art set: loading/shell backdrops, Las Olas as the demo hero block, drive-by visuals, and crew UI from the mockups.
Boot & chrome: Auth wait now uses a cinematic
SplashScreen(sharedloading_screen_v001plate with AgeGate). Deadbg_desktop.jpgreferences across several screens are replaced withos_shell_wallpaper_v001, restoring non-black backgrounds.Map & drive-by: Demo seed and
assetManifestregisterblock_lasolas_1208_001with Las Olas topdown art. Drive-by preloads/assets/runtime/*.webp(fixing missing.jpgpaths) and composites a static in-car POV plate under gameplay.Crew: Active contacts use
RoleContactCard(per-role neon theme, segmented stats, SEND TO BLOCK → map, profile/backdoor preserved). Member Creation is a full-screen flow (reroll attributes, role pick, name) wired from Add Member and mapped intoGangMemberstats viasegmentsToStat.Small follow-ups in the same PR:
recruit/k9/policeentries in role color/resolver maps,BlockOverlayGeoJSON typing relaxed, one NPC enforcer in seed data.Reviewed by Cursor Bugbot for commit 3b158af. Bugbot is set up for automated code reviews on this repo. Configure here.