32 Commits
Author SHA1 Message Date
rgriffithandClaude Opus 4.6 54cc5e9b2e fix(lan-client): swap P3/P4 grid positions for clockwise turn order
Swapped CSS grid-area, zone-row anchoring, commander-row anchoring,
label corners, and life-panel positions for .p3/.p4 so the turn
sequence P1→P2→P3→P4 reads clockwise around the battlefield.
Also added PLAYER_INDEX_TO_QUADRANT lookup in player-panels.js.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 22:22:32 -04:00
rgriffithandClaude Opus 4.6 9b79d18201 feat(lan-client): triggers panel + CMD DMG score badges + fix encoding project-wide
Left action panel revised to show triggers list + Create Token/Auto-Arrange.
CMD DMG badges added to center life-panel score areas (click opens matrix).
Removed renderEnhancedPanels calls that split the battlefield on damage adjust.
Added encoding='utf-8' to all bare open() calls across 17 Python files to
prevent cp1252 crashes on MTG card text with smart quotes/em-dashes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 22:14:56 -04:00
rgriffithandClaude Opus 4.6 45ca961064 fix(lan-client): wire exit button to location.reload()
executeReset() references #game-board which doesn't exist in this HTML,
so the function threw a TypeError and silently did nothing. Swap the
exit button's onclick to location.reload() — the browser-refresh path
the user confirmed works to return to the setup screen.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 18:36:25 -04:00
rgriffithandClaude Opus 4.6 69bdd94ef2 feat(lan-client): hide AI hands + persist Scryfall image cache
AI hand privacy (rendering layer only):
- renderHandZone(): when player.isAI, render face-down violet card backs
  (dark purple diagonal hatch + ornate ring) instead of face-up thumbnails.
  Count stays public (standard MTG). No image, name, preview, drag, or
  click-to-open-modal on face-down thumbs.
- renderZoneModal(): filter the "Hand" tab out of the zone modal when
  inspecting an AI opponent; reset activeZoneTab to 'graveyard' if it was
  'hand' when an AI modal opens.
- New CSS: .hand-thumb.face-down (+ .overflow variant) with violet hatch
  pattern, radial glow, and centered purple ring pseudo-element.

Scryfall image cache persistence (eliminates per-game refetching):
- _scryfallCache now saves to localStorage under commanderLab.scryfallCache.v1
- 30-day TTL, 20,000-entry cap, graceful quota-exceeded handling
- Debounced auto-save (750ms) after each batch enrichment
- Cache-hit logging: logs hit ratio when refetching, or "from cache" when
  a whole game's card pool is already in localStorage
- clearScryfallCache() helper exposed on window for manual purges

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 18:32:43 -04:00
rgriffithandClaude Opus 4.6 8fbebc21f3 feat(lan-client): charcoal felt battlefield + top-bar polish + return-to-start
Battlefield (charcoal felt):
- Darken --felt / --felt-light / --felt-dark to #181818 / #202020 / #0d0d0d
- Tighter --felt-line opacities (0.06 / 0.12) on the darker surface
- Finer-grain noise texture (baseFrequency 1.2, tile 180px) at 0.14 alpha
  with mix-blend-mode: overlay so the grain rides on the felt
- Deeper vignette (35% center, rgba(0,0,0,0.6) at edges)

Top bar:
- .top-bar-logo: 14px → 28px, align-self: stretch, flex-centered so
  "COMMANDER" fills the full 44px height
- .phase-step: 10px → 11px, roomier padding (2px 8px), gap 2→4px,
  letter-spacing 0.02em
- .btn-util: 22×22 → 32×32, font 10px → 15px (readable icons again)
- New .btn-util.btn-util-exit ✕ button (red-tinted, wired to
  confirmReset() → return to setup screen)
- Remove deck generator (⚡) and collection (📚) util buttons from the
  top bar (those panels are still reachable from other entry points)

Setup screen:
- Swap .setup-title from MTG gold to the same neon violet sign effect
  as the top-bar logo (4-layer text-shadow, uppercase, ls 0.08em)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 18:05:47 -04:00
rgriffithandClaude Opus 4.6 7cfdecb2c3 feat(lan-client): polish setup screen — charcoal bg, no rainbow bar, fit-to-screen
- .setup-card background: rgba(26,26,46,0.97) violet-tint → rgba(22,22,22,0.97)
  true charcoal that matches --color-surface-3
- Remove the 3px rainbow p1→p4 gradient strip from .setup-card::before
  (display: none)
