1332 lines
53 KiB
Markdown
1332 lines
53 KiB
Markdown
# Sunday - Webcomic Website Template
|
|
|
|
A Flask-based webcomic website with server-side rendering using Jinja2 templates.
|
|
|
|
## Table of Contents
|
|
|
|
- [What is This?](#what-is-this)
|
|
- [How Does This Compare to Rarebit?](#how-does-this-compare-to-rarebit)
|
|
- [Simple Hosting Options](#simple-hosting-options)
|
|
- [PythonAnywhere (Recommended for Beginners)](#pythonanywhere-recommended-for-beginners)
|
|
- [Render](#render)
|
|
- [Railway](#railway)
|
|
- [DigitalOcean App Platform](#digitalocean-app-platform)
|
|
- [What You'll Need](#what-youll-need)
|
|
- [Features](#features)
|
|
- [Accessibility](#accessibility)
|
|
- [Accessibility Features](#accessibility-features)
|
|
- [Testing Accessibility](#testing-accessibility)
|
|
- [Accessibility Best Practices for Comic Creators](#accessibility-best-practices-for-comic-creators)
|
|
- [Accessibility Score](#accessibility-score)
|
|
- [Search Engine Optimization (SEO)](#search-engine-optimization-seo)
|
|
- [SEO Features](#seo-features)
|
|
- [Using SEO Features](#using-seo-features)
|
|
- [SEO Best Practices for Webcomics](#seo-best-practices-for-webcomics)
|
|
- [SEO Checklist for Launch](#seo-checklist-for-launch)
|
|
- [Common SEO Questions](#common-seo-questions)
|
|
- [Content Protection & AI Scraping Prevention](#content-protection--ai-scraping-prevention)
|
|
- [Protection Features](#protection-features)
|
|
- [Advanced: Image-Level Protection Tools](#advanced-image-level-protection-tools)
|
|
- [Important Limitations](#important-limitations)
|
|
- [Customizing Your Terms](#customizing-your-terms)
|
|
- [Testing Your Protection](#testing-your-protection)
|
|
- [Reporting Violations](#reporting-violations)
|
|
- [Project Structure](#project-structure)
|
|
- [Setup](#setup)
|
|
- [Keeping Your Fork Up-to-Date](#keeping-your-fork-up-to-date)
|
|
- [Environment Variables](#environment-variables)
|
|
- [Configuration](#configuration)
|
|
- [Global Settings](#global-settings)
|
|
- [Adding Comics](#adding-comics)
|
|
- [Adding a New Comic](#adding-a-new-comic)
|
|
- [Generating RSS Feed](#generating-rss-feed)
|
|
- [Markdown Support](#markdown-support)
|
|
- [Production Deployment](#production-deployment)
|
|
- [Option 1: Docker (Recommended)](#option-1-docker-recommended)
|
|
- [Option 2: Manual Deployment with Gunicorn](#option-2-manual-deployment-with-gunicorn)
|
|
- [Using a Reverse Proxy (Recommended)](#using-a-reverse-proxy-recommended)
|
|
- [Using a CDN for Static Assets](#using-a-cdn-for-static-assets)
|
|
- [Additional Production Considerations](#additional-production-considerations)
|
|
- [Upgrading to a Database](#upgrading-to-a-database)
|
|
- [Customization](#customization)
|
|
- [Branding](#branding)
|
|
- [Styling](#styling)
|
|
- [About Page](#about-page)
|
|
- [Icon Navigation](#icon-navigation)
|
|
- [Social Links](#social-links)
|
|
- [Shareable Banner](#shareable-banner)
|
|
- [Navigation](#navigation)
|
|
- [Mouse/Touch Navigation](#mousetouch-navigation)
|
|
- [Keyboard Navigation](#keyboard-navigation)
|
|
- [Pages](#pages)
|
|
- [API Endpoints](#api-endpoints)
|
|
- [Credits](#credits)
|
|
- [AI Usage Transparency](#ai-usage-transparency)
|
|
- [License & Content Ownership](#license--content-ownership)
|
|
|
|
## 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](https://rarebit.neocities.org/) 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:
|
|
|
|
### PythonAnywhere (Recommended for Beginners)
|
|
**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](https://www.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](https://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](https://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](https://www.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
|
|
- **Built-in CDN support** for static assets (images, CSS, JavaScript)
|
|
- **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**
|
|
```yaml
|
|
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:
|
|
|
|
```bash
|
|
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:**
|
|
```python
|
|
# 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):
|
|
```html
|
|
<meta name="description" content="Your custom description here">
|
|
```
|
|
|
|
**templates/comic.html** - Comic-specific descriptions:
|
|
```html
|
|
{% block meta_description %}{{ comic.alt_text }}{% endblock %}
|
|
```
|
|
|
|
**templates/index.html** - Homepage description:
|
|
```html
|
|
{% 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:
|
|
```html
|
|
<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:
|
|
|
|
```bash
|
|
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
|
|
|
|
#### 4. Build Backlinks
|
|
- 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:
|
|
|
|
```html
|
|
<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](https://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](https://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:**
|
|
```bash
|
|
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:
|
|
```html
|
|
<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:
|
|
- [US Copyright Office DMCA](https://www.copyright.gov/dmca/)
|
|
- [EU Copyright Directive](https://digital-strategy.ec.europa.eu/en/policies/copyright-legislation)
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
sunday/
|
|
├── app.py # Main Flask application
|
|
├── comics_data.py # Global configuration (your settings)
|
|
├── comics_data.py.example # Configuration template (reference for new options)
|
|
├── 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
|
|
├── UPSTREAM.md # Guide for keeping forks up-to-date
|
|
├── 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/
|
|
│ ├── variables.css # Design variables (your customization)
|
|
│ └── style.css # Core framework styles
|
|
├── 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:
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
2. Run the application:
|
|
```bash
|
|
python app.py
|
|
```
|
|
|
|
3. Visit http://127.0.0.1:3000 in your browser
|
|
|
|
## Keeping Your Fork Up-to-Date
|
|
|
|
**If you forked Sunday Comics to create your own webcomic site**, you can stay up-to-date with framework improvements while keeping your customizations.
|
|
|
|
Sunday Comics is designed with a **fork-and-customize workflow**:
|
|
- ✅ **Core framework files** (app.py, templates, scripts) - updated by upstream
|
|
- ✅ **User customization** (comics_data.py, variables.css) - your settings
|
|
- ✅ **User content** (comics, images, markdown) - your creative work
|
|
|
|
When you pull upstream updates, you'll get new features and bug fixes without losing your content or design.
|
|
|
|
**📖 [Read the complete guide: UPSTREAM.md](UPSTREAM.md)**
|
|
|
|
The UPSTREAM.md guide covers:
|
|
- Setting up your fork with an upstream remote
|
|
- Pulling and merging updates
|
|
- Handling merge conflicts (with examples)
|
|
- Understanding which files to modify vs. leave alone
|
|
- Troubleshooting common issues
|
|
|
|
**Quick update workflow:**
|
|
```bash
|
|
# Every few weeks/months:
|
|
git fetch upstream # Get new commits
|
|
git merge upstream/main # Merge updates
|
|
# Resolve any conflicts if needed
|
|
git push origin main # Push to your fork
|
|
python scripts/publish_comic.py # Rebuild site
|
|
```
|
|
|
|
**First time?** See [UPSTREAM.md](UPSTREAM.md) for the initial setup steps.
|
|
|
|
## 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:**
|
|
```bash
|
|
export DEBUG=True
|
|
python app.py
|
|
```
|
|
|
|
**Production:**
|
|
```bash
|
|
export SECRET_KEY="your-secure-random-secret-key"
|
|
export PORT=3000
|
|
python app.py
|
|
```
|
|
|
|
**Disable caching (debugging):**
|
|
```bash
|
|
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
|
|
|
|
```python
|
|
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)
|
|
CDN_URL = None # CDN URL for static assets (None = use local)
|
|
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:
|
|
|
|
```yaml
|
|
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):**
|
|
```yaml
|
|
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)**
|
|
```bash
|
|
# 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:
|
|
```bash
|
|
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:**
|
|
```bash
|
|
# 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:
|
|
```yaml
|
|
# 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
|
|
```
|
|
|
|
```bash
|
|
# 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:**
|
|
```yaml
|
|
# 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):**
|
|
```yaml
|
|
# 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:**
|
|
```yaml
|
|
# 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:
|
|
|
|
### Option 1: Docker (Recommended)
|
|
|
|
**1. Generate a secure secret key:**
|
|
```bash
|
|
python -c "import secrets; print(secrets.token_hex(32))"
|
|
```
|
|
|
|
**2. Create a `.env` file:**
|
|
```bash
|
|
SECRET_KEY=your-generated-secret-key-here
|
|
```
|
|
|
|
**3. Build and run with Docker Compose:**
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
**Or build and run manually:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
docker-compose logs -f
|
|
```
|
|
|
|
### Option 2: Manual Deployment with Gunicorn
|
|
|
|
**1. Generate a Secure Secret Key**
|
|
|
|
```bash
|
|
python -c "import secrets; print(secrets.token_hex(32))"
|
|
```
|
|
|
|
**2. Set Environment Variables**
|
|
|
|
```bash
|
|
export SECRET_KEY="generated-secret-key-from-above"
|
|
export DEBUG=False
|
|
export PORT=3000
|
|
```
|
|
|
|
**3. Use a Production WSGI Server**
|
|
|
|
**Install Gunicorn:**
|
|
```bash
|
|
pip install gunicorn
|
|
```
|
|
|
|
**Run with Gunicorn:**
|
|
```bash
|
|
gunicorn app:app --bind 0.0.0.0:3000 --workers 4
|
|
```
|
|
|
|
### Using a Reverse Proxy (Recommended)
|
|
|
|
Set up Nginx or another reverse proxy in front of your app for:
|
|
- HTTPS/SSL termination
|
|
- Static file serving
|
|
- Load balancing
|
|
- Better security
|
|
|
|
### Using a CDN for Static Assets
|
|
|
|
For better performance, especially with high traffic or global audiences, you can serve static assets (images, CSS, JavaScript) from a Content Delivery Network (CDN).
|
|
|
|
**How it works:**
|
|
|
|
Sunday Comics includes built-in CDN support through the `CDN_URL` configuration option. When set, all static assets (comic images, CSS, JavaScript, icons, etc.) are served from your CDN instead of your application server.
|
|
|
|
**Setup Steps:**
|
|
|
|
1. **Upload your static files to a CDN:**
|
|
- Upload the entire `static/` directory to your CDN provider
|
|
- Popular CDN options: Cloudflare, AWS CloudFront, BunnyCDN, KeyCDN
|
|
- Maintain the same directory structure (e.g., `static/css/style.css` → `your-cdn.com/static/css/style.css`)
|
|
|
|
2. **Configure Sunday Comics:**
|
|
```python
|
|
# In comics_data.py
|
|
CDN_URL = 'https://cdn.example.com' # No trailing slash!
|
|
```
|
|
|
|
3. **Deploy and test:**
|
|
- Restart your application
|
|
- Verify images and CSS load from the CDN by checking network requests in browser DevTools
|
|
|
|
**Benefits:**
|
|
- ⚡ **Faster loading** - Static assets served from edge servers closer to your readers
|
|
- 📉 **Reduced server load** - Your application server only handles dynamic content
|
|
- 💰 **Lower bandwidth costs** - CDN bandwidth is often cheaper than server bandwidth
|
|
- 🌍 **Global performance** - Readers worldwide get fast load times
|
|
- 🛡️ **DDoS protection** - Many CDNs include built-in protection
|
|
|
|
**Example Configuration:**
|
|
|
|
```python
|
|
# Local development (no CDN)
|
|
CDN_URL = None
|
|
|
|
# Production with CDN
|
|
CDN_URL = 'https://d1abc123xyz.cloudfront.net' # AWS CloudFront example
|
|
CDN_URL = 'https://cdn.yourcomic.com' # Custom domain example
|
|
```
|
|
|
|
**Important Notes:**
|
|
- When using a CDN, update your static files on the CDN whenever you make changes
|
|
- Consider using cache-busting techniques for CSS/JS updates (version query parameters)
|
|
- Test thoroughly after enabling CDN to ensure all assets load correctly
|
|
- The `cdn_static` template filter automatically handles URL generation
|
|
- When `CDN_URL` is `None`, Sunday Comics falls back to local static file serving
|
|
|
|
**Free CDN Options:**
|
|
- **Cloudflare** - Free tier includes CDN and DDoS protection
|
|
- **jsDelivr** - Free CDN for GitHub repositories
|
|
- **BunnyCDN** - Low-cost pay-as-you-go pricing
|
|
|
|
### Additional Production Considerations
|
|
|
|
- Use a process manager (systemd, supervisor) for non-Docker deployments
|
|
- Set appropriate file permissions
|
|
- Enable HTTPS with Let's Encrypt
|
|
- Use a CDN for static assets (see [Using a CDN](#using-a-cdn-for-static-assets) above)
|
|
- 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
|
|
- **Customize design:** Edit `static/css/variables.css` to change colors, fonts, spacing, and layout dimensions
|
|
- **Framework styles:** `static/css/style.css` contains core styles that reference the variables (avoid modifying for easier upstream updates)
|
|
- Variables are organized by category: Colors, Typography, Spacing, Borders, Layout, Transitions
|
|
|
|
### 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`
|
|
|
|
### Social Links
|
|
Configure social media links in `comics_data.py`:
|
|
```python
|
|
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`:
|
|
```python
|
|
BANNER_IMAGE = 'banner.jpg' # Your banner filename
|
|
```
|
|
3. Set to `None` to hide the "Link to Me" section entirely:
|
|
```python
|
|
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
|
|
```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!"
|
|
}
|
|
]
|
|
```
|
|
|
|
- **GET `/api/comics/<id>`** - Returns a specific comic as JSON
|
|
```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
|
|
|
|
- Inspired by [Rarebit](https://rarebit.neocities.org/)
|
|
- Favicon generated using [favicon.io](https://favicon.io)
|
|
- Example comics sourced from Boots and Her Buddies comic strip at [Comic Book Plus](https://comicbookplus.com/?cid=2561)
|
|
|
|
## 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. In fact, the website itself does its best to protect your work from AI training! See the
|
|
"Content Protection & AI Scraping Prevention" section above.
|
|
|
|
**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](https://rarebit.neocities.org/)
|
|
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](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
|