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.