- Compress spacing so the full lobby fits without scrolling:
  - padding 2.5rem → 1.25rem 1.5rem
  - title text-3xl → text-2xl, subtitle 2rem margin → 0.85rem
  - section margin 1.5rem → 0.75rem
  - label text-sm → text-xs with tighter margin
  - player-count-btn padding 0.75rem → 0.4rem
  - deck-precon-list max-height 140px → 90px
  - btn-start padding 1rem → 0.6rem

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 17:53:27 -04:00
rgriffithandClaude Opus 4.6 38f3837f5a feat(lan-client): animated smoky purple summoning-sick overlay
Replace the nearly-invisible black diagonal stripes with a layered
animated purple hatch so sick creatures read instantly as "can't attack":

- Double-layer repeating-linear-gradient (two purple stripe opacities)
- sick-drift animation (3s linear) — stripes crawl diagonally
- sick-pulse animation (2.4s ease-in-out) — soft opacity breathing
- Inset 14px purple box-shadow for hazy edge glow

Matches the --accent / violet palette from the AI Lab redesign.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 17:42:27 -04:00
rgriffithandClaude Opus 4.6 681888adcd feat(lan-client): port pure-black + violet + neon palette from AI Lab redesign
Apply the same 5-step visual redesign to the LAN client's MTG battlefield
theme while preserving functional game colors (mana, felt table, player
quadrants p1-p4).

