Found a deeper silent-failure mode that explains why some players' Dossiers still weren't updating after v0.20.13. The server's UPDATE player_stats query was a no-op for any user without a pre-seeded player_stats row — the transaction committed cleanly, the endpoint returned 200 OK, the client logged success, but zero rows actually changed. v0.20.13 fixed the client side; v0.20.15 fixes the server side.
- D-STATS — Upsert before update. The server now
INSERT INTO player_stats (user_id) VALUES ($1) ON CONFLICT (user_id) DO NOTHINGimmediately before theUPDATE, guaranteeing a row exists. No more silent zero-row updates. - D-STATS — Server observability. Every
/api/stats/gamePOST now logs[stats/game] OK user_id=X callsign=Y result=victory faction=usa turns=15on success and aWARNif the UPDATE somehow still affects 0 rows. Future regressions will be visible inpm2 logs hexarmyimmediately. - D-STATS — Client diagnostic logging.
finalizeGameStats()now prints[STATS]-tagged console lines at every key checkpoint: entry, retry attempt, bail-out, and successful POST. F12 in any future "stats not updating" report will surface the exact failure point in seconds.
Same caveat as v0.20.13: matches that failed silently before this build cannot be retroactively recovered. From v0.20.15 forward, every match POSTs cleanly.
The faction maxDraft cap now applies to total alive units at any time, not just initial draft. Previously, New Zealand could draft 6 units, lose 2 in combat, then produce 4 more from a city — climbing to 8 alive units, blowing past the doctrine. That loophole is closed.
- D-36 — Production cap. When you open a city's production overlay, all unit cards are disabled if you're at or above your faction's cap. A red banner explains the cap (e.g. "Force cap reached (6 / 6). Lose a unit before recruiting more."). The actual
produceUnit()function also rejects with a clear alert — defence in depth. - The math. NZ caps at 6, USA at 7, all other factions at 8. Counts only alive player units (HP > 0). Killed units free up cap space immediately, so attrition replacements still work as intended.
- Why this matters for NZ. "Lean Volunteer Force" is now actually lean. You commit to 6 units, you lose them carefully, and every casualty is a real loss until the next opening. That's the doctrine working as designed.
Steam-authenticated games now correctly update your Dossier. A latent bug was silently dropping every game's stats on the floor: Steam auto-login completed and gave you a session, but the client-side playerAccount variable never refreshed, so finalizeGameStats() bailed out at its first guard and nothing got POSTed to /api/stats/game. Wins, losses, kills, damage — all lost.
- D-35 — Auto-login state propagation. The Steam autoLogin success path was calling a
refreshAuthState()hook that didn't exist anywhere in the codebase, so thetypeof === 'function'check silently skipped it. Now callsloadAccount()directly — which actually exists and correctly hydratesplayerAccount,playerStats, and the rest of the auth-derived UI state. - D-35 — Belt-and-suspenders retry in finalizeGameStats. If
playerAccountis still null when a match ends (e.g. timing race where Steam autoLogin completed mid-match),finalizeGameStats()now does oneloadAccount()retry before giving up. Last line of defence against silently-dropped match results.
If you played any matches between v0.20.7 and v0.20.13 via Steam, those games are not retroactively recorded — but every match from v0.20.13 forward will land in your Dossier the way it should.
Dossiers now load automatically every time you open the panel. No more clicking Search on an empty input to populate the list — the moment you click Dossiers, the panel fetches every public player (sorted by Top Wins by default) and shows you who's on the server.
- D-34 — Auto-load on open. Removed the cache guard that was suppressing reloads on subsequent opens. Each open now resets the search box, snaps to page 1, and re-fetches the current "all players" view.
- Sort persistence. Your selected sort (Top Wins, Top Kills, Top Streaks, Most Decorated, Recent) carries over between opens within a session. You only have to set it once.
HexArmy now distributes exclusively through Steam. The standalone-installer auto-update channel has been retired in favour of Steam's native update system.
- Steam players see no change. Updates continue to arrive automatically through the Steam client.
- Standalone installs (pre-Steam) keep working at their current version. The in-game "Update Available" modal has been removed; existing installs will no longer prompt to download updates. To receive future updates, install HexArmy through Steam.
- Server cleanup. The legacy
/api/versionand/updates/endpoints have been retired. The Tauri custom updater code (Rust + JS modal) is gone too — one update channel, one source of truth.
Three-part fix so Steam-authenticated players appear in the Personnel Dossiers panel as soon as they sign in — not only after they finish their first match.
- D-34 — Default Dossiers list now includes Steam users with zero games. The browse list previously hid any account with
games_played = 0. Steam players who launched the desktop app and signed in but hadn't completed a match yet were invisible until you searched their callsign. The filter now also lets through any account with a linkedsteam_id, so Steam players appear immediately. - D-35 — Pre-existing accounts that link Steam are now retroactively visible. The Steam login UPDATE branch did not flip
profile_publicfrom FALSE to TRUE, so any account created before Steam auth shipped (or with a manually-set FALSE) stayed hidden even after linking a Steam ID. The UPDATE now setsprofile_public = TRUEon every Steam sign-in, mirroring the new-account INSERT. - D-36 — Clear server warning when
STEAM_WEB_API_KEYis missing. Without the key, every Steam sign-in returned HTTP 500 silently. The server now prints a multi-line warning at boot if the key is unset or doesn't look like a 32-char hex string, explaining the downstream effect on Dossiers visibility.
Five tactical bug fixes reported from playtest. Map clarity, production rules, faction limits, and the Infantry Veteran promotion all tightened.
- D-29 — Minimap during draft. The minimap could leak into the draft screen on some transitions. Now hard-guarded:
renderMinimap()early-returns during draft, and the container is explicitly hidden the moment the draft phase starts. - D-30 — Production on occupied hex. You could buy a new unit on a city tile while the capturing unit was still on it, stacking two units on one hex. Now blocked:
produceUnit()checks for an existing unit and shows "A unit is already on this city. Move it off the city tile first." - D-31 — New Zealand draft cap. NZ's "Lean Volunteer Force" doctrine declares a 6-unit max but the cap was hardcoded to 8 in three places. The faction's
maxDraftmodifier is now actually honoured in the draft logic, count display, and disabled-card state. NZ caps at 6, USA at 7, everyone else at 8. - D-32 — Field Manual right-click claim. The manual said you could deselect with right-click, but right-click was never wired up. The hint now reads "Click an empty hex or press ESC."
- D-33 — New movement rule: attacking now requires at least 1 MP. A unit that has fully exhausted its movement points can no longer also attack on the same turn. This adds a meaningful tactical decision: do you advance into striking range now and shoot, or close the gap and finish next turn?
- D-33 — Infantry Veteran "Assault" promotion reworked. The old description ("Can move AND attack, +1 ATK, +1 HP") was a no-op — units already could move and attack. The new "Assault" is a real combat promotion: +2 ATK, +1 HP, and the ability to attack even with 0 MP remaining (one attack per turn). It's the only way to fully advance AND strike in the same turn — turning Veteran infantry into the backbone of the assault wave.
Steam players now appear in Dossiers. When you launch HexArmy through Steam, the game silently authenticates your Steam ticket against Valve's Web API, creates (or refreshes) your server-side dossier, and surfaces you in the global Dossiers panel. No login form, no second password — just play.
- D-STEAM — Steam ticket auth. New
POST /api/auth/steam-loginendpoint validates Steam auth-session tickets viaISteamUserAuth/AuthenticateUserTicket. Returns a session cookie identical to email/password login. - D-STEAM — User schema.
userstable gainedsteam_id,steam_persona_name,steam_avatar_url,steam_last_seen. Steam users default toprofile_public = TRUEso they appear in Dossiers immediately. - D-STEAM — Callsign collision handling. If your Steam persona name is already taken by another HexArmy player, the system appends your SteamID3 suffix (e.g.
Andrew_4321) so you don’t collide. - D-STEAM — Profile enrichment.
GetPlayerSummariespulls your Steam avatar URL on first login and refreshes it on every launch. Surfaces nicely in Dossier cards (UI work pending follow-up). - D-FOG2 — Faction reveal modal trap fixed. The "Intelligence Report" modal can now be dismissed by clicking the dark backdrop, pressing Escape, or by the ACKNOWLEDGED button (now always visible — max-height capped to viewport with internal scroll).
- D-FOG2 — AI counter-attack crash fixed. A
defIsHuman is not definedReferenceError was breaking the AI turn whenever an AI attack landed AND the player’s counter-attack also hit. The two stat-tracking variables are now hoisted to function scope. - D-FOG2 — AudioContext double-close guarded. Closing the faction reveal music context twice no longer throws
InvalidStateError. - D-FOG2 — Player-owned cities never fall under fog. The structure-vision pass now force-rebuilds its cache on every visibility update, so captured cities and ally cities stay visible even when units move away.
Smaller-screen polish across the entire game. Game setup, faction selection, theater of operations, draft, multiplayer lobby, and the in-game HUD now fit cleanly at 1280×720 minimum. Specifically tuned for Steam Deck (1280×800) and 14-inch laptops (1366×768) where panels and headers used to crowd the map.
- New short-screen breakpoints at 820px and 720px height — reduces top/bottom HUD bar height so the map keeps real estate on the Steam Deck and on 14″ laptops.
- Tightened 1280px-wide breakpoint — left/right sidebars now scale down sooner, font scale tuned, fewer pixels wasted on chrome.
- Faction selection / Theater of Operations — header and grid spacing now use viewport-relative units so the map preview never gets pushed off-screen.
- Draft screen — title and budget rows now scale; unit grid stacks to a single column at ≤1100px width so cards aren’t squeezed into 4-letter labels.
- Multiplayer lobby — left panel width now fluid; both column headers scale.
- Modals (intel, Field Manual, medals, stats) — max-heights now relative to viewport; medal-layout left column shrinks at narrower widths.
- Home screen panels — padding and section headers now scale with viewport so the home overlay no longer clips on short screens.
Routine version bump — no functional changes. Carries forward all v0.20.4 victory-condition polish (D-25 through D-28) and v0.20.3 fixes. Issued to keep the auto-updater channel and installer artifact aligned with the current build.
D-25 — HQ Takeover Elimination Fix: HQ Takeover victory mode no longer eliminates a player when all their troops are destroyed if their HQ still stands. Only capturing the HQ eliminates a player in this mode.
D-26 — Advance-on-Kill City Bypass Fix: Units no longer advance onto enemy cities with active defenses (HP > 0) after killing a defending unit. The attacker stays in place and the log reports “city defenses hold.”
D-27 — Disband Units on Elimination (HQ Takeover): When a player is eliminated in HQ Takeover or Infantry Only mode, all their remaining units are disbanded and removed from the battlefield.
D-28 — Neutralize Cities on Elimination (Military Annihilation): When a player is eliminated in Military Annihilation mode, all their cities, HQ, and camps revert to neutral ownership and can be captured by remaining players.
One commander. Multiple fronts. Ten thousand hexes. Fifteen milestones engineered to put solo commanders against two and three thinking AI opponents on battlefields ten times the size of anything we've shipped before.
- M-1 — Theater of Scale: Engine rebuilt to think in tens of thousands of tiles. Legacy size caps removed; spatial backbone reground from scratch. 10,000-hex maps are no longer a stretch goal — they're the new ceiling.
- M-2 — Tile Stream: Active tiles stream into memory on demand; idle ones drift to the background. Smooth pan and zoom across the full battlefield without waiting for the front line to catch up.
- M-3 — Render Cone: Aggressive frustum culling and overdraw elimination. Off-screen tiles, fogged units, and out-of-frame chrome no longer hit the GPU — 10K-tile combat now runs on machines that used to choke at 4K.
- M-4 — Vector Pathfind: Pathfinding rebuilt on a hierarchical mesh. Units think in regions, then refine. A tank corps now plots a 200-hex flanking maneuver in milliseconds instead of seconds.
- M-5 — Doctrine Tree: Faction AIs got an upbringing. A layered decision graph lets each faction play in its own style — Russia grinds, NATO maneuvers, China encircles. Every faction now plays like itself, not a difficulty slider with a flag.
- M-6 — Fog Multiplex: Fog of war is now per-faction, computed in parallel. With 1v3 on the table, the engine maintains three independent sight grids without breaking a sweat. Your enemies know what they know — and nothing more.
- M-7 — Memory Drill: Runtime memory footprint trimmed; unit allocator rewired to recycle slots without GC stalls. A 10,000-hex four-faction battle now fits comfortably in memory on a mid-range rig.
- M-8 — Network Compression: (Phase A complete — landed in 0.16.7, locked in for 0.20.0) Dictionary + RLE compression cut the initial map transfer from ~960 KB to ~113 KB at 10,000 tiles — an 88% reduction. Per-turn deltas push only what changed (~214 bytes for a typical 5-tile move). The 10K-tile front is open for business.
- M-9 — Multi-AI Turn System: The headline. HexArmy now runs 2, 3, or 4 thinking opponents simultaneously, each in its own slot, each making real decisions on its own turn. Solo play just became multiplayer-grade. 1v2 and 1v3 are live.
- M-10 — Difficulty Per Slot: Independent difficulty and faction settings on every AI slot. Hard NATO holding the north, Medium China probing the east, Hard Russia driving the central pocket — design your own asymmetric campaign in 10 seconds.
- M-11 — Coalition Intelligence: 1v3 doesn't mean three lone wolves. Enemy AIs can coordinate when their interests align: shared sightings, divided fronts, no friendly-fire fratricide. They don't always cooperate — but when they do, you'll feel it.
- M-12 — Procedural Theater: A new generator builds 10,000-tile maps with terrain that actually makes tactical sense. Mountain passes choke advance routes, river deltas fragment the map into theaters, urban sprawl gives infantry the edge. No two wars play the same.
- M-13 — Deep Save: Save and load any game state — even with three AIs mid-turn on a 10K-tile map. Saves are deterministic, compressed, and small enough to share. Pause your war, resume it tomorrow, send it to a friend.
- M-14 — Framerate Lock: Engine targets and holds 60 FPS on the recommended spec, even at maximum scale. Adaptive quality scaling drops effects before frames — the game stays responsive when it counts.
- M-15 — Commander's Brief: Redesigned new-game flow walks first-time commanders through faction selection, AI loadout, and map size in under 30 seconds. The threshold to your first 1v3 just got a lot lower.
- Stability foundation: D-9 through D-13 (iron flag, first contact, false victory, draft insurance, CSP unblock) were neutralized in 0.16.7 and lock 0.20.0 in. See the v0.16.7 entry below for details.
- D-9: Cities and HQs no longer display two faction flags in isometric view — removed duplicate flag draw from HP bar overlay pass
- D-12: AI draft now includes diagnostic logging and an emergency fallback — if the AI ends the draft with zero units, 3 infantry are force-spawned to ensure the game is always playable
- D-11: HQ Takeover no longer triggers a false victory after turn 1 when AI has no units (fixed by D-12)
- D-10: Enemy faction reveal modal now correctly appears on first visual contact (fixed by D-12 — previously no AI units existed to trigger the reveal)
- D-13: Tauri Content Security Policy no longer blocks API connections to hexarmy.com — changed
dangerousDisableAssetCspModificationtotrueto prevent Tauri v2 from overwriting the connect-src directive - M-8: Network Payload Optimization — dictionary + RLE compression reduces initial map transfer from ~960 KB to ~113 KB at 10,000 tiles (88% reduction). Per-turn tile deltas send only changed tiles (~214 bytes for a typical 5-tile change vs 113 KB full resync). Resync-on-demand path for divergence recovery. Completes Phase A — 10,000-tile multiplayer is now unblocked
- Blind Faction Pick: Other players' faction selections are now hidden in the lobby (only visible to self and same-team allies)
- Lobby Chat: Added in-lobby chat so players can communicate before the match starts
- Text Overflow Fix: Long callsigns and faction names no longer overflow their container boxes in the lobby UI
- Ready State Fix: Players no longer appear as "Ready" before they actually click the Ready button — faction lock and ready are now separate steps
- Map Type Sync: Players joining after the host changes map type now see the correct type instead of "Standard"
- Map Preview for Non-Host: Non-host players can now toggle and view the map preview — preview controls are no longer blocked by read-only mode
- Map Preview Sync: Host map generation now broadcasts the seed so all players see the same preview
- Placement Phase Visibility: Fog of war now correctly applies during unit placement after Force Composition — fixed ordering of placement hex calculation before visibility rebuild
- Draft Ready Event: Fixed event name mismatch between server and client for draft-ready notifications
- Game Start for All Roles: Non-host players (including player3/player4) now correctly receive map data and enter the game — previously only player2 was supported
- MP Menu Seed Display: Map seed now shows in the hamburger menu during PvP matches
- Forward Operating Bases (FOBs) now appear immediately after an Engineer builds them — previously the structure was invisible until the next turn
- Added explicit visibility rebuild and terrain redraw after FOB construction to ensure the new structure renders in the same frame
- Game now correctly ends when AI has no units and no functional cities/HQ — previously could get stuck in an unwinnable state
- Auto-recovers initial AI unit count for saved games that predate this tracking field
- Cities and HQs with 0 HP (defenses destroyed) now count as "fallen" for Complete Domination victory checks
- Universal fallback: if either side has zero units AND zero functional structures, the game ends
- Multiplayer lobby preset buttons (Small/Medium/Large/Max) and map type buttons now use dedicated class names and event delegation, preventing single-player code from overwriting their handlers
- Map preset buttons (Small, Medium, Large, Max) in multiplayer lobby now respond to clicks
- Map type buttons (Standard, Continents, Archipelago, etc.) in multiplayer lobby now respond to clicks
- Root cause: single-player map setup was overwriting multiplayer button click handlers due to unscoped CSS class selectors
- Map type (Continents, Archipelago, etc.) now saved to the server and applied when the game starts
- Map size and game mode changes in the lobby properly propagate to the actual game
- Non-host players see map type changes in real time as the host adjusts settings
- Bundled Socket.IO client for Tauri desktop — multiplayer now works from the desktop app
- Map type buttons (Continents, Archipelago, Pangea, etc.) now visible for Medium (20×20) maps and above — previously hidden until 800+ tiles
- Single-player map type selection threshold updated to match
- Fixed Socket.IO client not loading in Tauri desktop app — multiplayer now works from the desktop client
- Steam lobby integration for desktop players — create, join, and browse lobbies via Steam
- Invite friends to your game directly through the Steam overlay
- Quick Match with ELO-based skill matching and expanding search range over time
- Quick Match supports 2, 3, or 4 player games with configurable player count
- 15 new Steamworks lobby commands in the Rust backend with async callback handling
- Steam lobbies store game metadata (map, faction, player count) for lobby browsing
- Web players retain the full Socket.IO lobby system — no changes to browser multiplayer
- All multiplayer games still use the server for authoritative game state and communication
- Matchmaking queue with stale entry cleanup (5-minute timeout)
- Players can now view all their submitted tickets from the Support modal
- Full ticket detail view with status, category, and creation time
- Conversation threading: players and admins can exchange messages on tickets
- Player responses automatically reopen resolved or closed tickets
- Admin panel now shows full response thread instead of just the last reply
- Admin responses are saved to the conversation thread for both sides to see
- Email notification to admin when a player replies to a ticket
- Version auto-fill fix on support ticket submission
- Admin panel at /admin.html for full support ticket management
- Dashboard with real-time stats: open, in-progress, awaiting, critical, and 24h ticket counts
- Filter by status, category, and priority with full-text search
- Sortable columns, pagination, and inline ticket detail panel
- Update ticket status, priority, and internal notes from the panel
- Send email responses directly to ticket submitters via SMTP
- Automatic admin notification email when new tickets are submitted
- Role-based access control with is_admin user flag
- Bug fix: Steam bulk achievement sync was passing objects instead of IDs
- Bug fix: game_history table now records all stat columns per game
- Bug fix: city garrison counter-attack kills now tracked in stats
- Steam Cloud integration — Game saves are now synced to Steam Cloud via the Remote Storage API. Players can save on one machine and resume on another seamlessly.
- Dual-write saves — When saving a game on the desktop app, the save is written to both the HexArmy server and Steam Cloud simultaneously. Deletes are also mirrored.
- Cross-machine sync on launch — On desktop startup, all 3 save slots are compared between server and Steam Cloud. The newer save wins, and missing saves are restored in both directions.
- 6 new Rust commands —
steam_cloud_status,steam_cloud_list_files,steam_cloud_write,steam_cloud_read,steam_cloud_delete, andsteam_cloud_file_existsexposed as Tauri invocations.
- Steam-aware updater — The custom auto-updater now detects when running via Steam and skips entirely, deferring to Steam's native update system. Prevents duplicate prompts and installer conflicts.
- Fixed version drift — Cargo.toml version was stuck at 0.15.0 while tauri.conf.json advanced, causing
get_app_version()to report the wrong version and trigger false "update available" prompts for all standalone users. - Build script version sync —
build-and-sign.ps1now auto-syncs Cargo.toml version from tauri.conf.json before building, preventing future drift. - Release date in update modal — The update notification now shows the release date alongside version and release notes.
- 25 Steam Stats — All tracked game statistics now sync to Steam: games played/won/lost, combat stats (kills, damage dealt/received), objective stats (cities captured, camps built, ultimates used, gold earned), records (best kills, fastest victory, perfect victories), win streaks, hard mode stats, clutch wins, rank XP, and multiplayer stats.
- Real-time sync — Stats push to Steam automatically after every completed match via efficient batch update (single API call for all 25 stats).
- Bulk sync on launch — Desktop app syncs all cumulative stats to Steam on startup, ensuring web-earned progress is reflected in the Steam client.
- Steamworks partner config — Upload script and VDF config ready for partner portal registration.
- In-app support modal — Submit bug reports, feature requests, and feedback without leaving the game. Accessible via the "Support" link in the home screen footer. Auto-fills your callsign, platform, and game version.
- Removed old ambient loops — Removed pre-v0.15.2 ambient drone, wind, tension, heartbeat, and radio chatter sound loops that were superseded by the new 9-track background music system.
- Simplified audio settings — Removed the Ambient volume slider. Audio panel now has Master, Music, and SFX controls.
- Streamlined phase audio — Phase transitions now only control background music playback (play/pause) rather than managing multiple ambient loop layers.
- 100 achievements mapped — All game achievements now sync to Steam when unlocked. Achievement API names match between the server database and Steam’s achievement system for seamless integration.
- Real-time sync — When you earn an achievement in-game, it immediately unlocks on Steam with the overlay notification.
- Bulk sync on launch — Desktop app automatically syncs any achievements earned on the web to your Steam profile when you launch the game. Checks each achievement to avoid redundant API calls.
- Steamworks VDF config — Achievement definitions exported in Valve’s VDF format, ready for upload to the Steamworks partner portal. Includes display names, descriptions, and hidden flags for ultra-rare achievements.
- 9 music tracks — Military-themed background music plays during draft, placement, and battle phases. Tracks are shuffled and auto-advance when each one ends.
- Skip Track button — New “Skip Track” button in the audio settings panel lets players advance to the next track at any time.
- Volume control — Music volume is controlled by the existing Music slider in the audio settings panel. Master volume and Mute All also affect music playback.
- Phase-aware playback — Music starts when entering gameplay (draft/placement/battle) and pauses in menus and on victory/defeat screens.
- Console window removed — The DevTools console window no longer appears when launching the desktop app in release builds.
- Steam DLL bundling — Fixed steam_api64.dll not being included in the NSIS installer. The build script now automatically copies the DLL from steamworks-sys output.
- Support page — New support.html page where players can submit bug reports, feature requests, and general feedback directly from the website.
- Ticket categories — Three submission types: Bug Report, Feature Idea, and General comment. Each ticket captures platform, game version, callsign, and optional contact email.
- Ticket tracking — Every submission receives a unique reference number (HX-XXXXXX) for follow-up. Tickets are stored in the database with status tracking and admin notes support.
- Rate limiting — Support submissions are rate-limited to 5 per 15 minutes per IP to prevent abuse.
- Auto-detection — Game version is auto-filled from the server’s version endpoint. Logged-in users are automatically linked to their account.
- Steam authentication — The desktop client now connects to Steam at launch. SteamID, persona name, and logged-on status are available to the game. Auth session tickets can be generated for server-side identity verification.
- Steam overlay — The Steam overlay can be opened to friends, community, achievements, or any URL directly from the game. Overlay availability is detected and reported.
- Achievements & stats — Full achievement API: unlock, query, and clear achievements by API name. Integer stats can be read and written. Stats are automatically persisted to Steam Cloud.
- Friends list — Query Steam friends with online/offline status for future social features and matchmaking.
- Graceful fallback — If Steam isn't running, the game operates normally in non-Steam mode. All Steam API calls return safe defaults with no errors surfaced to the player.
- Background callbacks — A dedicated thread runs Steam callbacks every 100ms, ensuring overlay events, achievement notifications, and auth responses are processed promptly.
- 504 new sprite variants — Every unit type (21) across all team colors (4) now has 6 unique directional sprites: E, NE, NW, W, SW, SE. Units visually face the direction they moved with distinct rotation, perspective, and lighting per direction.
- 6-direction facing system — Replaced the 2-direction left/right flip with a proper hex-direction system.
getHexDirection()computes the exact hex direction from movement paths, and both renderers select the correct pre-rendered sprite variant. - Direction-aware animation — During movement animations, the sprite updates per path segment to show the correct facing for each step of the move.
- Perspective effects — NE/NW sprites lean back with slight vertical compression (away from camera). SE/SW sprites lean forward with subtle stretch (toward camera). E/W are standard orientation.
- AI vision system — AI now computes its own fog of war grid using the same rules as the player: unit vision radii, line-of-sight, desert/plains bonuses, radar directional scans, deep scan reveals, city/camp vision, and smoke blocking.
- Difficulty scaling — Easy AI remains omniscient. Medium AI gets +1 bonus vision range. Hard AI plays under strict identical fog of war rules.
- Vision-filtered decisions — Threat maps, target selection, production counter-building, vulnerable city scouting, and retreat decisions all operate on visible player units only. AI vision rebuilds after each unit acts to reflect newly revealed areas.
- Stealth & submarine rules — Snipers, PsyOps (Ghost Protocol), and submerged submarines remain invisible to the AI unless an AI unit is adjacent, matching the player's stealth detection rules.
- Medium difficulty upgraded — All 10 faction strategies (draft orders, production weights, tactical priorities, retreat thresholds, camp priorities, income raiding, terrain preferences) now activate on Medium, not just Hard.
- Faction-aware production — Medium AI blends 50% faction weights with 50% generic weights for a balanced but faction-flavored army composition. Counter-building remains Hard-only.
- Faction-aware targeting — Medium AI receives lighter faction targeting bonuses: Iran flanks, USA prioritizes air, NZ rushes cities, Russia finishes weak units, UK maximizes damage per shot.
- Faction-aware movement — Medium AI uses faction terrain preferences (India seeks mountains, Canada prefers forests, NK holds cities) and faction aggressiveness to weight movement decisions.
- Faction-aware drafting — Medium AI now uses the faction draft order instead of the generic order, producing doctrinally correct starting armies.
- Move-to-attack & retreat — Medium AI now evaluates optimal repositioning before attacking and uses faction-specific retreat thresholds.
- Units now face their movement direction — Sprites are horizontally flipped based on direction of travel. Units face right when moving right and face left when moving left, making it much easier to read unit intent and track AI actions.
- Animation-aware facing — During movement animation, sprites update facing per path segment so units visually turn as they follow multi-step routes.
- Advance-on-kill facing — When a melee unit kills a defender and advances into the hex, the sprite faces the direction of the advance.
- Initial spawn facing — Player units spawn facing right (toward the enemy), AI units spawn facing left (toward the player).
- Force Composition sorted by cost — The draft screen now sorts all available units by their effective cost (cheapest first), taking faction cost modifiers into account. Previously, units appeared in a fixed hardcoded order.
- Production menu sorted by cost — The city/HQ/camp production menu also sorts units by effective cost, with bombardment damage cost increases reflected in the displayed price.
- Structure HP bars (isometric view) — Cities, HQs, FOBs, FABs, and Ports now display a color-coded HP bar directly on the hex tile in isometric view. The bar is green above 50% HP, orange between 25–50%, and red below 25%. An HP fraction (e.g., “7/10”) is shown below the bar.
- Faction flags on structures — Owned cities and HQs now display the controlling faction’s flag above the tile in isometric view. Neutral structures show no flag.
- Defense shield icon — Structures with active garrison or HQ guard defenses show a shield icon on the tile.
- Bombardment damage overlay — Structures taking bombardment damage display the damage percentage (e.g., “40% dmg”) in red below the HP bar.
- Flat view expanded — The existing flat-view HP bars now also cover FOBs, FABs, and Ports, matching the isometric view’s coverage.
- Turn-start restriction — Ultimate abilities can now only be activated at the very start of a unit’s turn, before any move or attack action. Previously, units could move into position and then activate their ultimate, allowing unintended combos like repositioning before Dig In or moving a scout then using Deep Scan without the expected action cost.
- Disabled button feedback — When a unit has already moved or attacked, the ultimate button now appears grayed out with a “Turn Start Only” label instead of disappearing, so players understand why the ability is unavailable.
- Safety guard — Added a validation check in the activateUltimate function to prevent activation after move/attack, even if the UI check is bypassed. AI ultimate usage is unaffected as AI always evaluates ultimates before acting.
- Fixed download URL routing — The “Install Update” button appeared to work but the app always reopened on the old version. The server was returning the game’s HTML page instead of the actual installer because the
/updates/directory wasn’t being served. Added both an Express static route and an Nginx location block to correctly serve installer files. - Content-type validation — The desktop updater now checks that the downloaded file isn’t HTML before attempting to run it as an installer. If the server returns the wrong content, the user sees a clear error message instead of a silent failure.
- AI city/HQ capture — Fixed a critical bug where AI units could move onto enemy cities and HQs but never actually capture them. AI movement bypassed the capture logic entirely, meaning the AI could never win by HQ Takeover or contribute to Complete Domination victory.
- Victory check logging — Added comprehensive console logging to the victory condition system. All victory checks now log the current state (HQ ownership, city counts, unit counts, victory mode) to help diagnose any future issues.
- Capture diagnostics — When a unit lands on a city/HQ but cannot capture it (wrong unit type, HP not zero), a diagnostic log is now emitted explaining why.
- All 5 modes reviewed — HQ Takeover, Military Annihilation, Complete Domination, Infantry Only, and Survival 20 victory conditions have been audited and confirmed correct.
- AA Ship sprites — New Arleigh Burke-class destroyer sprites for the Naval Anti-Air unit across all 4 team colors (blue, red, green, yellow).
- Transport sprites — New carrier/LHD-style ship sprites for the Transport unit across all 4 team colors, replacing the old patrol vessel art.
- Sprite mapping fix — Transport units now correctly load the
naval_transportsprite instead of looking for a missingtransport.png. AA Ship added to sprite preloader.
- Robust update mechanism — Rewrote the desktop auto-updater to use a self-cleaning batch script that properly waits for the app to exit, runs the NSIS installer in passive mode, relaunches HexArmy, and cleans up temp files. Fixes “The system cannot execute the specified program” and “The batch file cannot be found” errors.
- Sprite deployment — Build script now uploads the entire sprites directory to the server during deployment.
- Coastal city naval production — Cities and HQs adjacent to water tiles can now produce naval units (Destroyer, Submarine, Transport, AA Ship). Naval units spawn on the nearest empty water tile.
- AI coastal production — AI can also produce naval units from coastal cities, enabling naval warfare on maps without dedicated ports.
- Board Transport action — Land units adjacent to a friendly Transport ship now display a “Board” button to embark. Foot and tracked units can board (capacity 3).
- Unload All — Transport units with cargo show an “Unload All” button that automatically distributes embarked units to adjacent passable tiles. Units that can’t deploy (no valid land tiles nearby) stay aboard until next turn.
- Individual unload — You can also unload units one at a time, choosing which unit to deploy first.
- Cargo manifest — Transport action bar shows which units are currently aboard.
- Cargo destruction — If a Transport is destroyed, all embarked units are lost (same as APC).
- FOB structures — Forward Operating Bases now render with sandbag perimeter, olive command tent, and supply crates in isometric view.
- FAB structures — Forward Air Bases show a diagonal runway with threshold markings, quonset-hut hangar, and orange windsock.
- Port structures — Ports display wooden pier with planks, warehouse building, crane with cable and hook, bollards, and water ripples.
- Graphical intel cards — Enemy intel cards now show inline threat level bars, territory control bars, K/D ratios, unit type breakdown tags, and combat record summaries.
- Enhanced Military tab — Force composition bar chart by movement class (infantry/armor/air/naval), unit roster with average HP bars, and scrollable tracking data.
- Enhanced Strategic tab — Stacked territory control bar, visual kill/loss comparison bars, and large K/D ratio display.
- Isometric zoom/pan completely fixed — All zoom handlers (wheel, keyboard, pinch, double-tap, gamepad) now use iso-specific coordinate math. Pan clamping centers correctly around the iso grid center, not the origin.
- Zoom no longer jumps or drifts — Removed the center-pull that fought zoom-toward-cursor, causing the viewport to slide away from where you were pointing.
- Smooth pan clamping — Replaced the hard branch in pan clamping (grid fits vs. doesn't fit viewport) with a unified formula. The old code snapped pan to ±20px when the grid barely fit the canvas, causing violent jumps when zooming out on large maps.
- Minimum zoom lowered to 0.5x — Large maps (30×30+) can now zoom out further to see the full battlefield.
- Pan limits scale properly — Navigation range now smoothly scales from minimal drift when the map fits the viewport to full navigation with small overscroll on large maps.
- Isometric view pan fixed — Pan clamping was using the flat view's grid dimensions, but the isometric renderer produces a grid 2–3× larger on screen (due to WORLD_HR-based coordinates and iso projection). Added
_isoGridScreenExtent()to compute actual iso grid bounds, so pan limits match what's rendered.
- App now exits and restarts after update — Fixed missing
process:allow-exitpermission in Tauri capabilities that prevented the app from closing during updates. - Silent install with auto-relaunch — Updates now run the NSIS installer silently (/S flag) via a helper script that waits for the app to close, installs the update, and automatically relaunches HexArmy.
- Fallback exit command — Added a direct
exit_appRust command as a fallback if the plugin-based exit fails.
- 3-tier promotion system — Units earn promotions through combat kills, surviving engagements, or capturing cities. Veteran (2 kills / 4 combats), Specialist (8 kills / 15 combats / 3 captures), Commander (16 kills / 30 combats / Specialist + 15 turns).
- Specialization choices — Each promotion rank offers two permanent specialization options per unit type (18 unit types supported). Choices shape unit roles with stat boosts, new abilities, and playstyle tradeoffs.
- Commander Aura — Rank 3 grants a passive aura buffing nearby same-class units. Only one Commander per unit type per player per game. Losing a Commander permanently removes the aura slot.
- Visual indicators — Bronze chevron (Veteran), silver double-chevron (Specialist), gold star (Commander). Commanders display a pulsing aura ring on the hex map. Pending promotions show a pulsing arrow.
- AI promotion support — AI units promote using the same criteria and auto-select specializations at end of turn.
- Combat integration — Commander aura bonuses (ATK, DEF, DGE, ACC) are applied in combat resolution. Auras do not stack (best aura wins).
- Installer download robustness — Auto-updater now explicitly flushes the downloaded installer to disk, validates file size before execution, and removes stale partial downloads. Adds a brief delay after write to let Windows finish any AV scan.
- Fallback launch method — If direct process spawn fails (e.g., OS error 1392 "corrupted or unreadable"), the updater falls back to
cmd /c startwhich handles Windows security prompts more gracefully. - Download validation — Rejects downloads smaller than 100KB to catch truncated or error-page responses before attempting to run them as installers.
- Game now ends immediately — Victory/defeat is checked after every player attack and city capture, not just at the end of the AI turn. Killing the last enemy unit or capturing the enemy HQ now triggers the game-over screen instantly.
- Path-following animation — Units now follow the actual Dijkstra hex path tile-by-tile instead of sliding in a straight line. Falls back to findFullPath when prev-pointer data is unavailable.
- Isometric grounding during animation — Sprite base Y-position interpolates between tiles during movement, preventing sprites from snapping to the destination ground level while still mid-path.
- Action bar icon sizing — Unit icon wrapper now scales responsively with clamp(44px, 5.5vw, 64px) to better match action button heights at all viewport sizes.
- Split Intel panel — Left panel now shows your Unit Roster in the top half and Enemy Intelligence in the bottom half, clearly separated.
- Per-enemy intel sections — Each enemy player gets their own intel section with faction flag, visible unit count, cities, and KIA/LOST combat stats. Supports multiple enemies in multiplayer.
- Enemy-only intelligence — The Intel panel no longer mixes your own units with enemy data. Your roster stays clean; enemy intel is in its own dedicated area.
- Smooth movement animation — Units now glide between tiles over 0.5 seconds with an ease-out curve instead of teleporting instantly. Works in both flat and isometric views.
- Jet movement reduced — MOV decreased from 6 to 3. Jets are now less mobile, making positioning more important.
- Bomber buffed — attack range increased from 1 to 2 (matching the jet) and MOV increased from 4 to 6. Bombers now fill the role of a fast, long-range strategic strike unit.
- In-app auto-updater — the desktop app now uses the Tauri updater plugin with signed binaries for seamless download-and-install updates. When a new version is available, clicking “Install Update” downloads, applies, and restarts the app automatically — no manual download needed.
- Consistent unit icons — all UI elements (minimap unit buttons, action bar unit card, selection panel, enemy intel cards) now use the same 3D team sprites shown on the game map, falling back to flat silhouettes only when sprites aren’t loaded.
- Action bar centered — the bottom action bar is now properly centered on the screen with the unit identification card anchored to its left edge.
- Turn indicator relocated — moved the turn counter from inside the minimap to the minimap action row, sitting to the left of the Center Map button for better visibility.
- Simple auto-updater — replaced the Tauri updater plugin (which required signed binaries and a complex build pipeline) with a lightweight version check. The desktop app now fetches the latest version from the server, and if an update is available, shows a themed modal with a “Download” button that opens the download page in the default browser. No signing keys needed.
- Action bar layout — action buttons now sit directly next to the unit card on the left side of the command bar, instead of floating to the center with a gap.
- Enemy Intel Cards — after first visual contact with an enemy faction, a compact card appears in the bottom-left of the map showing the faction flag, name, visible unit count, and known city count. Cards stack vertically for multi-enemy games.
- Intelligence Modal — click the intel button on any enemy card to open a detailed Intelligence report with tabbed sections: Military (visible units, positions, HP), Strategic (threat level, territory control, combat record K/D), and Faction Info (doctrine, bonuses, full unit roster with stats).
- Multiplayer Dossier Tab — in multiplayer games, the Intelligence modal includes a Dossier tab showing the opponent’s profile, win rate, kills, and streaks fetched from the server.
- Fog-of-war integration — enemy faction identity is only revealed after units are spotted in the game. Intel updates in real-time as visibility changes each turn.
- Combat stat tracking — kills and losses are tracked per enemy faction during combat (including counter-attacks), feeding into the Strategic tab’s combat record.
- Scout & APC icons — added missing unit icons for Scout and APC units. They now display correctly in the action bar unit card and minimap unit buttons.
- Unit button status colors — minimap unit buttons now show dim green when a unit has partially moved (moved some hexes but can still move and attack), yellow for attack-only, and blue for move-only. Previously all units with remaining actions showed green.
- Menu button works — the minimap menu button now opens a local popup menu with SFX toggle, Reset Zoom, Field Manual, Save Game, Surrender, and Exit options. Previously it tried to toggle the top-bar hamburger menu which was invisible from the bottom of the screen.
- Field Manual formatting — the in-game Field Manual modal now renders with full styling (tables, stat cards, faction cards, tips). Previously the modal used a different element ID than the CSS targeted, so all guide content appeared unstyled.
- Viewport indicator now accurate in isometric mode — the minimap camera rectangle now correctly reflects the isometric projection, rotation, and zoom. Previously it used flat hex math which didn't match the isometric view.
- Unit buttons, action row, and turn counter now visible — restructured the minimap layout from absolute positioning (which placed elements off-screen) to a proper flexbox layout. Unit buttons appear to the left of the minimap, action buttons below.
- Viewport drawn on canvas — switched from a CSS div to drawing the viewport polygon directly on the minimap canvas, enabling correct shape rendering for the rotated isometric view.
- Tactical minimap — a real-time minimap in the bottom-right corner shows the full battlefield with terrain, cities, HQs, and unit positions. Click anywhere on the minimap to pan the camera instantly.
- Unit action buttons — up to 8 unit buttons appear along the right edge of the minimap for units that still have moves or attacks available. Green border = can move & attack, yellow = attack only, blue = move only. Click to select and center on the unit.
- Turn counter — circular turn indicator in the top-left of the minimap shows the current turn number.
- Quick-access buttons — Center Map, Field Manual (Help), and Menu buttons arranged below the minimap for fast access.
- Fog-of-war compliant — enemy units only appear on the minimap when in your vision range. Undiscovered tiles remain black; previously seen tiles are darkened.
- Cinematic letterbox turn splash — black bars slide in from top and bottom with a scan-line effect when turns change. Shows "YOUR TURN" in your faction color with flag, or "ENEMY TURN" for the opponent. Lasts 1.5 seconds and auto-dismisses.
- Fog-of-war safe — enemy faction name, flag, and colors are hidden until first visual contact. Before discovery, shows "Unidentified Force" in generic red.
- Works everywhere — appears at game start, when ending your turn (AI takes over), when AI finishes (your turn starts), and in PvP multiplayer turn changes.
- Minimum zoom raised to 0.85x — the map already fits the viewport at 1.0x, so zooming out past 85% just creates unnecessary void. Previously 0.6x allowed the map to become tiny on wide monitors.
- Pan clamping tightened — when the map is smaller than the viewport, pan is now limited to ±20px drift (was 10% of viewport width, which allowed ~290px drift on ultra-wide monitors).
- Auto-recenter on zoom-out — when zooming out below 1.2x, the camera gradually pulls back toward center, preventing the map from drifting into a corner of the screen.
- Finer zoom steps — zoom increment reduced from 0.15 to 0.1 per scroll tick for smoother, more precise zoom control.
- Zoom display shows zoom-out — the zoom percentage indicator now appears when zoomed out (below 100%), not just when zoomed in.
- Buff-type ultimates now work correctly — Sniper Killshot, Tank Blitz, Anti-Air Missile Salvo, AA Ship Missile Salvo, Jet Bombing Run, Bomber Strategic Strike, and Scout Recon Dash no longer consume the unit's attack action on activation. Units can now attack after activating these buff ultimates to actually use the buff.
- Tank Blitz "attack twice" now functional — Tank Blitz ultimate correctly allows two attacks per turn. After the first attack, the tank stays selected with attack targets highlighted for a second strike. Blitz buff indicator shows attack count (1/2).
- Intel Panel fog of war — enemy unit details are no longer shown in the Intel Panel before first contact. Unmet enemies show "Unidentified Contact" and met-but-not-visible enemies show "Enemy Unit" with "Intel unavailable."
- Scout ultimate: Recon Dash — doubles movement and reveals all enemy units within vision range.
- APC ultimate: Rapid Deploy — unloaded units can move and attack immediately this turn instead of waiting until next turn.
- AA Ship ultimate: Missile Salvo — next attack deals 2x damage with range 4 and guaranteed hit vs air units.
- AI uses new ultimates — AI opponents on Medium and Hard difficulty now use Scout Recon Dash, APC Rapid Deploy, and AA Ship Missile Salvo.
- Can no longer get lost in the void — completely rewrote the pan clamping system. When zoomed out so the map is smaller than the screen, the camera now locks near center with only minimal drift allowed. When zoomed in, at least 30% of the map stays on-screen at all times.
- Minimum zoom raised to 0.6x — the map always fills at least 60% of the viewport at maximum zoom-out, preventing the tiny-dot-in-blackness issue.
- CENTER MAP button — added a floating button in the bottom-right of the map that instantly resets zoom and pan to the default view. Also accessible via the Home key or clicking the zoom display in the command bar.
- Scout and APC now draftable — both units are now available in the draft selection screen. Scout offers high vision and forest pathfinding; APC can transport up to 5 units with a Rapid Deploy ultimate.
- Zoom no longer loses the map — raised minimum zoom from 0.3x to 0.55x so the map stays visible, and tightened pan margins from 25% to 10% so you can't scroll far past the map edges.
- Server stability — switched from bcrypt (native binary) to bcryptjs (pure JS) to prevent crash loops caused by ELF header mismatches on the server. CORS handling moved to raw HTTP server level for reliability.
- Desktop app login now works — resolved CORS preflight failure that prevented the Tauri desktop app from making API calls to hexarmy.com. Added explicit OPTIONS preflight handling at the Nginx reverse proxy layer, which was intercepting preflight requests before they reached the Express CORS middleware.
- Fixed "fullUrl is not defined" error — corrected variable scoping in the apiCall() function so error logging works properly when fetch requests fail.
- Updated Tauri CSP — added http://tauri.localhost to connect-src and default-src to allow the desktop app WebView to make cross-origin requests without CSP violations.
- Splash images now display — split CSS background shorthand into separate properties (background-image, background-size, background-position) for full WebView2 compatibility. The shorthand center/cover syntax was silently failing in some renderers.
- Splash now transitions to menu — fixed a race condition where clicking the splash screen before all scripts finished loading meant audio initialization never started. The splash now polls for script availability and triggers SFX init directly, rather than relying on a document-level click listener that hadn't been registered yet.
- Audio failure resilience — if audio initialization fails, the splash now transitions immediately instead of hanging for the full 8-second safety timeout.
- Scout — cheapest unit in the game (250g). High mobility (MOV 5), excellent vision (5), but very fragile (HP 3). Pathfinder passive ignores forest movement penalty. Recon Dash ultimate doubles movement and reveals all units in vision range.
- APC (Armored Personnel Carrier) — land transport that carries up to 5 foot/vehicle units (600g). MOV 5, moderate defense. Load adjacent friendly units, unload to adjacent hexes. Rapid Deploy ultimate lets all unloaded units act immediately. Cargo destroyed if APC is lost.
- PsyOps reworked — now limited to 3 decoy deployments. After deploying its 3rd decoy, the PsyOps unit is consumed and removed from the battlefield. This makes each decoy deployment a strategic decision.
- Quick Compositions removed — the preset draft buttons (Rush, Armor Push, Air Superiority, Economy Play) have been removed. Players now build their army composition manually.
- Splash screen now displays correctly — fixed an issue where the splash screen was invisible in the Tauri desktop build because the home overlay rendered on top of it despite lower z-index
- Deferred home overlay — the home screen now starts hidden and is only revealed when the splash screen is dismissed, ensuring reliable splash visibility across all WebView renderers
- Auto-update detection — the desktop app now checks for updates on launch via the Tauri updater plugin and displays a styled modal when a new version is available
- One-click update install — download progress bar with percentage, automatic install, and app relaunch after update completes
- Server update endpoint — new
/api/update/:target/:arch/:versionendpoint serves platform-specific update manifests with semver comparison
- 5 new cinematic splash screens — replaced the previous 3 splash images with 5 high-quality themed screens: HQ Logo, Ground Forces, Air Superiority, Naval Warfare, and 10 Nations
- Slower crossfade — splash slideshow now holds each image for 3 seconds (up from 1s) with a smoother 1.2s transition
- New app icon — custom HexArmy icon with hex frame, fighter jet, and neon glow applied to the Tauri desktop app (taskbar, installer, window title bar)
- HQ buildings now render correctly — faction-specific HQ sprites were not appearing because the sprite loader stored images under abbreviated keys (e.g.
us) while the renderer looked them up by full faction key (e.g.usa). Sprites are now stored under both keys so the lookup always succeeds
- Native desktop application — HexArmy now runs as a standalone Windows desktop app via Tauri 2, wrapping the existing web frontend in a native window with WebView2
- Seamless remote connection — desktop app automatically connects to hexarmy.com for multiplayer, authentication, and stats — same experience as the browser version
- Window management — default 1280×800 with 1024×768 minimum, resizable, F11 fullscreen toggle, and dynamic window title showing current game phase and turn
- NSIS & MSI installers — production build generates both installer formats for easy Windows distribution
- Tauri environment detection — game automatically detects desktop vs browser context via
window.__TAURI__and routes API calls and Socket.IO accordingly
- Gamepad input — full controller support via the Gamepad API with virtual cursor, map panning, zoom, unit selection, and turn management
- Button mapping — A=select, B=cancel, X=next unit, Y=end turn, LB/RB=zoom, triggers=analog zoom, left stick=pan, right stick=cursor, D-pad=menu navigation
- Visual cursor — glowing green cursor appears when using the right stick, with hover detection on the game canvas
- CORS updated for Tauri — server now accepts requests from
tauri://localhostandhttps://tauri.localhostorigins in production
- Base64 font rendering — added
data:to the Content Security Policy font-src directive so embedded woff2 fonts are no longer blocked - Phase cycling on game restart — starting a new game after victory caused rapid placement/draft phase looping. Orphaned setTimeout callbacks from the previous game instance were firing during the new game. Timer IDs are now tracked and cleared on reset
- Render suppression reset — rendering is no longer left frozen between games if a previous game was abandoned during the AI draft transition
- Placement centering — camera now correctly centers on the player HQ and valid placement area when the deployment phase begins. Previously, pan coordinates were computed before canvas dimensions were finalized, causing the view to land off-target
- Map flash after placement — eliminated the brief full-map reveal that occurred between the placement phase and game start. Rendering is now suppressed during the AI draft transition so only the fog-of-war view is shown
- Premature victory on large maps — AI units can now spawn on all traversable terrain (forest, hills, desert, etc.) instead of only plains. On max-size continent maps, the AI HQ could be surrounded by non-plains terrain, resulting in zero AI units and an immediate false victory. Added a safety guard requiring at least one AI unit before annihilation victory can trigger
- Scroll zoom cursor centering — mouse wheel zoom now reliably zooms toward the cursor position. The zoom handler uses the actual last-rendered pixel offsets instead of recomputed values, eliminating drift between the cursor and the map point beneath it
- Force composition sprites — draft cards now reliably show team sprites even when they load after the draft screen opens. Added a callback that redraws all draft card icons when team sprites finish loading
- Ranged units no longer advance — snipers, artillery, and mortar units no longer move into the defeated unit's tile after a kill. Only melee units (infantry, tank, recon, engineer, paratrooper, psyops, anti-air, radar) advance on kill
- Modular client architecture — split the 15,355-line monolithic game file into ~30 ES6 modules organized by domain: data, core, engine, UI, audio, rendering, and network
- Vite build system — zero-config dev server with hot module replacement, proxy to backend, and production build output to server public directory
- TypeScript-ready — tsconfig.json configured for incremental TypeScript adoption with allowJs enabled
- Event bus — centralized pub/sub system in core/state.js for decoupled module communication
- Global bridge — temporary window exposure layer maintains compatibility with HTML onclick handlers during transition
- Data layer — terrain, units, factions, achievements, and victory modes extracted to dedicated JSON-like modules
- Engine layer — combat, pathfinding, map generation, AI, turns, ultimates, and unit management as independent modules
- UI layer — panels, events, screens, draft, and account systems separated
- Audio & rendering — Web Audio DSP, canvas rendering, and sprite management isolated
- Network — complete multiplayer PvP system (Socket.IO) extracted to standalone module
- No gameplay changes — pure structural refactoring
- Original monolith preserved as reference/fallback
- Prepares codebase for future Steam deployment via Tauri
- Produce menu team sprites — produce unit cards now display team-colored 3D sprites instead of tinted icons, matching the draft screen visual upgrade
- Structure HP system — cities start with 20 HP and HQs with 30 HP. Structures must be damaged to 0 HP before capture
- Attack-advance for foot and vehicle units — infantry, tracked vehicles, and APCs automatically move into an enemy hex when their attack kills the defender. Provides tactical advantage for melee-range units
- Advance-capture mechanic — units that advance into a city or HQ with 0 HP automatically capture it and restore its structure HP
- Render suppression now works — replaced the ineffective
window.renderoverride with a global_suppressRenderflag checked at the top of therender()function declaration. This properly blocks all render calls during the placement-to-play transition until the camera is positioned
- Psyops unit sprite — new isometric SIGINT/communications vehicle sprite for the psyops unit, replacing the old SVG placeholder. Features satellite dishes, antennas, and communications equipment on an armored 6-wheel chassis
- All 4 teams — psyops sprite deployed to blue, red, green, and yellow team sprite folders
- Formation-based stacking — stacked units now display in a triangular formation instead of a linear offset. Unit 1 is center, unit 2 is right-front, and unit 3 is back-left, giving a clearer visual of the stack composition
- Back-to-front depth sorting — stacked sprites are drawn in depth order so rear units are behind front units, with slight dimming for depth perception
- Larger stacked sprite offsets — increased from 3px/4px to 8px/10px per unit in the stack, making individual sprites in a stack much more visible and distinct
- Battle start flash eliminated — rendering is now fully suppressed during the placement-to-play transition using a render gate. The
render()function is temporarily replaced with a no-op while zoom and camera position are calculated, then restored for the first proper render at the correct zoom level
- Draft screen team sprites — the force composition screen now displays the full team-colored unit sprites instead of the old tinted silhouette icons
- Stacked unit visuals — when units are stacked on a tile, multiple offset sprites are drawn (one per unit in the stack) with depth fading, giving a clear visual indication of stack size
- Battle start flash fixed — eliminated the brief full-map flash that occurred when transitioning from placement to battle phase. Canvas dimensions are now updated without rendering until the zoom and center position are properly calculated
- Stack target highlighting — clicking the "Stack" button now highlights valid target hexes in cyan in the isometric view (was only working in flat view)
- Battle start camera — when the battle begins after unit placement, the camera now automatically zooms in (1.5x–3.0x) and centers on the player's visible tiles, providing an immediate tactical view instead of a zoomed-out overview
- Faction flags on structures — captured cities, HQ, FOB, FAB, and port tiles now display the actual faction flag image on the flagpole instead of a generic blue/red triangle
- Map centering in isometric mode — clicking "Next Unit" or clicking a unit in the Intel panel now properly centers the isometric camera on that unit's hex position
- Stack Units button — new "Stack" action card appears in the command bar when a unit can merge with an adjacent same-type friendly unit. Click to enter stack targeting mode (cyan highlights), then click a valid target to merge. Combined unit gets scaled stats (80% per additional unit)
- Ownership flag — captured cities, HQ, FOB, FAB, and port tiles now display a colored flag (blue for player, red for AI) on a pole to clearly indicate who controls the structure
- Ownership hex border — structure tiles with an owner also get a colored hex border outline matching the owner's color
- Flag detail — flags include a highlight for 3D appearance and are positioned at the top-right of the tile for visibility
- Movement range highlight restored — blue hex overlay now correctly appears on movable tiles when a unit is selected (was referencing
gameState._moveHexesinstead ofgameState.movableHexes) - Attack range highlight restored — red hex overlay now correctly appears on attackable tiles (was referencing
gameState._atkHexesinstead ofgameState.attackableHexes) - All 12 highlight types now working — ported all overlay types from flat renderer: placement, deep scan, barrage, airdrop, relocate, nuke, smoke, decoy, smoke zones, radiation zones, attack range, movement range — all with correct colors matching the flat view
- Standing 3D unit sprites — units in isometric view now render as full-size standing sprites directly from team sprite files, replacing the small tinted icon system. Blue team for player, red team for AI
- Uniform unit sizing — all units fit within the same bounding box (75% of hex diameter), scaled proportionally by aspect ratio for visual consistency
- Air unit elevation — jets, bombers, and helicopters float 45% above ground level, appearing to fly over the battlefield
- Grounded positioning — land units positioned at 55% between tile centroid and bottom vertex so they sit naturally on the tile surface
- Stack count badges — units with multiple stacks show a yellow count badge
- Deployed indicator — deployed artillery/radar shows an anchor emoji above the unit
- Stealth visibility — submerged submarines and ghost protocol snipers/psyops only visible when adjacent to player units
- Isometric 3D rendering — the game map now renders in full isometric perspective with 3D hex tiles featuring visible side faces, directional lighting gradients, and depth-based shading
- Map rotation — press Q/E to rotate the map in 90° increments (4 directions), providing different tactical viewpoints
- Painter's algorithm — tiles, highlights, and units are all depth-sorted back-to-front for correct visual overlap in the isometric view
- Full game integration — fog of war, owner tinting, movement/attack highlights, unit selection, and click-to-hex all work seamlessly in the new 3D view
- Backward compatible — the original flat 2D view is preserved and can be toggled via
_useIsometric = falsein the console
- Projection system —
hexToWorld_iso(),worldToScreen_iso(),getHexScreenVerts_iso()for full isometric coordinate transformation with rotation - Inverse projection —
screenToWorld_iso()andpixelToHex_iso()for accurate mouse-to-hex detection in isometric mode - 3D tile rendering —
drawIsometricTile()draws hex prisms with side faces and top faces using terrain-specific color palettes - Isometric render pipeline —
renderIsometric()handles full scene rendering with depth sorting, culling, and all overlay types
- Isometric forests — lush hand-painted trees with visible trunks, roots, and multi-layered canopies in 4 distinct variants. Trees are depth-sorted for proper visual overlap
- Isometric mountains — craggy rock formations with jagged spires, stratified ledges, vertical crack lines, secondary peaks, and moss patches clinging to rock faces. Each mountain variant is procedurally different
- Isometric cities — dense urban centers with 7-10 varied buildings per tile, featuring grey/slate and orange/terracotta color palettes, windows with multiple styles (dark, lit, glass), rooftop details (AC units, antennas, satellite dishes), street-level trees, and lamp posts
- Isometric HQ rendering — faction headquarters buildings rendered as sprite-based structures sized to fill hexes prominently
- Seeded PRNG variation — mulberry32 algorithm used for all decoration generation, ensuring consistent terrain appearance per hex tile while maintaining visual diversity
- Depth-sorted rendering — decorations drawn after all tiles, using painter's algorithm for correct layering
- Decoration system — new
drawDecorations_iso(sx, sy, row, col)function handles all terrain-specific visual detail rendering - PRNG integration —
mulberry32_iso()seeded PRNG provides deterministic random generation for tile variation - Render pipeline update —
renderIsometric()extended with secondary decoration loop for layered depth composition
- HP bar — replaced the circular HP ring with a horizontal bar beneath each unit. Green above 50% health, orange 25–50%, red below 25%
- Ultimate cooldown bar — second bar below HP shows ultimate ability status. Bright green when ready, purple shrinking bar during cooldown. Only appears for units with ultimates
- Owner dot removed — team-colored unit sprites already indicate ownership, so the blue/red dot beneath units is no longer needed
- Selection highlight — selected units now show a white rectangle outline around their status bars instead of a circular ring
- 4 team-colored sprite sets — blue, red, green, and yellow team variants for all 17 unit types (68 sprites total), each with distinct color tinting to identify team ownership at a glance
- Team-based sprite loading — sprites organized in
/sprites/units/blue/,red/,green/,yellow/subdirectories, loaded per-team at startup - Player 1 = Blue, Player 2 = Red — player units use blue team sprites, AI units use red team sprites (expandable to 4 players with green and yellow)
- Embedded base64 for all 4 teams — SPRITE_DATA contains base64 sprites for all 4 teams for offline fallback
- HQ scale increased to 20 — headquarters buildings now fill the majority of their hex tile
- 3D raised platform — all HQ buildings now sit on a 3D elliptical platform with a visible side face, edge lines, top face with highlight, and ground shadow — giving them a raised, solid appearance on the map
- HQ buildings enlarged — faction headquarters base scale increased from 10 to 16, making them fill more of their hex tile
- Air units raised — jet, bomber, and helicopter sprites are now drawn higher above the tile (lifted by 45% of the unit box size), giving the appearance of flight rather than sitting on the ground
- Shadow removed — ground shadow ellipse removed from all units for a cleaner look
- Uniform sizing — all units now fit within the same bounding box (75% of tile hex diameter), scaled proportionally. Previously sprite width was fixed but height varied by aspect ratio, making tall units huge and wide units tiny
- Faction circle removed — units now stand directly on the tile with just a ground shadow beneath them, no colored circle or pedestal
- Units grounded on circle — pushed faction circle further down tile (60% toward bottom vertex, up from 45%), sprite bottom overlaps circle by 2px so units look planted on it rather than floating above
- Trimmed sprite padding — all 16 sprites re-processed to trim transparent padding around edges, so image bottom actually matches content bottom
- Alpha fringe cleanup — cleaned semi-transparent background pixels (alpha < 15 set to 0) on paratrooper, infantry, artillery, engineer, helicopter, and tank sprites to eliminate visible background artifacts
- Flat faction circle — replaced the 3D raised pedestal with a simple flat ellipse in faction accent color with a dark outline, sitting flush on the tile surface
- Units sit on the circle — sprite bottom edge aligns directly with the flat circle, so units appear grounded rather than floating above a raised platform
- Anti-Air sprite now renders — fixed unit type mismatch (
antiairvsanti_air) that caused the Anti-Air unit to show as a fallback "A" circle instead of its sprite image - Units sit on tile surface — moved unit base position from tile centroid down toward the bottom vertex (45% blend), so sprites appear grounded on the tile rather than floating above it
- Standing 3D units — units now render as upright sprites standing on the tile surface like miniature figures, replacing the hex-framed token approach entirely
- No hex border — removed all hex clipping, hex borders, and hex prism effects from unit rendering. Sprites are drawn directly and unmodified
- Faction base pedestal — small 3D elliptical pedestal in faction accent color beneath each unit, with a darker side face and highlighted top rim
- Ground shadow — elliptical shadow cast on the tile surface beneath each standing unit
- 3D prism depth — unit tokens now render as raised hex prisms with visible side faces, matching the 3D style of terrain tiles. Side faces are drawn between a top hex (raised up) and bottom hex (at tile surface), with faction-colored shading
- Directional side lighting — 6 side faces use different shade levels (15%–25% of faction accent color) for realistic directional lighting
- Bevel highlight/shadow — top-left inner edges have a subtle white highlight, bottom-right edges have a dark shadow for an embossed 3D look on the top face
- Side edge lines — vertical edges on visible sides add definition to the prism shape
- Ground shadow — larger offset shadow beneath the raised token for depth perception
- 16 new isometric unit tokens — high-quality transparent-background sprites (resized from 1024px to 256px for web), replacing previous artwork. Sprites are displayed unmodified within the hex clip
- Faction-based hex border colors — unit hex borders and star badges now use the selected faction's accent/flag colors (e.g., US blue, Russia red, India orange) instead of generic green/red team colors
destroyer.png→ ship unit typemobile_missile_launcher.png→ missile unit typemobile_radar.png→ radar unit typemortarman.png→ mortar unit type
- Centered unit hexes on tiles — unit sprite hexagons are now perfectly centered on their tile by using the computed tile vertex centroid directly, removing the previous offset that anchored units to the top-left of the tile
- Isometric hex orientation — unit sprite hexagons now use the actual isometric-projected tile vertices from
getHexScreenVerts(), matching the 3D tile orientation exactly instead of using flat 2D pointy-top hexes - Perspective-correct clipping — sprite images are clipped to the projected hex shape, rotating and distorting with the isometric camera view
- Cover-fit within projected bounds — sprite sizing uses the bounding box of the projected hex for proper aspect-ratio-preserving fill
- 16 new high-quality unit sprites — all unit types replaced with new hand-crafted artwork featuring richer detail and consistent art style
- Updated sprite mapping — destroyer sprite mapped to ship unit type, nuclear sprite mapped to missile unit type
- Embedded base64 fallback — all 16 new sprites embedded as base64 data for offline/no-server operation
- Hex-shaped unit sprites — unit sprites are now clipped to a pointy-top hexagon that consumes 75% of the tile hex area, replacing the previous elliptical base plate
- Team-color hex border — thick colored hex border (green for player, red for AI) clearly identifies unit ownership at a glance
- Hex drop shadow — hex-shaped shadow beneath each unit for depth
- Cover-fit sprite scaling — sprites are aspect-ratio-preserved and cover the hex area, clipped to the hex boundary for clean edges
- Team badge — small star indicator badge in bottom-right corner of hex for additional team identification
- Fallback rendering — if sprite fails to load, unit displays as a team-colored hex with the unit type initial
Replaced all Canvas 2D hand-drawn unit sprites with an image-based PNG sprite system using ctx.drawImage(). Units now load pre-rendered 256x256 artwork from /sprites/units/, enabling realistic painted-style graphics that Canvas primitives cannot achieve.
- Tank: Sherman/T-34 style with rounded turret, sloped hull, detailed running gear, muzzle brake
- Infantry: Standing soldier with M1 helmet, rifle with bayonet, belt and buckle detail
- Artillery: Towed field gun with split trail legs, spoked wheels, curved gun shield, long barrel
- Recon: Open-top WW2 Willys Jeep with windshield, spare tire, grille slats, headlights
- Anti-Air: Half-track with twin upward AA barrels, ammo magazine, open fighting compartment
- Jet: Swept-wing fighter (MiG/F-86 era) with glass canopy, intake ring, team roundel
- Helicopter: Attack helicopter with tandem cockpit, stub wings, rocket pods, chin turret, rotor disc
- Engineer: Soldier with yellow hard hat, tool belt with pouches, wrench and shovel
- Ship: Naval destroyer with superstructure, gun turrets, funnel, mast with radar, bow wave
- Submarine: Cigar hull with conning tower, periscope, dive planes, wake bubbles
- Radar: Truck with large parabolic radar dish, feed horn, signal waves, flatbed detail
- Bomber: Multi-engine wide-wing aircraft with glass nose, 4 engine nacelles, propeller discs
- Sniper: Prone soldier in ghillie suit, scoped rifle on bipod, boonie hat
- Paratrooper: Soldier descending with parachute canopy, suspension lines, panel detail
- Missile: TEL truck with ballistic missile on angled launch rail, nosecone, rear fins
- Mortar: Mortar tube on baseplate with bipod, ammo crate with standing rounds
Every unit sprite in the 3D isometric prototype has been completely redrawn with realistic, organic shapes replacing the blocky rectangular primitives:
- Curved geometry — All primary shapes now use quadratic Bezier curves for natural, organic silhouettes instead of flat rectangles
- Multi-tone shading — Each unit features 3-4 tonal layers (shadow, body, highlight, specular accent) for depth and volume
- Sub-component detail — Rivets, hatches, wheel hubs, lug nuts, panel lines, glass reflections, scope lenses, and weapon details
- All 16 unit types — Tank, infantry, artillery, recon jeep, anti-air, jet, helicopter, engineer, ship, submarine, radar vehicle, bomber, sniper, paratrooper, missile TEL, and mortar
Units now stand out clearly on all terrain types — especially forests and mountains — with a new 3-layer visibility system:
- Ground Shadow: Wider, softer elliptical shadow anchors units to the terrain
- Base Plate: 3-tone olive drab platform under every unit, visually separating it from terrain decorations like tree canopies and rock spires
- Team-Color Rim Glow: Colored ring (green for player, red for AI) around the base plate for instant team identification at a glance
- Forest tiles — trees now spread across full tile area (ox 0.65→1.0, oy 0.35→0.55), increased count (2–3→3–4), larger trunks (3→3.8 width, 10→13 height), bigger canopies (6.5→8.5 radius), increased individual scale (0.7–1.2→0.9–1.5)
- Mountain tiles — larger rock formations (baseW 14–20→20–28, baseH 16–26→22–36), more spires (2–3→3–4), wider spread (0.6→0.85), wider rubble field (0.8→1.1, 4→6 stones)
- City tiles — larger sidewalk pad (0.55→0.80), more buildings (3–4→4–6), wider spread (ox 0.55→0.85, oy 0.28→0.45), bigger buildings (bw 3.5–7.5→4.5–9.5, bh 5–17→7–21), wider tree and lamp placement
- Varied city layouts — each city tile now generates a unique cluster of 3–5 buildings with different heights, widths, and color palettes so no two cities look the same
- 3-color building palettes — grey/slate, orange/terracotta, and dark blue building types with proper isometric front face, right side face, and roof face rendering
- Window grid system — auto-scaled rows and columns of windows on front and side faces with 3 styles: dark, warm-lit, and glass reflection
- Ground-level detail — dark entrance doors with frames, darker base band for entrance areas, concrete sidewalk pad
- Rooftop equipment — randomized AC units with fan grilles, antenna towers with cross-bars and red blinking lights, satellite dishes
- Street trees — 1–2 small round-canopy trees with layered foliage per city tile
- Street lamps — occasional lamp posts with warm glow heads
- Depth sorting — buildings sorted back-to-front by Y position for correct isometric overlap
- Multi-spire rock formations — mountains now consist of 2–3 jagged rock spires with depth-sorted back-to-front rendering, each with unique height, width, and jaggedness
- Stratified rock faces — 4-tone rock palette (dark shadow, mid slate, light face, bright highlight edge) with realistic cliff face geometry
- Horizontal ledge lines — 3–5 jagged stratification lines per spire simulating geological layering
- Vertical crack detail — curved crack lines running down rock faces for weathered appearance
- Secondary peaks — smaller jagged sub-spires on higher-variant formations
- Moss/vegetation patches — green elliptical patches clinging to rock faces at lower elevations
- Ground detail — grass/moss base ring and scattered rock rubble at mountain base
- Lush deciduous trees — complete rewrite of forest tile rendering inspired by hand-painted sprite sheet; trees now feature thick tapered trunks with bark texture, knot/whorl details, and dark crevice lines
- Bubble-cluster canopies — 4-layer canopy system (dark back, mid-green mass, light highlights, bright top spots) using overlapping circles for a lush, organic illustrated look
- Exposed root system — visible gnarled roots spreading from trunk base using quadratic curves
- Branch stubs — visible branch connections below canopy for added depth
- Leaf edge detail — small circles along canopy perimeter creating a bubble/leaf-cluster silhouette
- Ground detail — grass/moss patches at tree bases with varied green tones
- Depth sorting — trees within each hex are sorted back-to-front by Y position for correct overlap
- Anti-Air — tracked chassis with open turret platform, dual upward-angled AA barrels with flash suppressors, ammo box detail
- Jet — pointed fuselage with swept wings, tail fins, vertical stabilizer, glass canopy, nose cone, wing roundels with team colors
- Helicopter — tail boom with tail rotor, main fuselage with curves, glass canopy, stub wings with rocket pylons, nose gun, semi-transparent rotor disc, landing skids
- Field Engineer — soldier body with bright yellow tool vest, belt with tools, wrench in hand, yellow-green hard hat
- Naval Ship — boat-shaped hull with deck, superstructure/bridge with windows, radar mast, forward and aft gun turrets, wake foam
- Submarine — elongated submerged hull, deck casing, conning tower with windows, periscope mast, propeller area, wake effect
- Mobile Radar — 6-wheeled chassis, equipment housing body, radar mast with concave dish and feed horn, windshield
- Bomber — wider fuselage and wings than jet, 4 engine nacelles, tail fins, canopy, bomb bay doors
- Sniper — prone/crouched ghillie suit body, extended arms, long rifle with scope and bipod, boonie hat, low profile silhouette
- Paratrooper — parachute canopy with team-color panels, suspension lines, compact soldier body, harness, weapon across chest, team-color beret
- Mobile Ballistic Launcher — 8-wheeled truck chassis, cab body, angled launch rail with missile body, nose cone, fins
- Mortar — elliptical baseplate, bipod legs with hinge, angled mortar tube with muzzle opening, stacked mortar rounds
- Spiral unit placement — all 16 unit types now placed around each HQ using spiral outward algorithm, with naval units on water tiles and land units on terrain
- Shared military palette — PAL object with 18 colors (olive, khaki, brown, steel, skin, navy, red, glass) for consistent rendering across all unit types
- Tank — complete rewrite with dual track assemblies (road wheels, return rollers, drive sprockets), track guards, angled glacis hull with engine deck grille/exhaust, tool stowage, tow cable, rounded turret with mantlet, bore evacuator on barrel, slotted muzzle brake, commander's cupola with hatch handle
- Infantry — full-body soldier with visible face/skin, prominent steel pot helmet with netting band and chin strap, olive jacket with chest pockets/button line, Y-harness webbing, leather belt with buckle, knee-highlighted trousers, detailed rifle with wooden stock and front sight
- Artillery — towed field gun with split trail legs and spade plates, large spoked wheels with hub caps, curved gun shield with edge outline, recoil mechanism/cradle detail, barrel with highlight and slotted muzzle brake
- Recon — open-top jeep with rounded fenders, fold-down windshield with glass reflection, visible seats and steering wheel, hood with center ridge and side vents, front grille with headlight, spare tire on rear, whip antenna
- Expanded palette — 14-color military palette (olive, khaki, brown, steel, skin) with highlights and shadows matching the sprite sheet's tonal range
- 10 factions — United States, Canada, New Zealand, Iran, China, United Kingdom, Australia, Russia, North Korea, India
- Faction selector — choose your faction and enemy faction from dropdowns in the control panel
- US — Pentagon — 5-sided ring building with inner courtyard
- Canada — Parliament — Centre Block with Peace Tower gothic spire and clock
- New Zealand — The Beehive — tiered circular building with dome
- Iran — Azadi Tower — inverted-Y arch monument with crown
- China — Bayi Building — columned hall with pagoda tower and red star
- UK — Whitehall — classical columns, pediment, and clock tower with spire
- Australia — Parliament House — low-profile building with iconic 81m flag mast
- Russia — Kremlin Tower — Spasskaya tower with clock, crenellations, and red star
- North Korea — Ryugyong Hotel — massive pyramid with window grid
- India — Rashtrapati Bhavan — sandstone building with Mughal dome and columns
- Olive-drab military palette — all units now use realistic military colors (#5a6b3a olive base) with small team-color accent markings (stars, stripes) instead of full team paint
- Tank — detailed tracks with road wheels, angled hull with engine deck hatches, turret with cupola, barrel with muzzle brake
- Infantry — steel pot helmet with highlight band, olive jacket with webbing/gear straps, belt, rifle with stock, team-color armband
- Artillery — towed howitzer with trail legs and spades, wheels with hubs, gun shield, breech, angled barrel with muzzle brake
- Recon — jeep with 4 wheels, hood, windshield with frame, roll bar, seats, spare tire, whip antenna with team-color tip
- Flat terrain — all tiles at uniform height; terrain type now indicated by tile color and decoration icons rather than elevation
- Uniform tile depth — all hex prism sides same height for a clean, consistent grid appearance
- Seamless hex tiling — hex corners are now computed in world space and projected through the isometric transform, so adjacent tiles share exact screen vertices with zero gaps
- Zoom-to-cursor — fixed math error where pan offset wasn't adjusted relative to canvas center; scrolling now correctly zooms toward the mouse pointer
- 90° map rotation — rotate the isometric view in 90° increments via UI buttons or Q/E keyboard shortcuts
- Zoom-toward-cursor — scroll wheel zooms toward mouse position instead of center; range expanded to 0.3x–4.0x
- Tile zoom fix — hex radius now scales with zoom level so tiles never split apart at any zoom
- Enhanced 3D tiles — proper side faces with dark shading, gradient lighting on top face, separate top/side/highlight colors per terrain, water shimmer effect
- Enhanced 3D units — tank with tracks/hull/turret/barrel, infantry with helmet/rifle/limbs, artillery with wheels/shield/angled barrel, recon vehicle with windshield/antenna; all with drop shadows
- Enhanced decorations — layered tree canopies, multi-ridge mountains with snow caps, 3D buildings with roofs/windows, HQ compounds with triangular flags
- Deterministic heights — mountain heights cached per tile position instead of random-per-frame
- Minimap unit dots — units now visible on minimap with team colors
- Improved sort order — painter's algorithm sorts by screen Y for correct overlap at all rotations
- Self-contained isometric renderer — complete Canvas 2D engine with 3D-looking hex prism rendering; zero external dependencies, no CDN required
- Hex prism depth — visible side faces with darker shading for convincing 3D depth effect using painter's algorithm
- Terrain decorations — forest trees with trunks/canopies, snow-capped mountain peaks, city buildings, HQ structures with colored flags
- 3D unit models — tank (body+turret+barrel), infantry (torso+head), artillery (base+barrel), recon (body+antenna) with team colors
- Camera controls — click-drag pan, scroll-wheel zoom, reset button
- Hex selection — click any hex to see terrain, coordinates, owner, and unit info
- Eliminated CDN dependency — no more Three.js CDN loading failures; works offline and behind any firewall
- All 8 map generators — preserved from previous versions with identical algorithms
- Local fallback — if CDN is blocked, Three.js loads from self-hosted
/lib/three.min.js - Resilient loading — synchronous fallback via
document.writeensures Three.js is available before game code runs
- Three.js 3D renderer — full rewrite using Three.js r128 from cdnjs CDN with manual camera controls (no OrbitControls dependency)
- Extruded hex terrain — CylinderGeometry hex tiles with terrain-based height variation (mountains elevated, water recessed)
- 3D unit models — tank (body + turret + barrel), infantry (torso + head), artillery (base + angled barrel), recon (body + antenna) with team coloring
- Terrain decorations — forest trees (trunk + canopy cones), mountain peaks with snow caps, city buildings, HQ compounds with flag poles
- Manual camera orbit — left-drag orbit, right-drag pan, scroll zoom using spherical coordinates; no CDN dependency on OrbitControls
- Hex raycasting — click-to-select hex tiles with emissive highlight and info panel display
- Grid edge lines — hex tile edges rendered with THREE.EdgesGeometry for clear grid visibility
- All 8 map generators — standard, continents, archipelago, pangea, highlands, desert wastes, forest basin, river networks
- Error banner — visible red error banner for debugging instead of silent failures
- Version in header — game version displayed next to prototype title for easy identification
- Zero-dependency renderer — complete rewrite using Canvas 2D with isometric projection; no CDN or external libraries needed
- 3/4 isometric hex view — hex prisms with terrain-based height, side faces for depth, and back-to-front rendering order
- Terrain decorations — trees on forests, snow-capped mountain peaks, city buildings with windows, HQ flags, water wave lines
- Pan & zoom — click-drag to pan, scroll to zoom toward cursor, auto-fit on map generate
- Hex selection — click any hex to see terrain type, coordinates, owner, and unit info
- Unit rendering — infantry, tank, artillery, recon with distinct shapes and team colors
- Minimap — live viewport indicator updates as you pan/zoom
- All 8 map generators — standard, continents, archipelago, pangea, highlands, desert wastes, forest basin, river networks
- CDN consolidation — switched Three.js and OrbitControls to same CDN (unpkg) to prevent cross-CDN loading failures
- OrbitControls fallback — tries both
THREE.OrbitControlsand globalOrbitControlsreferences; falls back to static camera with error message if neither loads - Camera switch — replaced OrthographicCamera with PerspectiveCamera for more reliable 3/4 view rendering
- Error display — visible on-screen error messages instead of silent failures when Three.js or controls fail to load
- Init guard — all render functions now check for initialized scene/camera/renderer before operating
- Version in header — game version now displayed next to "HEXARMY 3D VIEW PROTOTYPE" title
- Smart camera framing — camera distance scales based on map size for proper framing at any grid dimension
- Renderer initialization — fixed typo
THREE.PCFShadowShadowMapthat prevented WebGL renderer from initializing - OrbitControls — fixed bare
OrbitControlsreference toTHREE.OrbitControlsfor CDN-loaded Three.js r128 - Camera frustum — orthographic camera viewable area was microscopic (dividing by 150); now uses proper frustumSize-based calculation
- Camera centering — camera and orbit target now auto-center on the generated map instead of always pointing at world origin
- 3D terrain prototype — standalone
test-3d.htmlpage renders hex maps in full 3D with Three.js r128 - All 7 map generators ported — standard, continents, archipelago, pangea, highlands, desert wastes, forest basin, and river networks render as 3D hex tiles with terrain-based height variation
- 3D terrain features — forests rendered as cone trees, mountains as peaks, cities and HQs as buildings on the hex grid
- 3/4 isometric camera — orthographic camera with OrbitControls for pan, zoom, and rotation
- Hex selection — raycasting-based hex picking with coordinate display and terrain info
- Placeholder 3D units — infantry, tank, artillery, jet, and helicopter models placed on the map
- Fog of war — toggleable fog visualization on the 3D terrain
- HEXARMY-themed UI overlay — controls panel, info panel, and minimap matching the dark military aesthetic
- Battalion tag display — your battalion's [TAG] now appears in its emblem color before your callsign throughout the game
- Tag shown everywhere — home screen, multiplayer lobby slots, turn indicators, ranked leaderboard, and dossier profiles
- Server-side support — battalion data included in auth session, multiplayer join/start queries, and dossier search results
- Field Manual updated — battalion section expanded with tag visibility documentation
- Design guide — comprehensive visual style reference document created
- Map preview proportions — canvas now preserves actual map aspect ratio instead of stretching to fill frame
- Accept Faction button — now a static button below the faction selection frame that never scrolls off-screen
- Faction change — players can change their faction after accepting but before selecting Ready
- Team designator — updates correctly when player changes team
- Teammate faction visibility — same-team players can now see each other's faction selection (blind pick preserved for opponents)
- Ready indicator — READY badge now displays correctly next to each player in the lobby
- Game start logic — fixed critical bug where local player's ready state wasn't written to the players object, preventing game start even when all players were ready
- Fatal syntax error — fixed duplicate variable declaration that prevented the entire game from loading past the splash screen
- Button overflow — Command row buttons (Tournaments, Service Record) no longer clip text on narrower viewports
- Features page — marketing-focused showcase highlighting all game systems, accessible from footer
- Release notes page — full version history with color-coded tags, accessible from footer
- Footer links — Features and Release Notes links open in new browser tabs from below the version display
- Ranked ladder — multiplayer games can now be flagged as ranked for competitive ELO tracking
- Human-only enforcement — ranked matches require all player slots to be filled by authenticated human players; no AI allowed
- Individual ranked leaderboard — top 100 players by ELO with battalion affiliation, win rate, and streak data
- Battalion ELO system — battalions earn their own ranked ELO based on members' ranked match results
- Battalion ranked leaderboard — top 100 battalions by ranked ELO with member counts and win rates
- Battalion ranked profile — detailed battalion stats, ELO history, and top members display
- Public lobby browser — real-time game list with Socket.io live updates
- Password-protected rooms — private games with bcrypt-hashed passwords
- Tournament bracket system — single-elimination tournaments with automatic progression
- Stale game cleanup — auto-cancels abandoned lobbies after 30 minutes
- 2–4 player matches — host selects player count when creating a room
- Team configurations — FFA, 2v2, 2v1v1, 3v1, and 2v1 modes
- Player elimination — eliminated players are removed from turn order; game continues until one remains
- Turn order system — sequential turns with skip for eliminated players
- Color-coded players — P1 Blue, P2 Red, P3 Yellow, P4 Green
- Fluid scaling — all UI elements use
clamp()for smooth scaling across desktop and tablet - Responsive breakpoints — 4 media queries at 1280px, 1024px, 860px, and 768px
- Click-to-enlarge map preview — full-screen modal for map inspection at any resolution
- Responsive faction selection — stacked layout on smaller screens
- Waypoint system — set multi-turn movement paths for units that execute automatically each turn
- Pathfinding — A* pathfinding calculates optimal routes accounting for terrain movement costs
- Visual waypoint trail — dashed path overlay shows planned movement routes on the map
- Transport naval unit — carries up to 3 foot/vehicle units across water; no attack capability
- AA Frigate naval unit — fleet air defense ship with anti-air auto-fire and Missile Salvo ultimate
- Dramatic faction reveal — cinematic curtain animation reveals opponent's faction at game start
- Radar & vision overhaul — mountain LOS blocking, improved fog of war
- Complete combat rework with updated unit effectiveness tables
- Terrain defense bonuses rebalanced for all terrain types
- Faction budget and production weight adjustments
- New terrain rendering — rich visual terrain with distinct textures for all terrain types
- Intel panel LOS enforcement — information panels respect fog of war visibility
- Callsign profile page — account management with password change and profile visibility toggle
- Main page auth gate — streamlined login/register flow on the home screen
- Personnel dossiers — searchable public profiles with paginated browse and ribbon bar display
- Mountain line-of-sight — mountains now block vision, creating tactical blind spots
- Public service records — opt-in profile visibility for other commanders to inspect
- 5,000 tile maps — massive battlefields for extended strategic campaigns
- 7 map generators — Continents, Archipelago, Pangaea, Desert Storm, Pacific Islands, Frozen Steppe, European Plains
- Terrain-first generation — natural landmass shapes with organic continent and island formations
- Fog of war: hidden faction — enemy faction identity is concealed until the dramatic faction reveal
- Nuclear rework — overhauled nuclear strike mechanics with area-of-effect radiation zones
- Radiation system — irradiated terrain damages units over time, creating denial zones
- Visual polish — enhanced explosion effects and irradiated terrain rendering
- 10 faction-specific AI strategies — each faction uses unique tactical priorities, aggression levels, and production weights
- Simulation-driven tuning — AI strategies balanced through automated battle simulations
- Adaptive behaviors — AI retreat thresholds, income raiding, and camp priorities vary by doctrine
- Unit stacking — multiple units can occupy the same hex tile
- Nuclear warfare — devastating area-of-effect weapons that reshape the battlefield
- New unit types — expanded army roster with additional tactical options
- Real-time PvP — Socket.io-powered multiplayer with room codes and lobby system
- Blind faction pick — simultaneous faction selection without knowing opponent's choice
- ELO rating system — competitive ranking with lifetime and monthly ladders
- Disconnect recovery — games pause on disconnect with 60-second grace period for reconnection
- 97 total achievements — expanded from 47 with new milestones across all categories
- Tiered ribbon system — visual commendation ribbons displayed on service records and dossiers
- Server-side validation — all achievements verified server-side to prevent manipulation
- Smart AI — complete AI rewrite with terrain analysis, threat mapping, and target prioritization
- Unit effectiveness matrix — 15x14 matchup table guiding AI combat decisions
- Three difficulty levels — Easy, Medium, and Hard with distinct AI behavior parameters
- Save/load system — 3 save slots per player with server-side persistence
- UI readability overhaul — improved fonts, colors, and contrast across all panels
- State cleanup — proper game state management on exit and resume