Add Stormbringer art gallery: 39 gpt-image-2 images, HTML gallery, prompts, generator script

- scenarios/art/stormbringer/: 39 PNG images generated with gpt-image-2 at high quality
  covering locations, characters, demons, elementals, creatures, weapons, religion
- asset-library/stormbringer-1e/stormbringer_reference.html: updated with full
  image gallery section, lightbox viewer, and nav entry
- scenarios/art/stormbringer/stormbringer-art-prompts.md: full prompt library (39 prompts)
- scenarios/art/stormbringer/dalle_generate.py: queue-based DALL-E/gpt-image generator
This commit is contained in:
2026-05-16 20:31:38 +00:00
parent b1fc3810dc
commit 0816aada90
42 changed files with 1085 additions and 0 deletions
@@ -297,6 +297,76 @@ td:first-child { color: var(--cream); }
section { padding: 18px 18px 8px; } section { padding: 18px 18px 8px; }
.page-title { padding: 20px 18px 14px; } .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); }
</style> </style>
</head> </head>
<body> <body>
@@ -1266,6 +1336,217 @@ Effective maximum: 99</div>
</ul> </ul>
</section> </section>
<section id="art-gallery">
<h2>Art Gallery</h2>
<p style="margin-bottom:1.5rem;color:var(--cream-dim);font-style:italic;">Generated with gpt-image-2 in the style of 1970s Michael Whelan sword and sorcery illustration. Click any image to view full size.</p>
<div class="gallery-category">
<h3>Locations</h3>
<div class="gallery-grid">
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l01-imrryr.png" data-caption="Imrryr — The Dreaming City of Melniboné">
<div class="gallery-caption">Imrryr — The Dreaming City</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l02-karlaak.png" data-caption="Karlaak — City on the Edge of the Weeping Waste">
<div class="gallery-caption">Karlaak — City by the Weeping Waste</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l03-pan-tang.png" data-caption="Pan Tang — Theocracy of Chaos">
<div class="gallery-caption">Pan Tang — Theocracy of Chaos</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l04-nadsokor.png" data-caption="Nadsokor — City of Beggars">
<div class="gallery-caption">Nadsokor — City of Beggars</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l05-map.png" data-caption="The Young Kingdoms — World Map">
<div class="gallery-caption">The Young Kingdoms — World Map</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l06-boiling-sea.png" data-caption="The Boiling Sea — Southern Boundary">
<div class="gallery-caption">The Boiling Sea</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l07-tavern.png" data-caption="A Young Kingdoms Tavern — Common Meeting Ground">
<div class="gallery-caption">A Young Kingdoms Tavern</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-l08-demon-realm.png" data-caption="The Demon Realm — Beyond the Mortal Plane">
<div class="gallery-caption">The Demon Realm</div>
</div>
</div>
</div>
<div class="gallery-category">
<h3>Characters</h3>
<div class="gallery-grid">
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c01-elric-portrait.png" data-caption="Elric of Melniboné — The Pale Prince">
<div class="gallery-caption">Elric of Melniboné — Portrait</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c02-elric-action.png" data-caption="Elric — Stormbringer Raised in Battle">
<div class="gallery-caption">Elric — In Battle</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c03-moonglum.png" data-caption="Moonglum of Elwher — Elric's Companion">
<div class="gallery-caption">Moonglum of Elwher</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c04-melnibonean-noble.png" data-caption="A Melnibonean Noble — Decadent Aristocrat">
<div class="gallery-caption">Melnibonean Noble</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c05-pan-tang-chaos-knight.png" data-caption="Pan Tang Chaos Knight — Servant of the Lords of Chaos">
<div class="gallery-caption">Pan Tang Chaos Knight</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c06-sorcerer.png" data-caption="A Young Kingdoms Sorcerer — Master of Summoning">
<div class="gallery-caption">A Young Kingdoms Sorcerer</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c07-tarkeshite-captain.png" data-caption="Tarkeshite Sea Captain — Warrior of the Purple Towns">
<div class="gallery-caption">Tarkeshite Sea Captain</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-c08-beggar-of-nadsokor.png" data-caption="A Beggar of Nadsokor — The City of Beggars">
<div class="gallery-caption">Beggar of Nadsokor</div>
</div>
</div>
</div>
<div class="gallery-category">
<h3>Demons</h3>
<div class="gallery-grid">
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-d01-demon-weapon.png" data-caption="Demon Weapon — A Bound Enchanted Sword">
<div class="gallery-caption">Demon Weapon</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-d02-combat-demon.png" data-caption="Combat Demon — Bound to Fight">
<div class="gallery-caption">Combat Demon</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-d03-intellect-demon.png" data-caption="Intellect Demon — Bound to Know">
<div class="gallery-caption">Intellect Demon</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-d04-beast-demon.png" data-caption="Beast Demon — A Bound Animal Demon">
<div class="gallery-caption">Beast Demon</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-d05-guardian-demon.png" data-caption="Guardian Demon — Set to Ward a Threshold">
<div class="gallery-caption">Guardian Demon</div>
</div>
</div>
</div>
<div class="gallery-category">
<h3>Elementals</h3>
<div class="gallery-grid">
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-e01-straasha.png" data-caption="Straasha — Lord of the Water Elementals">
<div class="gallery-caption">Straasha — Lord of Water</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-e02-grome.png" data-caption="Grome — Lord of the Earth Elementals">
<div class="gallery-caption">Grome — Lord of Earth</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-e03-lassa.png" data-caption="Lassa — Lord of the Air Elementals">
<div class="gallery-caption">Lassa — Lord of Air</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-e04-fire-elemental.png" data-caption="A Fire Elemental — Summoned and Bound">
<div class="gallery-caption">Fire Elemental</div>
</div>
</div>
</div>
<div class="gallery-category">
<h3>Creatures</h3>
<div class="gallery-grid">
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-cr01-cave-bear.png" data-caption="Cave Bear — Four Times the Size of a Man">
<div class="gallery-caption">Cave Bear</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-cr02-tiger-pan-tang.png" data-caption="Tiger of Pan Tang — Ridden Into Battle">
<div class="gallery-caption">Tiger of Pan Tang</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-cr03-gorilla.png" data-caption="Gorilla — From the Jungles Beyond the Boiling Sea">
<div class="gallery-caption">Gorilla</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-cr04-baboon-troop.png" data-caption="Baboon Troop — Pack Predators of the Steppe">
<div class="gallery-caption">Baboon Troop</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-cr05-falcon.png" data-caption="Falcon — The Aerial Hunter">
<div class="gallery-caption">Falcon</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-cr06-chaos-creature.png" data-caption="Chaos Creature — Touched Beyond Classification">
<div class="gallery-caption">Chaos Creature</div>
</div>
</div>
</div>
<div class="gallery-category">
<h3>Weapons &amp; Equipment</h3>
<div class="gallery-grid">
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-i01-stormbringer-sword.png" data-caption="Stormbringer — The Black Runesword">
<div class="gallery-caption">Stormbringer — The Black Runesword</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-i02-broadsword.png" data-caption="Broadsword — The Weapon of a Working Fighter">
<div class="gallery-caption">Broadsword</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-i03-lormyrian-axe.png" data-caption="Lormyrian Great Axe — 165cm of Northern Steel">
<div class="gallery-caption">Lormyrian Great Axe</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-i04-grimoire.png" data-caption="A Grimoire — Ten Thousand Gold per Spell">
<div class="gallery-caption">Grimoire</div>
</div>
<div class="gallery-item portrait" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-i05-armour.png" data-caption="Full Plate Armour — Equipment of a Wealthy Fighter">
<div class="gallery-caption">Full Plate Armour</div>
</div>
</div>
</div>
<div class="gallery-category">
<h3>Religion &amp; The Cosmic Balance</h3>
<div class="gallery-grid">
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-r01-church-of-law.png" data-caption="The Church of Law — Order Made Architectural">
<div class="gallery-caption">Church of Law</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-r02-chaos-cult.png" data-caption="A Chaos Cult — Worshippers of the Lords of Chaos">
<div class="gallery-caption">Chaos Cult</div>
</div>
<div class="gallery-item" onclick="openLightbox(this)">
<img src="../../scenarios/art/stormbringer/sb-r03-the-balance.png" data-caption="The Cosmic Balance — Law and Chaos in Equilibrium">
<div class="gallery-caption">The Cosmic Balance</div>
</div>
</div>
</div>
</section>
<!-- LIGHTBOX -->
<div id="lightbox" onclick="closeLightbox(event)">
<button id="lightbox-close" onclick="document.getElementById('lightbox').classList.remove('open')">✕</button>
<img id="lightbox-img" src="" alt="">
<div id="lightbox-caption"></div>
</div>
</div><!-- end #main --> </div><!-- end #main -->
<script> <script>
@@ -1363,6 +1644,14 @@ const navData = [
{ text: "GM Guidance", id: "gm-guidance" }, { text: "GM Guidance", id: "gm-guidance" },
{ text: "What Magic Solves", id: "gm-guidance" }, { text: "What Magic Solves", id: "gm-guidance" },
]}, ]},
{ title: "Art Gallery", links: [
{ text: "Locations", id: "art-gallery" },
{ text: "Characters", id: "art-gallery" },
{ text: "Demons & Elementals", id: "art-gallery" },
{ text: "Creatures", id: "art-gallery" },
{ text: "Weapons & Equipment", id: "art-gallery" },
{ text: "Religion & The Balance", id: "art-gallery" },
]},
]; ];
// ── BUILD NAV ── // ── BUILD NAV ──
@@ -1484,6 +1773,23 @@ sections.forEach(s => observer.observe(s));
// Auto-open first nav section // Auto-open first nav section
document.querySelector('.nav-section-title').classList.add('open'); document.querySelector('.nav-section-title').classList.add('open');
document.querySelector('.nav-links').classList.add('open'); document.querySelector('.nav-links').classList.add('open');
// ── LIGHTBOX ──
function openLightbox(item) {
const img = item.querySelector('img');
document.getElementById('lightbox-img').src = img.src;
document.getElementById('lightbox-caption').textContent = img.dataset.caption || '';
document.getElementById('lightbox').classList.add('open');
}
function closeLightbox(e) {
if (e.target === document.getElementById('lightbox') || e.target.id === 'lightbox-close') {
document.getElementById('lightbox').classList.remove('open');
}
}
document.addEventListener('keydown', e => {
if (e.key === 'Escape') document.getElementById('lightbox').classList.remove('open');
});
</script> </script>
</body> </body>
</html> </html>
@@ -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())
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

@@ -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
```