multi-image comics

This commit is contained in:
mi
2025-11-15 18:52:14 +10:00
parent f71720c156
commit 91b6d4efeb
7 changed files with 356 additions and 66 deletions

114
README.md
View File

@@ -158,6 +158,7 @@ Don't have a server? No problem! Here are beginner-friendly options to get your
## Features
- Comic viewer with navigation (First, Previous, Next, Latest)
- **Multi-image comics** with vertical scrolling (webtoon style) and lazy loading
- Client-side navigation using JSON API (no page reloads)
- Keyboard navigation support (arrow keys, Home/End)
- Archive page with thumbnail grid
@@ -732,10 +733,10 @@ Comics are stored in the `COMICS` list in `comics_data.py`. Each comic entry:
```python
{
'number': 1, # Comic number (required, sequential)
'filename': 'comic-001.png', # Image filename (required)
'mobile_filename': 'comic-001-mobile.png', # Optional mobile version
'filename': 'comic-001.png', # Image filename (required) OR list for multi-image
'mobile_filename': 'comic-001-mobile.png', # Optional mobile version (single-image only)
'date': '2025-01-01', # Publication date (required)
'alt_text': 'Alt text for comic', # Accessibility text (required)
'alt_text': 'Alt text for comic', # Accessibility text (required) OR list for multi-image
'title': 'Comic Title', # Title (optional, shows #X if absent)
'author_note': 'Optional note', # Author note (optional, plain text)
'author_note_md': '2025-01-01.md', # Optional markdown file for author note
@@ -744,6 +745,17 @@ Comics are stored in the `COMICS` list in `comics_data.py`. Each comic entry:
}
```
**For multi-image comics (webtoon style):**
```python
{
'number': 2,
'filename': ['page1.png', 'page2.png', 'page3.png'], # List of images
'alt_text': ['Panel 1 description', 'Panel 2', 'Panel 3'], # Individual alt texts
'date': '2025-01-08',
'full_width': True # Recommended for webtoons
}
```
### Adding a New Comic
**Option 1: Use the script (recommended)**
@@ -800,6 +812,102 @@ The `/about` route renders `content/about.md` as HTML. Edit this file to customi
**Note:** Client-side navigation displays author notes as plain text. Markdown author notes only render properly on initial page load (server-side rendering). For full markdown rendering, users need to refresh the page or navigate directly to the comic URL.
### Multi-Image Comics (Webtoon Style)
Sunday Comics supports vertical scrolling comics with multiple images stacked seamlessly, perfect for webtoon-style storytelling.
**How it works:**
- Set `filename` to a list of image filenames instead of a single string
- Images display vertically with no gaps between them
- First image loads immediately, subsequent images lazy-load as readers scroll
- No click-through navigation on multi-image comics (use navigation buttons instead)
**Basic Example:**
```python
# In comics_data.py
{
'number': 4,
'title': 'Webtoon Episode 1',
'filename': ['page1.jpg', 'page2.jpg', 'page3.jpg'], # List of images
'alt_text': 'A three-part vertical story', # Single alt text for all images
'date': '2025-01-22',
}
```
**Individual Alt Text (Recommended for Accessibility):**
```python
{
'number': 5,
'title': 'Long Scroll Episode',
'filename': ['scene1.png', 'scene2.png', 'scene3.png', 'scene4.png'],
'alt_text': [
'Opening scene showing the city at dawn',
'Character walking through the marketplace',
'Close-up of the mysterious artifact',
'Dramatic reveal of the antagonist'
], # List must match number of images (or use single string for all)
'date': '2025-01-29',
}
```
**Important:** If you provide `alt_text` as a list, it should match the number of images in `filename`. If the counts don't match, you'll see a warning in the logs. To use the same alt text for all images, just provide a single string instead of a list.
**Features:**
- ✅ **Seamless vertical layout** - Images stack with no visible gaps
- ✅ **Lazy loading** - Only loads images as they scroll into view (performance optimization)
- ✅ **Responsive** - Works on desktop and mobile devices
- ✅ **Accessible** - Supports individual alt text for each image panel
- ✅ **Backward compatible** - Single-image comics continue to work as before
**Best Practices:**
1. **Image consistency** - Use the same width for all images in a multi-image comic for best results
2. **Alt text per panel** - Provide individual alt text for each image to describe what's happening in that section
3. **File naming** - Use descriptive, sequential names like `comic-004-panel-1.png`, `comic-004-panel-2.png`
4. **Image optimization** - Compress images appropriately since readers will load multiple images per comic
**Example with all options:**
```python
{
'number': 6,
'title': 'Chapter 2: The Journey Begins',
'filename': [
'ch2-001.png',
'ch2-002.png',
'ch2-003.png',
'ch2-004.png',
'ch2-005.png'
],
'alt_text': [
'Panel 1: Hero packs their bag at sunrise',
'Panel 2: Saying goodbye to the village elder',
'Panel 3: Walking along the forest path',
'Panel 4: Encountering a mysterious stranger',
'Panel 5: Accepting a map to the ancient ruins'
],
'date': '2025-02-05',
'author_note': 'This was so much fun to draw! The journey arc begins.',
'full_width': True, # Recommended for webtoon-style comics
'section': 'Chapter 2', # Optional: mark the start of a new chapter
}
```
**Technical Details:**
- Images appear in the order listed in the `filename` array
- If `alt_text` is a single string, it applies to all images
- If `alt_text` is a list, it must match the length of `filename` (or it will pad with empty strings)
- The first image in the array is used as the thumbnail in the archive page
- Lazy loading uses Intersection Observer API with 50px margin for smooth loading
**When to use multi-image:**
- Long-form vertical scrolling stories (webtoons, manhwa style)
- Comics with natural panel breaks across multiple images
- Stories that benefit from vertical pacing and reveals
**When to stick with single images:**
- Traditional comic strip or page layouts
- Self-contained single-panel comics
- When you want click-through navigation on the comic image
## Production Deployment
For production, you should **NOT** use Flask's built-in development server. Choose one of the following deployment methods: