Koubou (ๅทฅๆฟ) transforms YAML into handcrafted App Store screenshots with artisan quality.
ๅทฅๆฟ (koubou) means "artisan's workshop" in Japanese - where masters create their finest work. Every screenshot is carefully crafted with professional precision using device frames, rich backgrounds, and elegant typography.
- ๐ Live Editing - Real-time screenshot regeneration when config or assets change
- ๐ Multi-Language Localization - Generate localized screenshots using familiar xcstrings format from Xcode
- ๐ผ๏ธ Localized Assets - Automatic language-specific asset resolution with convention-based and explicit mapping
- ๐จ 100+ Device Frames - iPhone 16 Pro, iPad Air M2, MacBook Pro, Apple Watch Ultra, and more
- ๐ Professional Backgrounds - Linear, radial, conic gradients with precise color control
- โจ Rich Typography - Advanced text overlays with stroke, alignment, wrapping, and custom fonts
- ๐ Gradient Typography - Linear, radial, and conic gradients for text with custom color stops
- ๐ฑ YAML-First Configuration - Elegant, declarative screenshot definitions
- ๐ Batch Processing - Generate multiple screenshots efficiently from a single config
- ๐ฆ Highlight Annotations - Circle, rounded rect, and rect shapes with spotlight dimming and background blur
- ๐ Zoom Callouts - Magnified callout bubbles with source indicators, advanced connectors (straight/curved/facing), and drop shadows
- โจ Anti-Aliased Rendering - Supersampled shape rendering for smooth edges at any resolution
- ๐ง Flexible API - Both simple and advanced configuration options
- ๐ Artisan Quality - Pixel-perfect output ready for App Store submission
PyPI (All Platforms)
pip install kouboumacOS/Linux - Homebrew
brew install bitomule/tap/koubouPython Developers
pip install koubou[dev] # With development dependenciesOption 1: Install Script (Recommended)
git clone https://github.com/bitomule/koubou.git
cd koubou
./install.shOption 2: From Source
git clone https://github.com/bitomule/koubou.git
cd koubou
pip install .Verify your installation:
kou --version
kou --help# Create a sample configuration
kou --create-config my-screenshots.yaml
# Generate screenshots
kou generate my-screenshots.yaml
# Live editing mode - regenerate automatically when files change
kou live my-screenshots.yamlReal-time screenshot regeneration when your YAML configuration or assets change.
# Start live editing mode
kou live my-screenshots.yaml
# Adjust debounce delay (default: 0.5s)
kou live my-screenshots.yaml --debounce 1.0
# Enable verbose logging
kou live my-screenshots.yaml --verboseHow it works:
- Monitors YAML config and all referenced assets
- Regenerates only affected screenshots
- Debounces rapid changes to prevent excessive regeneration
Perfect for iterative design - edit assets in design tools, update text, tweak positioning, and see results instantly.
Platform support: macOS and Linux only (standard generation works on Windows)
Generate localized screenshots for international App Store submissions using xcstrings format from Xcode.
project:
name: "My App Screenshots"
output_dir: "Screenshots/Generated"
device: "iPhone 15 Pro Portrait"
output_size: "iPhone6_9"
localization:
base_language: "en"
languages: ["en", "es", "ja", "fr", "de"]
xcstrings_path: "Localizable.xcstrings" # Optional - auto-creates if missing
screenshots:
welcome_screen:
content:
- type: "text"
content: "Welcome to Amazing App" # Text becomes localization key
position: ["50%", "20%"]
size: 48
color: "#8E4EC6"
- type: "image"
asset: "screenshots/home.png"
position: ["50%", "60%"]Output structure:
Screenshots/Generated/
โโโ en/iPhone_15_Pro_Portrait/welcome_screen.png
โโโ es/iPhone_15_Pro_Portrait/welcome_screen.png
โโโ ja/iPhone_15_Pro_Portrait/welcome_screen.png
โโโ fr/iPhone_15_Pro_Portrait/welcome_screen.png
โโโ de/iPhone_15_Pro_Portrait/welcome_screen.png
Workflow: Koubou extracts text content and creates/updates your xcstrings file. Edit translations in Xcode's xcstrings editor, then regenerate screenshots. Live mode watches both YAML config and xcstrings file for changes.
Key benefits: Uses iOS-native xcstrings format, natural text as keys (no IDs), supports plurals and device variants, works seamlessly with live mode.
Automatically resolve language-specific images for multi-language screenshots. Perfect for RTL layouts, region-specific content, or tools like Maestro that generate per-locale screenshots.
Organize assets in {lang}/ subdirectories - Koubou resolves them automatically:
localization:
base_language: "en"
languages: ["en", "es", "ja"]
screenshots:
hero_screen:
content:
- type: "image"
asset: "screenshots/hero.png" # Auto-resolves to screenshots/{lang}/hero.png
position: ["50%", "50%"]Directory structure:
screenshots/
โโโ en/hero.png
โโโ es/hero.png
โโโ ja/hero.png
โโโ hero.png # Fallback for missing languages
Resolution order: {lang}/path โ {base_lang}/path โ direct_path
For non-standard structures or external tool outputs:
screenshots:
onboarding:
content:
- type: "image"
asset:
en: "maestro/en_iphone/onboarding.png"
es: "maestro/es_iphone/onboarding.png"
ja: "maestro/ja_iphone/onboarding.png"
default: "screenshots/fallback.png" # Optional
position: ["50%", "50%"]Mix both approaches in the same screenshot as needed.
Koubou provides predefined App Store screenshot sizes configured at the project level. All screenshots in a single YAML file use the same output size.
Specify the output size once in your project configuration:
project:
name: "My App Screenshots"
output_dir: "Screenshots/Generated"
device: "iPhone 15 Pro Portrait"
output_size: "iPhone6_9" # All screenshots will be 1320ร2868
screenshots:
welcome_screen:
content:
- type: "image"
asset: "screenshots/home.png"View all available sizes with descriptions:
kou list-sizesCommon Sizes:
iPhone6_9- iPhone 16 Pro Max, 15 Pro Max (1320ร2868)iPhone6_7- iPhone 15/14/13/12 Pro Max, Plus (1290ร2796)iPhone6_1- iPhone 16/15/14/13 Pro (1179ร2556)iPadPro12_9- iPad Pro 12.9" (2048ร2732)iPadPro11- iPad Pro 11", iPad Air 11" M2 (1668ร2388)
You can still specify custom dimensions when needed:
project:
name: "My App Screenshots"
device: "iPhone 15 Pro Portrait"
output_size: [1200, 2600] # Custom width ร heightTo generate screenshots for different sizes, create separate YAML files:
iphone-6-9.yaml- All iPhone 6.9" screenshotsiphone-6-7.yaml- All iPhone 6.7" screenshotsipad-pro.yaml- All iPad Pro screenshots
Create screenshots with YAML configuration:
project:
name: "My Beautiful App"
output_dir: "Screenshots/Generated"
device: "iPhone 15 Pro Portrait"
output_size: "iPhone6_9" # iPhone 16 Pro Max, 15 Pro Max
defaults:
background:
type: linear
colors: ["#E8F0FE", "#F8FBFF"]
direction: 180
screenshots:
welcome_screen:
content:
- type: "text"
content: "Beautiful App"
position: ["50%", "15%"]
size: 48
color: "#8E4EC6"
weight: "bold"
- type: "text"
content: "Transform your workflow today"
position: ["50%", "25%"]
size: 24
color: "#1A73E8"
- type: "image"
asset: "screenshots/home.png"
position: ["50%", "60%"]
scale: 0.6
frame: trueSee the YAML API Reference below for all available options including gradients, strokes, and advanced positioning.
kou generate <config.yaml>- Generate screenshots from configurationkou live <config.yaml>- Live editing mode with real-time regenerationkou list-sizes- List available App Store screenshot sizeskou --create-config <output.yaml>- Create a sample configuration filekou --version- Show version informationkou --help- Show detailed help
# Override output directory
kou generate config.yaml --output ./custom-screenshots
# Use custom frame directory
kou generate config.yaml --frames ./my-frames
# Enable verbose logging
kou generate config.yaml --verbose# Start live editing with default settings
kou live config.yaml
# Adjust debounce delay (default: 0.5s)
kou live config.yaml --debounce 1.0
# Enable verbose logging to see file changes
kou live config.yaml --verbose# Create config with custom project name
kou --create-config config.yaml --name "My App Screenshots"For uploading screenshots, we recommend App Store Connect CLI:
brew install appstoreconnect-cli
asc auth login
# Upload per device type and language
asc assets screenshots upload \
--version-localization "LOC_ID" \
--path "./output/en/iPhone_16_Pro_.../" \
--device-type "IPHONE_69"Koubou outputs screenshots organized by {language}/{device}/, mapping directly to individual asc upload calls.
Koubou includes 100+ professionally crafted device frames:
- iPhone 16 Pro (Black, Desert, Natural, White Titanium)
- iPhone 16 (Black, Pink, Teal, Ultramarine, White)
- iPhone 15 Pro/Max (All titanium colors)
- iPhone 14 Pro/Max, 12-13 series, and more
- iPad Air 11"/13" M2 (Blue, Purple, Space Gray, Stardust)
- iPad Pro 11"/13" M4 (Silver, Space Gray)
- iPad Pro 2018-2021, iPad mini, and classic models
- MacBook Pro 2021 (14" & 16"), MacBook Air 2020/2022
- iMac 24" Silver, iMac 2021
- Apple Watch Series 4/7, Watch Ultra
project:
name: string # Project name
output_dir: string # Output directory (default: "output")
device: string # Target device frame (default: "iPhone 15 Pro Portrait")
output_size: string | [int, int] # Named size ("iPhone6_9") or custom [width, height] (default: "iPhone6_9")
defaults: # Default settings applied to all screenshots
background: # Default background configuration
type: "solid" | "linear" | "radial" | "conic"
colors: [string, ...] # Hex colors array
direction: float? # Degrees for gradients (default: 0)screenshots:
screenshot_id: # Unique identifier for each screenshot
content: # Array of content items
- type: "text" | "image" | "highlight" | "zoom"
# Text content properties
content: string? # Text content (for type: "text")
position: [string, string] # Position as ["x%", "y%"] or ["xpx", "ypx"]
size: int? # Font size (default: 24)
color: string? # Hex color (default: "#000000")
weight: string? # "normal" or "bold" (default: "normal")
alignment: string? # "left", "center", "right" (default: "center")
# Image content properties
asset: string | dict? # Image path (string) or localized mapping (dict)
scale: float? # Scale factor (default: 1.0)
frame: bool? # Apply device frame (default: false)background:
type: "solid" | "linear" | "radial" | "conic"
colors: [string, ...] # Hex colors (e.g., ["#667eea", "#764ba2"])
direction: float? # Degrees for linear gradients (default: 0)
center: [string, string]? # Center point for radial/conic ["x%", "y%"]# Text Content Item
- type: "text"
content: string # Text to display
position: [string, string] # Position as ["50%", "20%"] or ["100px", "50px"]
size: int # Font size in pixels (default: 24)
# Fill Options (choose exactly one):
color: string # Solid color (hex format, e.g., "#000000")
# OR
gradient: # Text gradient
type: "linear" | "radial" | "conic"
colors: [string, ...] # Hex colors array (minimum 2)
positions: [float, ...]? # Color stops 0.0-1.0 (optional)
direction: float? # Angle in degrees (linear)
center: [string, string]? # Center point (radial/conic)
radius: string? # Radius for radial ("50%", "100px")
start_angle: float? # Starting angle (conic)
weight: string # "normal" or "bold" (default: "normal")
alignment: string # "left", "center", "right" (default: "center")
# Stroke Options (optional):
stroke_width: int? # Stroke width in pixels
stroke_color: string? # Solid stroke color (hex format)
# OR
stroke_gradient: # Gradient stroke (same structure as gradient)
# Image Content Item
- type: "image"
asset: string # Path to image file
position: [string, string] # Position as ["50%", "60%"] or ["200px", "300px"]
scale: float # Scale factor (default: 1.0)
frame: bool # Apply device frame around image (default: false)
# Highlight Content Item
- type: "highlight"
shape: "circle" | "rounded_rect" | "rect" # Shape (required)
position: [string, string] # Center position as ["50%", "50%"]
dimensions: [string, string] # Width, height as ["20%", "15%"]
border_color: string? # Border color in hex (e.g., "#FF3B30")
border_width: int? # Border width in pixels (default: 3)
fill_color: string? # Fill color in hex, supports alpha (e.g., "#FF3B3020")
corner_radius: int? # Corner radius for rounded_rect (default: 16)
shadow: bool? # Enable drop shadow (default: false)
shadow_color: string? # Shadow color with alpha (default: "#00000040")
shadow_blur: int? # Shadow blur radius (default: 15)
shadow_offset: [string, string]? # Shadow X,Y offset (default: ["0", "6"])
spotlight: bool? # Dim everything except highlight (default: false)
spotlight_color: string? # Overlay color (default: "#000000")
spotlight_opacity: float? # Overlay opacity 0.0-1.0 (default: 0.5)
blur_background: bool? # Blur outside highlight area (default: false)
blur_radius: int? # Background blur radius (default: 20)
# Zoom Content Item
- type: "zoom"
source_position: [string, string] # Center of area to magnify (required)
source_size: [string, string] # Crop region size (required)
display_position: [string, string] # Where magnified view appears
display_size: [string, string] # Size of magnified bubble (or use zoom_level)
zoom_level: float? # Auto-calculate display_size (e.g., 2.5 = 2.5x)
shape: "circle" | "rounded_rect" # Bubble shape (default: "circle")
border_color: string? # Border color in hex
border_width: int? # Border width (default: 3)
corner_radius: int? # For rounded_rect (default: 16)
shadow: bool? # Enable drop shadow (default: false)
shadow_color: string? # Shadow color with alpha (default: "#00000040")
shadow_blur: int? # Shadow blur radius (default: 15)
shadow_offset: [string, string]? # Shadow X,Y offset (default: ["0", "6"])
source_indicator: bool? # Show outline on source region (default: true)
source_indicator_style: string? # "border" | "dashed" | "fill" (default: "border")
connector: bool? # Draw line from source to display (default: false)
connector_style: string? # "straight" | "curved" | "facing" (default: "straight")
connector_color: string? # Line color (defaults to border_color)
connector_width: int? # Line width (default: 2)
connector_fill: string? # Fill color between facing connector linesKoubou uses a clean, modular architecture:
- CLI Layer (
koubou.cli): Command-line interface with rich output - Configuration (
koubou.config): Pydantic-based type-safe configuration - Generation Engine (
koubou.generator): Core screenshot generation logic - Renderers (
koubou.renderers): Specialized rendering for backgrounds, text, frames - Device Frames (
koubou.frames): 100+ device frame assets and metadata
# Clone the repository
git clone https://github.com/bitomule/koubou.git
cd koubou
# Install in development mode with all dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linting
black src/ tests/
isort src/ tests/
flake8 src/ tests/
mypy src/# Run all tests with coverage
pytest -v --cov=src/koubou
# Run specific test file
pytest tests/test_generator.py -v
# Run with live output
pytest -sContributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests and linting (
pytest,black,isort,flake8,mypy) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See CHANGELOG.md for complete version history.
MIT License - see LICENSE for details.
In the spirit of Japanese craftsmanship, Koubou embodies:
- ่ทไบบๆฐ่ณช (Shokunin-kishitsu) - Artisan spirit and dedication to craft
- ๅฎ็ง (Kanpeki) - Pursuit of perfection in every detail
- ็ฐกๆฝ (Kanketsu) - Elegant simplicity in design and usage
- ๅ่ณช (Hinshitsu) - Uncompromising quality in output
Every screenshot generated by Koubou reflects these values - carefully crafted, pixel-perfect, and ready for the world's most demanding app stores.