diff --git a/asset-library/stormbringer-1e/stormbringer_reference.html b/asset-library/stormbringer-1e/stormbringer_reference.html index a5450f9..d276445 100644 --- a/asset-library/stormbringer-1e/stormbringer_reference.html +++ b/asset-library/stormbringer-1e/stormbringer_reference.html @@ -297,6 +297,76 @@ td:first-child { color: var(--cream); } section { padding: 18px 18px 8px; } .page-title { padding: 20px 18px 14px; } } + +/* ── ART GALLERY ── */ +.gallery-category { margin-bottom: 2.5rem; } +.gallery-category h3 { color: var(--gold); margin-bottom: 1rem; border-bottom: 1px solid var(--border); padding-bottom: 6px; } +.gallery-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 16px; +} +.gallery-item { + background: var(--panel-bg); + border: 1px solid var(--border); + border-radius: 4px; + overflow: hidden; + cursor: pointer; + transition: border-color 0.2s, transform 0.2s; +} +.gallery-item:hover { border-color: var(--gold-dim); transform: translateY(-2px); } +.gallery-item img { + width: 100%; + height: 180px; + object-fit: cover; + display: block; +} +.gallery-item.portrait img { height: 240px; } +.gallery-caption { + padding: 8px 10px; + font-size: 0.8rem; + color: var(--cream-dim); + font-style: italic; +} +/* Lightbox */ +#lightbox { + display: none; + position: fixed; + inset: 0; + background: rgba(0,0,0,0.92); + z-index: 1000; + align-items: center; + justify-content: center; + flex-direction: column; + gap: 12px; +} +#lightbox.open { display: flex; } +#lightbox img { + max-width: 90vw; + max-height: 80vh; + object-fit: contain; + border: 1px solid var(--border); + border-radius: 4px; +} +#lightbox-caption { + color: var(--cream); + font-size: 0.9rem; + font-style: italic; + text-align: center; +} +#lightbox-close { + position: absolute; + top: 16px; + right: 24px; + color: var(--cream-dim); + font-size: 2rem; + cursor: pointer; + line-height: 1; + background: none; + border: none; +} +#lightbox-close:hover { color: var(--gold); } + @@ -1266,6 +1336,217 @@ Effective maximum: 99 + + + + + diff --git a/scenarios/art/stormbringer/dalle_generate.py b/scenarios/art/stormbringer/dalle_generate.py new file mode 100644 index 0000000..6455773 --- /dev/null +++ b/scenarios/art/stormbringer/dalle_generate.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 +""" +DALL-E 3 image generator for the Stormbringer MJ bridge queue. + +Reads queued prompts from the mj_bridge queue.jsonl, generates images via +DALL-E 3, downloads them into the asset library, and marks jobs as done. + +Usage: + python3 scripts/dalle_generate.py --api-key sk-... + python3 scripts/dalle_generate.py --api-key sk-... --limit 5 + python3 scripts/dalle_generate.py --api-key sk-... --quality hd + python3 scripts/dalle_generate.py --api-key sk-... --dry-run +""" + +from __future__ import annotations + +import argparse +import json +import os +import re +import sys +import time +import urllib.request +from dataclasses import dataclass +from datetime import datetime, timezone +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +DEFAULT_QUEUE = REPO_ROOT / "output" / "assets" / "midjourney" / "queue.jsonl" +DEFAULT_LIBRARY = REPO_ROOT / "output" / "assets" / "midjourney" +DEFAULT_PROJECT = "Stormbringer" + + +# ── Aspect ratio → DALL-E 3 size mapping ───────────────────────────────────── + +AR_TO_SIZE: dict[str, str] = { + "1:1": "1024x1024", + "2:3": "1024x1792", + "3:4": "1024x1792", + "9:16": "1024x1792", + "16:9": "1792x1024", + "3:2": "1792x1024", + "2:1": "1792x1024", +} +DEFAULT_SIZE = "1792x1024" + + +def extract_ar(params: str) -> str: + """Pull --ar value from a Midjourney param string and return DALL-E size.""" + match = re.search(r"--ar\s+(\d+:\d+)", params or "") + if match: + return AR_TO_SIZE.get(match.group(1), DEFAULT_SIZE) + return DEFAULT_SIZE + + +def clean_prompt(prompt: str) -> str: + """Strip Midjourney-specific flags that DALL-E doesn't understand.""" + cleaned = re.sub(r"--(?:ar|v|style|no|chaos|weird|tile|q|s|seed)\s*\S*", "", prompt) + cleaned = re.sub(r"\s{2,}", " ", cleaned).strip().rstrip(",") + return cleaned + + +# ── Queue I/O ───────────────────────────────────────────────────────────────── + +def read_queue(path: Path) -> list[dict]: + if not path.exists(): + return [] + jobs = [] + with path.open("r", encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if line: + jobs.append(json.loads(line)) + return jobs + + +def write_queue(path: Path, jobs: list[dict]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", encoding="utf-8") as fh: + for job in jobs: + fh.write(json.dumps(job, ensure_ascii=True, sort_keys=True) + "\n") + + +def append_index(library: Path, metadata: dict) -> None: + index = library / "index.jsonl" + index.parent.mkdir(parents=True, exist_ok=True) + with index.open("a", encoding="utf-8") as fh: + fh.write(json.dumps(metadata, ensure_ascii=True, sort_keys=True) + "\n") + + +# ── DALL-E 3 API call ───────────────────────────────────────────────────────── + +# Size mapping for gpt-image-2 +GI2_SIZE_MAP: dict[str, str] = { + "1024x1024": "1024x1024", + "1024x1792": "1024x1536", # portrait + "1792x1024": "1536x1024", # landscape +} + + +def generate_image( + api_key: str, + prompt: str, + size: str = "1792x1024", + quality: str = "standard", +) -> bytes: + """Call gpt-image-2 and return raw PNG bytes.""" + # Map legacy DALL-E sizes to gpt-image-2 sizes + gi2_size = GI2_SIZE_MAP.get(size, "1536x1024") + # Map quality: standard→medium, hd→high + gi2_quality = "high" if quality == "hd" else "medium" + + payload = json.dumps({ + "model": "gpt-image-2", + "prompt": prompt, + "n": 1, + "size": gi2_size, + "quality": gi2_quality, + "output_format": "png", + }).encode("utf-8") + + req = urllib.request.Request( + "https://api.openai.com/v1/images/generations", + data=payload, + headers={ + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + }, + method="POST", + ) + + try: + with urllib.request.urlopen(req, timeout=180) as resp: + body = json.loads(resp.read().decode("utf-8")) + except urllib.error.HTTPError as exc: + error_body = exc.read().decode("utf-8", errors="replace") + raise RuntimeError(f"OpenAI API error {exc.code}: {error_body}") from exc + + import base64 + b64 = body["data"][0]["b64_json"] + return base64.b64decode(b64) + + +def download_image(image_bytes: bytes, dest: Path) -> None: + """Write image bytes to dest.""" + dest.parent.mkdir(parents=True, exist_ok=True) + dest.write_bytes(image_bytes) + + +# ── Slug / filename helpers ─────────────────────────────────────────────────── + +def slugify(value: str, max_len: int = 60) -> str: + slug = re.sub(r"[^a-zA-Z0-9]+", "-", value.lower()).strip("-") + return slug[:max_len] or "image" + + +def utc_stamp() -> str: + return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + +def compact_stamp() -> str: + return datetime.now().strftime("%Y%m%d_%H%M%S") + + +# ── Main generation loop ────────────────────────────────────────────────────── + +def run(args: argparse.Namespace) -> int: + jobs = read_queue(args.queue) + queued = [j for j in jobs if j.get("status") == "queued" + and j.get("project", DEFAULT_PROJECT) == args.project] + + if not queued: + print("No queued prompts found for project:", args.project) + return 0 + + limit = args.limit if args.limit else len(queued) + to_process = queued[:limit] + + project_dir = args.library / slugify(args.project) + project_dir.mkdir(parents=True, exist_ok=True) + + print(f"Generating {len(to_process)} image(s) via DALL-E 3 " + f"[quality={args.quality}]") + print(f"Output → {project_dir}\n") + + job_index = {j["id"]: j for j in jobs} + generated = 0 + failed = 0 + + for job in to_process: + notes = job.get("notes", "") + raw_prompt = job.get("prompt", "") + params = job.get("midjourney_params", "") + size = extract_ar(params) + prompt = clean_prompt(raw_prompt) + + label = notes or job["id"] + print(f"[{generated + 1}/{len(to_process)}] {label}") + print(f" size={size} prompt={prompt[:80]}…") + + if args.dry_run: + print(" [dry-run — skipped]\n") + continue + + try: + image_bytes = generate_image(args.api_key, prompt, size=size, quality=args.quality) + + filename = f"{compact_stamp()}_{slugify(notes or job['id'], 50)}.png" + dest = project_dir / filename + download_image(image_bytes, dest) + + sidecar = { + "id": f"asset_{dest.stem}", + "generated_at": utc_stamp(), + "prompt_id": job["id"], + "prompt": prompt, + "raw_mj_prompt": raw_prompt, + "asset_path": str(dest), + "project": args.project, + "notes": notes, + "model": "gpt-image-2", + "size": size, + "quality": args.quality, + + } + sidecar_path = dest.with_suffix(".json") + sidecar_path.write_text( + json.dumps(sidecar, indent=2, ensure_ascii=True, sort_keys=True), + encoding="utf-8", + ) + append_index(args.library, sidecar) + + job_index[job["id"]]["status"] = "done" + job_index[job["id"]]["asset_path"] = str(dest) + job_index[job["id"]]["generated_at"] = utc_stamp() + + print(f" ✓ saved → {dest.name}\n") + generated += 1 + + except Exception as exc: + print(f" ✗ FAILED: {exc}\n", file=sys.stderr) + job_index[job["id"]]["status"] = "error" + job_index[job["id"]]["error"] = str(exc) + failed += 1 + + # Brief pause to stay inside OpenAI rate limits + if generated < len(to_process): + time.sleep(args.delay) + + write_queue(args.queue, list(job_index.values())) + + print(f"Done — {generated} generated, {failed} failed.") + if failed: + print("Failed jobs have status='error' in the queue. Re-run to retry.") + return 0 if failed == 0 else 1 + + +# ── CLI ─────────────────────────────────────────────────────────────────────── + +def build_parser() -> argparse.ArgumentParser: + p = argparse.ArgumentParser( + description="Generate queued Stormbringer prompts via DALL-E 3." + ) + p.add_argument( + "--api-key", + default=os.environ.get("OPENAI_API_KEY", ""), + help="OpenAI API key (or set OPENAI_API_KEY env var).", + ) + p.add_argument("--queue", type=Path, default=DEFAULT_QUEUE) + p.add_argument("--library", type=Path, default=DEFAULT_LIBRARY) + p.add_argument("--project", default=DEFAULT_PROJECT) + p.add_argument("--quality", choices=["standard", "hd"], default="hd", + help="DALL-E 3 quality tier (default: hd).") + p.add_argument("--limit", type=int, default=0, + help="Max images to generate (0 = all queued).") + p.add_argument("--delay", type=float, default=3.0, + help="Seconds between API calls (default: 3).") + p.add_argument("--dry-run", action="store_true", + help="Print what would be generated without calling the API.") + return p + + +def main(argv: list[str] | None = None) -> int: + args = build_parser().parse_args(argv) + if not args.api_key and not args.dry_run: + print("Error: provide --api-key or set OPENAI_API_KEY.", file=sys.stderr) + return 2 + return run(args) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scenarios/art/stormbringer/sb-c01-elric-portrait.png b/scenarios/art/stormbringer/sb-c01-elric-portrait.png new file mode 100644 index 0000000..10abe79 Binary files /dev/null and b/scenarios/art/stormbringer/sb-c01-elric-portrait.png differ diff --git a/scenarios/art/stormbringer/sb-c02-elric-action.png b/scenarios/art/stormbringer/sb-c02-elric-action.png new file mode 100644 index 0000000..fbee0ba Binary files /dev/null and b/scenarios/art/stormbringer/sb-c02-elric-action.png differ diff --git a/scenarios/art/stormbringer/sb-c03-moonglum.png b/scenarios/art/stormbringer/sb-c03-moonglum.png new file mode 100644 index 0000000..66f4a43 Binary files /dev/null and b/scenarios/art/stormbringer/sb-c03-moonglum.png differ diff --git a/scenarios/art/stormbringer/sb-c04-melnibonean-noble.png b/scenarios/art/stormbringer/sb-c04-melnibonean-noble.png new file mode 100644 index 0000000..1d5414c Binary files /dev/null and b/scenarios/art/stormbringer/sb-c04-melnibonean-noble.png differ diff --git a/scenarios/art/stormbringer/sb-c05-pan-tang-chaos-knight.png b/scenarios/art/stormbringer/sb-c05-pan-tang-chaos-knight.png new file mode 100644 index 0000000..3bf78db Binary files /dev/null and b/scenarios/art/stormbringer/sb-c05-pan-tang-chaos-knight.png differ diff --git a/scenarios/art/stormbringer/sb-c06-sorcerer.png b/scenarios/art/stormbringer/sb-c06-sorcerer.png new file mode 100644 index 0000000..5a20e8f Binary files /dev/null and b/scenarios/art/stormbringer/sb-c06-sorcerer.png differ diff --git a/scenarios/art/stormbringer/sb-c07-tarkeshite-captain.png b/scenarios/art/stormbringer/sb-c07-tarkeshite-captain.png new file mode 100644 index 0000000..62e9e54 Binary files /dev/null and b/scenarios/art/stormbringer/sb-c07-tarkeshite-captain.png differ diff --git a/scenarios/art/stormbringer/sb-c08-beggar-of-nadsokor.png b/scenarios/art/stormbringer/sb-c08-beggar-of-nadsokor.png new file mode 100644 index 0000000..331cf25 Binary files /dev/null and b/scenarios/art/stormbringer/sb-c08-beggar-of-nadsokor.png differ diff --git a/scenarios/art/stormbringer/sb-cr01-cave-bear.png b/scenarios/art/stormbringer/sb-cr01-cave-bear.png new file mode 100644 index 0000000..e51f197 Binary files /dev/null and b/scenarios/art/stormbringer/sb-cr01-cave-bear.png differ diff --git a/scenarios/art/stormbringer/sb-cr02-tiger-pan-tang.png b/scenarios/art/stormbringer/sb-cr02-tiger-pan-tang.png new file mode 100644 index 0000000..575b9f2 Binary files /dev/null and b/scenarios/art/stormbringer/sb-cr02-tiger-pan-tang.png differ diff --git a/scenarios/art/stormbringer/sb-cr03-gorilla.png b/scenarios/art/stormbringer/sb-cr03-gorilla.png new file mode 100644 index 0000000..2a6d115 Binary files /dev/null and b/scenarios/art/stormbringer/sb-cr03-gorilla.png differ diff --git a/scenarios/art/stormbringer/sb-cr04-baboon-troop.png b/scenarios/art/stormbringer/sb-cr04-baboon-troop.png new file mode 100644 index 0000000..4b2444b Binary files /dev/null and b/scenarios/art/stormbringer/sb-cr04-baboon-troop.png differ diff --git a/scenarios/art/stormbringer/sb-cr05-falcon.png b/scenarios/art/stormbringer/sb-cr05-falcon.png new file mode 100644 index 0000000..305474e Binary files /dev/null and b/scenarios/art/stormbringer/sb-cr05-falcon.png differ diff --git a/scenarios/art/stormbringer/sb-cr06-chaos-creature.png b/scenarios/art/stormbringer/sb-cr06-chaos-creature.png new file mode 100644 index 0000000..001648a Binary files /dev/null and b/scenarios/art/stormbringer/sb-cr06-chaos-creature.png differ diff --git a/scenarios/art/stormbringer/sb-d01-demon-weapon.png b/scenarios/art/stormbringer/sb-d01-demon-weapon.png new file mode 100644 index 0000000..36d070c Binary files /dev/null and b/scenarios/art/stormbringer/sb-d01-demon-weapon.png differ diff --git a/scenarios/art/stormbringer/sb-d02-combat-demon.png b/scenarios/art/stormbringer/sb-d02-combat-demon.png new file mode 100644 index 0000000..0606057 Binary files /dev/null and b/scenarios/art/stormbringer/sb-d02-combat-demon.png differ diff --git a/scenarios/art/stormbringer/sb-d03-intellect-demon.png b/scenarios/art/stormbringer/sb-d03-intellect-demon.png new file mode 100644 index 0000000..4e2a7d9 Binary files /dev/null and b/scenarios/art/stormbringer/sb-d03-intellect-demon.png differ diff --git a/scenarios/art/stormbringer/sb-d04-beast-demon.png b/scenarios/art/stormbringer/sb-d04-beast-demon.png new file mode 100644 index 0000000..fe43b3f Binary files /dev/null and b/scenarios/art/stormbringer/sb-d04-beast-demon.png differ diff --git a/scenarios/art/stormbringer/sb-d05-guardian-demon.png b/scenarios/art/stormbringer/sb-d05-guardian-demon.png new file mode 100644 index 0000000..167e344 Binary files /dev/null and b/scenarios/art/stormbringer/sb-d05-guardian-demon.png differ diff --git a/scenarios/art/stormbringer/sb-e01-straasha.png b/scenarios/art/stormbringer/sb-e01-straasha.png new file mode 100644 index 0000000..3912ad9 Binary files /dev/null and b/scenarios/art/stormbringer/sb-e01-straasha.png differ diff --git a/scenarios/art/stormbringer/sb-e02-grome.png b/scenarios/art/stormbringer/sb-e02-grome.png new file mode 100644 index 0000000..9735d44 Binary files /dev/null and b/scenarios/art/stormbringer/sb-e02-grome.png differ diff --git a/scenarios/art/stormbringer/sb-e03-lassa.png b/scenarios/art/stormbringer/sb-e03-lassa.png new file mode 100644 index 0000000..8bd1cf4 Binary files /dev/null and b/scenarios/art/stormbringer/sb-e03-lassa.png differ diff --git a/scenarios/art/stormbringer/sb-e04-fire-elemental.png b/scenarios/art/stormbringer/sb-e04-fire-elemental.png new file mode 100644 index 0000000..d2d6cee Binary files /dev/null and b/scenarios/art/stormbringer/sb-e04-fire-elemental.png differ diff --git a/scenarios/art/stormbringer/sb-i01-stormbringer-sword.png b/scenarios/art/stormbringer/sb-i01-stormbringer-sword.png new file mode 100644 index 0000000..a0fba3f Binary files /dev/null and b/scenarios/art/stormbringer/sb-i01-stormbringer-sword.png differ diff --git a/scenarios/art/stormbringer/sb-i02-broadsword.png b/scenarios/art/stormbringer/sb-i02-broadsword.png new file mode 100644 index 0000000..0c15f4e Binary files /dev/null and b/scenarios/art/stormbringer/sb-i02-broadsword.png differ diff --git a/scenarios/art/stormbringer/sb-i03-lormyrian-axe.png b/scenarios/art/stormbringer/sb-i03-lormyrian-axe.png new file mode 100644 index 0000000..2cc2d3c Binary files /dev/null and b/scenarios/art/stormbringer/sb-i03-lormyrian-axe.png differ diff --git a/scenarios/art/stormbringer/sb-i04-grimoire.png b/scenarios/art/stormbringer/sb-i04-grimoire.png new file mode 100644 index 0000000..cc6fcc3 Binary files /dev/null and b/scenarios/art/stormbringer/sb-i04-grimoire.png differ diff --git a/scenarios/art/stormbringer/sb-i05-armour.png b/scenarios/art/stormbringer/sb-i05-armour.png new file mode 100644 index 0000000..5a8cabd Binary files /dev/null and b/scenarios/art/stormbringer/sb-i05-armour.png differ diff --git a/scenarios/art/stormbringer/sb-l01-imrryr.png b/scenarios/art/stormbringer/sb-l01-imrryr.png new file mode 100644 index 0000000..42a8f08 Binary files /dev/null and b/scenarios/art/stormbringer/sb-l01-imrryr.png differ diff --git a/scenarios/art/stormbringer/sb-l02-karlaak.png b/scenarios/art/stormbringer/sb-l02-karlaak.png new file mode 100644 index 0000000..4587b8b Binary files /dev/null and b/scenarios/art/stormbringer/sb-l02-karlaak.png differ diff --git a/scenarios/art/stormbringer/sb-l03-pan-tang.png b/scenarios/art/stormbringer/sb-l03-pan-tang.png new file mode 100644 index 0000000..4d884ac Binary files /dev/null and b/scenarios/art/stormbringer/sb-l03-pan-tang.png differ diff --git a/scenarios/art/stormbringer/sb-l04-nadsokor.png b/scenarios/art/stormbringer/sb-l04-nadsokor.png new file mode 100644 index 0000000..87a1927 Binary files /dev/null and b/scenarios/art/stormbringer/sb-l04-nadsokor.png differ diff --git a/scenarios/art/stormbringer/sb-l05-map.png b/scenarios/art/stormbringer/sb-l05-map.png new file mode 100644 index 0000000..ba94be4 Binary files /dev/null and b/scenarios/art/stormbringer/sb-l05-map.png differ diff --git a/scenarios/art/stormbringer/sb-l06-boiling-sea.png b/scenarios/art/stormbringer/sb-l06-boiling-sea.png new file mode 100644 index 0000000..5a79b56 Binary files /dev/null and b/scenarios/art/stormbringer/sb-l06-boiling-sea.png differ diff --git a/scenarios/art/stormbringer/sb-l07-tavern.png b/scenarios/art/stormbringer/sb-l07-tavern.png new file mode 100644 index 0000000..6fa27e9 Binary files /dev/null and b/scenarios/art/stormbringer/sb-l07-tavern.png differ diff --git a/scenarios/art/stormbringer/sb-l08-demon-realm.png b/scenarios/art/stormbringer/sb-l08-demon-realm.png new file mode 100644 index 0000000..94f7e56 Binary files /dev/null and b/scenarios/art/stormbringer/sb-l08-demon-realm.png differ diff --git a/scenarios/art/stormbringer/sb-r01-church-of-law.png b/scenarios/art/stormbringer/sb-r01-church-of-law.png new file mode 100644 index 0000000..d00f64a Binary files /dev/null and b/scenarios/art/stormbringer/sb-r01-church-of-law.png differ diff --git a/scenarios/art/stormbringer/sb-r02-chaos-cult.png b/scenarios/art/stormbringer/sb-r02-chaos-cult.png new file mode 100644 index 0000000..3082b8e Binary files /dev/null and b/scenarios/art/stormbringer/sb-r02-chaos-cult.png differ diff --git a/scenarios/art/stormbringer/sb-r03-the-balance.png b/scenarios/art/stormbringer/sb-r03-the-balance.png new file mode 100644 index 0000000..1426a0c Binary files /dev/null and b/scenarios/art/stormbringer/sb-r03-the-balance.png differ diff --git a/scenarios/art/stormbringer/stormbringer-art-prompts.md b/scenarios/art/stormbringer/stormbringer-art-prompts.md new file mode 100644 index 0000000..b4aa96e --- /dev/null +++ b/scenarios/art/stormbringer/stormbringer-art-prompts.md @@ -0,0 +1,487 @@ +# Midjourney Prompts — Stormbringer RPG (French Oriflam 1984 / Young Kingdoms) + +Dark sword and sorcery. Michael Moorcock's Young Kingdoms: a world of decaying empire, ancient pacts with demons, and the eternal struggle of Law versus Chaos. Art direction: 1970s–80s fantasy illustration — Michael Whelan, Chris Achilleos, John Blanche. Rich jewel tones bleeding into deep shadow. Ornate detail. Decay under beauty. + +**Global style anchor (add to any prompt):** +`Stormbringer RPG Young Kingdoms dark fantasy illustration, 1970s sword and sorcery art, rich jewel tones and deep shadow, decadent ancient empire, Michael Whelan style painterly, occult atmosphere` + +--- + +## LOCATIONS + +**SB-L01 — Melniboné / Imrryr, the Dreaming City (Ruined)** +``` +The Dreaming City of Imrryr Melniboné in ruins, Dragon Isle, vast towers of +iridescent dragon jade and bone-white stone crumbling into the sea, a decadent +empire ten thousand years old in its final decay, impossible architecture, the +pink dawn light on shattered spires, ruins that were once more beautiful than +anything the Young Kingdoms ever built, distant dragon shapes in smoky sky, +Stormbringer Young Kingdoms dark fantasy illustration, Michael Whelan painterly +style, jewel tones and ruin, 1970s sword and sorcery atmosphere +--ar 16:9 --v 6.1 --style raw +``` + +**SB-L02 — Karlaak by the Weeping Waste** +``` +Karlaak city on the edge of the Weeping Waste, a city of white-walled merchant +towers and hanging gardens bordering a vast grey desolate plain, the contrast +between the city's warm light and the cold wasted land beyond, the most cosmopolitan +city of the Young Kingdoms, caravans on the road, a young albino lord visible at +the gate, Stormbringer Young Kingdoms fantasy illustration, jewel tones against +pale desert, 1970s sword and sorcery painterly +--ar 16:9 --v 6.1 --style raw +``` + +**SB-L03 — Pan Tang, Isle of the Sorcerer Kings** +``` +Pan Tang island fortress city, black volcanic rock and bone-white towers, a theocracy +of Chaos worshippers, tiger-riders on the battlements, demon-bound architecture +that writhes slightly in the eye's peripheral vision, the sea around it stained +dark, smoke from the eternal ritual fires, Stormbringer Young Kingdoms dark fantasy +illustration, sinister beauty, 1970s sword and sorcery +--ar 16:9 --v 6.1 --style raw +``` + +**SB-L04 — Nadsokor, the City of Beggars** +``` +Nadsokor the City of Beggars, a vast ruin-city inhabited entirely by the outcast +and diseased, crumbling towers packed with the desperate, open fires in the streets, +a mad beggar king on a throne of refuse, the smell of disease and desperation +implied in every surface, one of the Young Kingdoms' most wretched places, +Stormbringer dark fantasy illustration, 1970s sword and sorcery, muted palette +of ash and rust +--ar 16:9 --v 6.1 --style raw +``` + +**SB-L05 — The Young Kingdoms Map Illustration** +``` +Fantasy map of the Young Kingdoms, cartographic illustration in the style of a +1970s fantasy sourcebook, showing the continents including Melniboné the Dragon +Isle, the Young Kingdoms mainlands, the Boiling Sea, the Desert of Sighs the +Desert of Tears, Pan Tang, compass rose, sea monsters in the margins, aged +parchment texture, hand-lettered place names, Stormbringer RPG sourcebook art +--ar 3:2 --v 6.1 --style raw +``` + +**SB-L06 — The Boiling Sea** +``` +The Boiling Sea, a vast ocean of superheated water with scalding mist rising in +columns, strange shapes visible below the surface, a small merchant vessel pushing +through the steam, the impossibility of the geography made physical, Young Kingdoms +dark fantasy illustration, 1970s sword and sorcery painterly, steam and deep colour +--ar 16:9 --v 6.1 --style raw +``` + +**SB-L07 — A Young Kingdoms Tavern** +``` +Interior of a Young Kingdoms tavern in a port city, rough-hewn tables, torchlight, +a mix of nationalities from across the continent, a Melnibonéan sitting alone in +the corner with silver-white hair and crimson eyes, bronze coins on the bar, a +merchant arguing with a Tarkeshite sailor, swords visible, atmosphere of careful +neutrality between people who could kill each other, 1970s fantasy illustration, +warm amber and shadow +--ar 16:9 --v 6.1 --style raw +``` + +**SB-L08 — The Demon Realm (Summoning Scene)** +``` +A chaotic extradimensional space glimpsed through a sorcerer's summoning circle, +swirling impossible geometry, a vast demon partially manifest through the threshold, +the sorcerer on one side holding the binding, the demon's true form visible on +the other, the membrane between worlds translucent and straining, Stormbringer +dark fantasy illustration, 1970s sword and sorcery, occult atmosphere, jewel tones +--ar 16:9 --v 6.1 --style raw +``` + +--- + +## ICONIC CHARACTERS + +**SB-C01 — Elric of Melniboné** +``` +Portrait of Elric of Melniboné, albino emperor, silver-white hair, crimson eyes, +cadaverously thin, the last emperor of a ten-thousand-year dynasty, wearing black +armour with the rune blade Stormbringer at his side, the sword pulsing with dark +energy, the expression of a man who knows what the sword costs and carries it +anyway, Young Kingdoms dark fantasy portrait, 1970s sword and sorcery illustration, +Michael Whelan painterly, jewel tones, regal and tragic +--ar 2:3 --v 6.1 --style raw +``` + +**SB-C02 — Elric with Stormbringer (Action)** +``` +Elric of Melniboné in battle, the black runesword Stormbringer raised, soul-energy +visibly flowing from a fallen enemy into the blade and through it into the albino +warrior, crimson eyes blazing, silver hair wild, the sword sentient and hungry, +the terrible cost of this symbiosis written in Elric's expression, Young Kingdoms +dark fantasy illustration, 1970s sword and sorcery, dramatic composition +--ar 2:3 --v 6.1 --style raw +``` + +**SB-C03 — Moonglum of Elwher** +``` +Portrait of Moonglum of Elwher, small wiry man with a wide cheerful grin that +hides considerable competence, Elric's only true friend and most loyal companion, +eastern Elwher features, colourful practical clothing, two curved blades at his +belt, the expression of someone who chose to stay beside the most dangerous man +in the world and has never regretted it, Young Kingdoms fantasy portrait, +1970s illustration, warm palette contrasting Elric's cold tones +--ar 2:3 --v 6.1 --style raw +``` + +**SB-C04 — A Melnibonéan Noble** +``` +Portrait of a Melnibonéan noble, aloof and ancient-looking despite apparent youth, +silver-white hair, elongated slightly inhuman features, elaborate armour of dragon +scale and bone-white metal, the casual cruelty of someone from a culture ten +thousand years past ordinary morality, a dragon visible behind them at distance, +Young Kingdoms dark fantasy portrait, 1970s sword and sorcery, cold jewel tones +--ar 2:3 --v 6.1 --style raw +``` + +**SB-C05 — A Pan Tang Chaos Knight** +``` +Portrait of a Pan Tang Chaos knight, warrior of the Theocracy of Chaos, black +armour bearing the eight-pointed star of Chaos, a broadsword in hand, features +half-hidden by a visored helm with daemon decorations, the bearing of a soldier +who has made pacts the listener cannot imagine, Young Kingdoms dark fantasy portrait, +1970s sword and sorcery illustration, dark palette +--ar 2:3 --v 6.1 --style raw +``` + +**SB-C06 — A Young Kingdoms Sorcerer** +``` +Portrait of a Young Kingdoms sorcerer mid-ritual, summoning circle glowing on +the floor, the air distorting around an elemental presence being called forth, +the sorcerer's expression of controlled terror, the power enormous and the binding +fragile, elaborate ritual robes, a grimoire open beside them, the cost of sorcery +visible in gauntness and the haunted quality of the eyes, Young Kingdoms dark +fantasy portrait, 1970s sword and sorcery +--ar 2:3 --v 6.1 --style raw +``` + +**SB-C07 — A Tarkeshite Merchant Captain** +``` +Portrait of a Tarkeshite sea merchant captain, weathered brown skin, pragmatic +practical clothing, the calculating expression of someone who has traded across +every coast of the Young Kingdoms and survived by understanding people, a manifest +at hand, a sword worn habitually not dramatically, Young Kingdoms fantasy portrait, +warm sea-light palette, 1970s illustration +--ar 2:3 --v 6.1 --style raw +``` + +**SB-C08 — A Beggar of Nadsokor** +``` +Portrait of a beggar from Nadsokor the City of Beggars, one of the outcast masses, +rags and disease and surprising cunning in the eyes, surviving on the margins of +a world that has no place for them, the particular dignity of someone who has +nothing left to lose, Young Kingdoms dark fantasy portrait, muted palette, 1970s +sword and sorcery illustration +--ar 2:3 --v 6.1 --style raw +``` + +--- + +## DEMONS + +**SB-D01 — Demon Weapon (Bound Sword)** +``` +A demon weapon, a broadsword bound with a lesser demon, the blade alive with dark +energy, runes along the flat that shift as the eye tries to read them, the hilt +warm and slightly pulsing, the weapon sentient in a limited way that makes its +wielder uneasy, a bound will in iron, Young Kingdoms dark fantasy illustration, +1970s sword and sorcery, occult metalwork detail +--ar 1:1 --v 6.1 --style raw +``` + +**SB-D02 — Combat Demon (Manifest)** +``` +A combat demon summoned and manifested in the Young Kingdoms, enormous humanoid +form of living shadow and killing intent, STR and SIZ at the peak of what the +binding allows, claws that can sever steel, bound but barely, the summoner's +circle glowing dangerously at its feet, Young Kingdoms dark fantasy illustration, +1970s sword and sorcery, demonic power barely contained +--ar 2:3 --v 6.1 --style raw +``` + +**SB-D03 — Intellect Demon** +``` +An intellect demon in partial manifestation, a shape of flickering wrongness +at the edge of perception, intelligence and alien knowledge visible in the geometry +of its presence rather than a face, the summoner speaking with it carefully, +every word measured, the demon offering information at a price, Young Kingdoms +dark fantasy illustration, 1970s occult atmosphere, implied form not shown directly +--ar 2:3 --v 6.1 --style raw +``` + +**SB-D04 — Beast Demon** +``` +A beast demon manifested, a vast animal form of impossible biology, parts of +several predators fused into something that was never natural, bound by sorcerous +chains of glowing rune-script, serving as mount or war-beast unwillingly, Young +Kingdoms dark fantasy illustration, 1970s sword and sorcery, biological wrongness +and power +--ar 3:2 --v 6.1 --style raw +``` + +**SB-D05 — Guardian Demon (Threshold)** +``` +A guardian demon at a threshold, a sorcerer's tower entrance bound with a demon +set to guard, a presence implied more than shown, the distortion of space around +a door that is very definitely not safe to open uninvited, the demon visible as +a wrongness in the geometry of the doorframe, Young Kingdoms dark fantasy +illustration, 1970s sword and sorcery, dread +--ar 2:3 --v 6.1 --style raw +``` + +--- + +## ELEMENTALS + +**SB-E01 — Straasha, Lord of the Water Elementals** +``` +Straasha Lord of the Water Elementals, a vast sea-being of living ocean, humanoid +in outline but composed entirely of deep water, cresting waves, abyssal darkness +visible within, the face ancient and oceanic, summoned by an albino emperor on +the deck of a ship at storm, Young Kingdoms dark fantasy illustration, 1970s sword +and sorcery, deep blue-green and black, enormous scale +--ar 2:3 --v 6.1 --style raw +``` + +**SB-E02 — Grome, Lord of the Earth Elementals** +``` +Grome Lord of the Earth Elementals, a vast being of living rock and deep soil, +humanoid in suggestion but geological in scale, the face of ancient mountains, +grudging power summoned against his will from the depths of the world, the Young +Kingdoms shaking slightly where he stands, Young Kingdoms dark fantasy illustration, +1970s sword and sorcery, grey-brown and iron-red, enormous and reluctant +--ar 2:3 --v 6.1 --style raw +``` + +**SB-E03 — Lassa, Lord of the Air Elementals** +``` +Lassa Lord of the Air Elementals, a presence of wind and sky barely made visible, +a face in storm clouds and high altitude, summoned over a high mountain pass, +the character barely able to perceive the entity at all, Young Kingdoms dark fantasy +illustration, 1970s sword and sorcery, pale blue and silver-white, implied rather +than described +--ar 2:3 --v 6.1 --style raw +``` + +**SB-E04 — A Fire Elemental** +``` +A fire elemental of the Young Kingdoms summoned and bound, living flame given +will and form, not a formless fire but an entity with awareness and pride, restrained +within a binding circle that glows white at the edges where the heat presses, +the summoner sweating at a careful distance, Young Kingdoms dark fantasy illustration, +1970s sword and sorcery, gold and red and deep shadow +--ar 2:3 --v 6.1 --style raw +``` + +--- + +## CREATURES + +**SB-CR01 — Cave Bear** +``` +A cave bear of the Young Kingdoms, enormous beyond any natural bear, four times +the size of a man, STR and SIZ at the upper reaches of anything terrestrial, +surprisingly quick for its bulk, in the remote Silent Lands or Desert of Sighs, +facing down a group of travellers with calm predatory assessment, Young Kingdoms +dark fantasy creature illustration, 1970s sword and sorcery, massive and real +--ar 3:2 --v 6.1 --style raw +``` + +**SB-CR02 — Tiger (Pan Tang)** +``` +A tiger of Pan Tang, the totem animal of Chardros the Reaper, serving as a battle +companion to a Pan Tang warrior, larger than any natural tiger, ridden into battle, +the particular intelligence of an animal used in war by a theocracy of Chaos +worshippers, Young Kingdoms dark fantasy creature illustration, 1970s sword and +sorcery, rich orange and black on dark backgrounds +--ar 3:2 --v 6.1 --style raw +``` + +**SB-CR03 — Gorilla (Jungle of the Boiling Sea)** +``` +A gorilla from the forbidden jungles of the far southwest beyond the Boiling Sea, +massive, not specifically dangerous but capable of lethal force, the kind of animal +that ends up in the menageries of southern continent lords, a figure below for +scale, tropical jungle setting, Young Kingdoms creature illustration, 1970s sword +and sorcery naturalistic +--ar 3:2 --v 6.1 --style raw +``` + +**SB-CR04 — Baboon Troop** +``` +A troop of fifteen to twenty baboons on the semi-arid steppes south of Shazaar, +aggressive and coordinated, attacking something larger than themselves, the +particular threat of pack predators that regularly take on great cats, Young +Kingdoms creature illustration, 1970s sword and sorcery naturalistic, dry steppe +landscape +--ar 3:2 --v 6.1 --style raw +``` + +**SB-CR05 — Falcon (Trained)** +``` +A falcon of the Young Kingdoms in a stoop from height, wings folded, talons +extended toward a target, the hunting dive of the most lethal aerial predator +in the book, kept by a noble for hunting or trained for war, Young Kingdoms +creature illustration, 1970s fantasy naturalistic, sky and speed +--ar 2:3 --v 6.1 --style raw +``` + +**SB-CR06 — A Chaos Creature** +``` +A chaos creature of the Young Kingdoms, something that was once an animal but +has been touched by Chaos until it is no longer classifiable, additional limbs +that bend incorrectly, fur that shifts colour, eyes in wrong locations, not +monstrous in the traditional sense but fundamentally and deeply wrong, Young +Kingdoms dark fantasy creature illustration, 1970s sword and sorcery, Chaos +corruption +--ar 3:2 --v 6.1 --style raw +``` + +--- + +## WEAPONS AND ITEMS + +**SB-I01 — Stormbringer (The Black Runesword)** +``` +The black runesword Stormbringer, a blade of impossible blackness that seems to +devour light, runes along the flat that move when unobserved, the hilt screaming +faintly when drawn, the weapon that has drunk ten thousand souls and is never +satisfied, a soul-eating entity in sword form, close-up dark fantasy illustration, +1970s sword and sorcery, deep black and bleeding soul-light, no wielder, just +the sword +--ar 2:3 --v 6.1 --style raw +``` + +**SB-I02 — A Young Kingdoms Broadsword** +``` +A broadsword of the Young Kingdoms, 100cm of honest steel, the weapon of a +professional fighter of moderate means, no sorcery just craft, worn grip and a +nick from the last serious fight, against a map of the Young Kingdoms on a tavern +table, Young Kingdoms fantasy still life illustration, 1970s sword and sorcery, +warm lamplight +--ar 2:3 --v 6.1 --style raw +``` + +**SB-I03 — A Lormyrian Great Axe** +``` +A Lormyrian great axe, two-handed, 165cm, the heaviest weapon in the Young +Kingdoms at 3D6 damage, ornate Lormyrian decoration on the head, clearly requiring +exceptional strength to wield, a weapon from a culture of large northerners, +Young Kingdoms fantasy weapons illustration, 1970s sword and sorcery, northern +iron aesthetic +--ar 2:3 --v 6.1 --style raw +``` + +**SB-I04 — A Grimoire of the Young Kingdoms** +``` +A grimoire of the Young Kingdoms, a book containing spells at ten thousand gold +coins per spell contained, bound in materials that are difficult to identify, +the pages feeling wrong to the touch, the ink shifting slightly in poor light, +lying on a sorcerer's lectern, the most expensive object in the scenario by some +margin, Young Kingdoms dark fantasy still life, 1970s occult illustration +--ar 2:3 --v 6.1 --style raw +``` + +**SB-I05 — Young Kingdoms Armour (Plate)** +``` +Full plate armour of the Young Kingdoms, the equipment of a wealthy professional +fighter, each 1AP through 8AP represented in the layering visible, practical and +maintained, beside it a broadsword and a large shield, the equipment of someone +who intends to survive, Young Kingdoms fantasy still life, 1970s sword and sorcery +equipment illustration, warm forge-light +--ar 2:3 --v 6.1 --style raw +``` + +**SB-I06 — Coin Purse with Young Kingdoms Currency** +``` +A leather coin purse spilling bronze coins on a tavern table, the large bronze +coins called Grande Bronzines and Petite Bronzines, one rare silver coin visible +among them, the economies of the Young Kingdoms made physical, a price list +fragment visible on a scrap of parchment beside them, Young Kingdoms fantasy +still life, 1970s illustration, warm candlelight +--ar 1:1 --v 6.1 --style raw +``` + +--- + +## CULTS AND RELIGION + +**SB-R01 — A Church of Law Ceremony** +``` +A ceremony in the Church of Law in the Young Kingdoms, white-robed priests in +a geometrically perfect temple, the ordered beauty of Law made architectural, +rituals of precision and structure, the lords of Law distant and demanding, +worshippers arranged in perfect symmetry, Young Kingdoms dark fantasy illustration, +1970s sword and sorcery, white and gold and cold perfection +--ar 16:9 --v 6.1 --style raw +``` + +**SB-R02 — A Chaos Cult Ritual** +``` +A Chaos cult ritual in the Young Kingdoms, worshippers of the lords of Chaos +making sacrifice, the eight-pointed star of Chaos burning in the air above, +reality bending slightly at the edges of the ritual space, the exhilaration and +terror of asking something vast and hungry for a favour, Young Kingdoms dark +fantasy illustration, 1970s sword and sorcery, deep reds and violets +--ar 16:9 --v 6.1 --style raw +``` + +**SB-R03 — The Balance (Neutral Cosmic Force)** +``` +An abstract representation of the Cosmic Balance in the Young Kingdoms, a vast +set of scales implied in the architecture of reality itself, the forces of Law +and Chaos visible as cold white and burning red on either side, a single figure +standing at the fulcrum, the Champion Eternal, Young Kingdoms dark fantasy +illustration, 1970s sword and sorcery, cosmic scale +--ar 16:9 --v 6.1 --style raw +``` + +--- + +## SCENARIO ATMOSPHERE + +**SB-A01 — Character Creation (Social Origins)** +``` +A street scene in a Young Kingdoms city showing the social spectrum: a noble in +finery, a merchant with bronze coins, a sailor with a port behind them, a beggar +in rags, a soldier in practical armour, all passing each other in the same +marketplace, the social origins of Stormbringer RPG made visual, Young Kingdoms +fantasy illustration, 1970s sword and sorcery, warm city light +--ar 16:9 --v 6.1 --style raw +``` + +**SB-A02 — The Resistance Table (Abstract)** +``` +Two figures locked in opposed contest of will, their strength and will represented +as visible energies meeting at a central point, the BRP resistance table made +visible as a struggle between active and passive forces, abstracted but grounded +in physical reality, Young Kingdoms dark fantasy illustration, 1970s sword and +sorcery +--ar 16:9 --v 6.1 --style raw +``` + +**SB-A03 — A Major Wound** +``` +A warrior in the aftermath of a major wound, the wound clearly severe at or +above half total hit points, the look of someone who is still standing through +sheer will, DEX halved until healing, the cost of combat in the Young Kingdoms +made physical, Young Kingdoms dark fantasy illustration, 1970s sword and sorcery, +gritty and real +--ar 2:3 --v 6.1 --style raw +``` + +**SB-A04 — Sanity Loss** +``` +A Young Kingdoms character experiencing SAN loss from a supernatural encounter, +the crack in the façade of rationality, something witnessed that cannot be +un-witnessed, the expression of a person whose model of the world has just been +broken in a specific place, Young Kingdoms dark fantasy illustration, 1970s +sword and sorcery, psychological horror through expression +--ar 2:3 --v 6.1 --style raw +``` +