Statac

Start

Starting a site

statac new makes a whole working site from four questions, and later turns on sharing cards or brings the starter’s files up to date.

Make a site

statac new my-site
A new site in `my-site`.
Enter takes the answer in brackets.

What is the site called?
  [My Site] > 

What will its address be?
  Enter for none yet.
  > 

What language is it written in?
  For more than one, the main one first, as `en, fr`.
  [en-GB] > 

How should dates look?
  1  31 December 2025
  2  December 31, 2025
  3  2025-12-31
  Or type an example of your own.
  [1] > 

Enter takes the answer in brackets, and --yes takes them all. With no terminal, as from a script, statac new reads its answers as lines.

Given Statac
A folder that isn’t there yet Makes it, and the site in it.
An empty folder Makes the site in it.
No folder Makes the site in the folder it is run in, which must be empty.

Where anything stops it part way, such as a full disk, it leaves the folder as it found it.

What does it ask?

Question Sets Enter takes
What is the site called? title The folder’s name read as words: my-site is My Site.
What will its address be? url, starting https:// or http://, as https://example.org Nothing, until you know it.
What language is it written in? language, a code such as en, en-GB or fr. For several, the main one first: en, fr. The computer’s own, from LC_ALL, LC_MESSAGES or LANG, or else en.
How should dates look? date_format: the language’s own look, the month first where the site is in English, the year first, or an example of your own. Three shorter dates follow from it. 1, the main language’s own look.

Change any answer later in statac.yaml.

With no terminal, statac new reads each line on standard input as the answer to the next question:

printf 'Site 1\nhttps://example.org\n' | statac new my-site

An empty line takes the answer in brackets, as does each question left when the lines run out: here the language and the dates.

Without an address, feeds, the sitemap and robots.txt wait for one: no site address.

The date choices are written in the site’s main language, as 31. Dezember 2025 in German. An example of your own is read as how dates look describes. A language Statac has no words for is offered the year first alone: see languages.

What does it write?

statac new --yes my-site
Made a new site in `my-site`: 83 files.
Times are in Europe/London, as this machine is set.

statac.yaml:
  title: My Site
  language: en-GB
  timezone: Europe/London
  date_format: 31 December 2025
  date_short: 31 Dec 2025
  date_day: 31 Dec
  date_stamp: 31 Dec 2025, 15:04
  feed_key: 27e0d434-c88d-87dd-bd24-4a6ec42e48e6

Next: `cd my-site`, then `statac serve`.

timezone is the computer’s own. feed_key is made fresh for each site: see entry ids.

The starter lists every file:

Folder What’s in it
my-site/ statac.yaml, the site’s settings, and .gitignore, which keeps .statac/ and _site/ out of the site’s history.
content/ Your writing: the home page; posts/, notes/ and photos/, each with its own page and a few samples; the 404 page, the sitemap and robots.txt.
templates/ The templates each kind of page, the feed, the sitemap and robots.txt are built in.
snippets/ Snippets: pieces of HTML you call by name, such as a picture with its caption or a post in a list.
snippets/markdown/ How two pieces of the writing are built: a picture and a callout written in Markdown.
data/ words.yaml: every word the pages show readers, for each language.
languages/ Only for a site in another language: the two lines Statac has in English alone, for you to translate.
assets/ site.css, the one stylesheet, light and dark as the reader’s own setting chooses.
static/ favicon.ico, a sample icon browsers show in the site’s tab: put your own in its place.

The samples are dated the day you run statac new and the days before it. One post, “What a post can hold”, shows everything a page’s writing can hold, each beside how it is written. Every file is yours to change or remove.

Most files start with a line saying what they build and where these pages describe it, as a path such as /pictures/.

Everything a reader sees is in the starter’s files, with two exceptions, and a file of your own takes the place of either: code.css, the colours for code, and six pieces of the writing, built as plain HTML.

The shorter dates

Line What it is for Day first Month first Year first
date_format A date written whole: a post’s, a photograph’s 31 December 2025 December 31, 2025 2025-12-31
date_short A date in a list of lines, and beside a related post 31 Dec 2025 Dec 31, 2025 2025-12-31
date_day A post’s day under its year’s heading 31 Dec Dec 31 12-31
date_stamp A note’s date and time, and what a note with no title is called 31 Dec 2025, 15:04 Dec 31, 2025, 15:04 2025-12-31 15:04

date_format is Statac’s setting. The other three are values of the site’s own, which a template hands to the date filter: {{ post.date | date(site.date_short) }}.

