Hex Maps

6 game generators with deterministic seeded output, SVG rendering, and a headless SDK for server-side consumers.

Embed via iframe

Embed a hex map generator into any page. The same seed always produces the same map.

<iframe
  src="https://engine.moddable.games/play/?embed=1&game=nukes&style=artistic&random=1"
  style="width:100%;max-width:560px;aspect-ratio:1/1;border:none"
  title="Hex Map"
></iframe>

URL parameters

ParamValuesDefault
embed1Required for embed mode
gamenukes | twilight | colony | talisman | mongo | endlessRequired
styleartistic | classic | kenney | realisticartistic
sizeInteger (ring count)Game default
playersIntegerGame default
seedAny stringRandom
random1Generate with random seed
bgHex colour (no #)Transparent

postMessage control

Control the embed without reloading:

// Switch game
iframe.contentWindow.postMessage({ type: 'hexmap:setGame', game: 'twilight', style: 'classic' }, '*')

// Change visual style
iframe.contentWindow.postMessage({ type: 'hexmap:setStyle', style: 'kenney' }, '*')

// Generate new map
iframe.contentWindow.postMessage({ type: 'hexmap:regenerate', random: true }, '*')
iframe.contentWindow.postMessage({ type: 'hexmap:regenerate', size: 5, players: 6 }, '*')
iframe.contentWindow.postMessage({ type: 'hexmap:regenerate', seed: 'my-seed' }, '*')

// Request data
iframe.contentWindow.postMessage({ type: 'hexmap:getMap' }, '*')
iframe.contentWindow.postMessage({ type: 'hexmap:exportSvg' }, '*')

// Change background
iframe.contentWindow.postMessage({ type: 'hexmap:setBg', bg: '#0B0F1A' }, '*')

Additional commands

// Export PNG (canvas-rendered)
iframe.contentWindow.postMessage({ type: 'hexmap:exportPng', scale: 2 }, '*')

// Edit a hex (cycle terrain type, games that support it)
iframe.contentWindow.postMessage({ type: 'hexmap:editHex', q: 0, r: 1 }, '*')

Events from embed

window.addEventListener('message', (e) => {
  switch (e.data.type) {
    case 'hexmap:ready':
      // { game, seed, size, players }
      break
    case 'hexmap:mapData':
      // { hexes: [{q, r, type, ...}], seed, game, structured }
      // structured: game-specific export (e.g. Twilight tile IDs)
      break
    case 'hexmap:svgData':
      // { svg: '<svg ...' }
      break
    case 'hexmap:pngData':
      // { png: 'data:image/png;base64,...', width, height }
      break
    case 'hexmap:hexEdited':
      // { q, r, type } — after editHex command
      break
  }
})

Hex SDK

Headless SDK for server-side tools, APIs, and direct browser consumption.

import {
  listGames,
  generate,
  renderSvg,
  getHexInfo,
  exportGameData,
  editHex,
  computeFov,
  pathfind,
  HexMath,
  HexSvg,
  createSeededRng,
} from 'moddable-engine/hex-sdk'

listGames()

Returns all registered games with metadata.

const games = listGames()
// [{ key: 'nukes', label: 'nukes', defaultSize: 5, defaultPlayers: 4,
//    orientation: 'pointy', styles: ['artistic','classic','kenney'] }]

generate(game, opts?)

Generate a map. Same seed always produces the same result.

const result = generate('nukes', { size: 4, players: 4, seed: 'abc123' })
// { hexes: [{q, r, type, ...}], annotations: [...], seed, game, size, players }

renderSvg(game, opts?)

Generate and render as SVG in one call. No DOM required.

const { svg, hexes, seed } = renderSvg('twilight', {
  seed: 'galaxy42',
  style: 'classic',
  bgColor: '#0a0d2a'
})
// svg = '<svg ...' (~10-15KB)

getHexInfo(hexes, q, r)

Look up a hex and its neighbours.

const info = getHexInfo(result.hexes, 0, 0)
// { hex: {q, r, type: 'mount'}, neighbours: [...], distance: 0 }

exportGameData(game, opts?)

Generate a map and export in game-specific structured format.

const result = exportGameData('nukes', { size: 4, seed: '12345' })
// { game: 'nukes', format: 'nukes', data: {...}, seed: '12345' }

const result = exportGameData('twilight', { size: 3, seed: '12345' })
// { game: 'twilight', format: 'hex', data: { hexes: [...], seed, size, players } }

editHex(game, hexes, q, r)

Cycle a hex through terrain types (games that support terrain editing).

const hex = editHex('nukes', hexes, 0, 1)
// { q: 0, r: 1, type: 'desert' } — type has been cycled
// Returns null for games without terrain editing or invalid coords

computeFov(hexes, origin, opts?)

Line-of-sight field-of-view from a hex. Blocking terrain creates shadows.

const result = computeFov(hexes, { q: 0, r: 0 }, {
  range: 3,              // max distance (default: 3)
  blocking: ['mountain'] // terrain types that block LOS
})
// { origin, range, blocking, visible: [{q,r,type,distance}], blocked: [...] }

pathfind(hexes, from, to, opts?)

BFS shortest path between two hexes, respecting impassable terrain.

const result = pathfind(hexes, { q: -2, r: 0 }, { q: 2, r: 0 }, {
  impassable: ['mountain', 'water'] // terrain types that cannot be traversed
})
// { reachable: true, from, to, distance: 4, path: [{q,r,type}, ...] }
// { reachable: false, from, to, path: null } — when no path exists

Games

KeyGameSizesStyles
nukesNukes (area control)2–6 ringsartistic, classic, kenney
twilightTwilight Imperium (galactic)3–8 playersartistic, classic
colonyColony (resource/trade)3–4 ringsclassic, kenney, realistic
talismanTalisman (fantasy adventure)3–5 ringsartistic, classic
mongoPlanet Mongo (pulp sci-fi)Fixed layoutartistic
endlessEndless Skies (exploration)Fixed layoutartistic

HexMath

Axial coordinate utilities for hex grids.

import { HexMath } from 'moddable-engine/hex-sdk'

HexMath.getNeighbors(q, r)       // [{q, r}] — 6 adjacent hexes
HexMath.axialDistance(a, b)      // integer distance between two {q, r} points
HexMath.hexRing(center, radius)  // all hexes at exactly N distance
HexMath.hexSpiral(center, radius) // all hexes within N distance

HexSvg

Low-level SVG renderer with tile images, labels, and overlays.

import { HexSvg } from 'moddable-engine/hex-sdk'

const svg = HexSvg.toSVG(hexes, {
  size: 30,
  orientation: 'pointy',    // or 'flat'
  bgColor: '#1a1a2e',
  colors: { mount: '#4a3728', plains: '#3d6b35' }
})

// With annotations (highlights, tokens, arrows, legend)
const svg = HexSvg.toAnnotatedSVG(hexes, annotations, opts)

Tile API

Tile set metadata available at /api/tiles/index.json.

const res = await fetch('https://engine.moddable.games/api/tiles/index.json')
const data = await res.json()
// { sets: [{ id, label, game, tileCount, path }] }

8 tile sets: nukes, nukes-kenney, talisman, talisman-kenney, colony, mongo, endless, twilight.