Turn your team's standup logs or git commits into a 6-panel comic strip using AI. Supports multiple visual styles — pixel art, manga, film noir, and more.
# Using uv (recommended)
uv sync
# Or pip
pip install pillow google-genaiexport GOOGLE_API_KEY="AIza..."The tool uses Google Gemini for both script writing (Gemini Flash) and image generation.
Drop headshots into characters/photos/ — filename is the person's first name:
characters/photos/
├── alice.jpg
├── bob.jpg
└── charlie.png
# Auto-generate text descriptions from photos
uv run python sprintquest.py --demo --refresh-descriptions
# Generate the master style reference + per-character sprites
uv run python sprintquest.py --demo --generate-style --generate-refs allReview the generated sprites in characters/references/pixel-art/. If any look off, regenerate individuals:
uv run python sprintquest.py --demo --generate-refs alice,bob# From a standup log file
uv run python sprintquest.py -f standups.txt
# From git log via pipe
git log --since="1 week ago" --pretty=format:"%an|%s" --no-merges | uv run python sprintquest.py --stdin
# Interactive paste mode
uv run python sprintquest.py
# Demo mode (sample data)
uv run python sprintquest.py --demoOutput: a timestamped PNG like comic_strip_pixel-art_0103260120.png.
The tool auto-detects the format.
Standup log (Slack-style):
alice:
Fixed login bug and updated tests
bob:
Refactored API endpoints
Performance improvements on search
Git log (pipe-delimited):
Alice|Fixed login bug
Alice|Updated tests
Bob|Refactored API endpoints
Six built-in styles. Pass --style <name> to switch:
| Style | Description |
|---|---|
pixel-art |
16-bit SNES/Genesis era RPG (default) |
8-bit |
Chunky NES-era, strict 4-color palette per sprite |
film-noir |
Sin City B&W, chiaroscuro lighting, red accent |
manga |
Shonen manga, black & white with screentone |
60s-superheroes |
Silver Age comic book style |
soviet-propaganda |
Bold propaganda poster aesthetic |
Each style needs its own sprites generated once:
uv run python sprintquest.py --demo --style manga --generate-style --generate-refs allAfter that, just use --style manga on any run.
- Create a directory under
config/styles/:
config/styles/my-style/
├── panel_style.md # One-line visual style prefix for panel prompts
├── style_reference.md # Prompt for generating the master style guide sprite
└── character_reference.md # Prompt template for per-character sprites
-
Look at existing styles for reference — copy one and modify the prompts.
-
character_reference.mduses{name}and{description}template variables. -
Generate sprites and test:
uv run python sprintquest.py --demo --style my-style --generate-style --generate-refs all
uv run python sprintquest.py --demo --style my-styleusage: sprintquest.py [options]
Input:
-f, --file FILE Read standup/git log from file
--stdin Read from stdin pipe
--demo Use sample demo data
-s, --script FILE Load existing script JSON (skip generation)
Output:
-o, --output FILE Output file path (default: comic_strip.png)
-w, --week N Calendar week number for header (default: previous week)
--lang en|de Language for dialogue and title (default: en)
--style NAME Visual style (default: pixel-art)
Panel control:
-p, --panels 1,4,6 Only regenerate specific panels
--assemble Reassemble strip from cached panels (no generation)
--skip-images Use placeholder panels (no image API calls)
--panel-dir DIR Panel cache directory (default: panels/)
Character setup:
--refresh-descriptions Regenerate text descriptions from photos
--generate-style Generate master style reference sprite
--generate-refs [NAMES] Generate character sprites (all, or comma-separated names)
-c, --characters DIR Character directory (default: characters/)
Advanced:
--google-key KEY Google API key (or set GOOGLE_API_KEY env var)
--model NAME Gemini model override
Don't like a panel? Regenerate just that one:
# Regenerate panels 3 and 6, keep the rest
uv run python sprintquest.py -s comic_strip_script.json -p 3,6
# Reassemble from cached panels (no API calls)
uv run python sprintquest.py -s comic_strip_script.json --assembleScripts are auto-saved as *_script.json alongside the output PNG.
sprintquest.py # Entry point (imports cli.main)
cli.py # Arg parsing, config loading, orchestration
parsing.py # Input detection and parsing
script.py # Gemini Flash script generation
images.py # Panel/sprite generation + strip assembly (Pillow)
config/
├── script_system.md # Story generation system prompt
├── panel_instructions.md # Speech bubble and group shot rules
├── language_en.md # English language prompt
├── language_de.md # German language prompt
└── styles/
├── pixel-art/ # Default style
├── 8-bit/
├── film-noir/
├── manga/
├── 60s-superheroes/
└── soviet-propaganda/
characters/
├── alice.md # Auto-generated text descriptions
├── photos/ # Input headshots
│ └── alice.jpg
└── references/ # Generated sprites (per style)
├── pixel-art/
│ ├── _style.png # Master style guide
│ └── alice.png # Character sprite
└── manga/
├── _style.png
└── alice.png
panels/ # Cached generated panels (per style)
├── pixel-art/
└── manga/
assets/
└── logo/
├── sprintquest-small.png # Logo emblem for footer
└── sprintquest-text.png # Text logo for footer
fonts/
├── Silkscreen-Bold.ttf # Primary pixel font (OFL licensed)
├── Silkscreen-Regular.ttf # Pixel font regular weight (OFL licensed)
└── PressStart2P-Regular.ttf # Fallback pixel font (OFL licensed)
- Parse — Auto-detect input format (standup log or git log), extract per-person entries
- Script — Gemini Flash turns the summary into a 6-panel RPG-themed comic script (JSON)
- Generate — Gemini image generation creates each panel using character reference sprites for consistency
- Assemble — Pillow stitches panels into a strip with header, borders, footer branding, and layout
The hardest problem. Solved with a 3-tier reference system:
- Master style reference (
_style.png) — Two generic characters that define proportions, shading, and palette for the style - Character sprites (
references/{style}/*.png) — Per-person sprites generated from headshot + style ref + text description - Panel generation — Sprites are attached as visual anchors to each panel prompt
| Operation | Cost |
|---|---|
| Script generation (Gemini Flash) | ~$0.15 |
| 6 panel images (Gemini image gen) | ~$0.12 |
| Total per comic | ~$0.27 |
| One-time setup (style + 5 sprites) | ~$0.13 |
Run as a Friday cron job:
# Every Friday at 4pm
0 16 * * 5 cd /path/to/sprintquest && \
git log --since="1 week ago" --pretty=format:"%an|%s" --no-merges | \
uv run python sprintquest.py --stdin -o /tmp/comic.png && \
curl -F file=@/tmp/comic.png $SLACK_WEBHOOK_URLThanks to my friend Andreas Neukötter for the initial idea.
- Python 3.14+
- Dependencies:
pillow,google-genai - API: Google Gemini (requires
GOOGLE_API_KEY) - Fonts: Silkscreen (primary) and Press Start 2P (fallback) — both SIL Open Font License
