Six interlocking picture books for my children and nieces and nephews, built with Claude Code.
Takeaway: Agentic coding tools excel at creating densely interconnected markdown structures—tracking relationships and maintaining consistency.
For the complete story world, characters, and narrative details, see story/overview.md.
katha-base/
├── characters/ # Character definitions
├── locations/ # Location and room definitions
├── story/ # Story structure and narrative design
│ ├── template.yaml # Shared narrative template
│ ├── page-template.yaml # Template for individual page files
│ ├── styles.yaml # Visual style definitions
│ ├── styles-skip.yaml # Skipped/experimental styles
│ └── overview.md # Story world and narrative overview
├── ref/ # Reference images for visual style
│ ├── styles/ # Visual style reference images
│ ├── characters/ # Character reference images
│ ├── locations/ # Location reference images
│ └── objects/ # Object reference images
├── out/ # Generated outputs (git-ignored)
│ ├── images/ # Shared image storage (reused across versions)
│ │ ├── *.txt # Prompt text files ({page_stem}-{hash}.txt)
│ │ └── *.jpg # Generated images ({page_stem}-{hash}.jpg)
│ ├── versions/ # Versioned output folders
│ │ └── {xx}/ # Version folders (01/, 02/, etc.)
│ │ ├── *-book.pdf
│ │ └── manifest.yaml
│ └── story/ # Generated story files
└── .streamlit/ # Streamlit configuration and secrets
- characters/ - Character definitions in YAML format
- locations/ - Location and room definitions in YAML format
- story/template.yaml - Shared page-by-page narrative template structure
- story/overview.md - Complete story world description, narrative architecture, and character details
- ref/ - Visual reference images for style and character appearances (JPG format, named as
name-##.jpg). Not checked into repo for privacy reasons.- ref/styles/ - Visual style reference images (see Visual Styles section below)
- ref/characters/ - Character reference images
- ref/locations/ - Location reference images
- ref/objects/ - Object reference images
- out/ - Generated outputs (not committed to repository)
- out/images/ - Shared storage for prompts and images (reused across versions)
- Prompts:
{page_stem}-{prompt_hash}.txt - Images:
{page_stem}-{prompt_hash}.jpg(raw, unframed)
- Prompts:
- out/versions/{xx}/ - Versioned output folders (e.g.,
out/versions/01/)- Books:
{character}-book.pdf manifest.yamlwith version metadata (references images inout/images/)
- Books:
- out/story/ - Generated story files
- out/images/ - Shared storage for prompts and images (reused across versions)
Style configuration is defined in story/styles.yaml, with reference images in ref/styles/ using the naming convention {style_id}-{##}.jpg.
Active styles (in priority order):
genealogy_witch— Benjamin Lacombe — Genealogy of a Witch, Madame Butterflyred_tree— Shaun Tan — The Red Treegashlycrumb— Edward Gorey — The Gashlycrumb Tinies *donothing_day— Beatrice Alemagna — On a Magical Do-Nothing Day *ghost_hunt— Cherie Zamazing — We're Going On A Ghost Huntghost_easy— Stephanie Laberis — It's Not Easy Being A Ghost
* No reference images in ref/styles/ for this style.
Skipped/experimental styles are in story/styles-skip.yaml.
- Install Google Cloud SDK:
curl https://sdk.cloud.google.com | bash - Authenticate:
gcloud auth application-default login - Set quota project:
gcloud auth application-default set-quota-project <PROJECT_ID> - Add reference images to
ref/subdirectories (characters/,locations/,objects/)
The scripts/gen_image.py script generates illustrations for story pages using AI image generation.
uv run scripts/gen_image.py <mode> <file> [style_id]Modes:
prompt <page_file> <style_id>- Display the image generation prompt and list all referenced imagesgemini <page_file> <style_id>- Generate the image using Geminiframe <image_file>- Frame an existing image for print with bleed and guide lines
Examples:
# Show the prompt for a page in genealogy_witch style
uv run scripts/gen_image.py prompt out/story/p09-arthur-cullan.yaml genealogy_witch
# Generate an image in red_tree style
uv run scripts/gen_image.py gemini out/story/p09-arthur-cullan.yaml red_tree
# Frame a generated image for printing (legacy - framing now happens during PDF creation)
uv run scripts/gen_image.py frame out/images/p09-arthur-cullan-a1b2c.jpgThe script assembles a comprehensive image generation prompt by combining:
- Style prompts from
story/styles.yaml(artist-specific visual characteristics) - Story setting from
story/template.yaml(house, Christmas atmosphere, etc.) - Character visual descriptions from each character's YAML file
- Location visual descriptions from the location YAML file
- Page-specific scene description from the page YAML file (
visualfield) - Page text to display from the page YAML file (
textfield) - Reference images from
ref/styles/,ref/characters/,ref/locations/, andref/objects/
- Generated images are saved to
out/images/{page_stem}-{prompt_hash}.jpg - Prompt text saved to
out/images/{page_stem}-{prompt_hash}.txt - Aspect ratio: 3:2 (closest to target ratio of 3507x2334 which is ~1.5)
- Images are stored raw (unframed); framing happens during PDF creation
- Images are shared across versions (same prompt hash = same image)
- Reference images must follow naming convention:
{id}-{number}.jpg(e.g.,arthur-01.jpg,genealogy_witch-02.jpg)
The scripts/gen_book.py script generates complete picture book PDFs for a character.
uv run scripts/gen_book.py <character_id> [--style STYLE] [--message MESSAGE]Options:
--style STYLE- Visual style to use (default: fromstory/template.yaml)--message MESSAGE- Required when creating a new version (prompts changed)
Examples:
# Generate Cullan's book (uses existing version if prompts unchanged)
uv run scripts/gen_book.py cullan
# Create a new version with a message
uv run scripts/gen_book.py cullan --message "Updated story text"
# Generate Arthur's book in a specific style
uv run scripts/gen_book.py arthur --style red_treeThe script automatically detects when prompts have changed:
- Prompts unchanged: Uses existing version, skips already-generated images
- Prompts changed: Requires
--messageflag to create a new version
This enables:
- Crash recovery: Re-run to resume interrupted generations
- Idempotent runs: Same prompt = same image (skipped if exists)
- Joint page efficiency: Generating one character's book also generates shared pages
- PDFs saved to:
out/versions/{xx}/{character}-book.pdf - Images saved to:
out/images/{page_stem}-{prompt_hash}.jpg(shared across versions) - Prompts saved to:
out/images/{page_stem}-{prompt_hash}.txt - Manifest:
out/versions/{xx}/manifest.yaml(tracks metadata, git commit, style, references to shared images)