Docs / Guides / SVG Integration

SVG Integration Guide

Export hex maps as clean SVG for use in documentation, PDFs, rulebooks, or other web projects. Two approaches: postMessage from an iframe embed, or direct JavaScript API in the same page.

Overview

The hexmaps engine can produce standalone SVG output from any generated map. SVGs are resolution-independent and work well in print/PDF contexts where Canvas output would pixelate.

Choose your approach based on context:

  • UI button — one-click download from the generator interface
  • postMessage — request SVG from an embedded iframe (cross-origin safe)
  • Direct API — generate SVG programmatically in the same page

Quick Export (UI Button)

The generator interface includes an "Export SVG" button in the sidebar (Random tab). Clicking it downloads the current map as an SVG file named {game}-{size}r-{seed}.svg.

This produces SVG with linked image references (relative paths to img/tiles/). The SVG is self-contained for colour-only styles (classic) but requires the tile images to be accessible at the referenced paths for image styles.

postMessage Export (iframe Integration)

Embed the generator in a hidden iframe and request SVG via the postMessage bridge. This is the recommended approach for external projects that need reproducible map output.

var iframe = document.createElement('iframe');
iframe.src = 'https://hex.moddable.games/generate/?game=talisman&size=4&seed=42&style=artistic&boardonly=1';
iframe.style.display = 'none';
document.body.appendChild(iframe);

iframe.onload = function() {
    iframe.contentWindow.postMessage({ type: 'hexmap:exportSvg' }, '*');
};

window.addEventListener('message', function(event) {
    if (event.data.type === 'hexmap:svgData') {
        document.getElementById('map-container').innerHTML = event.data.svg;
    }
});

The boardonly=1 parameter hides the UI chrome, reducing iframe load time. The seed ensures the same map is generated every time.

Available postMessage commands:

SendReceivePurpose
hexmap:exportSvghexmap:svgDataGet full SVG markup
hexmap:getMaphexmap:mapDataGet hex data as JSON
hexmap:regenerateGenerate new random map
hexmap:setStyleChange visual style
hexmap:setGameSwitch active game

Direct API (Same-Page Usage)

Import the engine modules and call HexSvg.toSVG() directly. This avoids the iframe overhead and gives full control over options.

<script type="module">
import { getGameConfig } from './js/game-registry.js';
import { HexSvg } from './js/hex-svg.js';
import './js/games/talisman.js';

var config = getGameConfig('talisman');
var hexes = config.generate(4, 0, '42');
var svg = HexSvg.toSVG(hexes, {
    hexSize: 40,
    flat: false,
    colors: config.getColors(),
    images: config.getImages('artistic'),
    imageMode: 'link',
    labels: true,
    padding: 15
});
document.getElementById('output').innerHTML = svg;
</script>

The module system handles all dependencies automatically. You only need to import what you use directly.

Annotated SVG (Tactical Diagrams)

Use HexSvg.toAnnotatedSVG() to add move highlights, player tokens, directional arrows, and legends on top of a base map. Useful for rulebooks and strategy guides.

var annotations = {
    highlights: [
        { q: 0, r: 1, style: 'valid' },
        { q: 1, r: -1, style: 'blocked' },
        { q: -1, r: 0, style: 'selected' }
    ],
    tokens: [
        { q: 0, r: 0, color: '#1c4a4a', label: 'P1', stroke: '#fff' }
    ],
    arrows: [
        { from: { q: 0, r: 0 }, to: { q: 1, r: 0 }, color: '#2aaa10', style: 'solid' }
    ],
    legend: [
        { style: 'valid', text: 'Legal move' },
        { style: 'blocked', text: 'Blocked' }
    ]
};

var svg = HexSvg.toAnnotatedSVG(hexes, annotations, {
    hexSize: 40,
    flat: false,
    colors: config.getColors()
});

Available highlight styles:

StyleAppearance
validGreen hex border
blockedRed X through hex
selectedGold hex border
friendlyGold hex border (alias)

Image Modes

The imageMode option controls how tile artwork is referenced in the SVG output:

ModeOutputUse when
'none'Flat colour polygons onlySmallest file size, works everywhere, no external dependencies
'link'<image href="img/tiles/...">SVG will be served from same origin as tile images
'embed'Inline data URIsSelf-contained SVG, works offline, larger file size

For most web use, 'link' keeps file sizes small. For PDF generation or offline contexts, use 'embed' so the SVG is fully self-contained.

Moddable Rules Integration Pattern

The Talisman Worlds rulebook project uses this workflow to produce reproducible map illustrations:

  1. Hidden iframe loads the hexmaps generator with a specific seed and style
  2. postMessage requests SVG export once the iframe loads
  3. SVG markup is inserted into the rulebook page at the designated container
  4. Puppeteer renders the full page (including SVG maps) to PDF

This gives map illustrations that automatically update when the generator improves. No manual re-export needed. The seed guarantees the same board layout every time.

// In the rulebook page
var maps = document.querySelectorAll('[data-hexmap]');
maps.forEach(function(container) {
    var iframe = document.createElement('iframe');
    iframe.src = container.dataset.hexmap + '&boardonly=1';
    iframe.style.display = 'none';
    document.body.appendChild(iframe);

    iframe.onload = function() {
        iframe.contentWindow.postMessage({ type: 'hexmap:exportSvg' }, '*');
    };

    window.addEventListener('message', function handler(event) {
        if (event.data.type === 'hexmap:svgData' && event.source === iframe.contentWindow) {
            container.innerHTML = event.data.svg;
            iframe.remove();
            window.removeEventListener('message', handler);
        }
    });
});

Usage in HTML:

<div data-hexmap="https://hex.moddable.games/generate/?game=talisman&size=4&seed=rulebook-map-1&style=artistic"></div>

Options Reference

OptionDefaultDescription
hexSize30Radius of each hex in SVG units
flatfalseFlat-top (true) or pointy-top (false) orientation
colors{}Map of terrain type → fill colour
imagesnullMap of terrain type → image path/URI
imageMode'none''none', 'link', or 'embed'
strokeColor'rgba(0,0,0,0.3)'Hex border colour
strokeWidth1Hex border width
labelsfalseShow hex labels
padding15Padding around the map in SVG units
bgColornullBackground colour (null = transparent)
scaleFactor0.95Hex polygon scale (gap between hexes)