- Swap Google Fonts import from Cinzel+Inter to Barlow Condensed + Barlow
- Pure black surfaces (#080808 / 0e / 11 / 16 / 1a)
- Swap primary accent from blue #5b8dd9 to electric violet #8b5cf6
- Square industrial radii (2/4/6/8px)
- Replace all hardcoded 'Cinzel' / 'Inter' with var(--font-display) /
  var(--font-body)
- Pure black top bar with violet underglow shadow
- Convert .top-bar-logo "Commander" title from gold to 4-layer violet
  neon sign with hover brightening
- Sweep 42 hardcoded rgba(91,141,217,...) blue values downstream to
  rgba(139,92,246,...) violet across buttons, zone tabs, stack items,
  combat UI, etc.

MTG functional colors (mana W/U/B/R/G, felt table, player quadrants)
remain intact.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 17:39:30 -04:00
rgriffithandClaude Opus 4.6 4cae97ab44 fix(lan-client): compact phase pills, wrap NEXT PHASE/NEXT TURN labels
The phase track (BEGIN · MAIN 1 · COMBAT · END) was losing labels to
ellipsis on narrow top bars, and the primary action buttons were
clipping "NEXT PHASE"/"NEXT TURN" because they had white-space: nowrap
and a fixed height.

.phase-step:
  - tighter padding (1px 5px) and gap (2px)
  - no letter-spacing, smaller border-radius, flex-shrink: 1 so pills
    compress uniformly when the top bar is crowded
  - merged duplicate .phase-step.active rule and made it bolder so the
    active step still reads well after the shrink

.btn-phase (NEXT PHASE / NEXT TURN):
  - white-space: normal + word-break: break-word enable two-line wrap
  - height: auto + min-height: 34px lets the label breathe inside
    the 44px top bar
  - min-width: 64px / max-width: 80px keeps the buttons square-ish
  - display: flex centers the wrapped text vertically & horizontally
  - align-items: stretch on .top-bar-actions so both buttons match
    the tallest sibling's height

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 10:39:18 -04:00
rgriffithandClaude Opus 4.6 d308e8f413 fix: AI land-only bug — enforce 1-land/turn, populate legal moves, tune policy
Addresses the three root causes in commander-ai-lab-land-only-bug-analysis.md
plus several collateral fixes discovered along the way.

P0 — Land-per-turn enforcement (engine.py, deepseek_engine.py, turn_manager.py)
  * Guard _play_land() against double plays by tracking
    _lands_played_this_turn vs _land_plays_this_turn_limit on each player
  * Reset per-turn counters at the start of each player's turn
  * Ramp cards that grant additional plays can bump the limit

P0 — Legal move pipeline (new legal_move_generator.py, game_state.py)
  * New generate_legal_moves() emits the full macro-action set
    (play_land, cast_creature, cast_removal, cast_ramp, cast_draw,
    cast_commander, attack, block, pass_priority) based on phase,
    active player, land-drop state, mana, and commander tax
  * get_legal_moves() delegates to the new generator instead of the
    pass-only stub that blocked the turn_manager/policy-server path
  * apply_move() gains handlers for play_land, cast_spell,
    cast_commander, and declare_attacker — spells resolve to
    battlefield or graveyard, stats update correctly

P1 — Policy exploration (LearnedPolicy.java, scope.py)
  * Default greedy=false so the neural policy samples its
    distribution instead of always taking argmax
  * Raise ppo_entropy_coeff 0.01 → 0.04 to keep the action
    distribution flat during PPO self-play and prevent the
    pass/land collapse

Collateral fixes pulled in during the same session:
  * lan-client/precon-loader.js: await enrichAllZonesWithScryfall()
    so opening-hand cards have typeLine/cmc before the AI's first turn
  * lan-client/ui.js: closeZoneModal auto-shuffles the library
    whenever the zone modal closes
  * routes/game.py: BatchState() was missing total_games/threads,
    crashing POST /api/game/start
  * routes/deckgen.py: dead code after raise left headers undefined,
    breaking the Anthropic API path

All sim/phase/integration tests pass (650+).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 10:34:37 -04:00
rgriffithandClaude Opus 4.6 44123f7622 fix: AI only plays lands — sync card enrichment, mana pool check, field alignment
- Add _enrichCardFromCache() in precon-loader.js for synchronous card
  enrichment at draw time (typeLine, cmc, oracle roles available before
  async Scryfall batch completes)
- Call _enrichCardFromCache in drawCard() so AI has complete card data
  on its first turn
- Improve _canAfford in ai-bridge.js: check actual mana pool before
  falling back to untapped land count; free spells (cmc 0) always castable
- Fix totalCards field name mismatch in ui.js and engine.js (lab.py
  returns totalCards, not card_count/total_cards)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 01:43:29 -04:00
rgriffithandClaude Opus 4.6 9eaa41a4ae feat: deck dropdown, user-decks pipeline, deckgen fixes, gpt-oss removal
- Add user-decks/ directory and USER_DECKS_DIR config for exported decks
- Update export-to-sim to write to user-decks/ with static mount in lab_api
- Replace import/paste UI with API-backed "My Decks" dropdown in LAN client
  and AI Lab, fetching from GET /api/lab/decks with source grouping
- Fix GET /api/lab/decks to JOIN deck_cards for totalCards count
- Fix deckgenerator: add missing DOM elements (dg-strategy-bar, dg-stats-bar,
  dg-card-groups) inside #dg-results, null guards on render functions,
  fix setLoading always hiding results
- Replace gpt-oss:20b with claude-opus-4-20250514 across all files
- Add user-decks/ to _BUILTIN_DECK_DIRS in deck_service.py
- Enrich missing type_line from Forge card cache in DB deck path
- Collapse import bar behind <details> toggle in AI Lab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 01:17:30 -04:00
rgriffithandClaude Opus 4.6 409aba26f4 feat: AI bug fixes, deck/collection migration, and enrichment pipeline
- Fix AI turn pipeline: add cmc to Scryfall cache, tag isRamp/isRemoval/
  isBoardWipe from oracle text during enrichment, enable post-combat spell
  casting for all difficulty levels
- Migrate deck builder, deck generator, and collection from ui/ to
  lan-client/ as iframe-embedded panels with LAB_API_BASE patching
- Fix ai-bridge.js: turnNumber, deck_name, battlefield serialization,
  5-playstyle mapping, window exports for cross-script access
- Fix engine.js: battlefieldCards flat array (not player.battlefield),
  aiDeclareAttacks extraction, combat overlay fixes
- Fix collection.js: template literal, column visibility alignment,
  set_code key, oracle text column, sortable category
- Add exile/graveyard last-card image rendering in ui.js
- Make state_encoder.py resilient to mixed input types
- Enrich type_line from Scryfall at card insert in deckbuilder.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 00:05:23 -04:00
rgriffithandClaude Opus 4.6 30c3ab5a89 fix: pass gameState to _canAfford in MacroActionMapper
Static method was referencing bare gameState which is always null.
Now accepts gameState as parameter, and all 5 callers pass it through.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 17:02:05 -04:00
rgriffithandClaude Opus 4.6 bbb7f7a966 fix: _getBattlefieldCards reads battlefieldCards instead of battlefield
Was reading gameState.battlefield (doesn't exist) causing AI to
receive empty board state. Now reads gameState.battlefieldCards
and matches by ownerIndex.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 17:00:39 -04:00
rgriffithandClaude Opus 4.6 ef739e1f49 feat: UI improvements — silver commander border, life panel border, hand drag-and-drop, card placement
- Add bright silver 3D smoky border around commander card zones
- Wrap all 4 life panels in a single bordered container
- Add drag-and-drop from hand zone to battlefield with ghost preview
- Update card placement to center of battlefield, avoiding overlaid zones
- Fix card dimensions in placement calc (110x150 -> 63x84)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 16:50:56 -04:00
rgriffithandClaude Opus 4.6 920d7d9787 fix: remove player color border and owner bar from battlefield cards
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 15:55:56 -04:00
rgriffithandClaude Opus 4.6 52d51ebd5e feat: battlefield UI overhaul — life panels, card sizing, layout
- Move life/cmd-dmg/poison into 3-box life panels as a top-level
  overlay (z-index 50) centered at quadrant intersections
- Remove center emblem
- Match battlefield card size to hand cards (63x84px)
- Overlay zone-row and commander-row on battlefield edges to
  eliminate dead space and maximize battlefield area
- Restructure poison badges from per-player absolute positioning
  into life-panel counters box

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 15:50:35 -04:00
rgriffithandClaude Opus 4.6 db3675aa6a feat: enlarge hand card thumbnails to fill zone height
Scale .hand-thumb from 32x45px to 63x84px so cards fill the
hand zone vertically while maintaining MTG card proportions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 14:36:50 -04:00
rgriffith 99044342c2 fix: remove stray } after showManaPool stub (line 1856) 2026-04-04 13:33:37 -04:00
rgriffith 022f89478d fix: restore ui.js from placeholder corruption + Phase 1 patches 2026-04-03 23:25:01 -04:00
KoalaTrapLord 336f913d4b feat(phase-1): no-op mana pool display functions in ui.js
- renderManaPool() -> stub (floating #mana-pool-display removed from UI)
- showManaPool() -> stub
- Remove 'Mana Auto-Clear' row from renderSettingsPanel()

Internal mana tracking state (manaPool object, canPayManaCost,
clearManaPool, clearAllManaPools, etc.) fully preserved in engine.js.
createInitialState() already had energy/experience/rad/emblems.
setupManaPoolDrag() in engine.js already a no-op stub.
index.html and style.css require no changes.
2026-04-03 18:54:22 -04:00
KoalaTrapLord 661847a4d8 feat(phase-1): no-op mana pool display functions in ui.js
- renderManaPool() → stub comment (floating #mana-pool-display removed)
- showManaPool() → stub comment
- Remove 'Mana Auto-Clear' row from renderSettingsPanel()

Internal mana tracking state (manaPool object, canPayManaCost,
clearManaPool, etc.) fully preserved in engine.js.
createInitialState() already had energy/experience/rad/emblems.
setupManaPoolDrag() in engine.js already stubbed.
index.html and style.css require no changes.

Closes #190 Phase 1
2026-04-03 18:51:15 -04:00
KoalaTrapLord e710fd5e03 placeholder 2026-04-03 18:50:51 -04:00
KoalaTrapLord e55ac9aebf feat: add Scryfall image enrichment after .dck load — batch fetch card art for all zones 2026-04-03 11:30:30 -04:00
KoalaTrapLord d2b86ef2ed fix: wire precon-loader.js into index.html script load order 2026-04-03 11:19:37 -04:00
KoalaTrapLord 081dd66121 fix: add startGameWithDecks() and loadPreconDeckFromDck() for precon .dck loading into simulator 2026-04-03 11:17:27 -04:00
Commander AI Lab e90efe1654 fix: serve lan-client from backend at /lan on port 8080
- Mount lan-client/ as static files at /lan with html=True
- Mount precon-decks/ at /precon-decks/ for direct .dck access
- ai-bridge.js: use same-origin (empty URLs, auto-detect from window.location)
- engine.js: simplify deck fetch to use /api/lab/precons/deck endpoint + /precon-decks/ static fallback
- Eliminates cross-origin issues by serving everything from localhost:8080

Access the LAN battlefield at http://localhost:8080/lan/
2026-04-03 14:30:55 +00:00
Commander AI Lab 7750b43494 fix: deck loading — wire startGameWithDecks, fetch .dck content, parse [sections]
Three fixes that prevented precon decks from loading into actual gameplay:

1. ui.js: window.startGame() now calls startGameWithDecks() when
   setupDeckChoices has entries (the 3-tab selector stores choices there).
   Previously it called initGame() which looked for old deck-sel-{i}
   dropdowns that no longer exist.

2. engine.js: loadPreconForPlayer() now fetches .dck file content from
   the backend (/api/lab/precons/deck?fileName=...) when precon.decklist
   is empty. Falls back to fetching precon-decks/{file} directly.
   PRECON_DATA entries only have metadata (name, commander, set) — the
   actual card list lives in the .dck files.

3. engine.js: parseDeckList() now handles .dck bracket-style section
   headers like [Commander], [Main], [metadata]. Previously only matched
   bare text like 'COMMANDER:' without brackets. Also skips [metadata]
   lines (e.g. 'Name=Elven Empire').

4. routes/precon.py: Added GET /api/lab/precons/deck?fileName=... endpoint
   to serve raw .dck file content for the LAN client.
2026-04-03 13:45:15 +00:00
Commander AI Lab 94b1e050d8 fix: setup screen overflows viewport — constrain height and use 2-col deck grid
- Add max-height: 92vh and overflow-y: auto to .setup-card
- Widen .setup-card to 860px to fit 2-column deck grid
- Change .deck-assignment-grid from vertical stack to 2-column grid
  so 4 player panels render in 2 rows instead of 4
- Tighten .deck-tab-content (170px) and .deck-precon-list (140px)
- Make top gradient bar sticky on scroll
- Responsive fallback to single column below 640px
2026-04-03 13:37:02 +00:00
KoalaTrapLord 8bfde0230b fix: add precons.js with 163 entries and fix backend precon UI refresh (#197)
- Generate lan-client/precons.js from precon-decks/precon-index.json so
  PRECON_DATA is always available for local/offline mode (163 precons)
- Add scripts/generate-precons-js.js for regeneration when precons update
- Fix _loadBackendPrecons() to re-render the precon tab UI when backend
  precons load successfully (was only updating status indicator text,
  not populating the dropdown)

Without precons.js, PRECON_DATA was undefined and the dropdown showed
'No precon data loaded' even though 163 .dck files exist in the repo.
2026-04-03 09:31:54 -04:00
KoalaTrapLordandClaude Opus 4.6 4214831e59 feat: LAN Battlefield App Integration with AI Pipeline (#196)
* feat: LAN Battlefield App integration with Commander-AI-Lab AI pipeline

Add the LAN Battlefield App as a browser client (lan-client/) that
connects to the Commander-AI-Lab backend for ML-powered AI opponents,
3-category deck selection, and enhanced player panels.

Phase 1 - Foundation:
- Remove floating mana pool display (keep internal tracking)
- Add energy, experience, rad, emblems fields to game state
- No-op renderManaPool(), showManaPool(), setupManaPoolDrag()

Phase 2 - Backend Connection (ai-bridge.js):
- BackendConnector: REST + WebSocket connectivity with retry/timeout
- GameStateBridge: Serializes engine.js state for /api/policy/decide
- MacroActionMapper: Translates 8 ML macro-actions to engine.js calls
- DeckSourceClient: Fetches precon/EDHREC decks from backend API

Phase 3 - Deck System:
- 3-tab deck selector (Precons / EDHREC / My Decks) replaces dropdown
- Precon grouping by set with collapsible sections and filtering
- EDHREC search integration (stub, ready for backend implementation)
- My Decks textarea import placeholder

Phase 4 - AI Integration:
- runAiTurn() priority chain: ML Pipeline > Forge > Local Heuristic
- _runMlAiTurn() async turn loop with multi-phase decision requests
- Backend session initialization on game start
- Automatic fallback to local AI on any ML pipeline error

Phase 5 - Enhanced Player Panels (player-panels.js):
- Collapsible panels with localStorage persistence
- Commander damage progress bars with warning/critical thresholds
- Poison, energy, experience, rad counter widgets
- Emblem tracking with add/remove

Phase 6 - Polish:
- Script loading order: precons > engine > ai-bridge > panels > ui
- Backend auto-detection on page load with status indicator
- Connection status display on setup screen

Closes #184, Closes #185, Closes #186, Closes #187, Closes #188, Closes #189

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: refine LAN battlefield integration with full JSDoc, proper phase IDs

- Add comprehensive JSDoc comments to all ai-bridge.js classes
- Use optional chaining for PHASES lookup in GameStateBridge
- Direct addLogEntry calls in player-panels.js (loaded after engine.js)
- Remove leftover mana pool CSS that was missed in initial pass
- Minor style.css cleanup for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-03 09:16:27 -04:00