2025-11-15 15:43:32 +10:00
2025-11-15 19:20:21 +10:00
2025-11-15 19:37:52 +10:00
2025-11-15 20:01:06 +10:00
🐳 docker
2025-11-06 22:30:56 +10:00
2025-11-07 16:37:10 +10:00
2025-11-15 19:37:52 +10:00
2025-11-15 19:37:52 +10:00
2025-11-15 19:20:21 +10:00
2025-11-15 19:37:52 +10:00
🐳 docker
2025-11-06 22:30:56 +10:00
🐳 docker
2025-11-06 22:30:56 +10:00
📝 license
2025-11-14 15:37:41 +10:00
2025-11-15 20:21:19 +10:00
2025-11-15 19:20:21 +10:00

Sunday - Webcomic Website Template

A Flask-based webcomic website with server-side rendering using Jinja2 templates.

Table of Contents

What is This?

Sunday Comics is a simple, ready-to-use website for publishing your webcomic online. If you're an artist or comic creator who wants to share your work on the web without dealing with complex platforms or databases, this is for you.

What you get:

  • A clean, professional website to display your comics
  • Easy navigation for readers (first, previous, next, latest buttons)
  • An archive page where readers can browse all your comics
  • RSS feed so readers can subscribe to updates
  • Mobile-friendly design that works on phones and tablets
  • No database required - just upload images and edit simple YAML files

Perfect for:

  • Independent comic artists starting their first webcomic
  • Artists who want full control over their comic's presentation
  • Creators who prefer simple file-based management over databases
  • Anyone looking for a lightweight, customizable comic platform

How it works: You add your comics by uploading image files and creating individual YAML files with basic information (title, date, description). The website handles everything else - displaying comics with navigation, creating an archive, generating an RSS feed, and making your comics shareable on social media.

No coding knowledge required for basic use - just follow the instructions below to add comics and customize your site's appearance.

How Does This Compare to Rarebit?

Rarebit is an excellent static webcomic template that inspired this project. Sunday Comics offers a different approach with its own strengths:

Sunday Comics:

  • Server-side application (Flask/Python) that runs on a web server
  • Comics stored as individual YAML files - easy version control and management
  • Includes an RSS feed generator and helper scripts
  • API endpoints for programmatic access
  • Markdown support for rich-formatted content
  • More flexibility for custom features and integrations
  • Requires Python installation and basic server setup

Rarebit:

  • Purely static HTML/CSS/JavaScript files
  • Comics are inferred from static images upload - edit a JS file to customize
  • Can be hosted for free on GitHub Pages, Neocities, etc.
  • No server or programming language required
  • Simpler deployment - just upload files

Which should you choose?

  • Choose Rarebit if you want the simplest possible setup and free hosting
  • Choose Sunday Comics if you want server-side features, plan to add custom functionality, or prefer working with Python
  • Both are great options - it depends on your technical comfort level and hosting preferences

Sunday Comics is meant as another option in the webcomic toolkit, not a replacement for Rarebit. Many creators might even use both for different projects!

Simple Hosting Options

Don't have a server? No problem! Here are beginner-friendly options to get your comic online:

Best for: First-time deployments, testing your comic site

  • Free tier available (with pythonanywhere.com subdomain)
  • No credit card required for free tier
  • Setup: Upload your files through their web interface, configure a few settings
  • Great beginner tutorials available on their site
  • Visit: pythonanywhere.com

Render

Best for: Automatic deployments from GitHub

  • Free tier available (site sleeps after inactivity)
  • Setup: Connect your GitHub repository, Render deploys automatically
  • No server management needed - just push code to GitHub
  • Custom domain support on free tier
  • Visit: render.com

Railway

Best for: Quick deployment with modern interface

  • Free trial credits included ($5/month after)
  • Setup: Connect GitHub, deploy with one click
  • Automatic deployments when you update your code
  • Simple dashboard to monitor your site
  • Visit: railway.app

DigitalOcean App Platform

Best for: Scaling as your audience grows

  • $5/month for basic tier (no free tier)
  • Very reliable for growing comics with traffic
  • Automatic scaling handles traffic spikes
  • One-click deploy from GitHub
  • Visit: digitalocean.com/products/app-platform

What You'll Need:

  1. Your comic files and images
  2. A GitHub account (free) for most modern hosting platforms
  3. Basic familiarity with uploading files or pushing to GitHub