From an example of your own, statac new writes them in the example’s order, with no weekday and the month’s short word: Wednesday, 31 December 2025 gives 31 Dec 2025, 31 Dec and 31 Dec 2025, 15:04.

Change any of them in statac.yaml, but keep the lines: the starter’s templates read all three.

The heading over each year’s posts, and the year at the foot of every page, come from an example in the template itself, date("2025").

The home page and the lists

The home page opens with its greeting and what content/index.md says. Under that is a part for each folder that has posts, with a link to its own page reading “See all”:

Folder Its part of the home page Written by
Any but notes and photos, such as posts Its 5 newest posts, each a line: the date, the title, and the post’s summary or else its opening {{ line(post) }}
notes Its 2 newest notes, each whole {{ short(post, nested=true) }}
photos Its 6 newest photographs, in a row {{ thumb(post) }}

The parts come in that order. Each heading is the title of the folder’s own page, such as content/notes/index.md, and so is each link in the menu.

  • A folder you add, such as content/links/ with its own index.md, has its link once it holds another page, and its part once that page has a date. Its pages are built as plain pages until its index.md hands them a layout, as pages.layout: post: see hand fields down.
  • A dated page loose in content/ is in no part of the home page while the site has any folder.
  • A site with no folders lists every post on the home page, under “Latest posts”. content/index.md says posts_per_page: 0, which keeps that list to one page. Take the line out to show ten to a page: see pages of a list.

The menu lists Home, then the site’s folders in the order of their addresses, with notes and photos last. A folder inside another has a link too, once it holds a page besides its index.md. To change which come last, change this line of templates/base.html:

{% set last = ["notes", "photos"] %}

The posts’ own page, and a tag’s or a series’, show more of each post under a heading for each year: its day, its title, its cover picture and its opening, by {{ entry(post, pictured=true) }}. {{ entry(post) }} leaves the picture out.

A post’s opening ends at a <!--more--> line, or else is its first paragraph: see excerpts.

Which template builds each page

Folder Its own page Each page in it
content/posts/ folder.html, naming no layout post.html, by pages.layout: post
content/notes/ notes.html, by layout: notes note.html, by pages.layout: note
content/photos/ photos.html, by layout: photos photo.html, by pages.layout: photo

The home page is built with home.html, a tag’s or a series’ page with folder.html, /404.html with 404.html, and any other page with page.html: which template builds a page has the rule.

To show a list another way, change the call in its template. line, entry, short and thumb each write a list item, so each goes inside <ol> or <ul>.

Notes and photographs

A note is a short page with a date and, most often, no title. Add one as a file in content/notes/:

---
date: =now
---
A few lines.

content/notes/index.md hands every note untitled: true. A note with no title is called by its date and time, as date_stamp writes them, wherever a title would stand. One snippet does this for every template: {{ called(post) }}, in snippets/called.html.

A photograph is a folder in content/photos/ holding the picture, and an index.md naming it as the cover:

---
title: Photo 7
date: =today
cover: photo-7.jpg
---
What the picture shows.

Describe the picture for readers who can’t see it, as pictures says.

  • A note’s page shows its title where it has one, its date and time, its writing, its tags and the notes either side. It shows no cover, summary or related posts, whatever its front matter says.
  • A photograph’s page shows the picture first and wide, then its title, date and writing. The photographs’ page is a grid of squares, 30 to a page so that each row of three is full: posts_per_page: 30 in content/photos/index.md.
  • Webmentions show only on posts. On a note or a photograph, mentions: true only says where other sites send them: see webmentions.

To do without notes or photographs, delete content/notes/ or content/photos/. Its part of the home page and its link in the menu go with it.

The templates and snippets that built it stay, and do no harm: templates/note.html, templates/notes.html and snippets/short.html for notes, and templates/photo.html, templates/photos.html and snippets/thumb.html for photographs. Remove them too if you like: --update then names them as files that aren’t here.

Change what the pages show

The starter’s templates read these fields:

