Spaces:
Running
on
Zero
Running
on
Zero
Julian Bilcke
commited on
Commit
·
355629c
1
Parent(s):
b182234
improve everything using AI
Browse files- CLAUDE.md +32 -9
- README.md +40 -4
- app.py +264 -100
- page_layouts.yaml +1396 -199
CLAUDE.md
CHANGED
|
@@ -39,25 +39,48 @@ pip install -r requirements.txt
|
|
| 39 |
- Supports custom styles and random style selection
|
| 40 |
- Each preset includes prefix, suffix, and negative prompt components
|
| 41 |
|
| 42 |
-
4. **Page Layouts System** (`app.py:89-
|
| 43 |
- `load_page_layouts()`: Loads multi-image layouts from `page_layouts.yaml`
|
| 44 |
-
-
|
|
|
|
|
|
|
| 45 |
- Dynamic layout selection based on number of images
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
- Uses ReportLab for high-quality PDF generation
|
| 50 |
- Preserves image quality at 95% JPEG compression
|
| 51 |
- A4 page size with flexible positioning system
|
|
|
|
| 52 |
|
| 53 |
-
|
| 54 |
-
- `
|
|
|
|
| 55 |
- Progressive generation with status updates
|
| 56 |
- Seed management for reproducibility across multiple images
|
| 57 |
- Returns PDF file, preview image, and seed information
|
| 58 |
|
| 59 |
-
|
| 60 |
-
- Slider for selecting 1-
|
| 61 |
- Dynamic layout dropdown that updates based on image count
|
| 62 |
- Style preset dropdown with custom style text option
|
| 63 |
- PDF download and image preview outputs
|
|
|
|
| 39 |
- Supports custom styles and random style selection
|
| 40 |
- Each preset includes prefix, suffix, and negative prompt components
|
| 41 |
|
| 42 |
+
4. **Page Layouts System** (`app.py:89-145`)
|
| 43 |
- `load_page_layouts()`: Loads multi-image layouts from `page_layouts.yaml`
|
| 44 |
+
- `get_layout_choices()`: Returns available layouts for a given number of images
|
| 45 |
+
- `get_layout_metadata()`: Extracts panel metadata (type, focus, composition) for each position
|
| 46 |
+
- Supports 1-8 images per page with 5-6 layout variations each
|
| 47 |
- Dynamic layout selection based on number of images
|
| 48 |
+
- **Panel Metadata System**: Each panel position includes metadata that describes:
|
| 49 |
+
- `panel_type`: establishing/action/closeup/dialogue/reaction/transition/detail/splash
|
| 50 |
+
- `focus`: environment/character/characters/action/emotion/object/event
|
| 51 |
+
- `composition`: wide/tall/square/portrait/landscape
|
| 52 |
+
- Metadata is used to guide the LLM in generating appropriate scene descriptions
|
| 53 |
+
|
| 54 |
+
5. **Story Generation System** (`app.py:147-265`)
|
| 55 |
+
- `generate_story_scenes()`: Uses Hugging Face InferenceClient with Qwen3-235B to generate scene descriptions
|
| 56 |
+
- Takes panel metadata as input to generate contextually appropriate content
|
| 57 |
+
- Adapts descriptions based on panel type, focus, and composition
|
| 58 |
+
- Returns structured scene data with captions and dialogue
|
| 59 |
+
- `parse_yaml_scenes()`: Parses LLM output into structured scene data
|
| 60 |
+
|
| 61 |
+
6. **Image Size Calculation** (`app.py:267-330`)
|
| 62 |
+
- `get_image_size_for_position()`: Calculates precise image dimensions based on layout aspect ratio
|
| 63 |
+
- Uses 8px rounding for model compatibility while maintaining aspect ratio accuracy
|
| 64 |
+
- Ensures images fill their layout containers without floating
|
| 65 |
+
- `get_layout_position_for_image()`: Retrieves position data for a specific panel
|
| 66 |
+
|
| 67 |
+
7. **PDF Generation** (`app.py:450-540`)
|
| 68 |
+
- `create_single_page_pdf()`: Creates PDF page with images arranged per layout
|
| 69 |
+
- `create_multi_page_pdf()`: Combines multiple pages into a single document
|
| 70 |
- Uses ReportLab for high-quality PDF generation
|
| 71 |
- Preserves image quality at 95% JPEG compression
|
| 72 |
- A4 page size with flexible positioning system
|
| 73 |
+
- Smart filling: fills space completely when aspect ratios match (<2% difference)
|
| 74 |
|
| 75 |
+
8. **Multi-Image Generation** (`app.py:545-650`)
|
| 76 |
+
- `infer_page()`: Main generation orchestrator
|
| 77 |
+
- Generates multiple images and combines into PDF
|
| 78 |
- Progressive generation with status updates
|
| 79 |
- Seed management for reproducibility across multiple images
|
| 80 |
- Returns PDF file, preview image, and seed information
|
| 81 |
|
| 82 |
+
9. **Gradio Interface** (`app.py:750-900+`)
|
| 83 |
+
- Slider for selecting 1-8 images per page
|
| 84 |
- Dynamic layout dropdown that updates based on image count
|
| 85 |
- Style preset dropdown with custom style text option
|
| 86 |
- PDF download and image preview outputs
|
README.md
CHANGED
|
@@ -1,13 +1,49 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: green
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 5.39.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
-
short_description: Generate
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: AiComicFactory2
|
| 3 |
+
emoji: 🦸
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: green
|
| 6 |
sdk: gradio
|
| 7 |
sdk_version: 5.39.0
|
| 8 |
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
+
short_description: Generate PDF comic books
|
| 11 |
---
|
| 12 |
|
| 13 |
+
## What is this?
|
| 14 |
+
|
| 15 |
+
This space is an app to generate comic books in PDF in a playful and easy way using AI.
|
| 16 |
+
|
| 17 |
+
It is designed to allow people having fun, without the technical constraint of manually typing text in speech bubbles etc. It is deliberately not designed for human-based manual editing.
|
| 18 |
+
|
| 19 |
+
## How can I use it?
|
| 20 |
+
|
| 21 |
+
The AiComicFactory2 is a standard Python/Gradio app that is free and open-source, but you need to have access to a GPU to run it.
|
| 22 |
+
|
| 23 |
+
The easiest way is to run it directly from my space on Hugging Face using the ZeroGPU system, which allows you to benefit from a free quota that gets refilled regularly.
|
| 24 |
+
|
| 25 |
+
You can subscribe to a PRO account on Hugging Face to get higher usage quotas 🫶
|
| 26 |
+
|
| 27 |
+
### Running in local
|
| 28 |
+
|
| 29 |
+
Alternatively if you already own your own GPU, then you simply have to install the Gradio app and run it!
|
| 30 |
+
|
| 31 |
+
While the commands to use varies depending on wether you use a Python package manager and your version of python, the basic CLI workflow is usually like this:
|
| 32 |
+
|
| 33 |
+
```bash
|
| 34 |
+
# prerequisites not covered by this quickstart:
|
| 35 |
+
# you need a terminal, Python, Git and Git LFS
|
| 36 |
+
|
| 37 |
+
# Get the code using Git
|
| 38 |
+
git clone git@hf.co:spaces/jbilcke-hf/AiComicFactory2
|
| 39 |
+
|
| 40 |
+
cd AiComicFactory2
|
| 41 |
+
|
| 42 |
+
# global install of dependencies
|
| 43 |
+
# the executable might be pip3 depending on your system
|
| 44 |
+
# but you should use a venv / package manager
|
| 45 |
+
pip install -r requirements.txt
|
| 46 |
+
|
| 47 |
+
# run the app (the executable might be python3, python3.12, python3.13 etc.. depending on your system)
|
| 48 |
+
python app.py
|
| 49 |
+
```
|
app.py
CHANGED
|
@@ -55,10 +55,10 @@ def load_page_layouts():
|
|
| 55 |
print(f"Error loading page layouts: {e}")
|
| 56 |
# Fallback to basic layouts
|
| 57 |
return {
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
}
|
| 63 |
|
| 64 |
# Load layouts at startup
|
|
@@ -72,6 +72,33 @@ def get_layout_choices(num_images: int) -> List[Tuple[str, str]]:
|
|
| 72 |
# Return empty list if no layouts found (shouldn't happen with our config)
|
| 73 |
return [("Default", "default")]
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
def get_random_style_preset():
|
| 76 |
"""Get a random style preset (excluding 'no_style' and 'random')."""
|
| 77 |
eligible_keys = [k for k in STYLE_PRESETS.keys() if k not in ['no_style', 'random']]
|
|
@@ -125,7 +152,7 @@ def apply_style_preset(prompt, style_preset_key, custom_style_text=""):
|
|
| 125 |
|
| 126 |
# --- Story Generation using Hugging Face InferenceClient ---
|
| 127 |
|
| 128 |
-
def generate_story_scenes(story_prompt, num_scenes, style_context=""):
|
| 129 |
"""
|
| 130 |
Generates a sequence of scene descriptions with captions and dialogues.
|
| 131 |
|
|
@@ -133,6 +160,7 @@ def generate_story_scenes(story_prompt, num_scenes, style_context=""):
|
|
| 133 |
story_prompt: The user's story prompt
|
| 134 |
num_scenes: Number of scenes to generate
|
| 135 |
style_context: Optional style context to consider
|
|
|
|
| 136 |
|
| 137 |
Returns:
|
| 138 |
List of dicts with 'caption' and 'dialogue' keys
|
|
@@ -156,29 +184,105 @@ def generate_story_scenes(story_prompt, num_scenes, style_context=""):
|
|
| 156 |
api_key=api_key,
|
| 157 |
)
|
| 158 |
|
| 159 |
-
#
|
| 160 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
|
| 162 |
IMPORTANT INSTRUCTIONS:
|
| 163 |
1. Output ONLY a YAML list with exactly {num_scenes} items
|
| 164 |
2. Each item must have exactly two fields:
|
| 165 |
- caption: A detailed visual description of the scene (describe characters, clothing, location, action, expressions)
|
| 166 |
- dialogue: Natural language description of what the character says/exclaims/shouts (can be empty string if no dialogue)
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
- DO NOT include character names in the dialogue text itself
|
| 171 |
-
- Use verbs like: says, exclaims, shouts, whispers, asks, replies, thinks
|
| 172 |
-
|
| 173 |
-
|
|
|
|
| 174 |
|
| 175 |
Example output format:
|
| 176 |
-
- caption: "
|
| 177 |
-
dialogue: "The detective
|
| 178 |
-
- caption: "
|
| 179 |
-
dialogue: "
|
| 180 |
-
- caption: "
|
| 181 |
-
dialogue: "The detective
|
| 182 |
|
| 183 |
Generate exactly {num_scenes} scenes. Output ONLY the YAML list, no other text."""
|
| 184 |
|
|
@@ -300,64 +404,73 @@ pipe.load_lora_weights(
|
|
| 300 |
"lightx2v/Qwen-Image-Lightning", weight_name="Qwen-Image-Lightning-8steps-V1.1.safetensors"
|
| 301 |
)
|
| 302 |
pipe.fuse_lora()
|
| 303 |
-
#pipe.unload_lora_weights()
|
| 304 |
-
|
| 305 |
-
#pipe.load_lora_weights("flymy-ai/qwen-image-realism-lora")
|
| 306 |
-
#pipe.fuse_lora()
|
| 307 |
-
#pipe.unload_lora_weights()
|
| 308 |
-
|
| 309 |
|
| 310 |
# --- UI Constants and Helpers ---
|
| 311 |
MAX_SEED = np.iinfo(np.int32).max
|
| 312 |
|
| 313 |
def get_image_size_for_position(position_data, image_index, num_images, max_resolution=1024):
|
| 314 |
-
"""
|
| 315 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
Args:
|
| 317 |
-
position_data: Layout position data [x, y, width, height] in relative units
|
| 318 |
image_index: Index of the current image (0-based)
|
| 319 |
num_images: Total number of images in the layout
|
| 320 |
max_resolution: Maximum resolution for any dimension (default 1024)
|
| 321 |
|
| 322 |
Returns:
|
| 323 |
-
tuple: (width, height)
|
| 324 |
"""
|
| 325 |
if not position_data:
|
| 326 |
return max_resolution, max_resolution # Default square
|
| 327 |
|
| 328 |
x_rel, y_rel, w_rel, h_rel = position_data
|
| 329 |
-
|
|
|
|
|
|
|
|
|
|
| 330 |
|
| 331 |
-
#
|
| 332 |
-
if
|
| 333 |
width = max_resolution
|
| 334 |
-
height =
|
| 335 |
-
# Ensure height is at least 384 for quality
|
| 336 |
-
if height < 384:
|
| 337 |
-
height = 384
|
| 338 |
-
width = int(384 * aspect_ratio)
|
| 339 |
else: # Taller than wide
|
| 340 |
height = max_resolution
|
| 341 |
-
width =
|
| 342 |
-
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
# Ensure we don't exceed max_resolution after rounding
|
| 352 |
if width > max_resolution:
|
| 353 |
width = max_resolution
|
|
|
|
| 354 |
if height > max_resolution:
|
| 355 |
height = max_resolution
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
| 360 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 361 |
return width, height
|
| 362 |
|
| 363 |
def get_layout_position_for_image(layout_id, num_images, image_index):
|
|
@@ -391,7 +504,13 @@ def get_layout_position_for_image(layout_id, num_images, image_index):
|
|
| 391 |
[0.666, 0.4, 0.283, 0.275], [0.666, 0.7, 0.283, 0.275]],
|
| 392 |
6: [[0.05, 0.05, 0.425, 0.283], [0.525, 0.05, 0.425, 0.283],
|
| 393 |
[0.05, 0.358, 0.425, 0.283], [0.525, 0.358, 0.425, 0.283],
|
| 394 |
-
[0.05, 0.666, 0.425, 0.283], [0.525, 0.666, 0.425, 0.283]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 395 |
}
|
| 396 |
|
| 397 |
positions = fallback_positions.get(num_images, fallback_positions[1])
|
|
@@ -522,26 +641,28 @@ def create_single_page_pdf(images: List[Image.Image], layout_id: str, num_images
|
|
| 522 |
if num_images == 1:
|
| 523 |
positions = [[0.02, 0.02, 0.96, 0.96]]
|
| 524 |
elif num_images == 2:
|
| 525 |
-
# Horizontal split with gap
|
| 526 |
positions = [[0.02, 0.02, 0.47, 0.96], [0.51, 0.02, 0.47, 0.96]]
|
| 527 |
elif num_images == 3:
|
| 528 |
-
# Three horizontal panels with gaps
|
| 529 |
positions = [[0.02, 0.2, 0.31, 0.6], [0.345, 0.2, 0.31, 0.6], [0.67, 0.2, 0.31, 0.6]]
|
| 530 |
elif num_images == 4:
|
| 531 |
-
# 2x2 grid with gaps
|
| 532 |
positions = [[0.02, 0.02, 0.47, 0.47], [0.51, 0.02, 0.47, 0.47],
|
| 533 |
[0.02, 0.51, 0.47, 0.47], [0.51, 0.51, 0.47, 0.47]]
|
| 534 |
elif num_images == 5:
|
| 535 |
-
# Hero top with 4 small panels below
|
| 536 |
positions = [[0.02, 0.02, 0.96, 0.44], [0.02, 0.48, 0.31, 0.5], [0.345, 0.48, 0.31, 0.5],
|
| 537 |
[0.67, 0.48, 0.31, 0.24], [0.67, 0.74, 0.31, 0.24]]
|
| 538 |
elif num_images == 6:
|
| 539 |
-
# 2x3 grid with gaps
|
| 540 |
positions = [[0.02, 0.02, 0.47, 0.31], [0.51, 0.02, 0.47, 0.31],
|
| 541 |
[0.02, 0.345, 0.47, 0.31], [0.51, 0.345, 0.47, 0.31],
|
| 542 |
[0.02, 0.67, 0.47, 0.31], [0.51, 0.67, 0.47, 0.31]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 543 |
else:
|
| 544 |
-
# For more than 6, create a simple grid
|
| 545 |
positions = [[0.02, 0.02, 0.96, 0.96]]
|
| 546 |
else:
|
| 547 |
positions = layout["positions"]
|
|
@@ -556,9 +677,6 @@ def create_single_page_pdf(images: List[Image.Image], layout_id: str, num_images
|
|
| 556 |
# Add small padding between panels (1% of page dimensions)
|
| 557 |
padding = 0.01
|
| 558 |
|
| 559 |
-
# Don't scale up - use the positions as defined in the layout
|
| 560 |
-
# This prevents overlapping when there are multiple images
|
| 561 |
-
|
| 562 |
# Apply padding to prevent images from touching edges
|
| 563 |
if x_rel < padding:
|
| 564 |
x_rel = padding
|
|
@@ -576,38 +694,49 @@ def create_single_page_pdf(images: List[Image.Image], layout_id: str, num_images
|
|
| 576 |
width = w_rel * page_width
|
| 577 |
height = h_rel * page_height
|
| 578 |
|
| 579 |
-
# Calculate
|
| 580 |
img_aspect = image.width / image.height
|
| 581 |
layout_aspect = width / height
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
actual_width = width
|
| 589 |
-
actual_height = new_height
|
| 590 |
-
actual_x = x
|
| 591 |
-
actual_y = y + y_offset
|
| 592 |
-
else:
|
| 593 |
-
# Image is taller than the layout space
|
| 594 |
-
new_width = height * img_aspect
|
| 595 |
-
x_offset = (width - new_width) / 2
|
| 596 |
-
actual_width = new_width
|
| 597 |
actual_height = height
|
| 598 |
-
actual_x = x
|
| 599 |
actual_y = y
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
|
| 601 |
# Convert PIL image to format suitable for ReportLab
|
| 602 |
img_buffer = io.BytesIO()
|
| 603 |
-
# Save with good quality
|
| 604 |
image.save(img_buffer, format='JPEG', quality=95)
|
| 605 |
img_buffer.seek(0)
|
| 606 |
|
| 607 |
-
# Draw the image on the PDF
|
|
|
|
|
|
|
| 608 |
pdf.drawImage(ImageReader(img_buffer), actual_x, actual_y,
|
| 609 |
width=actual_width, height=actual_height,
|
| 610 |
-
preserveAspectRatio=
|
| 611 |
|
| 612 |
# Save the PDF
|
| 613 |
pdf.save()
|
|
@@ -655,7 +784,7 @@ def create_multi_page_pdf(session_manager: SessionManager) -> str:
|
|
| 655 |
return str(pdf_path)
|
| 656 |
|
| 657 |
# --- Main Inference Function (with session support) ---
|
| 658 |
-
@spaces.GPU(duration=
|
| 659 |
def infer_page(
|
| 660 |
prompt,
|
| 661 |
guidance_scale=1.0,
|
|
@@ -677,8 +806,9 @@ def infer_page(
|
|
| 677 |
num_inference_steps (int): The number of denoising steps.
|
| 678 |
style_preset (str): The key of the style preset to apply.
|
| 679 |
custom_style_text (str): Custom style text when 'no_style' is selected.
|
| 680 |
-
num_images (int): Number of images to generate (1-
|
| 681 |
layout (str): The layout ID for arranging images in the PDF.
|
|
|
|
| 682 |
session_state: Current session state dictionary.
|
| 683 |
progress (gr.Progress): A Gradio Progress object to track generation.
|
| 684 |
|
|
@@ -702,9 +832,20 @@ def infer_page(
|
|
| 702 |
generated_images = []
|
| 703 |
used_seeds = []
|
| 704 |
|
| 705 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 706 |
progress(0, f"Generating story with {num_images} scenes...")
|
| 707 |
-
scenes = generate_story_scenes(prompt, int(num_images), style_preset)
|
| 708 |
|
| 709 |
# Generate the requested number of images
|
| 710 |
for i in range(int(num_images)):
|
|
@@ -718,6 +859,21 @@ def infer_page(
|
|
| 718 |
# Use scene caption and dialogue for this image
|
| 719 |
scene_prompt = scenes[i]['caption']
|
| 720 |
scene_dialogue = scenes[i]['dialogue']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 721 |
|
| 722 |
# Generate single image with automatic aspect ratio
|
| 723 |
image, used_seed = infer_single_auto(
|
|
@@ -767,10 +923,10 @@ def infer_single_auto(
|
|
| 767 |
num_images=1,
|
| 768 |
guidance_scale=1.0,
|
| 769 |
num_inference_steps=8,
|
| 770 |
-
dialogue="",
|
| 771 |
style_preset="no_style",
|
| 772 |
custom_style_text="",
|
| 773 |
-
max_resolution=1024,
|
| 774 |
):
|
| 775 |
"""
|
| 776 |
Generates an image with automatically determined aspect ratio based on layout position.
|
|
@@ -780,7 +936,15 @@ def infer_single_auto(
|
|
| 780 |
|
| 781 |
# Automatically determine image size based on position with custom max resolution
|
| 782 |
width, height = get_image_size_for_position(position_data, image_index, num_images, max_resolution)
|
| 783 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 784 |
# Set up the generator for reproducibility
|
| 785 |
generator = torch.Generator(device="cuda").manual_seed(seed)
|
| 786 |
|
|
@@ -793,7 +957,6 @@ def infer_single_auto(
|
|
| 793 |
|
| 794 |
# Add dialogue to the prompt if present
|
| 795 |
if dialogue and dialogue.strip():
|
| 796 |
-
# Simply append the dialogue as it's already properly formatted from the LLM
|
| 797 |
styled_prompt = f"{styled_prompt}. {dialogue.strip()}"
|
| 798 |
|
| 799 |
# Use style negative prompt if available, otherwise default
|
|
@@ -811,12 +974,11 @@ def infer_single_auto(
|
|
| 811 |
height=height,
|
| 812 |
num_inference_steps=num_inference_steps,
|
| 813 |
generator=generator,
|
| 814 |
-
true_cfg_scale=guidance_scale,
|
| 815 |
).images[0]
|
| 816 |
|
| 817 |
# Convert to grayscale if using manga_no_color style
|
| 818 |
if style_preset == "manga_no_color":
|
| 819 |
-
# Convert to grayscale while preserving quality
|
| 820 |
image = image.convert('L').convert('RGB')
|
| 821 |
|
| 822 |
return image, seed
|
|
@@ -980,10 +1142,10 @@ with gr.Blocks(css=css) as demo:
|
|
| 980 |
num_images_slider = gr.Slider(
|
| 981 |
label="Images per page",
|
| 982 |
minimum=1,
|
| 983 |
-
maximum=
|
| 984 |
step=1,
|
| 985 |
value=1,
|
| 986 |
-
info="Number of images to generate for the PDF (1-
|
| 987 |
)
|
| 988 |
|
| 989 |
# Page layout dropdown
|
|
@@ -1032,17 +1194,19 @@ with gr.Blocks(css=css) as demo:
|
|
| 1032 |
with gr.Accordion("Examples", open=True):
|
| 1033 |
styled_examples = [
|
| 1034 |
["A capybara wearing a suit holding a sign that reads Hello World", "no_style", "", 1],
|
| 1035 |
-
["
|
| 1036 |
-
["
|
| 1037 |
-
["
|
| 1038 |
-
["
|
| 1039 |
-
["
|
|
|
|
|
|
|
| 1040 |
]
|
| 1041 |
|
| 1042 |
gr.Examples(
|
| 1043 |
examples=styled_examples,
|
| 1044 |
inputs=[prompt, style_preset, custom_style_text, num_images_slider],
|
| 1045 |
-
outputs=None,
|
| 1046 |
fn=None,
|
| 1047 |
cache_examples=False
|
| 1048 |
)
|
|
|
|
| 55 |
print(f"Error loading page layouts: {e}")
|
| 56 |
# Fallback to basic layouts
|
| 57 |
return {
|
| 58 |
+
"1_image": [{"id": "full_page", "label": "Full Page", "positions": [[0.05, 0.05, 0.9, 0.9]]}],
|
| 59 |
+
"2_images": [{"id": "horizontal_split", "label": "Horizontal Split", "positions": [[0.05, 0.05, 0.425, 0.9], [0.525, 0.05, 0.425, 0.9]]}],
|
| 60 |
+
"3_images": [{"id": "grid", "label": "Grid", "positions": [[0.05, 0.05, 0.283, 0.5], [0.358, 0.05, 0.283, 0.5], [0.666, 0.05, 0.283, 0.5]]}],
|
| 61 |
+
"4_images": [{"id": "grid_2x2", "label": "2x2 Grid", "positions": [[0.05, 0.05, 0.425, 0.425], [0.525, 0.05, 0.425, 0.425], [0.05, 0.525, 0.425, 0.425], [0.525, 0.525, 0.425, 0.425]]}]
|
| 62 |
}
|
| 63 |
|
| 64 |
# Load layouts at startup
|
|
|
|
| 72 |
# Return empty list if no layouts found (shouldn't happen with our config)
|
| 73 |
return [("Default", "default")]
|
| 74 |
|
| 75 |
+
def get_layout_metadata(layout_id: str, num_images: int) -> List[Dict]:
|
| 76 |
+
"""Get metadata for each panel in a layout.
|
| 77 |
+
|
| 78 |
+
Args:
|
| 79 |
+
layout_id: ID of the selected layout
|
| 80 |
+
num_images: Total number of images
|
| 81 |
+
|
| 82 |
+
Returns:
|
| 83 |
+
List of metadata dicts with panel_type, focus, composition, shot_type, and camera_angle
|
| 84 |
+
"""
|
| 85 |
+
key = f"{num_images}_image" if num_images == 1 else f"{num_images}_images"
|
| 86 |
+
layouts = PAGE_LAYOUTS.get(key, [])
|
| 87 |
+
layout = next((l for l in layouts if l["id"] == layout_id), None)
|
| 88 |
+
|
| 89 |
+
if layout and "metadata" in layout:
|
| 90 |
+
return layout["metadata"]
|
| 91 |
+
|
| 92 |
+
# Fallback metadata if not found
|
| 93 |
+
fallback_meta = {
|
| 94 |
+
"panel_type": "action",
|
| 95 |
+
"focus": "character",
|
| 96 |
+
"composition": "square",
|
| 97 |
+
"shot_type": "medium",
|
| 98 |
+
"camera_angle": "eye_level"
|
| 99 |
+
}
|
| 100 |
+
return [fallback_meta] * num_images
|
| 101 |
+
|
| 102 |
def get_random_style_preset():
|
| 103 |
"""Get a random style preset (excluding 'no_style' and 'random')."""
|
| 104 |
eligible_keys = [k for k in STYLE_PRESETS.keys() if k not in ['no_style', 'random']]
|
|
|
|
| 152 |
|
| 153 |
# --- Story Generation using Hugging Face InferenceClient ---
|
| 154 |
|
| 155 |
+
def generate_story_scenes(story_prompt, num_scenes, style_context="", panel_metadata=None):
|
| 156 |
"""
|
| 157 |
Generates a sequence of scene descriptions with captions and dialogues.
|
| 158 |
|
|
|
|
| 160 |
story_prompt: The user's story prompt
|
| 161 |
num_scenes: Number of scenes to generate
|
| 162 |
style_context: Optional style context to consider
|
| 163 |
+
panel_metadata: List of metadata dicts for each panel
|
| 164 |
|
| 165 |
Returns:
|
| 166 |
List of dicts with 'caption' and 'dialogue' keys
|
|
|
|
| 184 |
api_key=api_key,
|
| 185 |
)
|
| 186 |
|
| 187 |
+
# Build panel descriptions from metadata
|
| 188 |
+
panel_descriptions = []
|
| 189 |
+
if panel_metadata and len(panel_metadata) == num_scenes:
|
| 190 |
+
for i, meta in enumerate(panel_metadata):
|
| 191 |
+
panel_type = meta.get('panel_type', 'action')
|
| 192 |
+
focus = meta.get('focus', 'character')
|
| 193 |
+
composition = meta.get('composition', 'square')
|
| 194 |
+
shot_type = meta.get('shot_type', 'medium')
|
| 195 |
+
camera_angle = meta.get('camera_angle', 'eye_level')
|
| 196 |
+
|
| 197 |
+
# Format shot type for readability
|
| 198 |
+
shot_display = shot_type.replace('_', ' ').title()
|
| 199 |
+
angle_display = camera_angle.replace('_', ' ').title()
|
| 200 |
+
|
| 201 |
+
# Create a descriptive text for this panel
|
| 202 |
+
desc = f"Panel {i+1}/{num_scenes} - {composition.upper()} composition, {shot_display} shot at {angle_display} angle, {panel_type} panel focusing on {focus}"
|
| 203 |
+
panel_descriptions.append(desc)
|
| 204 |
+
else:
|
| 205 |
+
# Fallback if no metadata
|
| 206 |
+
panel_descriptions = [f"Panel {i+1}/{num_scenes}" for i in range(num_scenes)]
|
| 207 |
+
|
| 208 |
+
# Create system prompt with panel-specific guidance
|
| 209 |
+
system_prompt = f"""You are a comic book story writer with expertise in cinematography and visual storytelling. Generate exactly {num_scenes} scenes for a comic page based on the user's story prompt.
|
| 210 |
+
|
| 211 |
+
PANEL LAYOUT INFORMATION:
|
| 212 |
+
The page has {num_scenes} panels with the following characteristics:
|
| 213 |
+
{chr(10).join(f"- {desc}" for desc in panel_descriptions)}
|
| 214 |
|
| 215 |
IMPORTANT INSTRUCTIONS:
|
| 216 |
1. Output ONLY a YAML list with exactly {num_scenes} items
|
| 217 |
2. Each item must have exactly two fields:
|
| 218 |
- caption: A detailed visual description of the scene (describe characters, clothing, location, action, expressions)
|
| 219 |
- dialogue: Natural language description of what the character says/exclaims/shouts (can be empty string if no dialogue)
|
| 220 |
+
|
| 221 |
+
3. **ADAPT EACH SCENE TO ITS PANEL TYPE:**
|
| 222 |
+
- ESTABLISHING panels: Describe the full environment, setting, atmosphere, time of day, location details
|
| 223 |
+
- ACTION panels: Focus on dynamic movement, motion lines, impact, energy, physical activity
|
| 224 |
+
- CLOSEUP panels: Describe facial features, eyes, expressions, emotions in extreme detail
|
| 225 |
+
- DIALOGUE panels: Focus on character interactions, body language during conversation
|
| 226 |
+
- REACTION panels: Emphasize emotional responses, facial expressions, body language
|
| 227 |
+
- DETAIL panels: Zoom in on specific objects, hands, symbols, or small but important elements
|
| 228 |
+
- TRANSITION panels: Show passage of time, change of location, or connecting moments
|
| 229 |
+
- SPLASH panels: Epic, dramatic, full-scene moments with maximum visual impact
|
| 230 |
+
|
| 231 |
+
4. **ADAPT TO SHOT TYPE (CINEMATOGRAPHY):**
|
| 232 |
+
- EXTREME WIDE SHOT: Vast landscapes, tiny characters in massive environments, epic scale
|
| 233 |
+
- WIDE SHOT: Full scene with characters and environment, establishing context
|
| 234 |
+
- FULL SHOT: Entire character from head to toe, showing their full body and stance
|
| 235 |
+
- MEDIUM FULL SHOT: Character from knees up, showing most of body with some environment
|
| 236 |
+
- MEDIUM SHOT: Character from waist up, balanced between character and setting
|
| 237 |
+
- MEDIUM CLOSEUP: Head and shoulders, focusing on face while showing some context
|
| 238 |
+
- CLOSEUP: Face filling frame, detailed facial features and expressions
|
| 239 |
+
- EXTREME CLOSEUP: Tiny detail - just eyes, hands, mouth, or specific object filling frame
|
| 240 |
+
|
| 241 |
+
5. **ADAPT TO CAMERA ANGLE:**
|
| 242 |
+
- EYE LEVEL: Neutral, straightforward angle - camera at character's eye level
|
| 243 |
+
- HIGH ANGLE: Camera looking down on subject - can make them seem vulnerable, small, or overwhelmed
|
| 244 |
+
- LOW ANGLE: Camera looking up at subject - makes them seem powerful, imposing, heroic
|
| 245 |
+
- OVERHEAD/BIRD'S EYE: Camera directly above looking down - shows spatial relationships, isolation
|
| 246 |
+
- DUTCH ANGLE/CANTED: Tilted camera - creates tension, disorientation, chaos, unease
|
| 247 |
+
- OVER THE SHOULDER (OTS): Camera behind one character looking at another - intimate conversation
|
| 248 |
+
- POV (Point of View): Camera as character's eyes - immersive, first-person perspective
|
| 249 |
+
|
| 250 |
+
6. **ADAPT TO COMPOSITION:**
|
| 251 |
+
- WIDE/LANDSCAPE: Emphasize horizontal elements, panoramic views, sweeping scenes, breadth
|
| 252 |
+
- TALL/PORTRAIT: Emphasize vertical elements, full-body shots, top-to-bottom action, height
|
| 253 |
+
- SQUARE: Balanced composition, centered subjects, symmetrical arrangements
|
| 254 |
+
|
| 255 |
+
7. **ADAPT TO FOCUS:**
|
| 256 |
+
- CHARACTER: Detailed character description (appearance, clothing, pose, expression)
|
| 257 |
+
- CHARACTERS (plural): Multiple people, their relationships, positioning, interactions
|
| 258 |
+
- ENVIRONMENT: Setting details, location, atmosphere, background elements, mood
|
| 259 |
+
- EVENT: What's happening, the action, the moment being captured, the incident
|
| 260 |
+
- EMOTION: Facial expression, body language, emotional state, feelings
|
| 261 |
+
- OBJECT: Detailed description of an important item, prop, symbol, or artifact
|
| 262 |
+
- ACTION: Movement, impact, dynamic poses, energy, motion
|
| 263 |
+
|
| 264 |
+
8. **CONSIDER PANEL PROGRESSION:**
|
| 265 |
+
- You're creating panel X of {num_scenes} - consider where you are in the story flow
|
| 266 |
+
- Early panels (1-2/{num_scenes}): Establish setting and introduce characters
|
| 267 |
+
- Middle panels: Build action, develop conflict, show character reactions
|
| 268 |
+
- Later panels ({num_scenes-1}-{num_scenes}/{num_scenes}): Resolve the moment, provide reaction or cliffhanger
|
| 269 |
+
|
| 270 |
+
9. For captions: Be VERY descriptive. Include shot type language like "wide shot of...", "close-up on...", "overhead view of...". Repeat character descriptions in each scene if needed.
|
| 271 |
+
|
| 272 |
+
10. For dialogue: Write as natural language action: "The [character] says: [what they say]" or "The [character] exclaims: [what they exclaim]"
|
| 273 |
- DO NOT include character names in the dialogue text itself
|
| 274 |
+
- Use verbs like: says, exclaims, shouts, whispers, asks, replies, thinks, mutters, screams
|
| 275 |
+
|
| 276 |
+
11. Keep continuity between scenes to tell a coherent story
|
| 277 |
+
12. Make each scene visually distinct but connected to the narrative
|
| 278 |
|
| 279 |
Example output format:
|
| 280 |
+
- caption: "Extreme wide shot from high angle of a dark alley at night, rain pouring down heavily, neon signs casting red and blue reflections in vast puddles covering the ground, tall buildings looming menacingly on both sides creating a narrow canyon, a young woman with long red hair wearing a blue detective coat stands small in the center of the frame examining glowing footprints on the wet pavement with a magnifying glass, dramatic lighting from above"
|
| 281 |
+
dialogue: "The detective whispers to herself: These tracks... they're not human"
|
| 282 |
+
- caption: "Extreme close-up at eye level of the detective's piercing green eyes widening in shock and fear, her pupils dilating rapidly, individual beads of rain clinging to her dark eyelashes, her face illuminated by an eerie pulsing blue glow from below, wrinkles forming on her forehead"
|
| 283 |
+
dialogue: ""
|
| 284 |
+
- caption: "Full shot at low angle, the red-haired detective in the blue coat leaping backwards dynamically with motion blur streaks, her coat billowing dramatically, a massive jagged shark fin erupting violently from a puddle behind her, water exploding upward in huge spray with droplets frozen mid-air, her expression one of pure terror, arms flailing"
|
| 285 |
+
dialogue: "The detective shouts at the top of her lungs: OH NO! SHARKS IN THE CITY!"
|
| 286 |
|
| 287 |
Generate exactly {num_scenes} scenes. Output ONLY the YAML list, no other text."""
|
| 288 |
|
|
|
|
| 404 |
"lightx2v/Qwen-Image-Lightning", weight_name="Qwen-Image-Lightning-8steps-V1.1.safetensors"
|
| 405 |
)
|
| 406 |
pipe.fuse_lora()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
|
| 408 |
# --- UI Constants and Helpers ---
|
| 409 |
MAX_SEED = np.iinfo(np.int32).max
|
| 410 |
|
| 411 |
def get_image_size_for_position(position_data, image_index, num_images, max_resolution=1024):
|
| 412 |
+
"""
|
| 413 |
+
Calculate EXACT image dimensions to match layout aspect ratio perfectly.
|
| 414 |
+
|
| 415 |
+
This function calculates pixel dimensions that precisely match the aspect ratio
|
| 416 |
+
of the layout rectangle to ensure images fill their containers without floating.
|
| 417 |
+
|
| 418 |
Args:
|
| 419 |
+
position_data: Layout position data [x, y, width, height] in relative units (0-1)
|
| 420 |
image_index: Index of the current image (0-based)
|
| 421 |
num_images: Total number of images in the layout
|
| 422 |
max_resolution: Maximum resolution for any dimension (default 1024)
|
| 423 |
|
| 424 |
Returns:
|
| 425 |
+
tuple: (width, height) with exact aspect ratio matching the layout
|
| 426 |
"""
|
| 427 |
if not position_data:
|
| 428 |
return max_resolution, max_resolution # Default square
|
| 429 |
|
| 430 |
x_rel, y_rel, w_rel, h_rel = position_data
|
| 431 |
+
|
| 432 |
+
# Calculate the EXACT aspect ratio from the layout rectangle
|
| 433 |
+
# This is crucial - we must match this aspect ratio precisely
|
| 434 |
+
layout_aspect_ratio = w_rel / h_rel if h_rel > 0 else 1.0
|
| 435 |
|
| 436 |
+
# Scale to max_resolution while maintaining EXACT aspect ratio
|
| 437 |
+
if layout_aspect_ratio >= 1: # Wider than tall
|
| 438 |
width = max_resolution
|
| 439 |
+
height = max_resolution / layout_aspect_ratio
|
|
|
|
|
|
|
|
|
|
|
|
|
| 440 |
else: # Taller than wide
|
| 441 |
height = max_resolution
|
| 442 |
+
width = max_resolution * layout_aspect_ratio
|
| 443 |
+
|
| 444 |
+
# Round to nearest 8 pixels for model compatibility
|
| 445 |
+
# Using 8px instead of 64px preserves aspect ratio much better
|
| 446 |
+
# Most diffusion models work well with multiples of 8
|
| 447 |
+
width = round(width / 8) * 8
|
| 448 |
+
height = round(height / 8) * 8
|
| 449 |
+
|
| 450 |
+
# After rounding, ensure we maintain the aspect ratio as closely as possible
|
| 451 |
+
# and don't exceed max_resolution
|
|
|
|
| 452 |
if width > max_resolution:
|
| 453 |
width = max_resolution
|
| 454 |
+
height = round((max_resolution / layout_aspect_ratio) / 8) * 8
|
| 455 |
if height > max_resolution:
|
| 456 |
height = max_resolution
|
| 457 |
+
width = round((max_resolution * layout_aspect_ratio) / 8) * 8
|
| 458 |
+
|
| 459 |
+
# Ensure minimum size of 256px (reduced from 384 for more flexibility)
|
| 460 |
+
# while maintaining the layout aspect ratio
|
| 461 |
+
min_size = 256
|
| 462 |
+
if width < min_size or height < min_size:
|
| 463 |
+
if layout_aspect_ratio >= 1: # Wider image
|
| 464 |
+
width = max(min_size, width)
|
| 465 |
+
height = round((width / layout_aspect_ratio) / 8) * 8
|
| 466 |
+
else: # Taller image
|
| 467 |
+
height = max(min_size, height)
|
| 468 |
+
width = round((height * layout_aspect_ratio) / 8) * 8
|
| 469 |
+
|
| 470 |
+
# Final safety checks
|
| 471 |
+
width = max(min_size, min(int(width), max_resolution))
|
| 472 |
+
height = max(min_size, min(int(height), max_resolution))
|
| 473 |
+
|
| 474 |
return width, height
|
| 475 |
|
| 476 |
def get_layout_position_for_image(layout_id, num_images, image_index):
|
|
|
|
| 504 |
[0.666, 0.4, 0.283, 0.275], [0.666, 0.7, 0.283, 0.275]],
|
| 505 |
6: [[0.05, 0.05, 0.425, 0.283], [0.525, 0.05, 0.425, 0.283],
|
| 506 |
[0.05, 0.358, 0.425, 0.283], [0.525, 0.358, 0.425, 0.283],
|
| 507 |
+
[0.05, 0.666, 0.425, 0.283], [0.525, 0.666, 0.425, 0.283]],
|
| 508 |
+
7: [[0.28, 0.02, 0.44, 0.3], [0.02, 0.25, 0.3, 0.25], [0.68, 0.25, 0.3, 0.25],
|
| 509 |
+
[0.25, 0.35, 0.5, 0.3], [0.02, 0.52, 0.3, 0.25], [0.68, 0.52, 0.3, 0.25],
|
| 510 |
+
[0.28, 0.68, 0.44, 0.3]],
|
| 511 |
+
8: [[0.02, 0.02, 0.23, 0.47], [0.27, 0.02, 0.23, 0.47], [0.52, 0.02, 0.23, 0.47],
|
| 512 |
+
[0.77, 0.02, 0.21, 0.47], [0.02, 0.51, 0.23, 0.47], [0.27, 0.51, 0.23, 0.47],
|
| 513 |
+
[0.52, 0.51, 0.23, 0.47], [0.77, 0.51, 0.21, 0.47]]
|
| 514 |
}
|
| 515 |
|
| 516 |
positions = fallback_positions.get(num_images, fallback_positions[1])
|
|
|
|
| 641 |
if num_images == 1:
|
| 642 |
positions = [[0.02, 0.02, 0.96, 0.96]]
|
| 643 |
elif num_images == 2:
|
|
|
|
| 644 |
positions = [[0.02, 0.02, 0.47, 0.96], [0.51, 0.02, 0.47, 0.96]]
|
| 645 |
elif num_images == 3:
|
|
|
|
| 646 |
positions = [[0.02, 0.2, 0.31, 0.6], [0.345, 0.2, 0.31, 0.6], [0.67, 0.2, 0.31, 0.6]]
|
| 647 |
elif num_images == 4:
|
|
|
|
| 648 |
positions = [[0.02, 0.02, 0.47, 0.47], [0.51, 0.02, 0.47, 0.47],
|
| 649 |
[0.02, 0.51, 0.47, 0.47], [0.51, 0.51, 0.47, 0.47]]
|
| 650 |
elif num_images == 5:
|
|
|
|
| 651 |
positions = [[0.02, 0.02, 0.96, 0.44], [0.02, 0.48, 0.31, 0.5], [0.345, 0.48, 0.31, 0.5],
|
| 652 |
[0.67, 0.48, 0.31, 0.24], [0.67, 0.74, 0.31, 0.24]]
|
| 653 |
elif num_images == 6:
|
|
|
|
| 654 |
positions = [[0.02, 0.02, 0.47, 0.31], [0.51, 0.02, 0.47, 0.31],
|
| 655 |
[0.02, 0.345, 0.47, 0.31], [0.51, 0.345, 0.47, 0.31],
|
| 656 |
[0.02, 0.67, 0.47, 0.31], [0.51, 0.67, 0.47, 0.31]]
|
| 657 |
+
elif num_images == 7:
|
| 658 |
+
positions = [[0.28, 0.02, 0.44, 0.3], [0.02, 0.25, 0.3, 0.25], [0.68, 0.25, 0.3, 0.25],
|
| 659 |
+
[0.25, 0.35, 0.5, 0.3], [0.02, 0.52, 0.3, 0.25], [0.68, 0.52, 0.3, 0.25],
|
| 660 |
+
[0.28, 0.68, 0.44, 0.3]]
|
| 661 |
+
elif num_images == 8:
|
| 662 |
+
positions = [[0.02, 0.02, 0.23, 0.47], [0.27, 0.02, 0.23, 0.47], [0.52, 0.02, 0.23, 0.47],
|
| 663 |
+
[0.77, 0.02, 0.21, 0.47], [0.02, 0.51, 0.23, 0.47], [0.27, 0.51, 0.23, 0.47],
|
| 664 |
+
[0.52, 0.51, 0.23, 0.47], [0.77, 0.51, 0.21, 0.47]]
|
| 665 |
else:
|
|
|
|
| 666 |
positions = [[0.02, 0.02, 0.96, 0.96]]
|
| 667 |
else:
|
| 668 |
positions = layout["positions"]
|
|
|
|
| 677 |
# Add small padding between panels (1% of page dimensions)
|
| 678 |
padding = 0.01
|
| 679 |
|
|
|
|
|
|
|
|
|
|
| 680 |
# Apply padding to prevent images from touching edges
|
| 681 |
if x_rel < padding:
|
| 682 |
x_rel = padding
|
|
|
|
| 694 |
width = w_rel * page_width
|
| 695 |
height = h_rel * page_height
|
| 696 |
|
| 697 |
+
# Calculate aspect ratios for comparison
|
| 698 |
img_aspect = image.width / image.height
|
| 699 |
layout_aspect = width / height
|
| 700 |
+
aspect_diff = abs(img_aspect - layout_aspect) / layout_aspect
|
| 701 |
+
|
| 702 |
+
# If aspect ratios match closely (within 2%), fill the space completely
|
| 703 |
+
# Otherwise, preserve aspect ratio to avoid distortion
|
| 704 |
+
if aspect_diff < 0.02: # Less than 2% difference
|
| 705 |
+
# Aspect ratios match well - fill the space completely
|
| 706 |
actual_width = width
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 707 |
actual_height = height
|
| 708 |
+
actual_x = x
|
| 709 |
actual_y = y
|
| 710 |
+
else:
|
| 711 |
+
# Significant aspect ratio difference - preserve it to avoid distortion
|
| 712 |
+
if img_aspect > layout_aspect:
|
| 713 |
+
# Image is wider than the layout space
|
| 714 |
+
new_height = width / img_aspect
|
| 715 |
+
y_offset = (height - new_height) / 2
|
| 716 |
+
actual_width = width
|
| 717 |
+
actual_height = new_height
|
| 718 |
+
actual_x = x
|
| 719 |
+
actual_y = y + y_offset
|
| 720 |
+
else:
|
| 721 |
+
# Image is taller than the layout space
|
| 722 |
+
new_width = height * img_aspect
|
| 723 |
+
x_offset = (width - new_width) / 2
|
| 724 |
+
actual_width = new_width
|
| 725 |
+
actual_height = height
|
| 726 |
+
actual_x = x + x_offset
|
| 727 |
+
actual_y = y
|
| 728 |
|
| 729 |
# Convert PIL image to format suitable for ReportLab
|
| 730 |
img_buffer = io.BytesIO()
|
|
|
|
| 731 |
image.save(img_buffer, format='JPEG', quality=95)
|
| 732 |
img_buffer.seek(0)
|
| 733 |
|
| 734 |
+
# Draw the image on the PDF
|
| 735 |
+
# When aspect ratios match (aspect_diff < 0.02), we fill completely
|
| 736 |
+
# Otherwise we preserve aspect ratio to prevent distortion
|
| 737 |
pdf.drawImage(ImageReader(img_buffer), actual_x, actual_y,
|
| 738 |
width=actual_width, height=actual_height,
|
| 739 |
+
preserveAspectRatio=(aspect_diff >= 0.02), mask='auto')
|
| 740 |
|
| 741 |
# Save the PDF
|
| 742 |
pdf.save()
|
|
|
|
| 784 |
return str(pdf_path)
|
| 785 |
|
| 786 |
# --- Main Inference Function (with session support) ---
|
| 787 |
+
@spaces.GPU(duration=240) # Increased duration for up to 8 images
|
| 788 |
def infer_page(
|
| 789 |
prompt,
|
| 790 |
guidance_scale=1.0,
|
|
|
|
| 806 |
num_inference_steps (int): The number of denoising steps.
|
| 807 |
style_preset (str): The key of the style preset to apply.
|
| 808 |
custom_style_text (str): Custom style text when 'no_style' is selected.
|
| 809 |
+
num_images (int): Number of images to generate (1-8).
|
| 810 |
layout (str): The layout ID for arranging images in the PDF.
|
| 811 |
+
max_resolution: Maximum resolution for any dimension.
|
| 812 |
session_state: Current session state dictionary.
|
| 813 |
progress (gr.Progress): A Gradio Progress object to track generation.
|
| 814 |
|
|
|
|
| 832 |
generated_images = []
|
| 833 |
used_seeds = []
|
| 834 |
|
| 835 |
+
# Get panel metadata for this layout
|
| 836 |
+
panel_metadata = get_layout_metadata(layout, int(num_images))
|
| 837 |
+
|
| 838 |
+
# Debug: print metadata
|
| 839 |
+
print(f"\n=== LAYOUT METADATA for {layout} with {num_images} images ===")
|
| 840 |
+
for i, meta in enumerate(panel_metadata):
|
| 841 |
+
shot_type = meta.get('shot_type', 'medium').replace('_', ' ').title()
|
| 842 |
+
camera_angle = meta.get('camera_angle', 'eye_level').replace('_', ' ').title()
|
| 843 |
+
print(f"Panel {i+1}/{num_images}: {meta['panel_type']} | Focus: {meta['focus']} | {meta['composition']} | {shot_type} @ {camera_angle}")
|
| 844 |
+
print("=" * 80 + "\n")
|
| 845 |
+
|
| 846 |
+
# Generate story scenes with metadata
|
| 847 |
progress(0, f"Generating story with {num_images} scenes...")
|
| 848 |
+
scenes = generate_story_scenes(prompt, int(num_images), style_preset, panel_metadata)
|
| 849 |
|
| 850 |
# Generate the requested number of images
|
| 851 |
for i in range(int(num_images)):
|
|
|
|
| 859 |
# Use scene caption and dialogue for this image
|
| 860 |
scene_prompt = scenes[i]['caption']
|
| 861 |
scene_dialogue = scenes[i]['dialogue']
|
| 862 |
+
|
| 863 |
+
# Get metadata for this panel
|
| 864 |
+
panel_meta = panel_metadata[i] if i < len(panel_metadata) else {}
|
| 865 |
+
|
| 866 |
+
# Debug output
|
| 867 |
+
print(f"\n--- Generating Panel {i+1}/{num_images} ---")
|
| 868 |
+
print(f"Type: {panel_meta.get('panel_type', 'unknown')}")
|
| 869 |
+
print(f"Focus: {panel_meta.get('focus', 'unknown')}")
|
| 870 |
+
print(f"Composition: {panel_meta.get('composition', 'unknown')}")
|
| 871 |
+
shot_display = panel_meta.get('shot_type', 'medium').replace('_', ' ').title()
|
| 872 |
+
angle_display = panel_meta.get('camera_angle', 'eye_level').replace('_', ' ').title()
|
| 873 |
+
print(f"Shot: {shot_display} at {angle_display} angle")
|
| 874 |
+
print(f"Caption: {scene_prompt[:100]}..." if len(scene_prompt) > 100 else f"Caption: {scene_prompt}")
|
| 875 |
+
print(f"Dialogue: {scene_dialogue if scene_dialogue else '(none)'}")
|
| 876 |
+
print("-" * 80)
|
| 877 |
|
| 878 |
# Generate single image with automatic aspect ratio
|
| 879 |
image, used_seed = infer_single_auto(
|
|
|
|
| 923 |
num_images=1,
|
| 924 |
guidance_scale=1.0,
|
| 925 |
num_inference_steps=8,
|
| 926 |
+
dialogue="",
|
| 927 |
style_preset="no_style",
|
| 928 |
custom_style_text="",
|
| 929 |
+
max_resolution=1024,
|
| 930 |
):
|
| 931 |
"""
|
| 932 |
Generates an image with automatically determined aspect ratio based on layout position.
|
|
|
|
| 936 |
|
| 937 |
# Automatically determine image size based on position with custom max resolution
|
| 938 |
width, height = get_image_size_for_position(position_data, image_index, num_images, max_resolution)
|
| 939 |
+
|
| 940 |
+
# Calculate layout aspect ratio for verification
|
| 941 |
+
if position_data:
|
| 942 |
+
x_rel, y_rel, w_rel, h_rel = position_data
|
| 943 |
+
layout_aspect = w_rel / h_rel if h_rel > 0 else 1.0
|
| 944 |
+
image_aspect = width / height
|
| 945 |
+
aspect_error = abs(image_aspect - layout_aspect) / layout_aspect * 100
|
| 946 |
+
print(f"Image {image_index + 1}/{num_images}: Layout aspect={layout_aspect:.4f}, Image aspect={image_aspect:.4f}, Error={aspect_error:.2f}%")
|
| 947 |
+
|
| 948 |
# Set up the generator for reproducibility
|
| 949 |
generator = torch.Generator(device="cuda").manual_seed(seed)
|
| 950 |
|
|
|
|
| 957 |
|
| 958 |
# Add dialogue to the prompt if present
|
| 959 |
if dialogue and dialogue.strip():
|
|
|
|
| 960 |
styled_prompt = f"{styled_prompt}. {dialogue.strip()}"
|
| 961 |
|
| 962 |
# Use style negative prompt if available, otherwise default
|
|
|
|
| 974 |
height=height,
|
| 975 |
num_inference_steps=num_inference_steps,
|
| 976 |
generator=generator,
|
| 977 |
+
true_cfg_scale=guidance_scale,
|
| 978 |
).images[0]
|
| 979 |
|
| 980 |
# Convert to grayscale if using manga_no_color style
|
| 981 |
if style_preset == "manga_no_color":
|
|
|
|
| 982 |
image = image.convert('L').convert('RGB')
|
| 983 |
|
| 984 |
return image, seed
|
|
|
|
| 1142 |
num_images_slider = gr.Slider(
|
| 1143 |
label="Images per page",
|
| 1144 |
minimum=1,
|
| 1145 |
+
maximum=8,
|
| 1146 |
step=1,
|
| 1147 |
value=1,
|
| 1148 |
+
info="Number of images to generate for the PDF (1-8)"
|
| 1149 |
)
|
| 1150 |
|
| 1151 |
# Page layout dropdown
|
|
|
|
| 1194 |
with gr.Accordion("Examples", open=True):
|
| 1195 |
styled_examples = [
|
| 1196 |
["A capybara wearing a suit holding a sign that reads Hello World", "no_style", "", 1],
|
| 1197 |
+
["Two astronauts discovering alien technology on Mars", "flying_saucer", "", 2],
|
| 1198 |
+
["Detective solving a mystery in a noir city", "manga_no_color", "", 3],
|
| 1199 |
+
["Epic battle between robots and monsters", "american_comic_90", "", 4],
|
| 1200 |
+
["Journey through an enchanted forest", "franco_belgian", "", 5],
|
| 1201 |
+
["Space station crew dealing with an emergency", "render", "", 6],
|
| 1202 |
+
["Medieval knights on a quest", "medieval", "", 7],
|
| 1203 |
+
["Superhero team assembling for final battle", "american_comic_90", "", 8],
|
| 1204 |
]
|
| 1205 |
|
| 1206 |
gr.Examples(
|
| 1207 |
examples=styled_examples,
|
| 1208 |
inputs=[prompt, style_preset, custom_style_text, num_images_slider],
|
| 1209 |
+
outputs=None,
|
| 1210 |
fn=None,
|
| 1211 |
cache_examples=False
|
| 1212 |
)
|
page_layouts.yaml
CHANGED
|
@@ -1,245 +1,1442 @@
|
|
| 1 |
# Page layouts configuration for multi-image PDF generation
|
| 2 |
# Each layout defines how images are arranged on a page
|
| 3 |
# Positions are defined as (x, y, width, height) in relative units (0-1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
layouts:
|
| 6 |
1_image:
|
| 7 |
-
- id: "
|
| 8 |
-
label: "Full
|
| 9 |
-
description: "Single image
|
| 10 |
positions:
|
| 11 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
2_images:
|
| 14 |
- id: "horizontal_split"
|
| 15 |
-
label: "
|
| 16 |
-
description: "Two
|
| 17 |
positions:
|
| 18 |
-
- [0.02, 0.02, 0.47, 0.96]
|
| 19 |
-
- [0.51, 0.02, 0.47, 0.96]
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
- id: "vertical_split"
|
| 22 |
-
label: "
|
| 23 |
-
description: "
|
| 24 |
positions:
|
| 25 |
-
- [0.02, 0.02, 0.96, 0.47]
|
| 26 |
-
- [0.02, 0.51, 0.96, 0.47]
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
-
- id: "
|
| 29 |
-
label: "
|
| 30 |
-
description: "Large
|
| 31 |
positions:
|
| 32 |
-
- [0.02, 0.02, 0.65, 0.96]
|
| 33 |
-
- [0.69, 0.
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
-
- id: "
|
| 36 |
-
label: "
|
| 37 |
-
description: "
|
| 38 |
positions:
|
| 39 |
-
- [0.02, 0.02, 0.96, 0.
|
| 40 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
description: "Three images in a row"
|
| 46 |
positions:
|
| 47 |
-
- [0.02, 0.
|
| 48 |
-
- [0.
|
| 49 |
-
|
|
|
|
|
|
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
|
|
|
| 54 |
positions:
|
| 55 |
-
- [0.
|
| 56 |
-
- [0.
|
| 57 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
- id: "hero_top"
|
| 60 |
-
label: "
|
| 61 |
-
description: "Large
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
positions:
|
| 63 |
-
- [0.02, 0.
|
| 64 |
-
- [0.
|
| 65 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
-
- id: "
|
| 68 |
-
label: "
|
| 69 |
-
description: "
|
| 70 |
positions:
|
| 71 |
-
- [0.02, 0.02, 0.
|
| 72 |
-
- [0.
|
| 73 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
-
- id: "
|
| 76 |
-
label: "
|
| 77 |
-
description: "
|
| 78 |
positions:
|
| 79 |
-
- [0.
|
| 80 |
-
- [0.
|
| 81 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
|
| 83 |
4_images:
|
| 84 |
- id: "grid_2x2"
|
| 85 |
-
label: "
|
| 86 |
-
description: "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
positions:
|
| 88 |
-
- [0.02, 0.02, 0.
|
| 89 |
-
- [0.
|
| 90 |
-
- [0.02, 0.
|
| 91 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
-
- id: "
|
| 94 |
-
label: "
|
| 95 |
-
description: "
|
| 96 |
positions:
|
| 97 |
-
- [0.
|
| 98 |
-
- [0.
|
| 99 |
-
- [0.
|
| 100 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
-
- id: "
|
| 103 |
-
label: "
|
| 104 |
-
description: "
|
| 105 |
positions:
|
| 106 |
-
- [0.
|
| 107 |
-
- [0.
|
| 108 |
-
- [0.
|
| 109 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
-
- id: "
|
| 112 |
-
label: "
|
| 113 |
-
description: "
|
| 114 |
positions:
|
| 115 |
-
- [0.
|
| 116 |
-
- [0.
|
| 117 |
-
- [0.
|
| 118 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
|
| 120 |
- id: "l_shape"
|
| 121 |
-
label: "
|
| 122 |
-
description: "L
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
positions:
|
| 124 |
-
- [0.
|
| 125 |
-
- [0.
|
| 126 |
-
- [0.
|
| 127 |
-
- [0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
|
| 129 |
5_images:
|
| 130 |
-
- id: "
|
| 131 |
-
label: "
|
| 132 |
-
description: "
|
| 133 |
-
positions:
|
| 134 |
-
- [0.02, 0.02, 0.96, 0.
|
| 135 |
-
- [0.02, 0.
|
| 136 |
-
- [0.
|
| 137 |
-
- [0.
|
| 138 |
-
- [0.
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
- [0.02, 0.
|
| 155 |
-
|
| 156 |
-
-
|
| 157 |
-
-
|
| 158 |
-
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
- [0.
|
| 167 |
-
- [0.
|
| 168 |
-
- [0.
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
-
|
| 175 |
-
-
|
| 176 |
-
-
|
| 177 |
-
|
| 178 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
|
| 180 |
6_images:
|
| 181 |
-
- id: "
|
| 182 |
-
label: "Classic
|
| 183 |
-
description: "Traditional
|
| 184 |
-
positions:
|
| 185 |
-
- [0.02, 0.02, 0.47, 0.31]
|
| 186 |
-
- [0.51, 0.02, 0.47, 0.31]
|
| 187 |
-
- [0.02, 0.345, 0.47, 0.31]
|
| 188 |
-
- [0.51, 0.345, 0.47, 0.31]
|
| 189 |
-
- [0.02, 0.67, 0.47, 0.31]
|
| 190 |
-
- [0.51, 0.67, 0.47, 0.31]
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
-
|
| 197 |
-
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
- [0.
|
| 208 |
-
- [0.
|
| 209 |
-
|
| 210 |
-
-
|
| 211 |
-
-
|
| 212 |
-
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
- [0.02, 0.
|
| 222 |
-
- [0.
|
| 223 |
-
- [0.
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
-
|
| 230 |
-
-
|
| 231 |
-
-
|
| 232 |
-
-
|
| 233 |
-
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
- [0.
|
| 241 |
-
- [0.05, 0.
|
| 242 |
-
- [0.
|
| 243 |
-
- [0.
|
| 244 |
-
- [0.
|
| 245 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Page layouts configuration for multi-image PDF generation
|
| 2 |
# Each layout defines how images are arranged on a page
|
| 3 |
# Positions are defined as (x, y, width, height) in relative units (0-1)
|
| 4 |
+
# Coordinate system: (0,0) is top-left, X increases right, Y increases down
|
| 5 |
+
#
|
| 6 |
+
# Panel metadata helps guide image generation:
|
| 7 |
+
# - panel_type: establishing/action/closeup/dialogue/reaction/transition/detail/splash
|
| 8 |
+
# - focus: environment/character/characters/action/emotion/object/event
|
| 9 |
+
# - composition: wide/tall/square/portrait/landscape
|
| 10 |
+
# - shot_type: extreme_wide/wide/full/medium_full/medium/medium_closeup/closeup/extreme_closeup
|
| 11 |
+
# - camera_angle: eye_level/high_angle/low_angle/overhead/dutch_angle/over_shoulder/pov
|
| 12 |
|
| 13 |
layouts:
|
| 14 |
1_image:
|
| 15 |
+
- id: "full_bleed"
|
| 16 |
+
label: "Full Bleed"
|
| 17 |
+
description: "Single image filling entire page"
|
| 18 |
positions:
|
| 19 |
+
- [0.0, 0.0, 1.0, 1.0]
|
| 20 |
+
metadata:
|
| 21 |
+
- {panel_type: "splash", focus: "event", composition: "square", shot_type: "full", camera_angle: "eye_level"}
|
| 22 |
+
|
| 23 |
+
- id: "classic_frame"
|
| 24 |
+
label: "Classic Frame"
|
| 25 |
+
description: "Single image with traditional margins"
|
| 26 |
+
positions:
|
| 27 |
+
- [0.05, 0.05, 0.9, 0.9]
|
| 28 |
+
metadata:
|
| 29 |
+
- {panel_type: "establishing", focus: "environment", composition: "square", shot_type: "wide", camera_angle: "high_angle"}
|
| 30 |
+
|
| 31 |
+
- id: "portrait_focus"
|
| 32 |
+
label: "Portrait Focus"
|
| 33 |
+
description: "Vertical emphasis for character shots"
|
| 34 |
+
positions:
|
| 35 |
+
- [0.15, 0.02, 0.7, 0.96]
|
| 36 |
+
metadata:
|
| 37 |
+
- {panel_type: "closeup", focus: "character", composition: "portrait", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 38 |
+
|
| 39 |
+
- id: "cinematic_wide"
|
| 40 |
+
label: "Cinematic Wide"
|
| 41 |
+
description: "Wide letterbox format"
|
| 42 |
+
positions:
|
| 43 |
+
- [0.02, 0.25, 0.96, 0.5]
|
| 44 |
+
metadata:
|
| 45 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "eye_level"}
|
| 46 |
+
|
| 47 |
+
- id: "floating_center"
|
| 48 |
+
label: "Floating Center"
|
| 49 |
+
description: "Centered with breathing room"
|
| 50 |
+
positions:
|
| 51 |
+
- [0.1, 0.15, 0.8, 0.7]
|
| 52 |
+
metadata:
|
| 53 |
+
- {panel_type: "dialogue", focus: "character", composition: "square", shot_type: "medium", camera_angle: "eye_level"}
|
| 54 |
|
| 55 |
2_images:
|
| 56 |
- id: "horizontal_split"
|
| 57 |
+
label: "Even Split"
|
| 58 |
+
description: "Two equal panels side by side"
|
| 59 |
positions:
|
| 60 |
+
- [0.02, 0.02, 0.47, 0.96]
|
| 61 |
+
- [0.51, 0.02, 0.47, 0.96]
|
| 62 |
+
metadata:
|
| 63 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait", shot_type: "wide", camera_angle: "eye_level"}
|
| 64 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 65 |
|
| 66 |
- id: "vertical_split"
|
| 67 |
+
label: "Top & Bottom"
|
| 68 |
+
description: "Stacked panels"
|
| 69 |
positions:
|
| 70 |
+
- [0.02, 0.02, 0.96, 0.47]
|
| 71 |
+
- [0.02, 0.51, 0.96, 0.47]
|
| 72 |
+
metadata:
|
| 73 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "high_angle"}
|
| 74 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "full", camera_angle: "eye_level"}
|
| 75 |
|
| 76 |
+
- id: "hero_sidekick"
|
| 77 |
+
label: "Hero & Sidekick"
|
| 78 |
+
description: "Large main panel with small detail"
|
| 79 |
positions:
|
| 80 |
+
- [0.02, 0.02, 0.65, 0.96]
|
| 81 |
+
- [0.69, 0.25, 0.29, 0.5]
|
| 82 |
+
metadata:
|
| 83 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "eye_level"}
|
| 84 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait", shot_type: "closeup", camera_angle: "eye_level"}
|
| 85 |
|
| 86 |
+
- id: "before_after"
|
| 87 |
+
label: "Before & After"
|
| 88 |
+
description: "Cause and effect layout"
|
| 89 |
positions:
|
| 90 |
+
- [0.02, 0.02, 0.96, 0.44]
|
| 91 |
+
- [0.02, 0.48, 0.96, 0.5]
|
| 92 |
+
metadata:
|
| 93 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "wide", camera_angle: "eye_level"}
|
| 94 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "medium_full", camera_angle: "dutch_angle"}
|
| 95 |
|
| 96 |
+
- id: "diagonal_tension"
|
| 97 |
+
label: "Diagonal Tension"
|
| 98 |
+
description: "Overlapping dynamic panels"
|
|
|
|
| 99 |
positions:
|
| 100 |
+
- [0.02, 0.02, 0.6, 0.6]
|
| 101 |
+
- [0.38, 0.38, 0.6, 0.6]
|
| 102 |
+
metadata:
|
| 103 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium", camera_angle: "high_angle"}
|
| 104 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium", camera_angle: "low_angle"}
|
| 105 |
|
| 106 |
+
3_images:
|
| 107 |
+
- id: "triptych"
|
| 108 |
+
label: "Triptych"
|
| 109 |
+
description: "Three equal vertical panels"
|
| 110 |
positions:
|
| 111 |
+
- [0.02, 0.02, 0.31, 0.96]
|
| 112 |
+
- [0.345, 0.02, 0.31, 0.96]
|
| 113 |
+
- [0.67, 0.02, 0.31, 0.96]
|
| 114 |
+
metadata:
|
| 115 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait", shot_type: "wide", camera_angle: "eye_level"}
|
| 116 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "eye_level"}
|
| 117 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 118 |
|
| 119 |
- id: "hero_top"
|
| 120 |
+
label: "Establishing Shot"
|
| 121 |
+
description: "Large top panel with details below"
|
| 122 |
+
positions:
|
| 123 |
+
- [0.02, 0.02, 0.96, 0.5]
|
| 124 |
+
- [0.02, 0.54, 0.47, 0.44]
|
| 125 |
+
- [0.51, 0.54, 0.47, 0.44]
|
| 126 |
+
metadata:
|
| 127 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "high_angle"}
|
| 128 |
+
- {panel_type: "action", focus: "character", composition: "square", shot_type: "medium", camera_angle: "eye_level"}
|
| 129 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square", shot_type: "closeup", camera_angle: "eye_level"}
|
| 130 |
+
|
| 131 |
+
- id: "l_shape"
|
| 132 |
+
label: "L-Shape Flow"
|
| 133 |
+
description: "Reading flow in L pattern"
|
| 134 |
+
positions:
|
| 135 |
+
- [0.02, 0.02, 0.47, 0.47]
|
| 136 |
+
- [0.51, 0.02, 0.47, 0.47]
|
| 137 |
+
- [0.02, 0.51, 0.96, 0.47]
|
| 138 |
+
metadata:
|
| 139 |
+
- {panel_type: "dialogue", focus: "character", composition: "square", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 140 |
+
- {panel_type: "dialogue", focus: "character", composition: "square", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 141 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "full", camera_angle: "eye_level"}
|
| 142 |
+
|
| 143 |
+
- id: "spotlight"
|
| 144 |
+
label: "Spotlight"
|
| 145 |
+
description: "Central focus with side panels"
|
| 146 |
positions:
|
| 147 |
+
- [0.02, 0.15, 0.28, 0.7]
|
| 148 |
+
- [0.32, 0.02, 0.36, 0.96]
|
| 149 |
+
- [0.7, 0.15, 0.28, 0.7]
|
| 150 |
+
metadata:
|
| 151 |
+
- {panel_type: "reaction", focus: "character", composition: "portrait", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 152 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 153 |
+
- {panel_type: "reaction", focus: "character", composition: "portrait", shot_type: "closeup", camera_angle: "eye_level"}
|
| 154 |
|
| 155 |
+
- id: "vertical_flow"
|
| 156 |
+
label: "Vertical Flow"
|
| 157 |
+
description: "Three stacked panels for sequential action"
|
| 158 |
positions:
|
| 159 |
+
- [0.02, 0.02, 0.96, 0.31]
|
| 160 |
+
- [0.02, 0.345, 0.96, 0.31]
|
| 161 |
+
- [0.02, 0.67, 0.96, 0.31]
|
| 162 |
+
metadata:
|
| 163 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "wide", camera_angle: "eye_level"}
|
| 164 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 165 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "medium", camera_angle: "dutch_angle"}
|
| 166 |
|
| 167 |
+
- id: "manga_action"
|
| 168 |
+
label: "Manga Action"
|
| 169 |
+
description: "Dynamic manga-style layout"
|
| 170 |
positions:
|
| 171 |
+
- [0.52, 0.02, 0.46, 0.45]
|
| 172 |
+
- [0.02, 0.02, 0.48, 0.65]
|
| 173 |
+
- [0.02, 0.69, 0.96, 0.29]
|
| 174 |
+
metadata:
|
| 175 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square", shot_type: "closeup", camera_angle: "low_angle"}
|
| 176 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 177 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "wide", camera_angle: "overhead"}
|
| 178 |
|
| 179 |
4_images:
|
| 180 |
- id: "grid_2x2"
|
| 181 |
+
label: "Classic Grid"
|
| 182 |
+
description: "Traditional 2x2 layout"
|
| 183 |
+
positions:
|
| 184 |
+
- [0.02, 0.02, 0.47, 0.47]
|
| 185 |
+
- [0.51, 0.02, 0.47, 0.47]
|
| 186 |
+
- [0.02, 0.51, 0.47, 0.47]
|
| 187 |
+
- [0.51, 0.51, 0.47, 0.47]
|
| 188 |
+
metadata:
|
| 189 |
+
- {panel_type: "establishing", focus: "environment", composition: "square", shot_type: "wide", camera_angle: "high_angle"}
|
| 190 |
+
- {panel_type: "dialogue", focus: "character", composition: "square", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 191 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium", camera_angle: "eye_level"}
|
| 192 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square", shot_type: "closeup", camera_angle: "eye_level"}
|
| 193 |
+
|
| 194 |
+
- id: "widescreen"
|
| 195 |
+
label: "Widescreen Strips"
|
| 196 |
+
description: "Four cinematic horizontal strips"
|
| 197 |
+
positions:
|
| 198 |
+
- [0.02, 0.02, 0.96, 0.23]
|
| 199 |
+
- [0.02, 0.27, 0.96, 0.23]
|
| 200 |
+
- [0.02, 0.52, 0.96, 0.23]
|
| 201 |
+
- [0.02, 0.77, 0.96, 0.21]
|
| 202 |
+
metadata:
|
| 203 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "eye_level"}
|
| 204 |
+
- {panel_type: "dialogue", focus: "characters", composition: "wide", shot_type: "medium", camera_angle: "eye_level"}
|
| 205 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "full", camera_angle: "low_angle"}
|
| 206 |
+
- {panel_type: "reaction", focus: "emotion", composition: "wide", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 207 |
+
|
| 208 |
+
- id: "hero_cluster"
|
| 209 |
+
label: "Hero with Cluster"
|
| 210 |
+
description: "Large panel with three supporting"
|
| 211 |
+
positions:
|
| 212 |
+
- [0.02, 0.02, 0.6, 0.63]
|
| 213 |
+
- [0.64, 0.02, 0.34, 0.3]
|
| 214 |
+
- [0.64, 0.34, 0.34, 0.31]
|
| 215 |
+
- [0.02, 0.67, 0.96, 0.31]
|
| 216 |
+
metadata:
|
| 217 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "full", camera_angle: "low_angle"}
|
| 218 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 219 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 220 |
+
- {panel_type: "transition", focus: "environment", composition: "wide", shot_type: "wide", camera_angle: "eye_level"}
|
| 221 |
+
|
| 222 |
+
- id: "comic_strip"
|
| 223 |
+
label: "Comic Strip"
|
| 224 |
+
description: "Newspaper strip style"
|
| 225 |
+
positions:
|
| 226 |
+
- [0.02, 0.3, 0.23, 0.4]
|
| 227 |
+
- [0.27, 0.3, 0.23, 0.4]
|
| 228 |
+
- [0.52, 0.3, 0.23, 0.4]
|
| 229 |
+
- [0.77, 0.3, 0.21, 0.4]
|
| 230 |
+
metadata:
|
| 231 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait", shot_type: "full", camera_angle: "eye_level"}
|
| 232 |
+
- {panel_type: "dialogue", focus: "characters", composition: "portrait", shot_type: "medium", camera_angle: "eye_level"}
|
| 233 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "medium", camera_angle: "eye_level"}
|
| 234 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait", shot_type: "closeup", camera_angle: "eye_level"}
|
| 235 |
+
|
| 236 |
+
- id: "z_pattern"
|
| 237 |
+
label: "Z-Pattern"
|
| 238 |
+
description: "Natural reading flow in Z shape"
|
| 239 |
+
positions:
|
| 240 |
+
- [0.02, 0.02, 0.47, 0.35]
|
| 241 |
+
- [0.51, 0.02, 0.47, 0.35]
|
| 242 |
+
- [0.02, 0.39, 0.47, 0.59]
|
| 243 |
+
- [0.51, 0.39, 0.47, 0.59]
|
| 244 |
+
metadata:
|
| 245 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "high_angle"}
|
| 246 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 247 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 248 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "medium_full", camera_angle: "dutch_angle"}
|
| 249 |
+
|
| 250 |
+
- id: "explosion"
|
| 251 |
+
label: "Explosion"
|
| 252 |
+
description: "Central impact with surrounding panels"
|
| 253 |
+
positions:
|
| 254 |
+
- [0.02, 0.02, 0.35, 0.35]
|
| 255 |
+
- [0.63, 0.02, 0.35, 0.35]
|
| 256 |
+
- [0.27, 0.27, 0.46, 0.46]
|
| 257 |
+
- [0.02, 0.63, 0.96, 0.35]
|
| 258 |
+
metadata:
|
| 259 |
+
- {panel_type: "establishing", focus: "environment", composition: "square", shot_type: "wide", camera_angle: "eye_level"}
|
| 260 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 261 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium", camera_angle: "low_angle"}
|
| 262 |
+
- {panel_type: "reaction", focus: "characters", composition: "wide", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 263 |
+
|
| 264 |
+
5_images:
|
| 265 |
+
- id: "hero_banner"
|
| 266 |
+
label: "Hero Banner"
|
| 267 |
+
description: "Wide establishing shot with four panels below"
|
| 268 |
+
positions:
|
| 269 |
+
- [0.02, 0.02, 0.96, 0.38]
|
| 270 |
+
- [0.02, 0.42, 0.47, 0.28]
|
| 271 |
+
- [0.51, 0.42, 0.47, 0.28]
|
| 272 |
+
- [0.02, 0.72, 0.47, 0.26]
|
| 273 |
+
- [0.51, 0.72, 0.47, 0.26]
|
| 274 |
+
metadata:
|
| 275 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "high_angle"}
|
| 276 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 277 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 278 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 279 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 280 |
+
|
| 281 |
+
- id: "manga_vertical"
|
| 282 |
+
label: "Manga Vertical"
|
| 283 |
+
description: "Japanese right-to-left vertical flow"
|
| 284 |
+
positions:
|
| 285 |
+
- [0.52, 0.02, 0.46, 0.32]
|
| 286 |
+
- [0.02, 0.02, 0.48, 0.32]
|
| 287 |
+
- [0.52, 0.36, 0.46, 0.3]
|
| 288 |
+
- [0.02, 0.36, 0.48, 0.3]
|
| 289 |
+
- [0.02, 0.68, 0.96, 0.3]
|
| 290 |
+
metadata:
|
| 291 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "eye_level"}
|
| 292 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 293 |
+
- {panel_type: "action", focus: "character", composition: "landscape", shot_type: "full", camera_angle: "low_angle"}
|
| 294 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 295 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "full", camera_angle: "overhead"}
|
| 296 |
+
|
| 297 |
+
- id: "pyramid"
|
| 298 |
+
label: "Pyramid"
|
| 299 |
+
description: "Building tension from top to bottom"
|
| 300 |
+
positions:
|
| 301 |
+
- [0.25, 0.02, 0.5, 0.25]
|
| 302 |
+
- [0.02, 0.29, 0.47, 0.3]
|
| 303 |
+
- [0.51, 0.29, 0.47, 0.3]
|
| 304 |
+
- [0.02, 0.61, 0.31, 0.37]
|
| 305 |
+
- [0.67, 0.61, 0.31, 0.37]
|
| 306 |
+
metadata:
|
| 307 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "high_angle"}
|
| 308 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 309 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 310 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 311 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "medium", camera_angle: "dutch_angle"}
|
| 312 |
+
|
| 313 |
+
- id: "spotlight_drama"
|
| 314 |
+
label: "Spotlight Drama"
|
| 315 |
+
description: "Central focus with corner details"
|
| 316 |
+
positions:
|
| 317 |
+
- [0.02, 0.02, 0.35, 0.35]
|
| 318 |
+
- [0.63, 0.02, 0.35, 0.35]
|
| 319 |
+
- [0.22, 0.22, 0.56, 0.56]
|
| 320 |
+
- [0.02, 0.63, 0.35, 0.35]
|
| 321 |
+
- [0.63, 0.63, 0.35, 0.35]
|
| 322 |
+
metadata:
|
| 323 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 324 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 325 |
+
- {panel_type: "action", focus: "character", composition: "square", shot_type: "full", camera_angle: "low_angle"}
|
| 326 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square", shot_type: "closeup", camera_angle: "low_angle"}
|
| 327 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square", shot_type: "closeup", camera_angle: "high_angle"}
|
| 328 |
+
|
| 329 |
+
- id: "euro_bd"
|
| 330 |
+
label: "Euro BD Classic"
|
| 331 |
+
description: "Franco-Belgian structured layout"
|
| 332 |
+
positions:
|
| 333 |
+
- [0.02, 0.02, 0.47, 0.29]
|
| 334 |
+
- [0.51, 0.02, 0.47, 0.29]
|
| 335 |
+
- [0.02, 0.33, 0.96, 0.31]
|
| 336 |
+
- [0.02, 0.66, 0.47, 0.32]
|
| 337 |
+
- [0.51, 0.66, 0.47, 0.32]
|
| 338 |
+
metadata:
|
| 339 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "eye_level"}
|
| 340 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 341 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "full", camera_angle: "eye_level"}
|
| 342 |
+
- {panel_type: "dialogue", focus: "characters", composition: "landscape", shot_type: "medium", camera_angle: "over_shoulder"}
|
| 343 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 344 |
+
|
| 345 |
+
- id: "action_burst"
|
| 346 |
+
label: "Action Burst"
|
| 347 |
+
description: "Dynamic superhero action layout"
|
| 348 |
+
positions:
|
| 349 |
+
- [0.02, 0.02, 0.55, 0.55]
|
| 350 |
+
- [0.59, 0.02, 0.39, 0.26]
|
| 351 |
+
- [0.59, 0.3, 0.39, 0.27]
|
| 352 |
+
- [0.02, 0.59, 0.47, 0.39]
|
| 353 |
+
- [0.51, 0.59, 0.47, 0.39]
|
| 354 |
+
metadata:
|
| 355 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "full", camera_angle: "low_angle"}
|
| 356 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 357 |
+
- {panel_type: "closeup", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "low_angle"}
|
| 358 |
+
- {panel_type: "action", focus: "character", composition: "landscape", shot_type: "medium_full", camera_angle: "dutch_angle"}
|
| 359 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 360 |
+
|
| 361 |
+
6_images:
|
| 362 |
+
- id: "classic_grid"
|
| 363 |
+
label: "Classic 2x3 Grid"
|
| 364 |
+
description: "Traditional American comic layout"
|
| 365 |
+
positions:
|
| 366 |
+
- [0.02, 0.02, 0.47, 0.31]
|
| 367 |
+
- [0.51, 0.02, 0.47, 0.31]
|
| 368 |
+
- [0.02, 0.345, 0.47, 0.31]
|
| 369 |
+
- [0.51, 0.345, 0.47, 0.31]
|
| 370 |
+
- [0.02, 0.67, 0.47, 0.31]
|
| 371 |
+
- [0.51, 0.67, 0.47, 0.31]
|
| 372 |
+
metadata:
|
| 373 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "high_angle"}
|
| 374 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 375 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 376 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 377 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "full", camera_angle: "low_angle"}
|
| 378 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 379 |
+
|
| 380 |
+
- id: "hero_surround"
|
| 381 |
+
label: "Hero Surrounded"
|
| 382 |
+
description: "Large central panel with five around it"
|
| 383 |
positions:
|
| 384 |
+
- [0.02, 0.02, 0.31, 0.28]
|
| 385 |
+
- [0.67, 0.02, 0.31, 0.28]
|
| 386 |
+
- [0.02, 0.7, 0.31, 0.28]
|
| 387 |
+
- [0.67, 0.7, 0.31, 0.28]
|
| 388 |
+
- [0.25, 0.25, 0.5, 0.5]
|
| 389 |
+
- [0.35, 0.35, 0.63, 0.33]
|
| 390 |
+
metadata:
|
| 391 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 392 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 393 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "closeup", camera_angle: "low_angle"}
|
| 394 |
+
- {panel_type: "detail", focus: "character", composition: "square", shot_type: "closeup", camera_angle: "eye_level"}
|
| 395 |
+
- {panel_type: "action", focus: "character", composition: "square", shot_type: "full", camera_angle: "low_angle"}
|
| 396 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium", camera_angle: "dutch_angle"}
|
| 397 |
|
| 398 |
+
- id: "staircase"
|
| 399 |
+
label: "Staircase"
|
| 400 |
+
description: "Diagonal reading flow"
|
| 401 |
positions:
|
| 402 |
+
- [0.02, 0.02, 0.45, 0.3]
|
| 403 |
+
- [0.49, 0.02, 0.49, 0.3]
|
| 404 |
+
- [0.02, 0.34, 0.45, 0.3]
|
| 405 |
+
- [0.49, 0.34, 0.49, 0.3]
|
| 406 |
+
- [0.02, 0.66, 0.45, 0.32]
|
| 407 |
+
- [0.49, 0.66, 0.49, 0.32]
|
| 408 |
+
metadata:
|
| 409 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "eye_level"}
|
| 410 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 411 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 412 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 413 |
+
- {panel_type: "action", focus: "character", composition: "landscape", shot_type: "full", camera_angle: "low_angle"}
|
| 414 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 415 |
|
| 416 |
+
- id: "splash_detail"
|
| 417 |
+
label: "Splash with Details"
|
| 418 |
+
description: "Full-page moment with detail insets"
|
| 419 |
positions:
|
| 420 |
+
- [0.05, 0.05, 0.4, 0.4]
|
| 421 |
+
- [0.55, 0.05, 0.4, 0.4]
|
| 422 |
+
- [0.05, 0.55, 0.4, 0.4]
|
| 423 |
+
- [0.55, 0.55, 0.4, 0.4]
|
| 424 |
+
- [0.25, 0.25, 0.5, 0.5]
|
| 425 |
+
- [0.35, 0.35, 0.3, 0.3]
|
| 426 |
+
metadata:
|
| 427 |
+
- {panel_type: "detail", focus: "environment", composition: "square", shot_type: "closeup", camera_angle: "eye_level"}
|
| 428 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 429 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "closeup", camera_angle: "low_angle"}
|
| 430 |
+
- {panel_type: "detail", focus: "character", composition: "square", shot_type: "closeup", camera_angle: "eye_level"}
|
| 431 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "full", camera_angle: "low_angle"}
|
| 432 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 433 |
|
| 434 |
+
- id: "manga_4koma_plus"
|
| 435 |
+
label: "Manga 4-Koma Plus"
|
| 436 |
+
description: "Japanese 4-panel with header/footer"
|
| 437 |
positions:
|
| 438 |
+
- [0.02, 0.02, 0.96, 0.15]
|
| 439 |
+
- [0.02, 0.19, 0.47, 0.25]
|
| 440 |
+
- [0.51, 0.19, 0.47, 0.25]
|
| 441 |
+
- [0.02, 0.46, 0.47, 0.25]
|
| 442 |
+
- [0.51, 0.46, 0.47, 0.25]
|
| 443 |
+
- [0.02, 0.73, 0.96, 0.25]
|
| 444 |
+
metadata:
|
| 445 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "eye_level"}
|
| 446 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 447 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "over_shoulder"}
|
| 448 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 449 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "full", camera_angle: "dutch_angle"}
|
| 450 |
+
- {panel_type: "reaction", focus: "emotion", composition: "wide", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 451 |
+
|
| 452 |
+
- id: "tension_build"
|
| 453 |
+
label: "Tension Builder"
|
| 454 |
+
description: "Progressive revelation layout"
|
| 455 |
+
positions:
|
| 456 |
+
- [0.02, 0.02, 0.96, 0.22]
|
| 457 |
+
- [0.02, 0.26, 0.47, 0.22]
|
| 458 |
+
- [0.51, 0.26, 0.47, 0.22]
|
| 459 |
+
- [0.02, 0.5, 0.31, 0.48]
|
| 460 |
+
- [0.345, 0.5, 0.31, 0.48]
|
| 461 |
+
- [0.67, 0.5, 0.31, 0.48]
|
| 462 |
+
metadata:
|
| 463 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "wide", camera_angle: "high_angle"}
|
| 464 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 465 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 466 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 467 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "medium_full", camera_angle: "dutch_angle"}
|
| 468 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 469 |
+
|
| 470 |
+
7_images:
|
| 471 |
+
- id: "hero_hexagon"
|
| 472 |
+
label: "Hero Hexagon"
|
| 473 |
+
description: "Central focus with six surrounding"
|
| 474 |
+
positions:
|
| 475 |
+
- [0.28, 0.02, 0.44, 0.3]
|
| 476 |
+
- [0.02, 0.25, 0.3, 0.25]
|
| 477 |
+
- [0.68, 0.25, 0.3, 0.25]
|
| 478 |
+
- [0.25, 0.35, 0.5, 0.3]
|
| 479 |
+
- [0.02, 0.52, 0.3, 0.25]
|
| 480 |
+
- [0.68, 0.52, 0.3, 0.25]
|
| 481 |
+
- [0.28, 0.68, 0.44, 0.3]
|
| 482 |
+
metadata:
|
| 483 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "high_angle"}
|
| 484 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 485 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 486 |
+
- {panel_type: "action", focus: "character", composition: "landscape", shot_type: "full", camera_angle: "low_angle"}
|
| 487 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 488 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 489 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 490 |
+
|
| 491 |
+
- id: "narrative_flow"
|
| 492 |
+
label: "Narrative Flow"
|
| 493 |
+
description: "Story progression with varied sizes"
|
| 494 |
+
positions:
|
| 495 |
+
- [0.02, 0.02, 0.47, 0.28]
|
| 496 |
+
- [0.51, 0.02, 0.47, 0.28]
|
| 497 |
+
- [0.02, 0.32, 0.96, 0.24]
|
| 498 |
+
- [0.02, 0.58, 0.31, 0.4]
|
| 499 |
+
- [0.345, 0.58, 0.31, 0.4]
|
| 500 |
+
- [0.67, 0.58, 0.31, 0.2]
|
| 501 |
+
- [0.67, 0.8, 0.31, 0.18]
|
| 502 |
+
metadata:
|
| 503 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "eye_level"}
|
| 504 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 505 |
+
- {panel_type: "action", focus: "event", composition: "wide", shot_type: "full", camera_angle: "low_angle"}
|
| 506 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "full", camera_angle: "eye_level"}
|
| 507 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "medium_full", camera_angle: "dutch_angle"}
|
| 508 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait", shot_type: "closeup", camera_angle: "low_angle"}
|
| 509 |
+
- {panel_type: "detail", focus: "object", composition: "portrait", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 510 |
+
|
| 511 |
+
- id: "double_spread"
|
| 512 |
+
label: "Double Feature"
|
| 513 |
+
description: "Two hero panels with details"
|
| 514 |
+
positions:
|
| 515 |
+
- [0.02, 0.02, 0.47, 0.45]
|
| 516 |
+
- [0.51, 0.02, 0.47, 0.45]
|
| 517 |
+
- [0.02, 0.49, 0.31, 0.24]
|
| 518 |
+
- [0.345, 0.49, 0.31, 0.24]
|
| 519 |
+
- [0.67, 0.49, 0.31, 0.24]
|
| 520 |
+
- [0.02, 0.75, 0.47, 0.23]
|
| 521 |
+
- [0.51, 0.75, 0.47, 0.23]
|
| 522 |
+
metadata:
|
| 523 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 524 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "full", camera_angle: "high_angle"}
|
| 525 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 526 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 527 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "closeup", camera_angle: "overhead"}
|
| 528 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 529 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 530 |
+
|
| 531 |
+
- id: "spiral_narrative"
|
| 532 |
+
label: "Spiral Narrative"
|
| 533 |
+
description: "Circular reading flow"
|
| 534 |
+
positions:
|
| 535 |
+
- [0.28, 0.02, 0.44, 0.25]
|
| 536 |
+
- [0.52, 0.15, 0.46, 0.25]
|
| 537 |
+
- [0.52, 0.42, 0.46, 0.25]
|
| 538 |
+
- [0.28, 0.55, 0.44, 0.25]
|
| 539 |
+
- [0.02, 0.42, 0.44, 0.25]
|
| 540 |
+
- [0.02, 0.15, 0.44, 0.25]
|
| 541 |
+
- [0.3, 0.3, 0.4, 0.22]
|
| 542 |
+
metadata:
|
| 543 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "high_angle"}
|
| 544 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 545 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 546 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "full", camera_angle: "low_angle"}
|
| 547 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 548 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 549 |
+
- {panel_type: "closeup", focus: "character", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "pov"}
|
| 550 |
+
|
| 551 |
+
- id: "action_montage"
|
| 552 |
+
label: "Action Montage"
|
| 553 |
+
description: "Fast-paced action sequence"
|
| 554 |
+
positions:
|
| 555 |
+
- [0.02, 0.02, 0.96, 0.3]
|
| 556 |
+
- [0.02, 0.34, 0.31, 0.3]
|
| 557 |
+
- [0.345, 0.34, 0.31, 0.3]
|
| 558 |
+
- [0.67, 0.34, 0.31, 0.3]
|
| 559 |
+
- [0.02, 0.66, 0.23, 0.32]
|
| 560 |
+
- [0.27, 0.66, 0.23, 0.32]
|
| 561 |
+
- [0.52, 0.66, 0.46, 0.32]
|
| 562 |
+
metadata:
|
| 563 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "eye_level"}
|
| 564 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium", camera_angle: "dutch_angle"}
|
| 565 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium_full", camera_angle: "low_angle"}
|
| 566 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "full", camera_angle: "high_angle"}
|
| 567 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait", shot_type: "closeup", camera_angle: "low_angle"}
|
| 568 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 569 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 570 |
+
|
| 571 |
+
- id: "cinematic_sequence"
|
| 572 |
+
label: "Cinematic Sequence"
|
| 573 |
+
description: "Movie-like panel progression"
|
| 574 |
+
positions:
|
| 575 |
+
- [0.02, 0.02, 0.96, 0.28]
|
| 576 |
+
- [0.02, 0.32, 0.47, 0.2]
|
| 577 |
+
- [0.51, 0.32, 0.47, 0.2]
|
| 578 |
+
- [0.02, 0.54, 0.31, 0.21]
|
| 579 |
+
- [0.345, 0.54, 0.31, 0.21]
|
| 580 |
+
- [0.67, 0.54, 0.31, 0.21]
|
| 581 |
+
- [0.02, 0.77, 0.96, 0.21]
|
| 582 |
+
metadata:
|
| 583 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "high_angle"}
|
| 584 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 585 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 586 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 587 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "full", camera_angle: "dutch_angle"}
|
| 588 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square", shot_type: "extreme_closeup", camera_angle: "pov"}
|
| 589 |
+
- {panel_type: "reaction", focus: "characters", composition: "wide", shot_type: "medium", camera_angle: "eye_level"}
|
| 590 |
+
|
| 591 |
+
8_images:
|
| 592 |
+
- id: "mega_grid"
|
| 593 |
+
label: "Mega Grid"
|
| 594 |
+
description: "Classic 4x2 grid"
|
| 595 |
+
positions:
|
| 596 |
+
- [0.02, 0.02, 0.23, 0.47]
|
| 597 |
+
- [0.27, 0.02, 0.23, 0.47]
|
| 598 |
+
- [0.52, 0.02, 0.23, 0.47]
|
| 599 |
+
- [0.77, 0.02, 0.21, 0.47]
|
| 600 |
+
- [0.02, 0.51, 0.23, 0.47]
|
| 601 |
+
- [0.27, 0.51, 0.23, 0.47]
|
| 602 |
+
- [0.52, 0.51, 0.23, 0.47]
|
| 603 |
+
- [0.77, 0.51, 0.21, 0.47]
|
| 604 |
+
metadata:
|
| 605 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait", shot_type: "wide", camera_angle: "high_angle"}
|
| 606 |
+
- {panel_type: "dialogue", focus: "character", composition: "portrait", shot_type: "medium", camera_angle: "eye_level"}
|
| 607 |
+
- {panel_type: "dialogue", focus: "character", composition: "portrait", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 608 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 609 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 610 |
+
- {panel_type: "action", focus: "character", composition: "portrait", shot_type: "medium", camera_angle: "dutch_angle"}
|
| 611 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait", shot_type: "closeup", camera_angle: "eye_level"}
|
| 612 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait", shot_type: "extreme_closeup", camera_angle: "low_angle"}
|
| 613 |
+
|
| 614 |
+
- id: "chapter_opener"
|
| 615 |
+
label: "Chapter Opener"
|
| 616 |
+
description: "Splash page with progressive reveal"
|
| 617 |
+
positions:
|
| 618 |
+
- [0.02, 0.02, 0.96, 0.45]
|
| 619 |
+
- [0.02, 0.49, 0.23, 0.24]
|
| 620 |
+
- [0.27, 0.49, 0.23, 0.24]
|
| 621 |
+
- [0.52, 0.49, 0.23, 0.24]
|
| 622 |
+
- [0.77, 0.49, 0.21, 0.24]
|
| 623 |
+
- [0.02, 0.75, 0.23, 0.23]
|
| 624 |
+
- [0.27, 0.75, 0.23, 0.23]
|
| 625 |
+
- [0.52, 0.75, 0.46, 0.23]
|
| 626 |
+
metadata:
|
| 627 |
+
- {panel_type: "splash", focus: "environment", composition: "wide", shot_type: "extreme_wide", camera_angle: "high_angle"}
|
| 628 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 629 |
+
- {panel_type: "detail", focus: "character", composition: "square", shot_type: "closeup", camera_angle: "low_angle"}
|
| 630 |
+
- {panel_type: "dialogue", focus: "character", composition: "square", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 631 |
+
- {panel_type: "dialogue", focus: "character", composition: "square", shot_type: "medium", camera_angle: "over_shoulder"}
|
| 632 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 633 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square", shot_type: "extreme_closeup", camera_angle: "pov"}
|
| 634 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 635 |
+
|
| 636 |
+
- id: "parallel_stories"
|
| 637 |
+
label: "Parallel Stories"
|
| 638 |
+
description: "Two simultaneous narratives"
|
| 639 |
+
positions:
|
| 640 |
+
- [0.02, 0.02, 0.47, 0.23]
|
| 641 |
+
- [0.51, 0.02, 0.47, 0.23]
|
| 642 |
+
- [0.02, 0.27, 0.47, 0.23]
|
| 643 |
+
- [0.51, 0.27, 0.47, 0.23]
|
| 644 |
+
- [0.02, 0.52, 0.47, 0.23]
|
| 645 |
+
- [0.51, 0.52, 0.47, 0.23]
|
| 646 |
+
- [0.02, 0.77, 0.47, 0.21]
|
| 647 |
+
- [0.51, 0.77, 0.47, 0.21]
|
| 648 |
+
metadata:
|
| 649 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "eye_level"}
|
| 650 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "high_angle"}
|
| 651 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 652 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 653 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "full", camera_angle: "low_angle"}
|
| 654 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium_full", camera_angle: "dutch_angle"}
|
| 655 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 656 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 657 |
+
|
| 658 |
+
- id: "hero_explosion"
|
| 659 |
+
label: "Hero Explosion"
|
| 660 |
+
description: "Central impact radiating outward"
|
| 661 |
+
positions:
|
| 662 |
+
- [0.02, 0.02, 0.3, 0.3]
|
| 663 |
+
- [0.68, 0.02, 0.3, 0.3]
|
| 664 |
+
- [0.02, 0.68, 0.3, 0.3]
|
| 665 |
+
- [0.68, 0.68, 0.3, 0.3]
|
| 666 |
+
- [0.34, 0.02, 0.32, 0.28]
|
| 667 |
+
- [0.02, 0.34, 0.28, 0.32]
|
| 668 |
+
- [0.7, 0.34, 0.28, 0.32]
|
| 669 |
+
- [0.34, 0.7, 0.32, 0.28]
|
| 670 |
+
metadata:
|
| 671 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "closeup", camera_angle: "overhead"}
|
| 672 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "eye_level"}
|
| 673 |
+
- {panel_type: "detail", focus: "character", composition: "square", shot_type: "closeup", camera_angle: "low_angle"}
|
| 674 |
+
- {panel_type: "detail", focus: "character", composition: "square", shot_type: "closeup", camera_angle: "high_angle"}
|
| 675 |
+
- {panel_type: "action", focus: "event", composition: "landscape", shot_type: "medium", camera_angle: "dutch_angle"}
|
| 676 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 677 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "medium_full", camera_angle: "high_angle"}
|
| 678 |
+
- {panel_type: "closeup", focus: "emotion", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "pov"}
|
| 679 |
+
|
| 680 |
+
- id: "magazine_style"
|
| 681 |
+
label: "Magazine Style"
|
| 682 |
+
description: "Editorial layout with varied sizes"
|
| 683 |
+
positions:
|
| 684 |
+
- [0.02, 0.02, 0.63, 0.35]
|
| 685 |
+
- [0.67, 0.02, 0.31, 0.35]
|
| 686 |
+
- [0.02, 0.39, 0.31, 0.28]
|
| 687 |
+
- [0.35, 0.39, 0.31, 0.28]
|
| 688 |
+
- [0.68, 0.39, 0.3, 0.28]
|
| 689 |
+
- [0.02, 0.69, 0.31, 0.29]
|
| 690 |
+
- [0.35, 0.69, 0.31, 0.29]
|
| 691 |
+
- [0.68, 0.69, 0.3, 0.29]
|
| 692 |
+
metadata:
|
| 693 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape", shot_type: "wide", camera_angle: "high_angle"}
|
| 694 |
+
- {panel_type: "dialogue", focus: "character", composition: "portrait", shot_type: "medium", camera_angle: "eye_level"}
|
| 695 |
+
- {panel_type: "detail", focus: "object", composition: "square", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 696 |
+
- {panel_type: "action", focus: "event", composition: "square", shot_type: "medium_full", camera_angle: "eye_level"}
|
| 697 |
+
- {panel_type: "dialogue", focus: "character", composition: "square", shot_type: "medium_closeup", camera_angle: "over_shoulder"}
|
| 698 |
+
- {panel_type: "action", focus: "character", composition: "square", shot_type: "full", camera_angle: "low_angle"}
|
| 699 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square", shot_type: "closeup", camera_angle: "eye_level"}
|
| 700 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square", shot_type: "extreme_closeup", camera_angle: "pov"}
|
| 701 |
+
|
| 702 |
+
- id: "epic_finale"
|
| 703 |
+
label: "Epic Finale"
|
| 704 |
+
description: "Climactic page layout"
|
| 705 |
+
positions:
|
| 706 |
+
- [0.02, 0.02, 0.31, 0.25]
|
| 707 |
+
- [0.345, 0.02, 0.31, 0.25]
|
| 708 |
+
- [0.67, 0.02, 0.31, 0.25]
|
| 709 |
+
- [0.02, 0.29, 0.47, 0.4]
|
| 710 |
+
- [0.51, 0.29, 0.47, 0.4]
|
| 711 |
+
- [0.02, 0.71, 0.31, 0.27]
|
| 712 |
+
- [0.345, 0.71, 0.31, 0.27]
|
| 713 |
+
- [0.67, 0.71, 0.31, 0.27]
|
| 714 |
+
metadata:
|
| 715 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "overhead"}
|
| 716 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape", shot_type: "medium_closeup", camera_angle: "eye_level"}
|
| 717 |
+
- {panel_type: "detail", focus: "object", composition: "landscape", shot_type: "closeup", camera_angle: "low_angle"}
|
| 718 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "full", camera_angle: "low_angle"}
|
| 719 |
+
- {panel_type: "action", focus: "event", composition: "portrait", shot_type: "full", camera_angle: "high_angle"}
|
| 720 |
+
- {panel_type: "closeup", focus: "emotion", composition: "landscape", shot_type: "closeup", camera_angle: "eye_level"}
|
| 721 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape", shot_type: "extreme_closeup", camera_angle: "pov"}
|
| 722 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape", shot_type: "medium", camera_angle: "eye_level"}
|
| 723 |
+
# Page layouts configuration for multi-image PDF generation
|
| 724 |
+
# Each layout defines how images are arranged on a page
|
| 725 |
+
# Positions are defined as (x, y, width, height) in relative units (0-1)
|
| 726 |
+
# Coordinate system: (0,0) is top-left, X increases right, Y increases down
|
| 727 |
+
#
|
| 728 |
+
# Panel metadata helps guide image generation:
|
| 729 |
+
# - panel_type: establishing/action/closeup/dialogue/reaction/transition/detail/splash
|
| 730 |
+
# - focus: environment/character/characters/action/emotion/object/event
|
| 731 |
+
# - composition: wide/tall/square/portrait/landscape
|
| 732 |
+
|
| 733 |
+
layouts:
|
| 734 |
+
1_image:
|
| 735 |
+
- id: "full_bleed"
|
| 736 |
+
label: "Full Bleed"
|
| 737 |
+
description: "Single image filling entire page"
|
| 738 |
+
positions:
|
| 739 |
+
- [0.0, 0.0, 1.0, 1.0]
|
| 740 |
+
metadata:
|
| 741 |
+
- {panel_type: "splash", focus: "event", composition: "square"}
|
| 742 |
+
|
| 743 |
+
- id: "classic_frame"
|
| 744 |
+
label: "Classic Frame"
|
| 745 |
+
description: "Single image with traditional margins"
|
| 746 |
+
positions:
|
| 747 |
+
- [0.05, 0.05, 0.9, 0.9]
|
| 748 |
+
metadata:
|
| 749 |
+
- {panel_type: "establishing", focus: "environment", composition: "square"}
|
| 750 |
+
|
| 751 |
+
- id: "portrait_focus"
|
| 752 |
+
label: "Portrait Focus"
|
| 753 |
+
description: "Vertical emphasis for character shots"
|
| 754 |
+
positions:
|
| 755 |
+
- [0.15, 0.02, 0.7, 0.96]
|
| 756 |
+
metadata:
|
| 757 |
+
- {panel_type: "closeup", focus: "character", composition: "portrait"}
|
| 758 |
+
|
| 759 |
+
- id: "cinematic_wide"
|
| 760 |
+
label: "Cinematic Wide"
|
| 761 |
+
description: "Wide letterbox format"
|
| 762 |
+
positions:
|
| 763 |
+
- [0.02, 0.25, 0.96, 0.5]
|
| 764 |
+
metadata:
|
| 765 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 766 |
+
|
| 767 |
+
- id: "floating_center"
|
| 768 |
+
label: "Floating Center"
|
| 769 |
+
description: "Centered with breathing room"
|
| 770 |
+
positions:
|
| 771 |
+
- [0.1, 0.15, 0.8, 0.7]
|
| 772 |
+
metadata:
|
| 773 |
+
- {panel_type: "dialogue", focus: "character", composition: "square"}
|
| 774 |
+
|
| 775 |
+
2_images:
|
| 776 |
+
- id: "horizontal_split"
|
| 777 |
+
label: "Even Split"
|
| 778 |
+
description: "Two equal panels side by side"
|
| 779 |
+
positions:
|
| 780 |
+
- [0.02, 0.02, 0.47, 0.96]
|
| 781 |
+
- [0.51, 0.02, 0.47, 0.96]
|
| 782 |
+
metadata:
|
| 783 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait"}
|
| 784 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 785 |
+
|
| 786 |
+
- id: "vertical_split"
|
| 787 |
+
label: "Top & Bottom"
|
| 788 |
+
description: "Stacked panels"
|
| 789 |
+
positions:
|
| 790 |
+
- [0.02, 0.02, 0.96, 0.47]
|
| 791 |
+
- [0.02, 0.51, 0.96, 0.47]
|
| 792 |
+
metadata:
|
| 793 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 794 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 795 |
+
|
| 796 |
+
- id: "hero_sidekick"
|
| 797 |
+
label: "Hero & Sidekick"
|
| 798 |
+
description: "Large main panel with small detail"
|
| 799 |
+
positions:
|
| 800 |
+
- [0.02, 0.02, 0.65, 0.96]
|
| 801 |
+
- [0.69, 0.25, 0.29, 0.5]
|
| 802 |
+
metadata:
|
| 803 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 804 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait"}
|
| 805 |
+
|
| 806 |
+
- id: "before_after"
|
| 807 |
+
label: "Before & After"
|
| 808 |
+
description: "Cause and effect layout"
|
| 809 |
+
positions:
|
| 810 |
+
- [0.02, 0.02, 0.96, 0.44]
|
| 811 |
+
- [0.02, 0.48, 0.96, 0.5]
|
| 812 |
+
metadata:
|
| 813 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 814 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 815 |
+
|
| 816 |
+
- id: "diagonal_tension"
|
| 817 |
+
label: "Diagonal Tension"
|
| 818 |
+
description: "Overlapping dynamic panels"
|
| 819 |
+
positions:
|
| 820 |
+
- [0.02, 0.02, 0.6, 0.6]
|
| 821 |
+
- [0.38, 0.38, 0.6, 0.6]
|
| 822 |
+
metadata:
|
| 823 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 824 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 825 |
+
|
| 826 |
+
3_images:
|
| 827 |
+
- id: "triptych"
|
| 828 |
+
label: "Triptych"
|
| 829 |
+
description: "Three equal vertical panels"
|
| 830 |
+
positions:
|
| 831 |
+
- [0.02, 0.02, 0.31, 0.96]
|
| 832 |
+
- [0.345, 0.02, 0.31, 0.96]
|
| 833 |
+
- [0.67, 0.02, 0.31, 0.96]
|
| 834 |
+
metadata:
|
| 835 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait"}
|
| 836 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 837 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait"}
|
| 838 |
+
|
| 839 |
+
- id: "hero_top"
|
| 840 |
+
label: "Establishing Shot"
|
| 841 |
+
description: "Large top panel with details below"
|
| 842 |
+
positions:
|
| 843 |
+
- [0.02, 0.02, 0.96, 0.5]
|
| 844 |
+
- [0.02, 0.54, 0.47, 0.44]
|
| 845 |
+
- [0.51, 0.54, 0.47, 0.44]
|
| 846 |
+
metadata:
|
| 847 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 848 |
+
- {panel_type: "action", focus: "character", composition: "square"}
|
| 849 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square"}
|
| 850 |
|
| 851 |
- id: "l_shape"
|
| 852 |
+
label: "L-Shape Flow"
|
| 853 |
+
description: "Reading flow in L pattern"
|
| 854 |
+
positions:
|
| 855 |
+
- [0.02, 0.02, 0.47, 0.47]
|
| 856 |
+
- [0.51, 0.02, 0.47, 0.47]
|
| 857 |
+
- [0.02, 0.51, 0.96, 0.47]
|
| 858 |
+
metadata:
|
| 859 |
+
- {panel_type: "dialogue", focus: "character", composition: "square"}
|
| 860 |
+
- {panel_type: "dialogue", focus: "character", composition: "square"}
|
| 861 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 862 |
+
|
| 863 |
+
- id: "spotlight"
|
| 864 |
+
label: "Spotlight"
|
| 865 |
+
description: "Central focus with side panels"
|
| 866 |
+
positions:
|
| 867 |
+
- [0.02, 0.15, 0.28, 0.7]
|
| 868 |
+
- [0.32, 0.02, 0.36, 0.96]
|
| 869 |
+
- [0.7, 0.15, 0.28, 0.7]
|
| 870 |
+
metadata:
|
| 871 |
+
- {panel_type: "reaction", focus: "character", composition: "portrait"}
|
| 872 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 873 |
+
- {panel_type: "reaction", focus: "character", composition: "portrait"}
|
| 874 |
+
|
| 875 |
+
- id: "vertical_flow"
|
| 876 |
+
label: "Vertical Flow"
|
| 877 |
+
description: "Three stacked panels for sequential action"
|
| 878 |
+
positions:
|
| 879 |
+
- [0.02, 0.02, 0.96, 0.31]
|
| 880 |
+
- [0.02, 0.345, 0.96, 0.31]
|
| 881 |
+
- [0.02, 0.67, 0.96, 0.31]
|
| 882 |
+
metadata:
|
| 883 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 884 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 885 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 886 |
+
|
| 887 |
+
- id: "manga_action"
|
| 888 |
+
label: "Manga Action"
|
| 889 |
+
description: "Dynamic manga-style layout"
|
| 890 |
+
positions:
|
| 891 |
+
- [0.52, 0.02, 0.46, 0.45]
|
| 892 |
+
- [0.02, 0.02, 0.48, 0.65]
|
| 893 |
+
- [0.02, 0.69, 0.96, 0.29]
|
| 894 |
+
metadata:
|
| 895 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square"}
|
| 896 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 897 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 898 |
+
|
| 899 |
+
4_images:
|
| 900 |
+
- id: "grid_2x2"
|
| 901 |
+
label: "Classic Grid"
|
| 902 |
+
description: "Traditional 2x2 layout"
|
| 903 |
+
positions:
|
| 904 |
+
- [0.02, 0.02, 0.47, 0.47]
|
| 905 |
+
- [0.51, 0.02, 0.47, 0.47]
|
| 906 |
+
- [0.02, 0.51, 0.47, 0.47]
|
| 907 |
+
- [0.51, 0.51, 0.47, 0.47]
|
| 908 |
+
metadata:
|
| 909 |
+
- {panel_type: "establishing", focus: "environment", composition: "square"}
|
| 910 |
+
- {panel_type: "dialogue", focus: "character", composition: "square"}
|
| 911 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 912 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square"}
|
| 913 |
+
|
| 914 |
+
- id: "widescreen"
|
| 915 |
+
label: "Widescreen Strips"
|
| 916 |
+
description: "Four cinematic horizontal strips"
|
| 917 |
+
positions:
|
| 918 |
+
- [0.02, 0.02, 0.96, 0.23]
|
| 919 |
+
- [0.02, 0.27, 0.96, 0.23]
|
| 920 |
+
- [0.02, 0.52, 0.96, 0.23]
|
| 921 |
+
- [0.02, 0.77, 0.96, 0.21]
|
| 922 |
+
metadata:
|
| 923 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 924 |
+
- {panel_type: "dialogue", focus: "characters", composition: "wide"}
|
| 925 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 926 |
+
- {panel_type: "reaction", focus: "emotion", composition: "wide"}
|
| 927 |
+
|
| 928 |
+
- id: "hero_cluster"
|
| 929 |
+
label: "Hero with Cluster"
|
| 930 |
+
description: "Large panel with three supporting"
|
| 931 |
positions:
|
| 932 |
+
- [0.02, 0.02, 0.6, 0.63]
|
| 933 |
+
- [0.64, 0.02, 0.34, 0.3]
|
| 934 |
+
- [0.64, 0.34, 0.34, 0.31]
|
| 935 |
+
- [0.02, 0.67, 0.96, 0.31]
|
| 936 |
+
metadata:
|
| 937 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 938 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 939 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 940 |
+
- {panel_type: "transition", focus: "environment", composition: "wide"}
|
| 941 |
+
|
| 942 |
+
- id: "comic_strip"
|
| 943 |
+
label: "Comic Strip"
|
| 944 |
+
description: "Newspaper strip style"
|
| 945 |
+
positions:
|
| 946 |
+
- [0.02, 0.3, 0.23, 0.4]
|
| 947 |
+
- [0.27, 0.3, 0.23, 0.4]
|
| 948 |
+
- [0.52, 0.3, 0.23, 0.4]
|
| 949 |
+
- [0.77, 0.3, 0.21, 0.4]
|
| 950 |
+
metadata:
|
| 951 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait"}
|
| 952 |
+
- {panel_type: "dialogue", focus: "characters", composition: "portrait"}
|
| 953 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 954 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait"}
|
| 955 |
+
|
| 956 |
+
- id: "z_pattern"
|
| 957 |
+
label: "Z-Pattern"
|
| 958 |
+
description: "Natural reading flow in Z shape"
|
| 959 |
+
positions:
|
| 960 |
+
- [0.02, 0.02, 0.47, 0.35]
|
| 961 |
+
- [0.51, 0.02, 0.47, 0.35]
|
| 962 |
+
- [0.02, 0.39, 0.47, 0.59]
|
| 963 |
+
- [0.51, 0.39, 0.47, 0.59]
|
| 964 |
+
metadata:
|
| 965 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 966 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 967 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 968 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 969 |
+
|
| 970 |
+
- id: "explosion"
|
| 971 |
+
label: "Explosion"
|
| 972 |
+
description: "Central impact with surrounding panels"
|
| 973 |
+
positions:
|
| 974 |
+
- [0.02, 0.02, 0.35, 0.35]
|
| 975 |
+
- [0.63, 0.02, 0.35, 0.35]
|
| 976 |
+
- [0.27, 0.27, 0.46, 0.46]
|
| 977 |
+
- [0.02, 0.63, 0.96, 0.35]
|
| 978 |
+
metadata:
|
| 979 |
+
- {panel_type: "establishing", focus: "environment", composition: "square"}
|
| 980 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 981 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 982 |
+
- {panel_type: "reaction", focus: "characters", composition: "wide"}
|
| 983 |
|
| 984 |
5_images:
|
| 985 |
+
- id: "hero_banner"
|
| 986 |
+
label: "Hero Banner"
|
| 987 |
+
description: "Wide establishing shot with four panels below"
|
| 988 |
+
positions:
|
| 989 |
+
- [0.02, 0.02, 0.96, 0.38]
|
| 990 |
+
- [0.02, 0.42, 0.47, 0.28]
|
| 991 |
+
- [0.51, 0.42, 0.47, 0.28]
|
| 992 |
+
- [0.02, 0.72, 0.47, 0.26]
|
| 993 |
+
- [0.51, 0.72, 0.47, 0.26]
|
| 994 |
+
metadata:
|
| 995 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 996 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 997 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 998 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 999 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1000 |
+
|
| 1001 |
+
- id: "manga_vertical"
|
| 1002 |
+
label: "Manga Vertical"
|
| 1003 |
+
description: "Japanese right-to-left vertical flow"
|
| 1004 |
+
positions:
|
| 1005 |
+
- [0.52, 0.02, 0.46, 0.32]
|
| 1006 |
+
- [0.02, 0.02, 0.48, 0.32]
|
| 1007 |
+
- [0.52, 0.36, 0.46, 0.3]
|
| 1008 |
+
- [0.02, 0.36, 0.48, 0.3]
|
| 1009 |
+
- [0.02, 0.68, 0.96, 0.3]
|
| 1010 |
+
metadata:
|
| 1011 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1012 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1013 |
+
- {panel_type: "action", focus: "character", composition: "landscape"}
|
| 1014 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1015 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 1016 |
+
|
| 1017 |
+
- id: "pyramid"
|
| 1018 |
+
label: "Pyramid"
|
| 1019 |
+
description: "Building tension from top to bottom"
|
| 1020 |
+
positions:
|
| 1021 |
+
- [0.25, 0.02, 0.5, 0.25]
|
| 1022 |
+
- [0.02, 0.29, 0.47, 0.3]
|
| 1023 |
+
- [0.51, 0.29, 0.47, 0.3]
|
| 1024 |
+
- [0.02, 0.61, 0.31, 0.37]
|
| 1025 |
+
- [0.67, 0.61, 0.31, 0.37]
|
| 1026 |
+
metadata:
|
| 1027 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1028 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1029 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1030 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1031 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1032 |
+
|
| 1033 |
+
- id: "spotlight_drama"
|
| 1034 |
+
label: "Spotlight Drama"
|
| 1035 |
+
description: "Central focus with corner details"
|
| 1036 |
+
positions:
|
| 1037 |
+
- [0.02, 0.02, 0.35, 0.35]
|
| 1038 |
+
- [0.63, 0.02, 0.35, 0.35]
|
| 1039 |
+
- [0.22, 0.22, 0.56, 0.56]
|
| 1040 |
+
- [0.02, 0.63, 0.35, 0.35]
|
| 1041 |
+
- [0.63, 0.63, 0.35, 0.35]
|
| 1042 |
+
metadata:
|
| 1043 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1044 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1045 |
+
- {panel_type: "action", focus: "character", composition: "square"}
|
| 1046 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square"}
|
| 1047 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square"}
|
| 1048 |
+
|
| 1049 |
+
- id: "euro_bd"
|
| 1050 |
+
label: "Euro BD Classic"
|
| 1051 |
+
description: "Franco-Belgian structured layout"
|
| 1052 |
+
positions:
|
| 1053 |
+
- [0.02, 0.02, 0.47, 0.29]
|
| 1054 |
+
- [0.51, 0.02, 0.47, 0.29]
|
| 1055 |
+
- [0.02, 0.33, 0.96, 0.31]
|
| 1056 |
+
- [0.02, 0.66, 0.47, 0.32]
|
| 1057 |
+
- [0.51, 0.66, 0.47, 0.32]
|
| 1058 |
+
metadata:
|
| 1059 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1060 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1061 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 1062 |
+
- {panel_type: "dialogue", focus: "characters", composition: "landscape"}
|
| 1063 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1064 |
+
|
| 1065 |
+
- id: "action_burst"
|
| 1066 |
+
label: "Action Burst"
|
| 1067 |
+
description: "Dynamic superhero action layout"
|
| 1068 |
+
positions:
|
| 1069 |
+
- [0.02, 0.02, 0.55, 0.55]
|
| 1070 |
+
- [0.59, 0.02, 0.39, 0.26]
|
| 1071 |
+
- [0.59, 0.3, 0.39, 0.27]
|
| 1072 |
+
- [0.02, 0.59, 0.47, 0.39]
|
| 1073 |
+
- [0.51, 0.59, 0.47, 0.39]
|
| 1074 |
+
metadata:
|
| 1075 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1076 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 1077 |
+
- {panel_type: "closeup", focus: "emotion", composition: "landscape"}
|
| 1078 |
+
- {panel_type: "action", focus: "character", composition: "landscape"}
|
| 1079 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape"}
|
| 1080 |
|
| 1081 |
6_images:
|
| 1082 |
+
- id: "classic_grid"
|
| 1083 |
+
label: "Classic 2x3 Grid"
|
| 1084 |
+
description: "Traditional American comic layout"
|
| 1085 |
+
positions:
|
| 1086 |
+
- [0.02, 0.02, 0.47, 0.31]
|
| 1087 |
+
- [0.51, 0.02, 0.47, 0.31]
|
| 1088 |
+
- [0.02, 0.345, 0.47, 0.31]
|
| 1089 |
+
- [0.51, 0.345, 0.47, 0.31]
|
| 1090 |
+
- [0.02, 0.67, 0.47, 0.31]
|
| 1091 |
+
- [0.51, 0.67, 0.47, 0.31]
|
| 1092 |
+
metadata:
|
| 1093 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1094 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1095 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1096 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1097 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1098 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1099 |
+
|
| 1100 |
+
- id: "hero_surround"
|
| 1101 |
+
label: "Hero Surrounded"
|
| 1102 |
+
description: "Large central panel with five around it"
|
| 1103 |
+
positions:
|
| 1104 |
+
- [0.02, 0.02, 0.31, 0.28]
|
| 1105 |
+
- [0.67, 0.02, 0.31, 0.28]
|
| 1106 |
+
- [0.02, 0.7, 0.31, 0.28]
|
| 1107 |
+
- [0.67, 0.7, 0.31, 0.28]
|
| 1108 |
+
- [0.25, 0.25, 0.5, 0.5]
|
| 1109 |
+
- [0.35, 0.35, 0.63, 0.33]
|
| 1110 |
+
metadata:
|
| 1111 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1112 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1113 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1114 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1115 |
+
- {panel_type: "action", focus: "character", composition: "square"}
|
| 1116 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1117 |
+
|
| 1118 |
+
- id: "staircase"
|
| 1119 |
+
label: "Staircase"
|
| 1120 |
+
description: "Diagonal reading flow"
|
| 1121 |
+
positions:
|
| 1122 |
+
- [0.02, 0.02, 0.45, 0.3]
|
| 1123 |
+
- [0.49, 0.02, 0.49, 0.3]
|
| 1124 |
+
- [0.02, 0.34, 0.45, 0.3]
|
| 1125 |
+
- [0.49, 0.34, 0.49, 0.3]
|
| 1126 |
+
- [0.02, 0.66, 0.45, 0.32]
|
| 1127 |
+
- [0.49, 0.66, 0.49, 0.32]
|
| 1128 |
+
metadata:
|
| 1129 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1130 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1131 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1132 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1133 |
+
- {panel_type: "action", focus: "character", composition: "landscape"}
|
| 1134 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1135 |
+
|
| 1136 |
+
- id: "splash_detail"
|
| 1137 |
+
label: "Splash with Details"
|
| 1138 |
+
description: "Full-page moment with detail insets"
|
| 1139 |
+
positions:
|
| 1140 |
+
- [0.05, 0.05, 0.4, 0.4]
|
| 1141 |
+
- [0.55, 0.05, 0.4, 0.4]
|
| 1142 |
+
- [0.05, 0.55, 0.4, 0.4]
|
| 1143 |
+
- [0.55, 0.55, 0.4, 0.4]
|
| 1144 |
+
- [0.25, 0.25, 0.5, 0.5]
|
| 1145 |
+
- [0.35, 0.35, 0.3, 0.3]
|
| 1146 |
+
metadata:
|
| 1147 |
+
- {panel_type: "detail", focus: "environment", composition: "square"}
|
| 1148 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1149 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1150 |
+
- {panel_type: "detail", focus: "character", composition: "square"}
|
| 1151 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1152 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square"}
|
| 1153 |
+
|
| 1154 |
+
- id: "manga_4koma_plus"
|
| 1155 |
+
label: "Manga 4-Koma Plus"
|
| 1156 |
+
description: "Japanese 4-panel with header/footer"
|
| 1157 |
+
positions:
|
| 1158 |
+
- [0.02, 0.02, 0.96, 0.15]
|
| 1159 |
+
- [0.02, 0.19, 0.47, 0.25]
|
| 1160 |
+
- [0.51, 0.19, 0.47, 0.25]
|
| 1161 |
+
- [0.02, 0.46, 0.47, 0.25]
|
| 1162 |
+
- [0.51, 0.46, 0.47, 0.25]
|
| 1163 |
+
- [0.02, 0.73, 0.96, 0.25]
|
| 1164 |
+
metadata:
|
| 1165 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 1166 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1167 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1168 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1169 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1170 |
+
- {panel_type: "reaction", focus: "emotion", composition: "wide"}
|
| 1171 |
+
|
| 1172 |
+
- id: "tension_build"
|
| 1173 |
+
label: "Tension Builder"
|
| 1174 |
+
description: "Progressive revelation layout"
|
| 1175 |
+
positions:
|
| 1176 |
+
- [0.02, 0.02, 0.96, 0.22]
|
| 1177 |
+
- [0.02, 0.26, 0.47, 0.22]
|
| 1178 |
+
- [0.51, 0.26, 0.47, 0.22]
|
| 1179 |
+
- [0.02, 0.5, 0.31, 0.48]
|
| 1180 |
+
- [0.345, 0.5, 0.31, 0.48]
|
| 1181 |
+
- [0.67, 0.5, 0.31, 0.48]
|
| 1182 |
+
metadata:
|
| 1183 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 1184 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1185 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1186 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 1187 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 1188 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait"}
|
| 1189 |
+
|
| 1190 |
+
7_images:
|
| 1191 |
+
- id: "hero_hexagon"
|
| 1192 |
+
label: "Hero Hexagon"
|
| 1193 |
+
description: "Central focus with six surrounding"
|
| 1194 |
+
positions:
|
| 1195 |
+
- [0.28, 0.02, 0.44, 0.3]
|
| 1196 |
+
- [0.02, 0.25, 0.3, 0.25]
|
| 1197 |
+
- [0.68, 0.25, 0.3, 0.25]
|
| 1198 |
+
- [0.25, 0.35, 0.5, 0.3]
|
| 1199 |
+
- [0.02, 0.52, 0.3, 0.25]
|
| 1200 |
+
- [0.68, 0.52, 0.3, 0.25]
|
| 1201 |
+
- [0.28, 0.68, 0.44, 0.3]
|
| 1202 |
+
metadata:
|
| 1203 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1204 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 1205 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 1206 |
+
- {panel_type: "action", focus: "character", composition: "landscape"}
|
| 1207 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1208 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1209 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1210 |
+
|
| 1211 |
+
- id: "narrative_flow"
|
| 1212 |
+
label: "Narrative Flow"
|
| 1213 |
+
description: "Story progression with varied sizes"
|
| 1214 |
+
positions:
|
| 1215 |
+
- [0.02, 0.02, 0.47, 0.28]
|
| 1216 |
+
- [0.51, 0.02, 0.47, 0.28]
|
| 1217 |
+
- [0.02, 0.32, 0.96, 0.24]
|
| 1218 |
+
- [0.02, 0.58, 0.31, 0.4]
|
| 1219 |
+
- [0.345, 0.58, 0.31, 0.4]
|
| 1220 |
+
- [0.67, 0.58, 0.31, 0.2]
|
| 1221 |
+
- [0.67, 0.8, 0.31, 0.18]
|
| 1222 |
+
metadata:
|
| 1223 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1224 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1225 |
+
- {panel_type: "action", focus: "event", composition: "wide"}
|
| 1226 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 1227 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 1228 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait"}
|
| 1229 |
+
- {panel_type: "detail", focus: "object", composition: "portrait"}
|
| 1230 |
+
|
| 1231 |
+
- id: "double_spread"
|
| 1232 |
+
label: "Double Feature"
|
| 1233 |
+
description: "Two hero panels with details"
|
| 1234 |
+
positions:
|
| 1235 |
+
- [0.02, 0.02, 0.47, 0.45]
|
| 1236 |
+
- [0.51, 0.02, 0.47, 0.45]
|
| 1237 |
+
- [0.02, 0.49, 0.31, 0.24]
|
| 1238 |
+
- [0.345, 0.49, 0.31, 0.24]
|
| 1239 |
+
- [0.67, 0.49, 0.31, 0.24]
|
| 1240 |
+
- [0.02, 0.75, 0.47, 0.23]
|
| 1241 |
+
- [0.51, 0.75, 0.47, 0.23]
|
| 1242 |
+
metadata:
|
| 1243 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1244 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1245 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 1246 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1247 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 1248 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1249 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1250 |
+
|
| 1251 |
+
- id: "spiral_narrative"
|
| 1252 |
+
label: "Spiral Narrative"
|
| 1253 |
+
description: "Circular reading flow"
|
| 1254 |
+
positions:
|
| 1255 |
+
- [0.28, 0.02, 0.44, 0.25]
|
| 1256 |
+
- [0.52, 0.15, 0.46, 0.25]
|
| 1257 |
+
- [0.52, 0.42, 0.46, 0.25]
|
| 1258 |
+
- [0.28, 0.55, 0.44, 0.25]
|
| 1259 |
+
- [0.02, 0.42, 0.44, 0.25]
|
| 1260 |
+
- [0.02, 0.15, 0.44, 0.25]
|
| 1261 |
+
- [0.3, 0.3, 0.4, 0.22]
|
| 1262 |
+
metadata:
|
| 1263 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1264 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1265 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1266 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1267 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1268 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1269 |
+
- {panel_type: "closeup", focus: "character", composition: "landscape"}
|
| 1270 |
+
|
| 1271 |
+
- id: "action_montage"
|
| 1272 |
+
label: "Action Montage"
|
| 1273 |
+
description: "Fast-paced action sequence"
|
| 1274 |
+
positions:
|
| 1275 |
+
- [0.02, 0.02, 0.96, 0.3]
|
| 1276 |
+
- [0.02, 0.34, 0.31, 0.3]
|
| 1277 |
+
- [0.345, 0.34, 0.31, 0.3]
|
| 1278 |
+
- [0.67, 0.34, 0.31, 0.3]
|
| 1279 |
+
- [0.02, 0.66, 0.23, 0.32]
|
| 1280 |
+
- [0.27, 0.66, 0.23, 0.32]
|
| 1281 |
+
- [0.52, 0.66, 0.46, 0.32]
|
| 1282 |
+
metadata:
|
| 1283 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 1284 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1285 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1286 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1287 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait"}
|
| 1288 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait"}
|
| 1289 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape"}
|
| 1290 |
+
|
| 1291 |
+
- id: "cinematic_sequence"
|
| 1292 |
+
label: "Cinematic Sequence"
|
| 1293 |
+
description: "Movie-like panel progression"
|
| 1294 |
+
positions:
|
| 1295 |
+
- [0.02, 0.02, 0.96, 0.28]
|
| 1296 |
+
- [0.02, 0.32, 0.47, 0.2]
|
| 1297 |
+
- [0.51, 0.32, 0.47, 0.2]
|
| 1298 |
+
- [0.02, 0.54, 0.31, 0.21]
|
| 1299 |
+
- [0.345, 0.54, 0.31, 0.21]
|
| 1300 |
+
- [0.67, 0.54, 0.31, 0.21]
|
| 1301 |
+
- [0.02, 0.77, 0.96, 0.21]
|
| 1302 |
+
metadata:
|
| 1303 |
+
- {panel_type: "establishing", focus: "environment", composition: "wide"}
|
| 1304 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1305 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1306 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1307 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1308 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square"}
|
| 1309 |
+
- {panel_type: "reaction", focus: "characters", composition: "wide"}
|
| 1310 |
+
|
| 1311 |
+
8_images:
|
| 1312 |
+
- id: "mega_grid"
|
| 1313 |
+
label: "Mega Grid"
|
| 1314 |
+
description: "Classic 4x2 grid"
|
| 1315 |
+
positions:
|
| 1316 |
+
- [0.02, 0.02, 0.23, 0.47]
|
| 1317 |
+
- [0.27, 0.02, 0.23, 0.47]
|
| 1318 |
+
- [0.52, 0.02, 0.23, 0.47]
|
| 1319 |
+
- [0.77, 0.02, 0.21, 0.47]
|
| 1320 |
+
- [0.02, 0.51, 0.23, 0.47]
|
| 1321 |
+
- [0.27, 0.51, 0.23, 0.47]
|
| 1322 |
+
- [0.52, 0.51, 0.23, 0.47]
|
| 1323 |
+
- [0.77, 0.51, 0.21, 0.47]
|
| 1324 |
+
metadata:
|
| 1325 |
+
- {panel_type: "establishing", focus: "environment", composition: "portrait"}
|
| 1326 |
+
- {panel_type: "dialogue", focus: "character", composition: "portrait"}
|
| 1327 |
+
- {panel_type: "dialogue", focus: "character", composition: "portrait"}
|
| 1328 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1329 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1330 |
+
- {panel_type: "action", focus: "character", composition: "portrait"}
|
| 1331 |
+
- {panel_type: "closeup", focus: "emotion", composition: "portrait"}
|
| 1332 |
+
- {panel_type: "reaction", focus: "emotion", composition: "portrait"}
|
| 1333 |
+
|
| 1334 |
+
- id: "chapter_opener"
|
| 1335 |
+
label: "Chapter Opener"
|
| 1336 |
+
description: "Splash page with progressive reveal"
|
| 1337 |
+
positions:
|
| 1338 |
+
- [0.02, 0.02, 0.96, 0.45]
|
| 1339 |
+
- [0.02, 0.49, 0.23, 0.24]
|
| 1340 |
+
- [0.27, 0.49, 0.23, 0.24]
|
| 1341 |
+
- [0.52, 0.49, 0.23, 0.24]
|
| 1342 |
+
- [0.77, 0.49, 0.21, 0.24]
|
| 1343 |
+
- [0.02, 0.75, 0.23, 0.23]
|
| 1344 |
+
- [0.27, 0.75, 0.23, 0.23]
|
| 1345 |
+
- [0.52, 0.75, 0.46, 0.23]
|
| 1346 |
+
metadata:
|
| 1347 |
+
- {panel_type: "splash", focus: "environment", composition: "wide"}
|
| 1348 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1349 |
+
- {panel_type: "detail", focus: "character", composition: "square"}
|
| 1350 |
+
- {panel_type: "dialogue", focus: "character", composition: "square"}
|
| 1351 |
+
- {panel_type: "dialogue", focus: "character", composition: "square"}
|
| 1352 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1353 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square"}
|
| 1354 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape"}
|
| 1355 |
+
|
| 1356 |
+
- id: "parallel_stories"
|
| 1357 |
+
label: "Parallel Stories"
|
| 1358 |
+
description: "Two simultaneous narratives"
|
| 1359 |
+
positions:
|
| 1360 |
+
- [0.02, 0.02, 0.47, 0.23]
|
| 1361 |
+
- [0.51, 0.02, 0.47, 0.23]
|
| 1362 |
+
- [0.02, 0.27, 0.47, 0.23]
|
| 1363 |
+
- [0.51, 0.27, 0.47, 0.23]
|
| 1364 |
+
- [0.02, 0.52, 0.47, 0.23]
|
| 1365 |
+
- [0.51, 0.52, 0.47, 0.23]
|
| 1366 |
+
- [0.02, 0.77, 0.47, 0.21]
|
| 1367 |
+
- [0.51, 0.77, 0.47, 0.21]
|
| 1368 |
+
metadata:
|
| 1369 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1370 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1371 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1372 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1373 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1374 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1375 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1376 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1377 |
+
|
| 1378 |
+
- id: "hero_explosion"
|
| 1379 |
+
label: "Hero Explosion"
|
| 1380 |
+
description: "Central impact radiating outward"
|
| 1381 |
+
positions:
|
| 1382 |
+
- [0.02, 0.02, 0.3, 0.3]
|
| 1383 |
+
- [0.68, 0.02, 0.3, 0.3]
|
| 1384 |
+
- [0.02, 0.68, 0.3, 0.3]
|
| 1385 |
+
- [0.68, 0.68, 0.3, 0.3]
|
| 1386 |
+
- [0.34, 0.02, 0.32, 0.28]
|
| 1387 |
+
- [0.02, 0.34, 0.28, 0.32]
|
| 1388 |
+
- [0.7, 0.34, 0.28, 0.32]
|
| 1389 |
+
- [0.34, 0.7, 0.32, 0.28]
|
| 1390 |
+
metadata:
|
| 1391 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1392 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1393 |
+
- {panel_type: "detail", focus: "character", composition: "square"}
|
| 1394 |
+
- {panel_type: "detail", focus: "character", composition: "square"}
|
| 1395 |
+
- {panel_type: "action", focus: "event", composition: "landscape"}
|
| 1396 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1397 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1398 |
+
- {panel_type: "closeup", focus: "emotion", composition: "landscape"}
|
| 1399 |
+
|
| 1400 |
+
- id: "magazine_style"
|
| 1401 |
+
label: "Magazine Style"
|
| 1402 |
+
description: "Editorial layout with varied sizes"
|
| 1403 |
+
positions:
|
| 1404 |
+
- [0.02, 0.02, 0.63, 0.35]
|
| 1405 |
+
- [0.67, 0.02, 0.31, 0.35]
|
| 1406 |
+
- [0.02, 0.39, 0.31, 0.28]
|
| 1407 |
+
- [0.35, 0.39, 0.31, 0.28]
|
| 1408 |
+
- [0.68, 0.39, 0.3, 0.28]
|
| 1409 |
+
- [0.02, 0.69, 0.31, 0.29]
|
| 1410 |
+
- [0.35, 0.69, 0.31, 0.29]
|
| 1411 |
+
- [0.68, 0.69, 0.3, 0.29]
|
| 1412 |
+
metadata:
|
| 1413 |
+
- {panel_type: "establishing", focus: "environment", composition: "landscape"}
|
| 1414 |
+
- {panel_type: "dialogue", focus: "character", composition: "portrait"}
|
| 1415 |
+
- {panel_type: "detail", focus: "object", composition: "square"}
|
| 1416 |
+
- {panel_type: "action", focus: "event", composition: "square"}
|
| 1417 |
+
- {panel_type: "dialogue", focus: "character", composition: "square"}
|
| 1418 |
+
- {panel_type: "action", focus: "character", composition: "square"}
|
| 1419 |
+
- {panel_type: "closeup", focus: "emotion", composition: "square"}
|
| 1420 |
+
- {panel_type: "reaction", focus: "emotion", composition: "square"}
|
| 1421 |
+
|
| 1422 |
+
- id: "epic_finale"
|
| 1423 |
+
label: "Epic Finale"
|
| 1424 |
+
description: "Climactic page layout"
|
| 1425 |
+
positions:
|
| 1426 |
+
- [0.02, 0.02, 0.31, 0.25]
|
| 1427 |
+
- [0.345, 0.02, 0.31, 0.25]
|
| 1428 |
+
- [0.67, 0.02, 0.31, 0.25]
|
| 1429 |
+
- [0.02, 0.29, 0.47, 0.4]
|
| 1430 |
+
- [0.51, 0.29, 0.47, 0.4]
|
| 1431 |
+
- [0.02, 0.71, 0.31, 0.27]
|
| 1432 |
+
- [0.345, 0.71, 0.31, 0.27]
|
| 1433 |
+
- [0.67, 0.71, 0.31, 0.27]
|
| 1434 |
+
metadata:
|
| 1435 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 1436 |
+
- {panel_type: "dialogue", focus: "character", composition: "landscape"}
|
| 1437 |
+
- {panel_type: "detail", focus: "object", composition: "landscape"}
|
| 1438 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1439 |
+
- {panel_type: "action", focus: "event", composition: "portrait"}
|
| 1440 |
+
- {panel_type: "closeup", focus: "emotion", composition: "landscape"}
|
| 1441 |
+
- {panel_type: "reaction", focus: "emotion", composition: "landscape"}
|
| 1442 |
+
- {panel_type: "reaction", focus: "characters", composition: "landscape"}
|