Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

- **🔄 Live Editing** - Real-time screenshot regeneration when config or assets change
- **🖥️ Live Preview Dashboard** - Auto-open a local dashboard for screenshot previews with hot reload
- **🧩 HTML/CSS Templates** - Render polished marketing layouts with Chrome or Playwright Chromium
- **🧩 HTML/CSS Templates** - Render polished marketing layouts with Playwright Chromium
- **🌍 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
Expand Down Expand Up @@ -47,7 +47,7 @@ brew install bitomule/tap/koubou
kou setup-html
```

If Google Chrome is already installed, HTML template rendering usually works without any extra setup. `kou setup-html` installs Playwright Chromium only when it is needed.
Koubou uses Playwright Chromium for all HTML rendering. `kou generate` and `kou live` install it automatically on first use for HTML projects, and `kou setup-html` is available when you want to preflight the environment explicitly.

**Python Developers**
```bash
Expand Down Expand Up @@ -91,9 +91,6 @@ kou --create-config my-html-screenshots.yaml --mode html
# Generate screenshots
kou generate my-screenshots.yaml

# Prepare HTML rendering if your project uses HTML templates
kou setup-html

# Inspect real frame geometry before designing HTML layouts
kou inspect-frame "iPhone 16 Pro - Black Titanium - Portrait" --output-size iPhone6_9

Expand All @@ -104,7 +101,7 @@ kou live my-screenshots.yaml
kou install-skills
```

`kou --create-config` also creates sample PNG assets in a sibling `screenshots/` directory, so the generated YAML can be rendered immediately. In `--mode html`, it also creates sample templates in `templates/` and the generated project is ready to run with `kou generate ... --setup-html`.
`kou --create-config` also creates sample PNG assets in a sibling `screenshots/` directory, so the generated YAML can be rendered immediately. In `--mode html`, it also creates sample templates in `templates/` and the generated project is ready to run with `kou generate ...`.

## 🧩 HTML Templates

Expand All @@ -122,8 +119,9 @@ screenshots:

- `variables:` are localizable `{{key}}` substitutions
- `assets:` are file-path substitutions exposed to the template as `{{key}}`
- `kou generate config.yaml --setup-html` prepares HTML rendering and generates in one run
- `kou live config.yaml --setup-html` does the same before starting live mode
- `kou generate config.yaml` prepares Playwright Chromium automatically when HTML templates are present
- `kou generate config.yaml --parallel-workers 4` renders multiple screenshots concurrently
- `kou live config.yaml` does the same before starting live mode
- `kou inspect-frame "<device>" --output-size <size> --output json` exposes frame and screen geometry for layout decisions

### Compact Layout JSON
Expand Down Expand Up @@ -260,6 +258,7 @@ project:
output_dir: "Screenshots/Generated"
device: "iPhone 15 Pro Portrait"
output_size: "iPhone6_9"
parallel_workers: 4 # Optional - render up to 4 screenshots concurrently

localization:
base_language: "en"
Expand Down Expand Up @@ -470,14 +469,18 @@ See the YAML API Reference below for all available options including gradients,
# Emit machine-readable results
kou generate config.yaml --output json

# Prepare HTML rendering and generate in one run
kou generate config.yaml --setup-html
# Override the worker count for this run
kou generate config.yaml --parallel-workers 4

# Generate HTML screenshots and auto-install Playwright Chromium on first run
kou generate config.yaml

# Enable verbose logging
kou generate config.yaml --verbose
```

For HTML screenshots, `--output json` includes `layout_path` alongside the PNG path so tooling can open the measured layout sidecar directly.
Set `project.parallel_workers` in YAML when you want the same concurrency level to apply to every run.

