images | ||
items | ||
output | ||
static | ||
theme/default | ||
.gitignore | ||
config.py | ||
Dockerfile | ||
LICENSE | ||
picopaper.py | ||
README.md | ||
requirements.txt |
picopaper
A minimal static site generator for blogs built with Python 3 and Jinja2
- Status: alpha - expect many changes
- Goals: keeping it simple and easy to understand
- Demo: picopaper.com
Show cases:
Features
Available:
- Simple use, easy to understand and modify
- config file for settings
- Themes
- Long- and short form content
- Pages
- Static files
- separate feeds (used for categories, tagging, etc)
/feed/{tag}
- exclusion of feeds from main feed (drafts or system notes)
- HTML anchors for headers
Ideas:
- RSS
- Dark mode
- logo
- custom error pages (404, etc)
Not planned:
Usage
Creating a new page or article
Put markdown file into items
dir. Important naming convention:
2025-10-03_long_building-a-static-site-generator.md
2025-10-05_short_quick-update_draft.md
Format: YYYY-MM-DD_type_slug[_feed].md
2025-10-03
- date of the article_long_
- type of content:long
,short
, orpage
building-a-static-site-generator
- slug/path for the URL_draft
(optional) - feed tag for categorization
The first #
header is the title of the article - no frontmatter needed.
Types of content:
long
- only title with link to articles will be displayed in feedshort
- title and all content will be displayedpage
- won't be displayed in feed at all
Feeds
Posts can be tagged with an optional feed category (e.g., _python
, _webdev
). Posts with feed tags:
- Appear on the main page (unless excluded in config)
- Have their own feed page at
/feed/{tag}/
Configuration in config.py
:
# Exclude specific feeds from main page (they'll still have /feed/name/ pages)
EXCLUDE_FEEDS_FROM_MAIN = ['draft', 'private']
This is useful for draft posts or topic-specific content you want separated from the main feed.
Installation
- Create and activate virtual environment:
python3 -m venv venv
source venv/bin/activate # On Linux/Mac
# or: venv\Scripts\activate # On Windows
- Install dependencies:
pip install -r requirements.txt
- Configure your blog in
config.py
:
BLOG_TITLE = "My Blog"
BLOG_DESCRIPTION = "A simple blog built with picopaper"
THEME = "default"
- Generate the site:
venv/bin/python picopaper.py
- Serve locally for testing:
cd output
python3 -m http.server 8000
Visit http://localhost:8000
Docker
Build and run with Docker:
# Build the image
docker build -t picopaper .
# Run the container
docker run --rm -v $(pwd):/app picopaper
For Podman (recommended for rootless):
# Build the image
podman build -t picopaper .
# Run with user namespace mapping
podman run --rm --userns=keep-id -v $(pwd):/app picopaper
The generated site will be available in the output/
directory.
Directory Structure
items/
- Markdown content filestheme/
- Theme directory containing templates and assetsdefault/
- Default themetemplates/
- Jinja2 templatesassets/
- CSS and static assets
images/
- Image files (copied to output)static/
- Static files copied as-is (GPG keys, .well-known, etc.)output/
- Generated site (do not edit)config.py
- Blog configuration
Themes
Themes are organized in the theme/
directory. Each theme has its own subdirectory containing:
templates/
- Jinja2 template filesassets/
- CSS, JavaScript, and other static assets
To switch themes, change the THEME
setting in config.py
Security
For security concerns or reports, please contact via hello a t uphillsecurity d o t com
gpg.
License
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
- ✅ Commercial use
- ✅ Modification
- ✅ Distribution
- ✅ Patent use
- ✅ Private use
- ✅ Limitations
- ❌Trademark use
- ❌Liability
- ❌Warranty