A small static site generator for blogs, written in Python.
TOML config → Markdown posts (Markdown-metadata frontmatter) → Jinja2 templates → static output directory → upload.
Kind of a love-letter to neocities.org.
Most static site generators (Hugo, Zola, Jekyll) are general-purpose
templating systems that happen to be good at blogs. neostatic does the
opposite: it only does one shape of site (a blog, plus static passthrough
content), and stays small enough to read end to end in one sitting.
A few things that follow from that:
neostatic
renders to a local site/ directory and then pushes it straight to
Neocities in the same invocation (--offline skips the upload step).
Most generators render only and leave publishing to a separate script..git or the site's own neostatic.toml, neostatic treats
that as a sign it's pointed at the wrong place and stops rather than
deleting it.meta extension rather
than a second data format embedded in the post.python -m neostatic <site-dir> [-v] [--offline] [--dry-run]
A site directory looks like:
site-dir/
neostatic.toml
static/ # copied through as-is (allow-listed extensions)
templates/
index.html
blogpost.html # default post template; override per-post
posts/
2024-01-01-hello.md
neostatic.toml)[blog]
[blog.paths]
static = "static"
templates = "templates"
posts = "posts"
site = "site"
[blog.meta]
title = "example"
strapline = "a blog"
[neocities]
proxy = "socks5://127.0.0.1:9150" # optional, e.g. for publishing over Tor
user = "..."
password = "path/to/password-file" # contents read at load time, not inline
api_key = "path/to/api-key-file" # preferred over user/password if present
[blog.paths] and [neocities] are both optional; paths default to the
names shown above, and Neocities upload just isn't available without that
section. If api_key isn't set yet but a path is given, neostatic will
fetch a key on first run (using user/password) and write it there.
Markdown-extension frontmatter, no delimiters — a block of key: value
lines followed by a blank line:
title: Hello
date: 2024-01-01T12:00:00+00:00
published: true
summary: An optional one-line summary.
slug: hello
template: blogpost
Body in Markdown.
Only title and date are required. published defaults to false;
slug defaults to a slugified title; template defaults to
blogpost. Only published: true posts get a generated page and appear
in the index; everything else is loaded but skipped at render time.
1 commits
Python
99.2%
A small static site generator for blogs, written in Python.
TOML config → Markdown posts (Markdown-metadata frontmatter) → Jinja2 templates → static output directory → upload.
Kind of a love-letter to neocities.org.
Most static site generators (Hugo, Zola, Jekyll) are general-purpose
templating systems that happen to be good at blogs. neostatic does the
opposite: it only does one shape of site (a blog, plus static passthrough
content), and stays small enough to read end to end in one sitting.
A few things that follow from that:
neostatic
renders to a local site/ directory and then pushes it straight to
Neocities in the same invocation (--offline skips the upload step).
Most generators render only and leave publishing to a separate script..git or the site's own neostatic.toml, neostatic treats
that as a sign it's pointed at the wrong place and stops rather than
deleting it.meta extension rather
than a second data format embedded in the post.python -m neostatic <site-dir> [-v] [--offline] [--dry-run]
A site directory looks like:
site-dir/
neostatic.toml
static/ # copied through as-is (allow-listed extensions)
templates/
index.html
blogpost.html # default post template; override per-post
posts/
2024-01-01-hello.md
neostatic.toml)[blog]
[blog.paths]
static = "static"
templates = "templates"
posts = "posts"
site = "site"
[blog.meta]
title = "example"
strapline = "a blog"
[neocities]
proxy = "socks5://127.0.0.1:9150" # optional, e.g. for publishing over Tor
user = "..."
password = "path/to/password-file" # contents read at load time, not inline
api_key = "path/to/api-key-file" # preferred over user/password if present
[blog.paths] and [neocities] are both optional; paths default to the
names shown above, and Neocities upload just isn't available without that
section. If api_key isn't set yet but a path is given, neostatic will
fetch a key on first run (using user/password) and write it there.
Markdown-extension frontmatter, no delimiters — a block of key: value
lines followed by a blank line:
title: Hello
date: 2024-01-01T12:00:00+00:00
published: true
summary: An optional one-line summary.
slug: hello
template: blogpost
Body in Markdown.
Only title and date are required. published defaults to false;
slug defaults to a slugified title; template defaults to
blogpost. Only published: true posts get a generated page and appear
in the index; everything else is loaded but skipped at render time.
1 commits
Python
99.2%