A Python-based static website generator specifically designed for web novels, with support for GitHub Actions and GitHub Pages deployment.
You can see a demo build live on: https://oekaki-connect.github.io/web-novel/
You can see our version of it live on: https://www.ocwn.net/
- I didn't see an existing static site generator for web novels which already existed
- Didn't want the baggage of trying to modifying an existing generic static site generator
- This generator works out of box fully with GitHub for free, it's easy to use, easy to modify
- You can open up issues in this repo to request features or improvements and they will be considered
- Do not open support issues if you can't figure out how to use this, this documentation is enough
- Do not join our discord or contact us for questions on how to set this up, read the docs
- If you can't figure it out on your own, ask a dev friend or a friendly AI to help you
- Multi-Novel Support: Host multiple novels from the same repository
- Translation System: Full multi-language support with language switching
- EPUB Downloads: Generate high-quality EPUB files for offline reading
- Front Page: Clean landing page listing all available novels
- Table of Contents: Organized by story arcs with manual chapter sorting
- Chapter Pages: Individual pages for each chapter with navigation
- Chapter Navigation: Dropdown menu for quick chapter jumping and breadcrumb navigation
- Story Statistics: Total length display with language-specific units (words/characters)
- Story Metadata: Publishing status (ongoing/complete/hiatus) and genre tags
- Publication Dates: Chapter publication dates displayed on table of contents
- Tag System: Categorize chapters with tags for easy discovery
- Chapter Images: Chapter-specific image support with automatic processing
- Front Matter Support: Rich metadata including author, translator, tags, and commentary
- Social Media Integration: Open Graph and Twitter Card meta tags for rich social sharing
- SEO Optimization: Configurable meta descriptions, keywords, and indexing controls
- Clean URLs: SEO-friendly URLs without .html extensions
- Responsive Design: Mobile-friendly layout
- GitHub Integration: Automated deployment via GitHub Actions
- Password Protection: Secure premium/beta content with client-side encryption
- Hidden Chapters: Chapters accessible only by direct link (not in navigation)
- Draft Chapters: Mark chapters as drafts to exclude from generation
- Footer System: Consistent footers with story-specific customization
- Dark Mode Toggle: System-aware dark/light theme with localStorage persistence
- RSS Feeds: Automatic RSS generation for site and individual stories
- Webring Support: Cross-promote with fellow authors through RSS-based discovery feeds
- Asset Minification: Build-time minification of HTML, CSS, and JavaScript for faster loading
- Comments System: Integrated Utterances comments with theme switching
- robots.txt Generation: Automatic SEO indexing control
- Sitemap Generation: XML sitemaps for search engine optimization
- Reading Progress Tracking: Track visited and completed chapters with localStorage
- Modular Template Extensions: Novel-specific template overrides for unique styling and branding
- Scheduled Publishing: Future-dated chapters automatically publish when their date arrives
- Story Length Statistics: Display word counts with language-specific units
- Story Publishing Status: Show "ongoing", "complete", or "hiatus" badges
- Story Genre Tags: Categorize stories by theme and genre
- Accessibility Features: ARIA labels, keyboard navigation, and alt text validation
- Manga Features: Supports comic / manga / manhwa too, though could still use some improvement
- AND MORE!!!: There are some additional undocumented features... check the examples!
web-novel-static-generator/
├── .github/
│ └── workflows/
│ └── deploy.yml # GitHub Actions workflow
├── content/
│ └── novel_title/
│ ├── config.yaml # Novel configuration
│ ├── templates/ # Novel-specific template overrides (optional)
│ └── chapters/ # Chapter content files
├── templates/
│ ├── index.html # Front page template
│ ├── toc.html # Table of contents template
│ ├── chapter.html # Chapter page template
│ ├── tags_index.html # Tags index template
│ └── tag_page.html # Individual tag page template
├── static/
│ ├── style.css # Main stylesheet
│ ├── theme-toggle.js # Dark mode toggle functionality
│ └── images/ # Image assets
├── build/ # Generated site (auto-created)
├── site_config.yaml # Site-wide configuration
├── webring.yaml # Webring configuration (optional)
├── generate.py # Main generator script
├── requirements.txt # Python dependencies
└── README.md # This file
Prerequisites:
- Python 3.8 or higher (Download Python)
- Git (optional, for cloning the repository)(use GitHub Desktop if you like GUIs https://desktop.github.com/download/ )
Verify Python is installed:
python --version # Should show Python 3.8 or higher
# On some systems, you may need to use python3 instead
Clone or download this generator and install dependencies:
# Clone the repository (if you have git)
git clone https://github.com/Oekaki-Connect/web-novel-static-generator.git
cd web-novel-static-generator
# Or download the ZIP file and extract it, then navigate to the folder
# Or fork it if you plan on contributing changes
# DO NOT fork if you want a private repo, you can't make forks private on GitHub
# If you want a private repo, download the ZIP, then make a new private repo
# Install Python dependencies
pip install -r requirements.txt
# On some systems, you may need to use pip3 instead
Create a site_config.yaml
file in the root directory for global settings:
site_name: "Your Web Novel Collection"
site_url: "https://your-username.github.io/your-repo-name"
site_description: "A collection of translated web novels and original stories"
# Social media embed settings
social_embeds:
default_image: "https://your-username.github.io/your-repo-name/static/images/site-default-social.jpg"
title_format: "{title} | Your Web Novel Collection"
twitter_handle: "your_twitter_handle"
# SEO settings
seo:
allow_indexing: true
# Footer configuration
footer:
copyright: "© 2025 Your Web Novel Collection"
links:
- text: "Privacy Policy"
url: "/privacy/"
- text: "Contact"
url: "/contact/"
# Comments system (Utterances)
comments:
enabled: true
repo: "your-username/your-comments-repo"
issue_term: "pathname"
label: "utterance-comment"
# RSS feed settings
rss:
enabled: true
max_items: 20
# Webring settings (cross-promotion with fellow authors)
webring:
enabled: true
max_items: 20 # Maximum number of recent chapters to display
sites:
- name: "Friend's Novel Site"
url: "http://www.ocwn.net/"
rss: "http://www.ocwn.net/rss.xml"
description: "A great fantasy series"
# EPUB generation configuration
epub:
generate_enabled: true
# NEW! chapter tags configuration
new_chapter_tags:
enabled: true # Show (NEW!) tags on recently published chapters
threshold_days: 7 # Days to consider a chapter "new"
# Accessibility features configuration
accessibility:
# Enable accessibility features and validation
enabled: true
# Require alt text for all images (warns about missing ones)
enforce_alt_text: true
# Automatically add ARIA labels to navigation elements
auto_aria_labels: true
# Enhance keyboard navigation support
keyboard_navigation: true
# Generate accessibility reports during build
build_reports: true
Create content/your-novel-name/config.yaml
:
title: "Your Awesome Novel"
description: "An epic fantasy adventure"
primary_language: "en"
status: "ongoing" # "ongoing", "complete", or "hiatus"
# Story genre/theme tags
tags: ["fantasy", "adventure", "magic", "prophecy", "hero's journey"]
# Length display configuration
length_display:
# Default unit for story length display on TOC pages
default_unit: "words" # "words" or "characters"
# Language-specific overrides for different languages
# This is useful because different languages have different conventions:
# - Western languages (English, Spanish, French) typically use word count
# - East Asian languages (Japanese, Chinese, Korean) typically use character count
language_units:
en: "words" # English uses words (typical for Western languages)
jp: "characters" # Japanese uses characters (typical for East Asian languages)
# Story arcs and chapters
arcs:
- title: "Arc 1: Beginning"
chapters:
- id: "chapter-1"
title: "Chapter 1: The Start"
- id: "chapter-2"
title: "Chapter 2: The Journey"
# Social media settings for this story
social_embeds:
image: "/static/images/your-novel-social.jpg"
description: "Follow the epic journey in this fantasy adventure"
keywords: ["fantasy", "adventure", "web novel"]
# SEO settings for this story
seo:
allow_indexing: true
meta_description: "Read Your Awesome Novel - an epic fantasy web novel"
# Comments configuration for this story
comments:
enabled: true # Enable comments on TOC and chapters
# Downloads configuration
downloads:
epub_enabled: true # Enable EPUB downloads for this story
include_arcs: true # Generate individual arc downloads
# Custom footer for this story (optional)
footer:
copyright: "© 2025 Your Awesome Novel - Original work by Author Name"
links:
- text: "Support the Author"
url: "https://ko-fi.com/pyramid"
- text: "Source Code"
url: "https://github.com/Oekaki-Connect/web-novel-static-generator"
# NEW! chapter tags override (optional)
new_chapter_tags:
enabled: true # Override site setting for this story
threshold_days: 14 # Custom threshold (2 weeks instead of site default)
Create markdown files in content/your-novel-name/chapters/
with front matter:
---
title: "Chapter 1: The Beginning"
author: "Original Author"
published: "2025-01-15"
tags: ["adventure", "magic", "prophecy"]
translation_notes: "Cultural context about specific terms"
hidden: false # Set to true to hide from navigation (accessible by direct link only)
draft: false # Set to true to exclude from generation (use --include-drafts to include)
password: "secret123" # Optional: password protect this chapter
password_hint: "Available for beta readers and Patreon supporters. Check your email for the password."
comments: true # Enable/disable comments for this chapter
# Social media settings for this chapter
social_embeds:
image: "/static/images/chapter-1-social.jpg"
description: "The hero begins their epic journey"
keywords: ["chapter 1", "beginning", "fantasy"]
# SEO settings for this chapter
seo:
allow_indexing: true
meta_description: "Chapter 1 - The hero's journey begins"
---
# Chapter 1: The Beginning
Your chapter content here...
You have two options for adding images to your novel:
Place images directly in the chapter's source directory and reference them with simple filenames:

Directory Structure:
content/
my-awesome-web-novel/
chapters/
chapter-1.md ← Your chapter file
ancient_scroll.jpg ← Your chapter image
jp/ ← Japanese translations
chapter-1.md
ancient_scroll_jp.jpg ← Japanese version of the image
Benefits:
- Images stay organized with their chapters
- Easy for contributors to manage
- Automatic copying and path resolution during build
- Language-specific images supported
You can also place images in the static/images/
directory for site-wide use:

See the Command-Line Reference section below for all available options.
Basic usage:
python generate.py # Standard build
python generate.py --include-drafts # Include draft chapters
The generated site will be in the build/
directory.
This generator includes automated deployment to GitHub Pages.
Here's how to set it up:
This method keeps your source code (and unpublished chapters) private while publishing only the built site.
Look up how to setup a domain with a GitHub repo if you want to use a domain. We're doing this with ocwn.net!
-
Create two repositories:
- Source repository: Your private repository with the generator code (e.g.,
my-novel-source
) - Publishing repository: Public repository for the built site (e.g.,
my-novel-site
)
- Source repository: Your private repository with the generator code (e.g.,
-
Generate a Personal Access Token:
- Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
- Click "Generate new token (classic)"
- Give it a descriptive name (e.g., "Novel Site Deployment")
- Select scopes:
repo
(Full control of private repositories)workflow
(Update GitHub Action workflows)
- Generate and copy the token (you won't see it again!)
-
Add the token to your source repository:
- Go to your source repository's Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name:
DEPLOY_TOKEN
- Value: Paste your personal access token
- Click "Add secret"
-
Update the deployment workflow:
- Edit
.github/workflows/deploy.yml
in your source repository - Update the repository reference:
- name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: personal_token: ${{ secrets.DEPLOY_TOKEN }} # DO NOT HARD CODE IT HERE! external_repository: your-username/my-novel-site # Your publishing repo publish_branch: main publish_dir: ./build
- Edit
-
Enable GitHub Pages on the publishing repository:
- Go to the publishing repository's Settings → Pages
- Under "Source", select "Deploy from a branch"
- Select "main" branch and "/ (root)" folder
- Save the settings
-
Push to trigger deployment:
git add . git commit -m "Setup deployment" git push origin main
Your site will be built in the source repository and deployed to: https://your-username.github.io/my-novel-site/
If you want to use a custom domain (e.g., www.yournovel.com
) with GitHub Pages:
-
Create a CNAME file:
- Create a file named
CNAME
(no extension) in the root directory of your project (next togenerate.py
) - Add your domain name to the file:
www.yournovel.com
- Create a file named
-
The generator will automatically:
- Copy the CNAME file to the build directory during generation
- Include it in the deployed site for GitHub Pages to recognize
-
Configure your domain:
- Set up DNS records with your domain provider to point to GitHub Pages
- In your GitHub repository, go to Settings → Pages
- Under "Custom domain", enter your domain name
- Enable "Enforce HTTPS" (recommended)
-
Verify the setup:
- After deployment, GitHub Pages will automatically use your custom domain
- Your site will be accessible at both the GitHub Pages URL and your custom domain
Note: The CNAME file must be in the root directory of your source repository and will be automatically included in every build.
- 403 Forbidden errors: Check that your DEPLOY_TOKEN has the correct permissions
- 404 Not Found: Ensure GitHub Pages is enabled and using the correct branch
- Build failures: Check the Actions tab for error logs
- Token issues: Regenerate the token if it expired or wasn't copied correctly
The generator supports various command-line options to customize the build process:
Standard site generation
- Builds the complete site with all features
- Excludes draft chapters (use
--include-drafts
to include them) - Generates EPUB downloads
- Updates table of contents with download links
Include draft chapters
- Same as standard build but includes chapters marked with
draft: true
- Useful for previewing work-in-progress content
- Draft chapters appear in navigation and downloads
Validate configuration and content
- Checks all config files for errors and missing required fields
- Validates that referenced chapter files exist
- Parses chapter front matter for syntax errors
- Reports warnings for missing optional fields
- Exits without building if validation fails
Example output:
Validating configuration files and content...
[OK] Site config loaded successfully
[OK] Novel config loaded: my-awesome-web-novel
==================================================
VALIDATION RESULTS
==================================================
[SUCCESS] Validation passed!
[PASSED] All configs and content are valid
Clean build directory
- Deletes the entire
build/
directory before generating - Ensures a completely fresh build without leftover files
- Useful when files have been deleted or renamed
- Can be combined with other options
Skip EPUB generation
- Generates the website but skips creating EPUB files
- Significantly faster builds during development
- Useful when only testing website functionality
- Table of contents pages will not show download links
Generate statistics report
- Creates a detailed
stats_report.md
file in the project root - Shows comprehensive statistics about novels, chapters, and content
- Includes word counts, translation progress, and tag usage
- Useful for tracking project growth and completion
Report includes:
- Total novels, chapters, words, and characters
- Per-novel breakdowns with arc statistics
- Translation progress percentages
- Popular tags and usage counts
- Build file counts and language coverage
- Template override usage and statistics
Check for broken links
- Validates all internal links, images, and resources
- Creates
broken_links_report.md
if issues are found - Checks social media preview images (og:image, twitter:image)
- Verifies CSS and JavaScript file references
- Should be run before deployment
Check accessibility compliance
- Validates all images have alt text attributes
- Creates
images_missing_alt_text_report.md
if issues are found - Skips report generation in GitHub Actions (detected automatically)
- Part of comprehensive accessibility feature set
- Helps ensure content is accessible to screen readers
Local development server with live reload
- Starts a local web server (default port 8000)
- Automatically rebuilds when files change
- Refreshes browser pages via websocket connection
- Injects live reload script into HTML pages
- Skips EPUB generation and image optimization for faster rebuilds
- Watches
content/
,templates/
,static/
, andpages/
directories
Usage examples:
python generate.py --serve # Start on port 8000
python generate.py --serve 3000 # Start on custom port
python generate.py --serve --include-drafts # Include draft chapters
Features:
- Live reload: Browser automatically refreshes when files change
- WebSocket connection: Fast communication between server and browser
- Smart rebuilding: Only rebuilds when relevant files are modified
- Development optimized: Skips slow operations for faster iteration
Watch and rebuild without server
- Monitors content files for changes
- Automatically rebuilds when changes detected
- No web server (use your own server setup)
- Useful with external development servers or static hosts
Usage examples:
python generate.py --watch # Basic watching
python generate.py --watch --include-drafts # Include drafts
Use cases:
- External server setups (Apache, Nginx, etc.)
- Integration with other development tools
- Automated deployment workflows
- Continuous integration environments
Convert images to WebP format
- Converts JPEG, PNG, BMP, and TIFF images to WebP format
- Preserves original files alongside optimized versions
- Can be enabled permanently in site config or used as one-time flag
- Configurable compression quality (0-100, default: 100 = no compression)
- Shows compression statistics and space savings
- Significantly reduces site size and loading times
Configuration in site_config.yaml
:
image_optimization:
enabled: true # Enable automatic optimization
quality: 85 # WebP quality (0-100)
Example output:
Optimizing images to WebP (quality: 85%)...
Converted 2 images to WebP
Original size: 298.9 KB
WebP size: 22.9 KB
Space saved: 92.4%
Enable (NEW!) tags for recently published chapters
- Shows a prominent (NEW!) indicator next to recently published chapters on table of contents
- Configurable threshold for how many days to consider chapters "new"
- Can be disabled globally or per-story for different content strategies
Configuration in site_config.yaml
:
new_chapter_tags:
enabled: true # Enable/disable (NEW!) tags globally
threshold_days: 7 # Days to show NEW! tag (default: 7)
Per-story override in content/story/config.yaml
:
new_chapter_tags:
enabled: true # Override global setting
threshold_days: 14 # Custom threshold (e.g., 2 weeks for this story)
Example display:
Chapter 5: The Climax (NEW!) 2025-07-22
- Published 1 day agoChapter 4: Building Tension 2025-07-15
- Published 8 days ago (no tag with 7-day threshold)
Use Cases:
- Serial releases: Highlight the latest chapters for returning readers
- Story updates: Draw attention to recently updated translations
- Multi-story sites: Different NEW! thresholds per story genre/audience
- Seasonal content: Longer thresholds for infrequently updated stories
- Clean TOCs: Disable entirely for completed stories or archives
Commands can be combined for complex workflows:
# Clean build with validation and stats
python generate.py --clean --validate --stats
# Fast development build without EPUBs
python generate.py --clean --no-epub --include-drafts
# Production build with link checking
python generate.py --clean --check-links
# Complete development workflow with live reload
python generate.py --clean --serve --include-drafts
# Watch-only mode for external servers
python generate.py --clean --watch --include-drafts
Get help and see all available options:
python generate.py --help
- Push this generator to a GitHub repository
- The included GitHub Actions workflow will automatically:
- Build the site when you push changes
- Deploy to GitHub Pages
- Enable GitHub Pages in your repository settings
- Set the source to "GitHub Actions"
- Push changes to trigger deployment
Edit static/style.css
to customize the appearance:
- Colors and fonts
- Layout and spacing
- Responsive breakpoints
Modify the Jinja2 templates in the templates/
directory:
index.html
: Front page layouttoc.html
: Table of contents structurechapter.html
: Chapter page layout
Create novel-specific template overrides for unique styling and branding:
Directory Structure:
content/
your-novel-name/
templates/
chapter.html ← Custom chapter template for this novel
toc.html ← Custom table of contents (optional)
chapters/
chapter-1.md ← Chapter content
config.yaml ← Novel configuration
Features:
- Novel-specific branding: Each novel can have its own unique look and feel
- Template inheritance: Falls back to default templates seamlessly
- Gradual customization: Override only the templates you want to customize
- Multi-novel support: Different novels can have completely different designs
- Statistics tracking: Monitor template override usage in stats reports
Example Custom Template:
<!-- Custom styling in content/my-novel/templates/chapter.html -->
<style>
.custom-novel-header {
background: linear-gradient(135deg, #4a5568 0%, #2d3748 100%);
color: white;
padding: 20px;
text-align: center;
border-radius: 8px;
}
</style>
<div class="custom-novel-header">
<h1>{{ novel_title }}</h1>
<div>Custom Story Template</div>
</div>
<!-- All standard template functionality preserved -->
Template Variables Available:
novel_slug
: Novel identifiernovel_title
: Novel display titlechapter_id
: Current chapter IDchapter_title
: Current chapter titlearcs
: Complete story arc structurelanguage
: Current language codeavailable_languages
: Available language options- All other standard template variables
Benefits:
- Create unique themes for different story genres
- Maintain consistent branding across novel chapters
- Easy to implement and maintain
- Full access to all template functionality
- Tracked in statistics reports
Chapters are displayed in the order they appear in the chapters
array within each arc. You can manually sort them by reordering the array:
"chapters": [
{"id": "prologue", "title": "Prologue"},
{"id": "chapter-1", "title": "Chapter 1"},
{"id": "interlude-1", "title": "Interlude 1"},
{"id": "chapter-2", "title": "Chapter 2"},
{"id": "epilogue", "title": "Epilogue"},
]
If you use password protection, you should not have your main repo public. This static generator wants you to have two different GitHub repos one for the source code and your project files, and another which you publish to. Although you're not required to publish to a GitHub repo. It's a static site generator, you can upload the static files to any server.
Secure premium or beta content with client-side encryption:
---
title: "Premium Chapter: Early Access"
password: "your-secret-password"
password_hint: "Available for beta readers and Patreon supporters. Check your email for the password."
---
Your premium content here...
Features:
- Client-side XOR encryption with SHA256 password hashing
- Custom password hints for users
- Encrypted content is never sent to unauthorized users
- Works without server-side processing
Hidden Chapters
Create chapters accessible only by direct link:
---
title: "Secret Chapter"
hidden: true
---
This chapter won't appear in navigation but can be accessed directly.
Use Cases:
- Easter eggs and bonus content
- Beta reader exclusive chapters
- Special event content
- Author notes or behind-the-scenes content
Note: If you are hosting on GitHub on a public repo anyone can discover hidden pages easily.
Mark work-in-progress chapters as drafts to exclude them from generation:
---
title: "Chapter 10: Work in Progress"
draft: true
published: "2025-02-01"
---
This chapter is still being written and won't be included in the generated site.
Features:
- Completely excluded from generation by default
- Not included in TOC, EPUB downloads, RSS feeds, or sitemaps
- Use
--include-drafts
flag to include them:python generate.py --include-drafts
- Console output shows skipped drafts: "Skipping draft chapter: chapter-10 - Chapter 10: Work in Progress"
- Perfect for work-in-progress content or scheduled releases
Use Cases:
- Work-in-progress chapters
- Scheduled content releases (see Scheduled Publishing)
- Beta testing new chapters
- Collaborative editing before publication
Publish chapters automatically when their scheduled date arrives:
---
title: "Chapter 10: The Big Reveal"
published: "2025-08-01"
tags: ["plot-twist", "reveal", "climax"]
---
This chapter will automatically appear on the site on August 1st, 2025.
How It Works:
- Chapters with future
published
dates are excluded from normal builds - Use
--include-scheduled
flag to preview:python generate.py --include-scheduled
- GitHub Actions workflows automatically rebuild when content becomes available
- Supports multiple date formats (ISO, RFC, plain dates)
- Time zone aware - uses UTC if no timezone specified
Date Format Examples:
published: "2025-08-01" # Simple date (midnight UTC)
published: "2025-08-01 14:30:00" # Date and time
published: "2025-08-01T14:30:00" # ISO format
published: "2025-08-01T14:30:00Z" # UTC timezone
published: "2025-08-01T14:30:00-05:00" # With timezone offset
GitHub Actions Automation:
You can remove these files if you only intend to update when you push changes / you do not want future scheduled releases.
-
Daily Scheduled Rebuild (
.github/workflows/scheduled-rebuild.yml
):- Runs daily at midnight UTC
- Rebuilds entire site for general maintenance and newly available content
- Provides reliable daily updates for future features
- Can be disabled if daily rebuilds aren't needed
-
Smart Hourly Rebuild (
.github/workflows/smart-scheduled-rebuild.yml
):- Runs every hour from 1 AM to 11 PM UTC (skips midnight)
- Checks if any scheduled content is ready for publishing
- Only rebuilds when chapters have actually become available
- More efficient for sites with frequent scheduled releases
Workflow Schedule:
# Daily rebuild at midnight
schedule:
- cron: '0 0 * * *' # Daily at midnight UTC
# Smart hourly rebuild (skips midnight to avoid conflicts)
schedule:
- cron: '0 1-23 * * *' # Every hour from 1 AM to 11 PM UTC
# Custom schedule examples:
- cron: '0 */12 * * *' # Every 12 hours
- cron: '0 9 * * MON' # Weekly on Monday at 9 AM
- cron: '0 6,18 * * *' # Twice daily at 6 AM and 6 PM
How the Dual System Works:
- Midnight (00:00): Daily rebuild runs for maintenance and batch updates
- 1 AM - 11 PM: Smart rebuild checks hourly for new scheduled content
- No conflicts: Workflows are designed to never overlap
- Flexibility: Either workflow can be disabled independently
Use Cases:
- Serial releases: Schedule chapters weeks in advance
- Timed reveals: Coordinate story events with real-world dates
- Buffer management: Upload multiple chapters but release gradually
- Event tie-ins: Release special chapters on holidays or anniversaries
- Time zone releases: Schedule for specific regions
Chapter Publishing Logic:
- No
published
date: Always included in builds (traditional behavior) - Past/current
published
date: Always included in builds - Future
published
date: Excluded until the date arrives (unless--include-scheduled
is used)
Console Output:
⏳ Skipping future chapter: chapter-10 - Chapter 10: The Big Reveal (publishes: 2025-08-01)
⏳ Skipping future chapter: chapter-11 - Chapter 11: Aftermath (publishes: 2025-08-08)
Best Practices:
- Chapters without dates work like traditional static content (always published)
- Set publish dates in UTC to avoid timezone confusion
- Test scheduled content with
--include-scheduled
before the release date - Monitor GitHub Actions runs to ensure successful rebuilds
- Consider using smart rebuilds for efficiency with many scheduled chapters
Integrated Utterances comments that automatically sync with your dark mode:
Site Configuration:
comments:
enabled: true
repo: "your-username/your-comments-repo"
issue_term: "pathname"
label: "utterance-comment"
Chapter Control:
---
comments: false # Disable comments for this chapter
---
Features:
- GitHub-based comment system
- Automatic theme switching (light/dark)
- Story-level and chapter-level control
- No comments on password-protected content
System-aware dark/light theme with user preference persistence:
Features:
- Detects system theme preference automatically
- Footer text toggle: "[ light mode | dark mode ]"
- Active mode shown in bold
- Saves preference in localStorage
- Switches Utterances comment themes automatically
- Optimized dark mode styling for all UI elements
Automatic RSS feed generation for content syndication:
Generated Files:
/rss.xml
- Site-wide feed with latest chapters from all stories/story-name/rss.xml
- Story-specific feeds
Features:
- Configurable maximum items per feed
- Proper RSS 2.0 format with metadata
- Automatic chapter descriptions and links
- Story-specific feeds for targeted subscriptions
Build community and cross-promote with fellow authors through RSS-based discovery feeds:
What is a Webring? A webring is a collection of websites linked together for mutual promotion and discovery. In web novel communities, webrings help authors support each other by featuring recent chapter releases from trusted authors on their front pages.
You can also set this only on your own RSS to show your most recent updates!
How it Works:
- Authors maintain a
webring.yaml
file listing RSS feeds of other authors they recommend - At build time, the generator fetches recent chapters from these RSS feeds
- A clean "Recent Updates from the Webring" section appears on your front page
- Readers discover new content from authors you trust and recommend
Configuration (webring.yaml
):
webring:
enabled: true
max_items: 20 # Number of recent items to display
cache_duration: 3600 # Cache feeds for 1 hour
sites:
- name: "Fantasy Author A"
url: "http://www.ocwn.net/novel/"
rss: "http://www.ocwn.net/novel/rss.xml"
description: "Epic fantasy adventure series"
- name: "Sci-Fi Author B"
url: "http://www.ocwn.net/"
rss: "http://www.ocwn.net/rss.xml"
description: "Space opera with great characters"
You can see an example of a site RSS here: https://oekaki-connect.github.io/web-novel/rss.xml
And a story RSS here: https://oekaki-connect.github.io/web-novel/my-awesome-web-novel/rss.xml
If you want to promote an entire site of someone else you can, otherwise you can promote a specific story.
# Display customization
display:
title: "Recent Updates from the Webring"
subtitle: "Check out recent chapters from fellow authors we recommend"
show_descriptions: true
show_dates: true
date_format: "%B %d, %Y"
Features:
- Build-time fetching: RSS feeds are fetched during site generation for fast loading
- Torrent tracker inspired design: Clean, information-dense layout showing [SITE] Chapter Title - Date
- Responsive layout: Works perfectly on mobile and desktop
- Failure resilient: If a feed is unavailable, other feeds still work
- Automatic sorting: Recent chapters from all sites sorted by publication date
- Trust-based: You control which authors appear on your site
Why Webrings Are Cool:
- Community building: Support indie authors and translators
- Reader discovery: Help your readers find great content from authors you trust
- Reciprocal promotion: Authors can feature each other's work
- Quality curation: Only recommend authors whose work you genuinely enjoy
- Decentralized: No central authority - each author controls their own webring
- SEO benefits: External links and fresh content help with search rankings
- Nostalgic: Brings back the community spirit of the early web
Setting Up Your Webring:
- Create
webring.yaml
in your project root - Add RSS feeds of authors you want to promote
- Rebuild your site - the webring section appears automatically
- Reach out to fellow authors to join their webrings too!
Best Practices:
- Only include authors whose work you've read and genuinely recommend
- Keep descriptions brief and appealing
- Update your webring periodically as you discover new authors
- Consider genre compatibility with your audience
- Reciprocate when other authors add you to their webrings
Control how novels appear on your site's front page with flexible sorting options:
Configuration in site_config.yaml
:
front_page:
# Sort novels by most recent chapter update
sort_by_recent_update: true
# Manual sort order for featured novels (by slug)
featured_order:
- tower-dungeon # Always appears first
- my-featured-novel # Always appears second
Sorting Behavior:
- Featured novels appear first in the exact order specified in
featured_order
- Non-featured novels follow after, sorted by:
- Most recent chapter update (if
sort_by_recent_update: true
) - Original order (if
sort_by_recent_update: false
)
- Most recent chapter update (if
Use Cases:
- Feature new releases: Pin a new novel to the top during launch period
- Promote completed stories: Feature finished novels to attract new readers
- Activity-based discovery: Let active stories naturally rise to the top
- Curated experience: Manually control the exact order for optimal presentation
Example Configurations:
Activity-focused site (default):
front_page:
sort_by_recent_update: true
featured_order: [] # No pinned novels
Curated recommendations:
front_page:
sort_by_recent_update: false
featured_order:
- editors-pick-1
- editors-pick-2
- new-release
Automatic SEO optimization files:
robots.txt:
- Controls search engine indexing
- Respects
allow_indexing
settings in config files - Links to sitemap for better discovery
sitemap.xml:
- Comprehensive XML sitemap
- All public pages included
- Proper priority and change frequency settings
- Supports search engine optimization
Consistent footers with story-specific customization:
Site-level Footer:
footer:
copyright: "© 2025 Your Website"
links:
- text: "Privacy Policy"
url: "/privacy/"
Story-level Override:
footer:
copyright: "© 2025 Story Title - Original work by Author"
links:
- text: "Support the Author"
url: "https://ko-fi.com/pyramid"
Add metadata to your chapters using YAML front matter:
---
title: "Chapter 1: The Beginning"
author: "Original Author"
translator: "Translator Name"
published: "2025-01-15"
tags: ["adventure", "magic", "prophecy"]
translation_notes: "Cultural context about specific terms used"
translator_commentary: |
This chapter establishes the fantasy setting beautifully. I chose to
translate certain terms to maintain the magical atmosphere while
keeping them accessible to readers.
---
# Chapter 1: The Beginning
Your chapter content here...
Supported Fields:
title
: Override chapter titleauthor
: Original author nametranslator
: Translator credit (for translations)published
: Publication datetags
: Array of tags for categorizationtranslation_notes
: Cultural/linguistic contexttranslator_commentary
: Extended commentary displayed at chapter endhidden
: Hide chapter from navigation (accessible by direct link only)draft
: Mark chapter as draft (excluded from generation unless --include-drafts is used)password
: Password protect the chapter contentpassword_hint
: Hint text shown to users for password-protected contentcomments
: Enable/disable comments for this specific chaptersocial_embeds
: Social media sharing configurationimage
: Custom social media imagedescription
: Social media descriptionkeywords
: Keywords for SEO and social sharing
seo
: SEO configurationallow_indexing
: Control search engine indexingmeta_description
: Custom meta description
Tags automatically create browsable indexes:
- All Tags Page:
/novel/language/tags/
- Lists all tags with chapter counts - Tag Pages:
/novel/language/tags/tag-name/
- Shows all chapters with that tag - Clickable Tags: All tags in chapter metadata are clickable links
Perfect for organizing content by theme, genre, or story elements.
URL Structure:
- English:
/my-awesome-web-novel/en/chapter-1/
- Japanese:
/my-awesome-web-novel/jp/chapter-1/
- Tags:
/my-awesome-web-novel/jp/tags/予言/
(supports Unicode)
Translation Workflow:
- Create language subdirectory:
chapters/jp/
- Add translated chapters with front matter
- Language switcher appears automatically
- Missing translations show helpful notices
The generator automatically creates rich social media previews:
Open Graph Tags (Facebook, LinkedIn, Discord):
og:title
,og:description
,og:image
og:url
,og:type
,og:site_name
- Article-specific tags for chapters
Twitter Cards:
twitter:card
,twitter:title
,twitter:description
twitter:image
,twitter:site
,twitter:creator
Hierarchical Configuration:
- Site-wide defaults in
site_config.yaml
- Story-level settings in
content/novel/config.yaml
- Chapter-level overrides in front matter
- Chapter settings override story settings, story settings override site defaults
Meta Tags:
- Configurable meta descriptions and keywords
- Robots meta tag for indexing control
- Canonical URLs for all pages
Structured Data:
- Article metadata for chapters
- Publication dates and author information
- Tag-based content organization
The generator automatically detects and processes multiple novels:
- Create subdirectories in
content/
for each novel - Add a
config.yaml
file in each novel directory - The front page will list all available novels
Display the current status of your story on the table of contents:
# In your story config.yaml
status: "ongoing" # "ongoing", "complete", or "hiatus"
Features:
- Shows "Ongoing", "Complete", or "Hiatus" badge on TOC page
- Color-coded badges (blue for ongoing, green for complete, orange for hiatus)
- Automatic dark mode styling
Display total story length with culturally appropriate units:
# In your story config.yaml
length_display:
default_unit: "words" # Default for all languages
language_units:
en: "words" # English shows word count
jp: "characters" # Japanese shows character count
zh: "characters" # Chinese shows character count
es: "words" # Spanish shows word count
Features:
- Automatically calculates total length from all visible chapters
- Excludes hidden and password-protected content
- Language-specific display (words for Western languages, characters for East Asian)
- Formatted with comma separators (e.g., "12,345 words")
Add genre and theme tags to your stories:
# In your story config.yaml
tags: ["fantasy", "adventure", "magic", "prophecy", "hero's journey"]
Features:
- Non-clickable genre tags displayed on TOC page
- Clean tag styling with dark mode support
- Helps readers understand story themes at a glance
Comprehensive accessibility support for improved usability and compliance:
ARIA Labels:
- Semantic navigation labeling for screen readers
- Breadcrumb navigation:
aria-label="Breadcrumb"
- Chapter navigation:
aria-label="Chapter navigation"
- Language switchers:
role="group" aria-label="Language selection"
- Reading settings:
role="group" aria-label="Reading settings"
- Footer links:
aria-label="Footer links"
Keyboard Navigation:
- Navigation shortcuts:
←/h
(previous chapter),→/l
(next chapter),t
(table of contents) - Scrolling shortcuts:
↑/k
(scroll up),↓/j
(scroll down),Home/g
(go to top),End/G
(go to bottom) - Reading controls:
+/=
(increase text size),-
(decrease text size),0
(reset settings) - Help system:
?
(show keyboard shortcuts modal),Esc
(close modals) - Smart detection to avoid conflicts with form inputs
- Comprehensive help modal with organized shortcut display
Alt Text Validation:
- Automated checking of all generated HTML files
- Detects images missing alt attributes using BeautifulSoup4
- Generates
images_missing_alt_text_report.md
for local builds - Skips report generation in GitHub Actions (detected automatically)
- Configurable enforcement levels
Configuration:
# In site_config.yaml
accessibility:
enabled: true # Enable all accessibility features
enforce_alt_text: true # Validate alt text on images
auto_aria_labels: true # Add ARIA labels to navigation
keyboard_navigation: true # Enable keyboard shortcuts
build_reports: true # Generate accessibility reports
Features:
- Works across both main templates and story-specific template overrides
- Respects site theme preferences (light/dark mode support)
- Mobile-responsive keyboard help modal
- No conflicts with existing JavaScript functionality
- Comprehensive accessibility reporting
Usage:
# Check accessibility compliance
python generate.py --check-accessibility
# Standard build includes accessibility checks if enabled
python generate.py
Generate high-quality EPUB files for offline reading:
Features:
- Full story EPUB downloads
- Individual arc EPUB downloads
- Multi-language support (separate EPUBs per language)
- Embedded images with proper centering
- Cover art integration for stories and arcs
- Clean chapter pagination and formatting
- Compatible with all major e-readers
Configuration:
# In site_config.yaml
epub:
generate_enabled: true
# In story config.yaml
downloads:
epub_enabled: true
include_arcs: true
Generated Files:
/static/epub/story-name.epub
- Full story download/static/epub/story-name_jp.epub
- Japanese version (if available)/static/epub/story-name-arc-1-title.epub
- Individual arc/volume downloads
Chapter Dropdown: Quick navigation dropdown on chapter pages
- Organized by story arcs
- Shows current chapter as selected
- Excludes hidden chapters
- JavaScript-powered navigation
Breadcrumb Navigation: Clear page hierarchy navigation
- Chapter pages: Home > Story > Chapter
- TOC pages: Home > Story
- Mobile-friendly responsive design
Publication Dates: Chapter publication dates displayed on TOC
- Shows publication date next to each chapter title
- Desktop: side-by-side layout
- Mobile: stacked layout
- Only shows if
published
date is set in chapter front matter
Automatically track reader progress with localStorage:
Features:
- Mark chapters as visited when opened
- Mark chapters as completed when scrolled to bottom
- Visual indicators on table of contents (○ for visited, ✓ for completed)
- "Continue Reading" section showing last completed chapter
- Persists across browser sessions
- Per-story tracking (multiple novels supported)
- Note: Reading is only tracked per browser, not on any server
URL Structure with Breadcrumbs:
Home (/)
└── Story (/story/en/toc/)
└── Chapter (/story/en/chapter-1/)
Chapter Page Features:
- Jump to Chapter dropdown for quick navigation
- Previous/Next chapter links
- Table of Contents link
- Breadcrumb navigation showing current location
jinja2
: Template engine for HTML generationmarkdown
: Markdown to HTML conversionpyyaml
: YAML configuration file parsingebooklib
: EPUB generation and manipulationPillow
: Image processing for WebP optimization (optional)watchdog
: File system monitoring for live reload (optional)websockets
: WebSocket server for live reload (optional)
For a complete list of available commands and options:
python generate.py --help
Use --validate
to check for configuration errors before building:
python generate.py --validate
- Ensure images are in the
static/images/
directory - Check that image paths in content use
static/images/filename.jpg
- Verify images are copied to the build directory
- Check that
requirements.txt
includes all dependencies - Ensure the workflow has proper permissions for GitHub Pages
- Verify the repository has GitHub Pages enabled
- Clear browser cache after CSS changes
- Check that
static/style.css
is being copied to the build directory - Verify CSS paths in templates are correct
Feel free to extend this generator with additional features:
- Search functionality (using offline database)
- Chapter bookmarking (using localStorage)
- Improve the manga reader (better page transitions, double vertical scroll)
- Break the current monolith generate.py into sub dependencies
- Maybe convert the webring feature into something dynamic done when someone visits front pages
- Something you think it needs! If you make pull requests please know what you're doing
- If you're a Firefox user and a dev, please fix any CSS that's Firefox specific
- Full screen single image mode on mobile 2:3 jumps around in a weird way when changing images
- Need to make the entire site text easier to localize, if the site lang is on a certain lang it should default to chapters of that lang if available