A strategic hexagonal board game played with dice as soldiers. HexDice blends tactical movement, resource management (dice), and unique class abilities into a fast-paced strategy experience.
- Play:
- Rules: Rules | v2.0 Manual
- Devlog: Development Blog
- Hexagonal Grid: Tactical positioning on a procedurally generated or hand-crafted hex grid.
- Dice as Units: Each face (1-6) represents a unique class with distinct stats (Attack, Armor, Range) and movement patterns.
- Merge & Reroll: Tactical depth through merging units for strength or rerolling to adapt to the battlefield.
- Campaign Mode: A single-player progression system with unique maps, persistent state, and collectible runes.
- Romance Mode: Spectate AI vs AI battles (Romance of the Dice Kingdoms).
- Terrain Effects: Forests, Lakes, Towers, and Mountains influence movement and combat.
game.js: The heart of the game. An Alpine.js component managing the game state, grid, and combat logic.index.html: Main entry point. PWA-ready reactive UI.service-worker.js: Handles offline caching for thousands of assets using chunked loading.
A modular AI system with multiple strategies:
ai-heuristic.js: Primary AI using weight-based evaluation and state simulation.heuristic-profiles.js: Personality profiles (Aggressive, Balanced, Defensive, Chaos).
campaign-manager.js: Handles level progression, RMI (Resource Management Interface) map loading, and player runes.generator.js: Procedural map generation for infinite replayability.
server.ts: Lightweight Deno server for local development.simulate.ts/tournament.ts: Headless Deno scripts for AI benchmarking and game balance analysis.replay.ts: Tool for replaying recorded matches.
/assets: Contains sprites, icons, andassets-manifest.jsonfor PWA caching.generate-assets-manifest.js: Utility to keep the PWA manifest up to date.
HexDice is designed to run with Deno.
-
Start the server:
deno run --allow-net --allow-read server.ts
Alternatively, use
npm startwhich includes necessary unstable flags for KV storage. -
Access the game: Open
http://localhost:1166in your browser.
The project uses npm as a task runner for asset management and automated testing:
- Asset Management:
npm run manifest:gen: Updatesassets/assets-manifest.jsonby scanning all files in/assets. Essential for PWA offline support.npm run sprites:gen: Scans/assets/sprites/sets/and updatesassets/sets.jsonwith the list of available sprite themes.
- Simulations & Benchmarking:
npm run simulate: Runs a standard balance simulation between AI profiles.npm run tournament:full: Runs an exhaustive 20-game tournament between all loaded heuristic profiles.npm run tournament:mutate: Runs a genetic-algorithm style simulation with property mutation.
- Campaign Tools:
npm run campaign:ro_rmi: Generates campaign map levels based on the RMI (Resource Management Interface) logic.
The /assets directory is organized to support a highly customizable and themeable experience:
/sprites: The core visual library./sets: Contains hundreds of thematic unit sets (e.g.,ro_job,aw_static_blue,tos_mix). Each folder typically contains sprites for dice values 1-6./terrain: Custom textures for Forests, Lakes, and Mountains.
/ro_maps: A collection of static map backgrounds used in Campaign and Romance modes./infographics: High-quality splash screens, rule summaries, and recap images./images: Essential PWA assets (favicons, manifest icons, logo).assets-manifest.json: Auto-generated index used by the Service Worker to ensure every image and script is available offline.
The game engine is encapsulated in the alpineHexDiceTacticGame function within game.js. It manages state reactively via Alpine.js.
setupTerrain(force): Generates the hex grid using either a "Roulette" (sum-of-6) algorithm or by loading an RMI map.rollInitialDice(playerId): Generates the starting pool of units (dice faces) for a player.deployUnit(hexId): Places a selected die from the pool onto the board, initializing its base stats.
The primary entry point for all player interaction. It contextually dispatches actions:
- Phase: SETUP_DEPLOY: Calls
deployUnit()on clicked hexes. - Phase: PLAYER_TURN:
- If no unit is selected: Selects a unit and calls
calcValidMoves(). - If a unit is selected:
- If clicking an empty valid hex: Initiates
MOVE. - If clicking an enemy: Initiates
ATTACK. - If clicking self: Deselects.
- If clicking an empty valid hex: Initiates
- If no unit is selected: Selects a unit and calls
calcValidMoves(unitHexId, isForMerging): Calculates reachable hexes based on unit class (Fencer: Any, Hussar: L-shape, Knight: X-shape).handleCombat(attackerHexId, defenderHexId, type): The core resolution engine. It comparesattackvsarmor, applies terrain modifiers, and handles unit destruction or "Scars" (fatigue).performAction(type, targetHexId): Dispatches specific logic forGUARD,REROLL,SKIRMISH, orSPELLCAST.
performMerge(mergingUnitHexId, targetUnitHexId): Combines two units, summing their values and potentially increasing stats.selectOracleSpell(spell): Handles the Oracle's (Die 6) unique abilities likeSHIELDorSWAP.
performAI(): Orchestrates the AI turn. It evaluates the board state usingai-heuristic.jsand executes the best move series.
HexDice has undergone hundreds of iterations to balance its unique "Dice Soldiers" mechanic.
- Design Backlogs: Check the
/backlogsdirectory for balance analysis and feature plans. - Rule Evolution: View the progression of the game in the
/rulesfolder.
To maintain the project's long-term health and readability, please adhere to the following standards:
- Surgical Changes: Modify only what is necessary. Avoid unrelated refactoring or "cleanup" in PRs.
- Plan First: For complex features, draft a plan in
.chat/before implementation. - Preserve History: When removing code, comment it out with a
// DEPRECATEDnotice instead of deleting it immediately. - Minimalism: Favor simple, readable logic over complex abstractions. "Less code is less debt."
- Vanilla JS First: Avoid adding new frameworks or large libraries. The core game logic should remain dependency-free.
- Global Scope Awareness: Since scripts are loaded via tags, be mindful of naming collisions and the global namespace.
- Functional Patterns: Prefer functional, immutable, and stateless approaches where they improve clarity.
- Indentation: Use Tabs.
- Semicolons: Always use semicolons.
- Braces: Use One True Brace Style (1TBS).
- Naming:
camelCase: Variables and functions (e.g.,handleHexClick).UPPER_SNAKE_CASE: Constants and global configuration (e.g.,UNIT_STATS)._prefix: Internal or private utility functions.
HexDice is designed with a "Physical-First" philosophy. The digital version serves as a testbed for the core mechanics, which are being refined for a premium physical board game release.
- Mechanics Testing: The AI and simulation tools ensure the "Dice Soldiers" classes are balanced for table play.
- Reserved Rights: While the source code is licensed under Apache 2.0, the commercial rights to the "Hex Dice" brand, thematic lore, and physical game production are reserved by the original author.
- Community Contributions: Rules adjustments or balance changes submitted via PRs may be incorporated into the official physical rulebook.
Contributions, balance suggestions, and bug reports are welcome! Note: This project follows a "surgical change" philosophy. Keep PRs focused and idiomatic.
Licensed under the Apache License, Version 2.0. See the LICENSE file for the full text. The Apache 2.0 license provides an explicit patent grant and protects the "Hex Dice" trade name, ensuring a secure foundation for both open-source contributors and future commercial production.