Field Where What it does
summary A page’s front matter A line about the page: under its title (not on a note or a photograph), in the home page’s lines, and in a link preview.
updated A post’s front matter The day it was last changed, as updated: 2026-10-04, shown beside its date after “Updated”.
cover A post’s or a photograph’s front matter A picture beside the page, as cover: photo-1.jpg: at the top of a post, and beside its opening in a list that shows pictures. In content/photos/ it is the photograph, and its square in the grid.
contents A post’s front matter contents: true shows a table of contents above the writing.
mentions A post’s front matter mentions: true shows the post’s webmentions beneath it.
greeting content/index.md The home page’s heading, Hello. on a new site. Without it, the heading is the site’s title.
tagline statac.yaml A line about the site: the feed’s <subtitle>.
author statac.yaml Who writes the site, in the feed and at the foot of every page, in place of the site’s title.
date_short, date_day, date_stamp statac.yaml The shorter dates. The only three that aren’t optional.

The first post is a folder, to keep its picture beside it. A post with no picture can be one file, such as content/posts/second-post.md.

Another language, or several

Every word the starter’s pages show readers, such as “Older posts”, is in data/words.yaml under each language’s code: the starter’s words says how to translate them.

Naming several languages, as en, fr, writes language: [en, fr] and a home page for each language besides the main one, in a folder of its own: content/fr/index.md. The starter’s base.html links each page to its translations, with a switch between them.

Statac has the words for a footnote’s way back to the text, and the callouts’ names, in English alone, so statac new writes both into languages/<code>.yaml for you to translate.

A site in several languages covers language folders, lists and addresses.

Turn on sharing cards

statac new --cards

Run it in the site’s folder, or give it the folder. It writes the card’s six files and nothing else. From the next build, once the site has an address, a sharing card is drawn for each page:

Folder What’s in it
templates/ og.yaml, the card’s settings: its background, its fonts, and the texts drawn.
templates/og/ The plain background, and two fonts with their licences: Noto Sans, and Noto Emoji, which an emoji in a card’s text is drawn in.

Given a folder that is empty or isn’t there, as statac new --cards my-site, it asks the four questions and makes the site with its card from the start.

It never writes over a file of yours. Turning cards on has the rest.

Bring the starter up to date

statac new --update

Once written, the starter’s files are yours, so a later Statac’s better starter never reaches a site already made. Run this in the site’s folder, or give it the folder, to bring it in.

Updated `templates/base.html`.
`templates/post.html` is yours and wasn't touched. Since the starter file nearest to it, the starter's has changed:
  @@ line 12
   <h1>{{ headline(page) }}</h1>
  -<p>{{ page.date }}</p>
  +<p><time datetime="{{ page.date | moment }}">{{ page.date }}</time></p>
   {% if page.tags %}
Updated 1 file. 1 of yours has something new, shown above.

Lines starting - left the starter file and lines starting + came. @@ line 12 is where the change starts in the newest version.

What it finds What it does
A starter file you never changed Replaces it with the newest version.
A text file you changed Leaves it, and shows what is new in the starter, for you to copy in what you want.
A file you changed that isn’t text, such as the card’s font or background Leaves it, and names it where the starter’s has changed.
A word the starter’s templates show that a language’s list in data/words.yaml lacks Adds it in English, and names it.
A starter file the site doesn’t have Names it, and writes it only with --missing. Never one in content/posts/, content/notes/ or content/photos/.
A starter file that is a link, or is in a folder that is one Names it and leaves it alone.

Nothing is kept in the site to tell your files from the starter’s. A file holding exactly what some version of the starter’s did is one you never changed. A file you changed is held to the version nearest it, and what is new is what changed in the starter since.

Where no file has anything new, --update says:

Nothing to update: every starter file here is the newest, or yours with nothing new.

The card’s files are brought up to date like any other, on a site that has templates/og.yaml. On one without, only --cards writes them.

Words a newer template shows

Added 2 words to `data/words.yaml` under `en-GB`: `minutes`, `all`.
Updated 1 file.

This is the one time --update writes to a file you may have changed. It adds each word a newer template shows, in English, at the end of that language’s list, and changes nothing else in the file. Translate them as you did the others.

Files that aren’t here

2 starter files aren't here: `snippets/quote.html`, `templates/photos.html`. To write them, run `statac new --update --missing`.

A starter file the site doesn’t have may be one you removed, or one new in this Statac, so --update names them and writes none. --missing writes each of them:

statac new --update --missing
Wrote `snippets/quote.html`.
Wrote `templates/photos.html`.
Updated 2 files.

The starter’s files in content/posts/, content/notes/ and content/photos/ are never named and never written back.

On a site with templates/og.yaml, a card file it lacks is among the missing, so a site that already has cards can get the emoji font, Noto Emoji.

Where next?

Something unclear or wrong? Open an issue on GitHub.