Skip to content

Card Generator — Usage


CLI Reference

python tools/card_generator/generate_cards.py \
  --cards-json PATH \
  [--art-dir PATH] \
  [--output-dir PATH] \
  [--template PATH] \
  [--config PATH] \
  [--dpi N] \
  [--decks DECK ...] \
  [--card-ids ID ...] \
  [--svg-only] \
  [--verbose]
Flag Default Description
--cards-json (required) Path to cards_v03.json
--art-dir none Directory with artwork images named <card_id>.<ext>
--output-dir tools/card_generator/output/ Where to write generated files
--template templates/card_template.svg SVG template path
--config templates/faction_config.json Faction colour/symbol configuration
--dpi 150 Output DPI (300 for commercial print)
--decks all Filter: warrior temple merchant stranger event forest
--card-ids all Generate specific card IDs only
--svg-only false Output SVG instead of PNG
--verbose / -v false Debug logging

Examples

# All decks, default 150 DPI, PNG
python tools/card_generator/generate_cards.py --cards-json cards/cards_v03.json

# Print-ready at 300 DPI
python tools/card_generator/generate_cards.py \
  --cards-json cards/cards_v03.json --dpi 300 --output-dir ./print_ready

# Only warrior and temple decks
python tools/card_generator/generate_cards.py \
  --cards-json cards/cards_v03.json --decks warrior temple

# Single card, SVG for Inkscape inspection
python tools/card_generator/generate_cards.py \
  --cards-json cards/cards_v03.json --card-ids temple_001 --svg-only

# With custom artwork
python tools/card_generator/generate_cards.py \
  --cards-json cards/cards_v03.json --art-dir ./my_art --dpi 300

svg_builder.py Internals

Load and Clone

The template SVG is parsed once (load_template), then deep-copied for each card to avoid cross-contamination. Elements are located by XML id attribute using XPath (//*[@id="..."]).

Element Operations

Operation Function Used For
Set text _set_text() Title, badge, metadata, action type
Set attribute _set_attr() Badge width, accent colours
Remove element _remove() Placeholder text, template stat boxes
Multi-line tspan _set_multiline() Rules text, flavour text, BDPD mapping
Embed image _embed_image() Base64-encoded PNG artwork
Build stat boxes _add_stat_boxes() Dynamically-generated HARVEST/HEALTH/etc.

Text Wrapping

Rules text is wrapped at 32 characters per line; flavour text at 46 characters. Both use word-boundary splitting, rendered as <tspan> elements inside the parent <text> node with configurable dy offset.

Stat Box Layout

Up to 3 stat boxes are placed in the horizontal band at x=50..310, y=650. Layout adapts to 1, 2, or 3 boxes:

# Stats Width Spacing
1 260 px Centred
2 128 px each x=50, x=178
3 88 px each x=50, x=138, x=226

Stats are extracted from card effects: HARVEST (always first), HEALTH (+/−), CAPACITY, PATIENCE, RENEWAL, STOCKPILE, TITHE.

Artwork Embedding

Artwork images are cropped to 16:9 aspect ratio, resized to fit the art box (650 × 365 px area), encoded as base64 PNG, and embedded via a <image> element with clip-path="url(#art-clip)". The placeholder text (text13) is removed when art is present.


rasterizer.py Internals

Uses cairosvg for SVG→PNG conversion. The template is authored at 96 DPI (Inkscape default); cairosvg scale is computed as target_dpi / 96.

Target DPI Scale Factor Output Size (approx)
150 1.5625 1172 × 1641 px
300 3.125 2344 × 3281 px

The unsafe=True flag is required to allow data: URIs for embedded base64 artwork images.


Template Variables Reference

The SVG template targets these element IDs. Custom templates can use any subset — missing elements are silently ignored.

text7   →  card ID + version metadata
text9   →  card title (UPPERCASE)
text10  →  deck badge label
rect9   →  badge border (stroke colour, width)
rect15  →  faction accent bar (fill colour)
text15  →  action type line
rect16, text16, text17          →  stat box 1 (removed and rebuilt)
rect16-6, text16-7, text17-5   →  stat box 2 (removed and rebuilt)
text13  →  artwork placeholder (removed if art present)
rect13  →  artwork frame border (preserved)
text21  →  rules text (tspan, max 32 chars/line)
text23  →  flavour text (tspan, max 46 chars/line)
text24  →  flavour source attribution
text26  →  BDPD mapping text (tspan, max 95 chars/line)

Card Data Format

Each card in cards_v03.json has:

{
  "id": "warrior_001",
  "name": "Cedar of Uruk",
  "deck": "warrior",
  "type": "harvest",
  "count": 3,
  "harvest_value": 2,
  "flavor": "...",
  "effects": [
    { "action": "harvest", "amount": 2 },
    { "action": "modify_forest_health", "delta": -1 }
  ],
  "seneca_clip_trigger": true,
  "bdpd_mapping": "Aggressive harvest exceeding sustainable rate...",
  "visual_prompt": "Assyrian bas-relief style..."
}

Dual-mode cards have "type": "dual_mode" with "coop" and "aggr" sub-objects, each with their own effects and flavor fields.