Files
sunday/README.md
2025-11-15 14:37:04 +10:00

27 KiB

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 a simple text file

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 adding basic information (title, date, description) to a configuration file. 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 in a Python file - edit text to add comics
  • 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 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)
  • 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)

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!
        # ...
    }
    
  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

Project Structure

sunday/
├── app.py                    # Main Flask application
├── comics_data.py            # Comic data and configuration
├── requirements.txt          # Python dependencies
├── Dockerfile                # Production Docker image
├── docker-compose.yml        # Docker Compose configuration
├── .dockerignore             # Docker build exclusions
├── scripts/                  # Utility scripts
│   ├── add_comic.py         # Script to add new comic entries
│   └── generate_rss.py      # Script to generate RSS feed
├── content/                  # Markdown content
│   ├── about.md             # About page content
│   └── 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)

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)

Development:

export DEBUG=True
python app.py

Production:

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

Configuration

The comics_data.py file contains both comic data and global configuration options:

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
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
NEWSLETTER_ENABLED = False                # Show newsletter section in footer
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 in the COMICS list in comics_data.py. Each comic entry:

{
    'number': 1,                           # Comic number (required, sequential)
    'filename': 'comic-001.png',           # Image filename (required)
    'mobile_filename': 'comic-001-mobile.png',  # Optional mobile version
    'date': '2025-01-01',                  # Publication date (required)
    'alt_text': 'Alt text for comic',      # Accessibility text (required)
    '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
}

Adding a New Comic

Option 1: Use the script (recommended)

# Add comic entry only
python scripts/add_comic.py

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

This will automatically add a new entry with defaults. The -m flag creates a markdown file in content/author_notes/{date}.md with a template and adds the author_note_md field to the comic entry. Then edit comics_data.py to customize.

Option 2: Manual

  1. Save your comic image in static/images/comics/ (e.g., comic-001.png)
  2. Optionally, create a thumbnail in static/images/thumbs/ with the same filename
  3. Add the comic entry to the COMICS list in comics_data.py

Generating RSS Feed

After adding comics, regenerate the RSS feed:

python scripts/generate_rss.py

This creates/updates static/feed.rss

Markdown Support

Author Notes: Add the author_note_md field to your comic entry in comics_data.py 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 comics_data.py
{
    '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.

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