#### HTML Setup
```bash
Expand Down Expand Up @@ -521,8 +524,8 @@ kou inspect-frame "iPhone 16 Pro - Black Titanium - Portrait" --output-size 1200
# Start live editing with default settings
kou live config.yaml

# Prepare HTML rendering before starting live mode
kou live config.yaml --setup-html
# Start live mode and auto-install Playwright Chromium on first run
kou live config.yaml

# Adjust debounce delay (default: 0.5s)
kou live config.yaml --debounce 1.0
Expand Down
51 changes: 31 additions & 20 deletions src/koubou/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
from .generator import ScreenshotGenerator
from .html_preview import HtmlPreviewServer
from .html_setup import (
check_html_environment,
format_html_environment_error,
setup_html_environment,
)
from .live_generator import LiveScreenshotGenerator
Expand Down Expand Up @@ -105,7 +103,7 @@ def _create_config_file_with_mode(
)
console.print("\nEdit the configuration file and run:", style="blue")
if normalized_mode == "html":
console.print(f" kou generate {output_file} --setup-html", style="cyan")
console.print(f" kou generate {output_file}", style="cyan")
else:
console.print(f" kou generate {output_file}", style="cyan")

Expand Down Expand Up @@ -546,21 +544,15 @@ def _prepare_html_environment(
verbose: bool,
output_console: Console,
) -> None:
if setup_requested:
status = setup_html_environment(verbose=verbose)
if status.did_install_browser:
output_console.print(
f"HTML ready: installed {status.browser_name}", style="green"
)
else:
output_console.print(
f"HTML ready: using {status.browser_name}", style="green"
)
status = setup_html_environment(verbose=verbose)
if status.did_install_browser:
output_console.print(
f"HTML ready: installed {status.browser_name}", style="green"
)
return

status = check_html_environment()
if not status.ready:
raise KoubouError(format_html_environment_error(status))
if setup_requested:
output_console.print(f"HTML ready: using {status.browser_name}", style="green")


def _parse_output_size_option(value: str) -> Tuple[int, int]:
Expand Down Expand Up @@ -703,10 +695,19 @@ def generate(
output: str = typer.Option(
"table", "--output", help="Output format: table or json"
),
parallel_workers: int = typer.Option(
None,
"--parallel-workers",
min=1,
help="Override the number of screenshots rendered concurrently",
),
setup_html: bool = typer.Option(
False,
"--setup-html",
help="Prepare HTML rendering before generating HTML template screenshots",
help=(
"Prepare HTML rendering before generating. "
"Usually automatic for HTML templates."
),
),
verbose: bool = typer.Option(False, "--verbose", help="Enable verbose logging"),
):
Expand All @@ -727,6 +728,10 @@ def generate(
with open(config_file) as f:
config_data = yaml.safe_load(f)

if parallel_workers is not None:
config_data.setdefault("project", {})
config_data["project"]["parallel_workers"] = parallel_workers

try:
project_config = ProjectConfig(**config_data)
stderr_console.print("Using flexible content-based API", style="blue")
Expand Down Expand Up @@ -849,11 +854,14 @@ def install_skills(
None,
"--agent",
"-a",
help="Target a specific agent (e.g. claude-code, cursor). Installs to all detected agents by default.",
help=(
"Target a specific agent (e.g. claude-code, cursor). "
"Installs to all detected agents by default."
),
),
verbose: bool = typer.Option(False, "--verbose", help="Enable verbose logging"),
):
"""Install the Koubou skill pack for AI coding agents (Claude Code, Cursor, Windsurf, and more)."""
"""Install the Koubou skill pack for AI coding agents."""

setup_logging(verbose)

Expand Down Expand Up @@ -1173,7 +1181,10 @@ def live(
setup_html: bool = typer.Option(
False,
"--setup-html",
help="Prepare HTML rendering before starting live mode",
help=(
"Prepare HTML rendering before starting live mode. "
"Usually automatic for HTML templates."
),
),
):
"""Live editing mode - regenerate screenshots when config or assets change"""
Expand Down
8 changes: 8 additions & 0 deletions src/koubou/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,14 @@ class ProjectInfo(BaseModel):
name: str = Field(..., description="Project name")
output_dir: str = Field(default="output", description="Output directory")
device: str = Field(..., description="Target device frame")
parallel_workers: int = Field(
default=1,
ge=1,
description=(
"Number of screenshots to render concurrently. "
"Use 1 to keep sequential rendering."
),
)
output_size: Tuple[int, int] = Field(
default=(1320, 2868), # Default to iPhone6_9 dimensions
description=(
Expand Down
Loading
Loading