Complete beginner? Start with PythonAnywhere - it has the gentlest learning curve and requires no GitHub knowledge. You can always migrate to other platforms later as you get more comfortable.

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
  • RSS feed support
  • Markdown support for author notes and about page
  • Optional icon-based navigation (comic navigation, header, and social links)
  • Configurable logo and header/footer images
  • Shareable banner button with embeddable HTML code
  • Mobile-responsive with optional mobile-specific comic images
  • Full-width and plain (headerless) display modes
  • JSON API for programmatic access
  • Open Graph and Twitter Card metadata for social sharing
  • Server-side rendering with Jinja2
  • Comprehensive accessibility features (WCAG compliant)
  • Search engine optimized (sitemap, robots.txt, meta tags, canonical URLs)

Accessibility

Sunday Comics is built with accessibility as a core feature, ensuring your webcomic can be enjoyed by all readers, including those using assistive technologies.

Accessibility Features

Keyboard Navigation

  • Full keyboard support - Navigate the entire site without a mouse
  • Visible focus indicators - Clear visual outlines on all interactive elements when using Tab navigation
  • Skip to main content - Press Tab on any page to reveal a "Skip to main content" link, allowing keyboard users to bypass navigation
  • Arrow key shortcuts - Use Left/Right arrows to navigate between comics, Home/End for first/latest
  • Focus management - Keyboard focus automatically moves to the comic content after navigation, maintaining context for screen reader users

Screen Reader Support

  • Semantic HTML - Proper use of <header>, <nav>, <main>, <footer> elements
  • ARIA live regions - Screen readers announce when new comics load during client-side navigation
  • ARIA labels - All icon buttons and links have descriptive labels
  • ARIA disabled states - Disabled navigation buttons properly announce their state
  • Alt text - All comic images require alt text (set via alt_text field in comics_data.py)
  • No redundant announcements - Decorative icons use empty alt text to avoid duplicate screen reader announcements

Visual Accessibility

  • High contrast - Focus indicators use solid 3px outlines for visibility
  • Responsive design - Works across desktop, tablet, and mobile screen sizes
  • No reliance on color alone - Disabled states use both color and opacity changes

Additional Accessibility Support

  • Language declaration - lang="en" attribute on HTML element
  • Heading hierarchy - Proper use of h1, h2, h3 throughout the site
  • Clickable regions - Comic images that advance to the next comic include descriptive labels
  • External link safety - rel="noopener noreferrer" on external links
  • Keyboard trap prevention - No focus traps; users can always navigate away

Testing Accessibility

To test keyboard navigation on your site:

  1. Tab Navigation

    • Press Tab repeatedly to move through interactive elements
    • Verify visible focus indicators appear on links and buttons
    • First Tab should reveal "Skip to main content" link
  2. Keyboard Shortcuts

    • On a comic page, press Right Arrow to advance
    • Press Left Arrow to go back
    • Press Home to jump to first comic
    • Press End to jump to latest comic
  3. Screen Reader Testing (Optional)

    • macOS: Enable VoiceOver (Cmd + F5)
    • Windows: Use NVDA (free) or JAWS
    • Navigate through the site and verify announcements are clear and logical

Accessibility Best Practices for Comic Creators

When adding comics to your site, follow these guidelines to maintain accessibility:

  1. Always provide alt text

    number: 1
    filename: comic-001.png
    alt_text: A descriptive summary of what happens in the comic  # Required!
    date: '2025-01-01'
    
  2. Write meaningful alt text

    • Describe the comic's content and context
    • Include dialogue if it's essential to understanding
    • Keep it concise but descriptive (aim for 1-2 sentences)
    • Bad: "Comic"
    • Good: "Sarah discovers her cat can talk and is planning world domination"
  3. Use proper image formats

    • Ensure comic images are clear and readable
    • Consider providing larger resolution images for zoom accessibility
    • Test your comics at different zoom levels (200%, 300%)
  4. Structure author notes clearly

    • Use markdown headings for long author notes
    • Break up long paragraphs
    • Use lists for clarity when appropriate

Accessibility Score

Sunday Comics follows WCAG 2.1 Level AA guidelines and scores 9.5/10 in accessibility compliance, with comprehensive support for:

  • Keyboard navigation
  • Screen reader compatibility
  • Focus management
  • ARIA attributes
  • Semantic HTML

Search Engine Optimization (SEO)

Sunday Comics is built with SEO best practices to help readers discover your webcomic through search engines and social media.

SEO Features

Sitemap & Crawling

  • XML Sitemap - Automatically generated sitemap that includes all comics, archive, and about pages
  • Robots.txt - Dynamically generated with correct URLs for your domain
  • Canonical URLs - Every page has a canonical URL to prevent duplicate content issues
  • Semantic HTML - Proper use of heading hierarchy (h1, h2, h3) for better indexing
  • Language declaration - lang="en" attribute helps search engines understand your content

