Implementation Plan 18.2: Landscape Pivot & State Stabilization
This document outlines the detailed architectural design and step-by-step implementation plan to transition the active game arena from a vertical scrolling portrait layout to a modern, desktop-native landscape split-screen. It also stabilizes the backend state transition engine to eliminate fatal database transaction hangs (RESOLVING status lock) caused by floating-point math violations on Prisma Int columns.
📋 Architectural Context & Objectives
Our objective is to consolidate Sandbox Crucible UI/UX feedback and backend state machine failures into a single, cohesive patch. This plan centers on:- Responsive Viewport Containment (Phase A): Eliminate global page scrolling. Lock active board UI inside a dual-column flex container fitting standard viewport heights (
h-screen lg:overflow-hidden). - Component Separation & Collisions (Phase B): Adapt contender slot layouts based on their geographic grid placement to prevent interactive action overlaps with the centered News Stub, and sync wallet aesthetics directly with the physical Political Compass Meme coordinates (Labor Top-Left, Dinars Top-Right).
- Player Retention Flow (Phase C): Eliminate dead-ends inside the game loop by offering clear secondary routing once a match reaches its terminal
RESOLVEDstatus. - Integer Math Safety (Phase D): Ensure 100% database schema compliance by rounding ELO deltas, payouts, distance outcomes, and tax increments before hitting Prisma transactions.
🛠️ Proposed Changes
Phase A: The Landscape Pivot
This phase re-architects the primary screen layout of the active game board into a geographic dual-column interface designed specifically for landscape/desktop monitors.[MODIFY] page.tsx
- Target: Overhaul the outer container and the main grid flow in the
DEBATE_PHASE. - Implementation Design:
- Add
h-screen flex flex-col overflow-hiddento the root layout container in/arena/[lobbyId]/page.tsxto completely lock down the viewport height and prevent global body scrollbars. - Refactor the compact header to remain height-bounded (
shrink-0 flex items-center justify-between border-b border-gray-800 pb-3 mb-4). - Restructure the main active area (
DEBATE_PHASE) to split the screen into two main columns usingflex flex-col lg:flex-row items-stretch justify-between gap-6 w-full h-full min-h-0:- Left Column (The Arena):
- CSS classes:
flex-1 min-h-0 flex items-center justify-center bg-zinc-950/20 border border-zinc-900/60 rounded-3xl relative overflow-hidden h-full p-4 lg:p-6. - Renders the classic 2x2 Political Compass quadrant grid and the centered, absolutely positioned
Active News Stub. This column dynamically expands to fill the remaining height.
- CSS classes:
- Right Column (The Command Center Sidebar):
- CSS classes:
w-full lg:w-96 shrink-0 flex flex-col h-full min-h-0 bg-gray-900/20 border border-gray-800/80 rounded-3xl p-4 lg:p-5 overflow-hidden. - To preserve space and ensure scroll-free immersion, this Right Column will be structured as an internally scrollable command panel using
overflow-y-auto h-full pr-1 scrollbar-thin scrollbar-thumb-zinc-800. - Inside this column, we place:
- Tactical HUD: The existing coordinates map, base values, delta preview calculations, and the primary “Lock In Vector Stack” action button.
- BASED/CRINGE Action Buttons: The local player’s primary vote-casting buttons when they are required to vote on opponents’ vectors.
- PlayerHand (The Fanned Hand): Relocate
PlayerHandfrom the bottom-level full-width section to the bottom section of this scrollable Right Column sidebar. The cards will render neatly as an internal deck or compact list within the command center, ensuring all interaction remains visible on a single screen.
- CSS classes:
- Left Column (The Arena):
- Add
Phase B: Slot Collisions & Wallet Alignment
This phase adapts layout components dynamically to resolve collision overlapping and realigns visual currency geography.1. Preventing Contender Slot Center Collisions
- File: page.tsx
- Target: Inside the
ContenderSlotcomponent, adapt the layout flow dynamically based on the quadrant the slot represents. - Problem: In Authoritarian (top row) slots, rendering the BASED/CRINGE buttons below the card slot pushes the buttons towards the absolute center of the Political Compass, causing them to collide with and overlap the central
Active News Stub. - Solution:
- Add an optional
quadrant?: stringprop toContenderSlotPropsand pass the player’s quadrant from the parent rendering loop. - Inside
ContenderSlot, conditionally toggle the layout flow of the contender card container and action buttons. - If the player’s quadrant is
AUTH_LEFTorAUTH_RIGHT, replaceflex-colwithflex-col-reverseon the parent card-and-button column wrapper: - This pushes the BASED/CRINGE buttons above the card in the Authoritarian slots (upwards and away from the center News Stub) and keeps them below the card in Libertarian slots (downwards and away from the center News Stub), entirely eliminating overlap collision.
- Add an optional
2. Compass-Aligned Wallet Currency Order
- File: WalletOverlay.tsx
- Target: Swap the rendering index of Dinars and Labor inside the grid display to mirror geographic political positions.
- Geography Map:
- Top-Left:
AUTH_LEFT(Labor / ⚒) - Top-Right:
AUTH_RIGHT(Dinars / đ) - Bottom-Left:
LIB_LEFT(Pronouns / ❀) - Bottom-Right:
LIB_RIGHT(Monke / 🐒)
- Top-Left:
- Modifications:
- Swap the rendering order in BOTH Inline Mode (lines 251-285) and the Floating Drawer list (lines 362-396) so
labor(Labor) is declared and rendered beforedinars(Dinars). - This ensures that when read as a 2x2 grid in inline mode, Labor correctly aligns with the top-left and Dinars with the top-right, creating a flawless mental map with the Political Compass.
- Swap the rendering order in BOTH Inline Mode (lines 251-285) and the Floating Drawer list (lines 362-396) so
Phase C: The Infinite Loop (Post-Match Summary Navigation)
This phase addresses post-match navigation limits by providing immediate secondary looping actions.[MODIFY] page.tsx
- Target: Rework the action segment of the
RESOLVEDpage view (lines 985-992). - Problem: When a match concludes, only a single button is provided to “Return to Arena Entryway”, which interrupts the play-queue loop.
- Solution:
- Add two prominent, high-fidelity action buttons positioned side-by-side or cleanly stacked inside the summary pane:
- “Next Match” (Primary Action):
- Renders as a highly visible, pulsing green/indigo gradient button (
bg-gradient-to-r from-emerald-600 to-indigo-600 hover:from-emerald-500 hover:to-indigo-500 shadow-lg hover:shadow-emerald-500/20). - Redirects the player back to
/arenaand automatically triggers a new matchmaking queue or triggers an immediate join sequence to maintain high combat engagement.
- Renders as a highly visible, pulsing green/indigo gradient button (
- “Return to Entryway” (Secondary Action):
- Renders as a neutral, high-quality dark bordered button (
border border-zinc-700 hover:bg-zinc-800 text-zinc-300). - Gracefully exits the lobby and redirects the player to the entryway dashboard (
/arena).
- Renders as a neutral, high-quality dark bordered button (
- “Next Match” (Primary Action):
- Add two prominent, high-fidelity action buttons positioned side-by-side or cleanly stacked inside the summary pane:
Phase D: The RESOLVING State Hotfix (Backend Integer Safety)
This phase resolves a critical backend exception where floating-point math violations on PostgresInt columns caused a fatal transaction rollback, locking lobbies in an infinite RESOLVING state.
[MODIFY] resolve.js
- Problem: Faction tax yields (e.g.
payout * 0.10) and multi-axis Euclidean distances generate float values (e.g.23.7291). When these are sent as values to Prisma databaseincrementoperations on strict Postgres integer columns (such aseloandcurrentGip), the SQL query crashes with a type exception, forcing a database rollback. Because the state machine status update toRESOLVEDoccurs after this database transaction, the table remains permanently locked inRESOLVING. - Solution:
- Update
resolve.jsto ensure absolute type compliance by wrapping all ELO, distance, and tax calculations inMath.round()prior to hitting database operations. - Refactor
applyPlayerResolveMutation(lines 75-148):- Wrap the database ELO update:
- Wrap the database Wallet balance update:
- Wrap GIP tax calculations and faction updates:
- Wrap the database ELO update:
- Wrap Distance Outcomes:
- Wrap
calculateDistanceoutcomes or distance values inside the ranking map loop (line 254) inMath.round()to guarantee strict integer compliance before values are distributed to the payload:
- Wrap
- Trace Logging Overhaul (Catch Block) (lines 482-486):
- Expand the catch block of the
POST /debate/resolverouter to dump complete error stack traces:
- Expand the catch block of the
- Update
🧪 Verification Plan
Automated Tests
Run the Express backend test suite to ensure that ELO and payouts resolve cleanly without any SQL compiler/runtime type exceptions:Manual Verification Flow
- Currency Orientation Audit:
- Open
/arena(with local servers running). Inspect the dashboard wallet overlay. Confirm that Labor is listed top-left, and Dinars is listed top-right. Open the profile control dropdown, and confirm the vertical balance order lists Labor then Dinars.
- Open
- Layout Overhaul & Scroll-Lock Test:
- Join a match (
/arena/[lobbyId]). Verify that the active debate phase is presented as a high-end landscape split layout. Attempt to force-scroll the page vertically—the page viewport should remain completely locked and static. - Confirm that the
PlayerHandrenders cleanly inside the Right Column sidebar (Command Center) alongside the Tactical HUD and Lock-In action button.
- Join a match (
- Collision Avoidance Audit:
- Position a player in
AUTH_LEFTorAUTH_RIGHT. Open the vote-casting prompt. Confirm that the “BASED/CRINGE” voting buttons render above the card frame, perfectly avoiding any central News Stub overlap.
- Position a player in
- Prisma Integer Compliance & Flow Check:
- Play a match to completion. Ensure that the backend successfully resolves and transitions the state from
RESOLVINGtoRESOLVEDwith zero database transaction exceptions. - Observe that the post-match summary displays both the “Next Match” queue button and “Return to Entryway” secondary button side-by-side.
- Play a match to completion. Ensure that the backend successfully resolves and transitions the state from