Meta Tags & Descriptions

  • Meta descriptions - Customizable descriptions for each page
  • Page titles - SEO-friendly title format: "Comic Title - Your Comic Name"
  • RSS feed link - Included in HTML head for feed discovery
  • Viewport meta tag - Mobile-friendly configuration

Social Media Sharing

  • Open Graph tags - Optimized previews when sharing on Facebook, LinkedIn, Discord, etc.
  • Twitter Cards - Rich media cards with images when sharing on Twitter/X
  • Custom preview images - Set comic-specific images for social sharing
  • Shareable URLs - Clean, readable URLs like /comic/1 instead of query parameters

Content Optimization

  • Alt text requirement - All comics must have descriptive alt text (helps SEO and accessibility)
  • Structured data - Semantic HTML provides context to search engines
  • Mobile-responsive - Mobile-friendly design is a ranking factor for Google
  • Fast loading - Server-side rendering provides quick initial page loads

Using SEO Features

Generate Your Sitemap

After adding or updating comics, regenerate your sitemap:

python scripts/generate_sitemap.py

This creates static/sitemap.xml with:

  • Homepage (priority: 1.0, updated weekly)
  • Archive page (priority: 0.9, updated weekly)
  • About page (priority: 0.7, updated monthly)
  • Individual comic pages (priority: 0.8, never updated)

Submit your sitemap to search engines:

  • Google Search Console: https://search.google.com/search-console
  • Bing Webmaster Tools: https://www.bing.com/webmasters

Your sitemap URL will be: https://yourdomain.com/sitemap.xml

Configure robots.txt

The robots.txt file is automatically generated at /robots.txt with your correct domain from SITE_URL in comics_data.py. It includes:

  • Sitemap location
  • Allows all search engine crawlers
  • No disallowed paths (everything is indexable)

Update your domain:

# In comics_data.py
SITE_URL = 'https://yourcomic.com'  # Update this for production!

Customize Meta Descriptions

By default, pages use a generic description. To customize, edit the templates:

templates/base.html - Default description (line 9):

<meta name="description" content="Your custom description here">

templates/comic.html - Comic-specific descriptions:

{% block meta_description %}{{ comic.alt_text }}{% endblock %}

templates/index.html - Homepage description:

{% block meta_description %}Read the latest comic from Your Comic Name{% endblock %}

Optimize Social Sharing

Set a default preview image:

  1. Create a 1200x630px image (recommended size for Open Graph)
  2. Save it in static/images/ (e.g., default-preview.png)
  3. Update base.html line 17:
    <meta property="og:image" content="{{ site_url }}/static/images/your-preview.png">
    

Comic-specific sharing images:

The comic.html template automatically uses each comic's image for social sharing. When someone shares a comic link, the actual comic image appears in the preview.

Generate RSS Feed

RSS feeds help readers subscribe and improve discoverability:

python scripts/generate_rss.py

This creates static/feed.rss which is automatically linked in the HTML head. Readers can subscribe via:

  • https://yourdomain.com/static/feed.rss

RSS feeds also signal to search engines that your site has regularly updated content.

SEO Best Practices for Webcomics

1. Write Descriptive Alt Text

Alt text serves dual purpose - accessibility AND SEO:

  • Include character names and actions
  • Describe the scene setting
  • Mention any important dialogue or text
  • Keep it concise but informative (1-3 sentences)

Good examples:

  • "Sarah discovers her cat plotting world domination while reading a mysterious ancient book"
  • "The hero confronts the villain in a dramatic rooftop battle at sunset"
  • "Comic" (too vague)
  • "Comic about a cat" (not descriptive enough)

2. Use Meaningful Comic Titles

If you set a title for each comic (optional), make it:

  • Descriptive of the comic's content or theme
  • Unique (don't reuse titles)
  • Natural language (avoid "Comic #1" style)
  • Under 60 characters for best search result display

3. Update Regularly

  • Consistent publishing schedule signals quality to search engines
  • Run generate_sitemap.py after each new comic
  • Update your about page periodically
  • List your comic in webcomic directories
  • Use the shareable banner feature to encourage fan sites to link back
  • Engage with other webcomic communities
  • Share on social media regularly

5. Monitor Your SEO

Free tools to track your webcomic's search performance:

  • Google Search Console - See how people find your site, track indexing issues
  • Bing Webmaster Tools - Similar to Google, for Bing search
  • Google Analytics - Track visitor behavior (requires separate setup)

6. Domain and URL Structure

  • Use a memorable domain name
  • Keep URLs clean: yourcomic.com/comic/1 vs yourcomic.com/?p=1
  • Sunday Comics uses SEO-friendly URLs by default

7. Page Speed

  • Optimize comic images (use compression, appropriate file formats)
  • Consider creating thumbnails for the archive page
  • Use a CDN for static assets if you have high traffic
  • Sunday Comics uses server-side rendering for fast initial loads

SEO Checklist for Launch

Before going live with your webcomic:

  • Update SITE_URL in comics_data.py to your production domain
  • Generate sitemap: python scripts/generate_sitemap.py
  • Generate RSS feed: python scripts/generate_rss.py
  • Customize meta description in templates/base.html
  • Create a 1200x630px social preview image
  • Write descriptive alt text for all comics
  • Set up Google Search Console account
  • Submit your sitemap to Google Search Console
  • Submit your sitemap to Bing Webmaster Tools
  • Test social sharing on Facebook, Twitter, Discord
  • Update your about page with relevant keywords
  • Set up RSS feed in Feedly or similar to verify it works

Common SEO Questions

Q: How long until my comic appears in Google? A: Typically 1-4 weeks after submitting your sitemap. You can request indexing in Google Search Console to speed this up.

Q: Should I include keywords in my comic alt text? A: Only naturally. Focus on accurate descriptions first. Keyword stuffing hurts SEO and accessibility.

Q: Do I need to regenerate the sitemap for every comic? A: Yes, run python scripts/generate_sitemap.py after adding new comics so search engines know about them.

Q: What about social media hashtags? A: Hashtags don't directly affect search engine SEO, but they help social media discoverability. Use relevant community hashtags like #webcomics #comics #indiecomics.

Q: Should I create a blog for my comic? A: Optional, but regular blog content about your comic's development can improve SEO through fresh content and more keywords.

Content Protection & AI Scraping Prevention

Sunday Comics includes built-in measures to discourage AI web scrapers from using your creative work for training machine learning models without permission.

Protection Features

robots.txt Blocking

The dynamically generated robots.txt file blocks known AI crawlers while still allowing legitimate search engines:

Blocked AI bots:

  • GPTBot & ChatGPT-User (OpenAI)
  • CCBot (Common Crawl - used by many AI companies)
  • anthropic-ai & Claude-Web (Anthropic)
  • Google-Extended (Google's AI training crawler, separate from Googlebot)
  • PerplexityBot (Perplexity AI)
  • Omgilibot, Diffbot, Bytespider, FacebookBot, ImagesiftBot, cohere-ai

Note: Regular search engine crawlers (Googlebot, Bingbot, etc.) are still allowed so your comic can be discovered through search.

The robots.txt also includes a reference to your Terms of Service for transparency.

HTML Meta Tags

Every page includes meta tags that signal to AI scrapers not to use the content:

<meta name="robots" content="noai, noimageai">
<meta name="googlebot" content="noai, noimageai">
  • noai - Prevents AI training on text content
  • noimageai - Prevents AI training on images (your comics)

Terms of Service

A comprehensive Terms of Service page at /terms legally prohibits:

  • Using content for AI training or machine learning
  • Scraping or harvesting content for datasets
  • Creating derivative works using AI trained on your content
  • Text and Data Mining (TDM) without permission

The Terms page is automatically linked in your footer and includes:

  • Copyright protection assertions
  • DMCA enforcement information
  • TDM rights reservation (EU Directive 2019/790 Article 4)
  • Clear permitted use guidelines

HTTP Headers

Sunday Comics automatically adds X-Robots-Tag: noai, noimageai headers to all responses for additional AI blocking enforcement.

TDM Reservation File

The /tdmrep.json endpoint formally reserves Text and Data Mining rights under EU Directive 2019/790, pointing to your Terms of Service.

Advanced: Image-Level Protection Tools

For artists who want to protect their work at the image level, consider these specialized tools:

Glaze (Style Protection)

What it does: Adds imperceptible changes to images that prevent AI models from accurately learning your artistic style.

Best for:

  • Protecting your unique art style from being copied by AI
  • Making AI-generated imitations look wrong or distorted
  • Artists concerned about style mimicry (e.g., "draw like [artist name]" prompts)

How to use:

  1. Download from glaze.cs.uchicago.edu
  2. Process your comic images before uploading to your site
  3. The changes are invisible to humans but confuse AI models

Trade-offs:

  • Processing time: Can take several minutes per image
  • Slight file size increase
  • Requires reprocessing all comics

Nightshade (Data Poisoning)

What it does: Makes images appear as something completely different to AI models while looking normal to humans.

Best for:

  • Active defense against unauthorized AI training
  • Making scraped data actively harmful to AI models
  • Artists who want to fight back against scraping

How to use:

  1. Download from nightshade.cs.uchicago.edu
  2. Process images before uploading (can combine with Glaze)
  3. AI models trained on these images will produce incorrect results

Trade-offs:

  • More aggressive than Glaze (may violate some ToS)
  • Processing time similar to Glaze
  • Ongoing research tool, effectiveness may vary

Recommendations

  • Use Glaze if: You want passive protection for your art style
  • Use Nightshade if: You want active defense and accept the risks
  • Use both if: Maximum protection is your priority
  • Combine with Sunday Comics protections: These tools complement the web-based protections (robots.txt, meta tags, etc.)

Note: Both tools are free, open-source projects from the University of Chicago's SAND Lab, specifically designed to help artists protect their work from AI exploitation.

Important Limitations

These measures are voluntary - they only work if AI companies respect them:

What this does:

  • Signals your intent to protect your content
  • Provides legal grounding for DMCA takedowns
  • Blocks responsible AI companies that honor robots.txt
  • Makes your copyright stance clear to users and crawlers

What this doesn't do:

  • Cannot physically prevent determined bad actors from scraping
  • Cannot remove already-scraped historical data from existing datasets
  • No guarantee all AI companies will honor these signals

Companies that claim to honor robots.txt:

  • OpenAI (GPTBot blocking)
  • Anthropic (anthropic-ai blocking)
  • Google (Google-Extended blocking, separate from search)

Customizing Your Terms

Edit /Users/pori/PycharmProjects/sunday/content/terms.md to customize:

  1. Jurisdiction - Add your country/state for legal clarity
  2. Permitted use - Adjust what you allow (fan art, sharing, etc.)
  3. Contact info - Automatically populated from comics_data.py

The Terms page uses Jinja2 template variables that pull from your configuration:

  • {{ copyright_name }} - From COPYRIGHT_NAME in comics_data.py
  • {{ social_email }} - From SOCIAL_EMAIL in comics_data.py

Testing Your Protection

Verify robots.txt:

curl https://yourcomic.com/robots.txt

You should see AI bot blocks and a link to your terms.

Check meta tags: View page source and look for:

<meta name="robots" content="noai, noimageai">

Validate Terms page: Visit https://yourcomic.com/terms to ensure it renders correctly.

Reporting Violations

If you discover your work in an AI training dataset or being used without permission:

  1. Document the violation - Screenshots, URLs, timestamps
  2. Review their TOS - Many AI services have content dispute processes
  3. Send DMCA takedown - Your Terms of Service provides legal standing
  4. Contact the platform - Use your SOCIAL_EMAIL from the Terms page

Resources:

Project Structure

sunday/
├── app.py                    # Main Flask application
├── comics_data.py            # Global configuration (not comic data)
├── data_loader.py            # YAML comic loader with caching
├── requirements.txt          # Python dependencies
├── Dockerfile                # Production Docker image
├── docker-compose.yml        # Docker Compose configuration
├── .dockerignore             # Docker build exclusions
├── data/                     # Comic data directory
│   └── comics/              # Individual comic YAML files
│       ├── 001.yaml         # Comic #1
│       ├── 002.yaml         # Comic #2
│       ├── TEMPLATE.yaml    # Template for new comics
│       └── .comics_cache.pkl # Auto-generated cache file
├── scripts/                  # Utility scripts
│   ├── add_comic.py         # Create new comic YAML files
│   ├── generate_rss.py      # Generate RSS feed
│   ├── generate_sitemap.py  # Generate sitemap.xml
│   ├── rebuild_cache.py     # Force rebuild comics cache
│   └── publish_comic.py     # Rebuild cache + RSS + sitemap
├── content/                  # Markdown content
│   ├── about.md             # About page content
│   ├── terms.md             # Terms of Service
│   └── author_notes/        # Author notes for comics (by date)
├── templates/                # Jinja2 templates
│   ├── base.html            # Base template with navigation
│   ├── index.html           # Latest comic page
│   ├── comic.html           # Individual comic viewer
│   ├── archive.html         # Archive grid
│   ├── page.html            # Generic markdown page template
│   └── 404.html             # Error page
└── static/                  # Static files
    ├── css/
    │   └── style.css        # Main stylesheet
    ├── js/
    │   └── comic-nav.js     # Client-side navigation
    ├── images/              # Image directory
    │   ├── comics/          # Comic images
    │   ├── thumbs/          # Thumbnail images for archive
    │   └── icons/           # Navigation and social icons (optional)
    ├── feed.rss             # RSS feed (generated)
    └── sitemap.xml          # Sitemap (generated)

Setup

  1. Install dependencies:
pip install -r requirements.txt
  1. Run the application:
python app.py
  1. Visit http://127.0.0.1:3000 in your browser

Environment Variables

The app can be configured via environment variables:

  • SECRET_KEY - Flask secret key (defaults to 'your-secret-key')
  • PORT - Port to run on (defaults to 3000)
  • DEBUG - Enable debug mode (defaults to False)
  • DISABLE_COMIC_CACHE - Set to 'true' to disable comic caching (useful for debugging)

Development:

export DEBUG=True
python app.py

Production:

export SECRET_KEY="your-secure-random-secret-key"
export PORT=3000
python app.py

Disable caching (debugging):

export DISABLE_COMIC_CACHE=true
python app.py

Configuration

The comics_data.py file contains global configuration options for your comic site. Comic data itself is stored in individual YAML files in the data/comics/ directory.

Global Settings

COMIC_NAME = 'Sunday Comics'              # Your comic/website name
COPYRIGHT_NAME = None                     # Name for copyright (defaults to COMIC_NAME)
SITE_URL = 'http://localhost:3000'        # Your domain (update for production)
FULL_WIDTH_DEFAULT = False                # Make all comics full-width by default
PLAIN_DEFAULT = False                     # Hide header/remove borders by default
LOGO_IMAGE = 'logo.png'                   # Path to logo (relative to static/images/)
LOGO_MODE = 'beside'                      # 'beside' or 'replace' title with logo
HEADER_IMAGE = None                       # Optional header image path
FOOTER_IMAGE = None                       # Optional footer image path
BANNER_IMAGE = 'banner.jpg'               # Shareable banner for "Link to Me" section
COMPACT_FOOTER = False                    # Display footer in compact mode
ARCHIVE_FULL_WIDTH = True                 # Full-width archive with 4 columns
SECTIONS_ENABLED = True                   # Enable section headers on archive page
USE_COMIC_NAV_ICONS = True                # Use icons for comic navigation buttons
USE_HEADER_NAV_ICONS = True               # Show icons in main header navigation
USE_FOOTER_SOCIAL_ICONS = True            # Use icons for social links
USE_SHARE_ICONS = True                    # Use icons in share buttons (permalink/embed)
NEWSLETTER_ENABLED = False                # Show newsletter section in footer
EMBED_ENABLED = True                      # Enable comic embed functionality
PERMALINK_ENABLED = True                  # Enable permalink copy button
SOCIAL_INSTAGRAM = None                   # Instagram URL (or None)
SOCIAL_YOUTUBE = None                     # YouTube URL (or None)
SOCIAL_EMAIL = None                       # Email mailto link (or None)
API_SPEC_LINK = None                      # API documentation link (or None)

Adding Comics

Comics are stored as individual YAML files in the data/comics/ directory. Each comic file contains:

number: 1                                  # Comic number (required, sequential)
filename: comic-001.png                    # Image filename (required) OR list for multi-image
date: '2025-01-01'                         # Publication date (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
full_width: true                           # Optional: override FULL_WIDTH_DEFAULT
plain: true                                # Optional: override PLAIN_DEFAULT

For multi-image comics (webtoon style):

number: 2
filename:
  - page1.png
  - page2.png
  - page3.png
alt_text:
  - Panel 1 description
  - Panel 2 description
  - Panel 3 description
date: '2025-01-08'
full_width: true  # Recommended for webtoons

Adding a New Comic

Option 1: Use the script (recommended)

# Add comic YAML file with defaults
python scripts/add_comic.py

# Add comic YAML file AND create markdown file for author notes
python scripts/add_comic.py -m

This will create a new YAML file in data/comics/ with the next comic number and reasonable defaults. The -m flag also creates a markdown file in content/author_notes/{date}.md with a template. Then:

  1. Edit the generated YAML file to customize title, alt_text, author_note, etc.
  2. Upload your comic image to static/images/comics/
  3. Optionally create a thumbnail in static/images/thumbs/ with the same filename

Option 2: Manual

  1. Copy data/comics/TEMPLATE.yaml and rename it (e.g., 003.yaml)
  2. Edit the YAML file to set comic properties
  3. Save your comic image in static/images/comics/
  4. Optionally, create a thumbnail in static/images/thumbs/ with the same filename

Publishing Comics

After adding or updating comics, use the publish script to update all generated files:

python scripts/publish_comic.py

This convenience script rebuilds the cache and regenerates both RSS feed and sitemap in one command.

Comic Caching System

Sunday Comics uses an automatic caching system to speed up comic loading:

How it works:

  • First load: Parses all YAML files, saves to data/comics/.comics_cache.pkl
  • Subsequent loads: Reads from cache (~100x faster)
  • Auto-invalidation: Cache rebuilds automatically when any YAML file is modified

Performance (1000 comics):

  • Initial load: ~2-3 seconds (builds cache)
  • Subsequent loads: ~0.01 seconds (uses cache)
  • Scripts share the same cache file on disk

Manual cache management:

# Force rebuild the cache (normally not needed)
python scripts/rebuild_cache.py

# Disable caching (for debugging)
export DISABLE_COMIC_CACHE=true
python app.py

The cache file is automatically excluded from git (listed in .gitignore).

Markdown Support

Author Notes: Add the author_note_md field to your comic YAML file to use markdown-formatted author notes. The field can be:

  • Just a filename (e.g., 2025-01-01.md) - looked up in content/author_notes/
  • A path relative to content/ (e.g., special/intro.md)

Markdown author notes take precedence over the plain text author_note field and render as HTML.

Example:

# In data/comics/001.yaml
number: 1
filename: comic-001.png
date: '2025-01-01'
alt_text: First comic
author_note_md: 2025-01-01.md  # References content/author_notes/2025-01-01.md
# Create the markdown file
echo "# My First Comic\n\nThis is **bold** text!" > content/author_notes/2025-01-01.md

About Page: The /about route renders content/about.md as HTML. Edit this file to customize your about page with markdown formatting.

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:

# In data/comics/004.yaml
number: 4
title: Webtoon Episode 1
filename:
  - page1.jpg
  - page2.jpg
  - page3.jpg
alt_text: A three-part vertical story  # Single alt text for all images
date: '2025-01-22'

Individual Alt Text (Recommended for Accessibility):

# In data/comics/005.yaml
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
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:

# In data/comics/006.yaml
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:

1. Generate a secure secret key:

python -c "import secrets; print(secrets.token_hex(32))"

2. Create a .env file:

SECRET_KEY=your-generated-secret-key-here

3. Build and run with Docker Compose:

docker-compose up -d

Or build and run manually:

# Build the image
docker build -t sunday-comics .

# Run the container
docker run -d \
  -p 3000:3000 \
  -e SECRET_KEY="your-secret-key" \
  -v $(pwd)/comics_data.py:/app/comics_data.py:ro \
  -v $(pwd)/static/images:/app/static/images:ro \
  --name sunday-comics \
  sunday-comics

View logs:

docker-compose logs -f

Option 2: Manual Deployment with Gunicorn

1. Generate a Secure Secret Key

python -c "import secrets; print(secrets.token_hex(32))"

2. Set Environment Variables

export SECRET_KEY="generated-secret-key-from-above"
export DEBUG=False
export PORT=3000

3. Use a Production WSGI Server

Install Gunicorn:

pip install gunicorn

Run with Gunicorn:

gunicorn app:app --bind 0.0.0.0:3000 --workers 4

Set up Nginx or another reverse proxy in front of your app for:

  • HTTPS/SSL termination
  • Static file serving
  • Load balancing
  • Better security

Additional Production Considerations

  • Use a process manager (systemd, supervisor) for non-Docker deployments
  • Set appropriate file permissions
  • Enable HTTPS with Let's Encrypt
  • Consider using a CDN for static assets
  • Monitor logs and performance
  • Set up automated backups of comics_data.py

Upgrading to a Database

For larger comic archives, consider replacing the COMICS list with a database:

  • SQLite for simple setups
  • PostgreSQL/MySQL for production
  • Use Flask-SQLAlchemy for ORM support

Customization

Branding

  • Update COMIC_NAME in comics_data.py to change your comic's name
  • Update SITE_URL in comics_data.py for production deployment
  • Customize logo by setting LOGO_IMAGE and LOGO_MODE

Styling

  • Modify static/css/style.css to change colors, fonts, and layout
  • Current color scheme uses blue (#3498db) and dark blue-gray (#2c3e50)

About Page

  • Edit content/about.md to add your bio and comic information (supports markdown)

Icon Navigation

To use icon navigation:

  1. Set USE_COMIC_NAV_ICONS = True in comics_data.py
  2. Add icons to static/images/icons/:
    • Comic navigation: first.png, previous.png, next.png, latest.png
    • Header navigation: alert.png, archive.png, info.png
    • Social links: instagram.png, youtube.png, mail.png

Configure social media links in comics_data.py:

SOCIAL_INSTAGRAM = 'https://instagram.com/yourhandle'
SOCIAL_YOUTUBE = 'https://youtube.com/@yourchannel'
SOCIAL_EMAIL = 'mailto:your@email.com'

Shareable Banner

Sunday Comics includes an old-school shareable banner button in the footer that visitors can use to link back to your site. To enable it:

  1. Create a banner image (any size) and save it in static/images/
  2. Set the BANNER_IMAGE variable in comics_data.py:
    BANNER_IMAGE = 'banner.jpg'  # Your banner filename
    
  3. Set to None to hide the "Link to Me" section entirely:
    BANNER_IMAGE = None  # Disables the shareable banner
    

When enabled, the banner appears in the footer with:

  • A preview of the banner image
  • A collapsible "Get code" section with copy-paste HTML
  • Fully keyboard accessible (Tab to navigate, Space/Enter to expand)
  • Automatic URL generation using your SITE_URL setting

Visitors can click "Get code" to reveal embeddable HTML they can paste on their own websites, creating a link back to your comic. Perfect for webrings, link exchanges, and building community!

Navigation

Sunday Comics provides multiple ways for readers to navigate through your comic:

Mouse/Touch Navigation

  • Navigation buttons: First, Previous, Next, Latest buttons (text or icon-based)
  • Click-through: Click on the comic image to advance to the next comic
  • Archive grid: Click any thumbnail to jump directly to that comic

Keyboard Navigation

When viewing a comic, readers can use keyboard shortcuts for quick navigation:

  • Left Arrow () - Go to previous comic
  • Right Arrow () - Go to next comic
  • Home - Jump to first comic
  • End - Jump to latest comic

Keyboard shortcuts respect navigation boundaries (won't navigate before the first comic or past the latest) and don't interfere with typing in input fields.

Pages

  • / - Shows the latest comic
  • /comic/<id> - View a specific comic by number
  • /archive - Browse all comics in a grid
  • /about - About the comic and author
  • /static/feed.rss - RSS feed

API Endpoints

The app exposes a JSON API for programmatic access:

  • GET /api/comics - Returns all comics as a JSON array

    [
      {
        "number": 1,
        "title": "First Comic",
        "filename": "comic-001.png",
        "date": "2025-01-01",
        "alt_text": "The very first comic",
        "author_note": "This is where your comic journey begins!"
      }
    ]
    
  • GET /api/comics/<id> - Returns a specific comic as JSON

    {
      "number": 1,
      "title": "First Comic",
      "filename": "comic-001.png",
      "date": "2025-01-01",
      "alt_text": "The very first comic",
      "author_note": "This is where your comic journey begins!"
    }
    

    Returns 404 with {"error": "Comic not found"} if the comic doesn't exist.

Credits

AI Usage Transparency

I want it to be clear that this section was written by a human!

This project has been built using Claude Code - an AI-assisted development tool. Considering several factors, I feel the need to be transparent about this.

My position on AI:

I do not condone the use of AI in regard to artistic expression, communication, or as a replacement real human beings. After all, what is the point of being alive if we leave it all to machines?

All artwork you see produced as assets here or in any of my other projects are made by real human beings and will remain that way. Images generated from AI are an infringement on copyright and intellectual property. I fully believe that the sourcing of data for models should be regulated. I also believe that human creative workers should be celebrated and well compensated.

Being a text-only platform, my choice in Claude is their claim to be an "ethical" AI provider. Of course, we can trust these vendors only so much. Should they act as advertised, there are also environmental considerations. My hope is that this will improve over time. As with data sourcing, I also hope this will be regulated.

How AI is used:

This project's code is written primarily by AI. The application itself does not and will never have any AI integration. When you start up the project, it is completely standalone just like any normal website. Your content remains yours.

So, why use AI?

I am interested in illustrating and making comics, not so much spending my time writing code. AI is a means to an end. Its use here is purely to produce a convenient platform to be used for artwork created by real people.

Should you choose to adopt this, the work you publish remains yours, as it should always be.

For the most part, I am comfortable with its use in technical matters. You can see that with the code on this project. This is a sentiment I generally share with the software development industry which has naturally embraced the new technology.

Why bother with transparency?

As controversial as the technology is, I believe in being transparent about its use. If you happen to like the look of Sunday and want to use that, you should know just in case you are fully anti-AI. This is a position I completely respect.

If you have any concerns or are outright put off, I highly recommend looking at Rarebit which is completely written by humans (and easier to get into if your technical knowledge is limited).

License & Content Ownership

This software is licensed under the MIT License - see the LICENSE file for details.

Your Comics Are Yours

The Sunday Comics software is open source and free to use, but any comics, artwork, and content you create and publish using this platform remain your intellectual property. The software license does not grant any rights to your creative work.

Think of it like using a camera: the camera might be shared, but the photos you take with it are yours. Sunday Comics is the camera, your comics are the photos.

What This Means

  • You can use Sunday Comics for free, forever
  • You can modify the code however you want
  • You can use it for commercial projects
  • Your comics and artwork remain 100% yours
  • No attribution required (but always appreciated!)
  • No revenue sharing or licensing fees
Description
Simple, stylish, and snappy template for hosting comics.
Readme MIT 2.2 MiB
Languages
Python 31.7%
HTML 23.7%
JavaScript 23.5%
CSS 20.3%
Dockerfile 0.8%