Technical reference
Build a zero-JS static article site from hand-written HTML fragments.
arachnopress reads hand-written HTML articles below
articles/ and builds a single-page or multi-page static site.
The generated interface uses only HTML and CSS; it requires no JavaScript,
cookies, or browser storage.
Generated output may be opened directly through file:// or
served as static files. It requires no CGI, PHP, application server, or
database.
The build uses sh, make, and standard Unix
utilities on BSD, Linux, and macOS. Pygments and GNU Source-highlight are
optional. A missing or failed highlighter falls back to escaped source.
sh and make build for BSD, Linux,
and macOS.
file:// access or static-file deployment without CGI,
PHP, an application server, or a database.
Run make build from the project root. It builds every source
article and replaces site/. Supply settings through the
environment or as make command-line variables.
Maintainers run make release followed by
make full to publish and integrate a generator release. Run
every target from the project root. Do not store source files in or run
make from site/; each successful target replaces
it.
The build requires a POSIX-like operating environment with
sh, make, awk, sed,
grep, sort, tr, date,
dirname, pwd,
printf, mktemp, mkdir, rm,
wc, cat, cksum,
chmod, mv, cp, and find.
The release and full profiles also require cmp,
tar, and gzip support in tar.
mktemp is widely available but is not specified by POSIX.
The generated interface requires browser support only for HTML and CSS.
It uses CSS :has(), :target,
prefers-color-scheme, native
details/summary, and the HTML popover API.
build, release, and full,
their defaults, and their explicit inclusion lists.
favicon.svg, automatic-theme
rules, and embedded navigation rules in the selected build root.
data-auto-dark and
data-auto-light pair mappings. Its IDs are reserved as page
anchors.
site/articles/ and linked from the page.
The example tree shows maintained source and make build
output. site/ contains deployed files and copied articles. The
generator article is articles/arachnopress;
GENERATOR_VERSION names release archives.
The Makefile defines the targets, profile defaults, and inclusion lists.
Each target copies its Makefile inclusion list to a private
.site-build.* tree in the project root. Build and full select
every staged article; release selects articles/arachnopress.
Inclusion paths must exist and contain no symbolic links.
tools/build.sh validates and renders the staged tree. Its
transient files remain below TMPDIR, or /tmp
when TMPDIR is unset.
The target completes the staged output before replacing
site/. A failure before publication preserves the previous
site/.
Exit and handled signal traps remove unpublished staging and rendering files. An untrappable termination may leave them behind.
Release and full prepare the generator-release marker and archive cleanup
in staging and update the source only after publication succeeds.
All targets share site/ and must not run concurrently.
Each article begins with a one-line article element. Its
class list must include article. Its id must
equal the containing directory name. data-title is required.
Optional data-created and data-modified values
begin with YYYY-MM-DD. data-created defaults to
the current UTC build date; data-modified defaults to
data-created. Set both on published articles to keep visible
metadata and date ordering stable.
data-listed defaults to true and accepts only
true or false.
SITE_MODE_UNLISTED=false excludes articles marked
data-listed=false from generated HTML and navigation in
either output mode.
SITE_MODE_UNLISTED=true enables unlisted output.
Enabled single-page output embeds unlisted articles after listed articles,
omits them from article indexes, and exposes them through their article,
section, and subsection fragments. Enabled multi-page output writes an
unlisted article as slug.html, omits it from listed-page
indexes, and includes it only in its own index.
A multi-page unlisted document includes a noindex, nofollow
directive. A single-page article shares index.html and cannot
have a separate robots directive. Unlisted output remains publicly
accessible. At least one listed article is required. Multi-page mode
reserves the index slug. Targets still copy included article
directories to site/articles/.
The source header contains an h1 and summary. The build inserts
Created and a time element before its closing tag. It adds
Updated when the dates differ and prefixes unlisted articles with
Unlisted. The order is Unlisted, Created, Updated, using one separator.
Use h2 for major sections and h3 for genuine
subdivisions. Indexable headings contain plain text and close on the same
source line. An h3 must follow an h2. The build
preserves a valid explicit ID or derives a unique ID from the heading and
article.
Article, heading, theme, generated control, and generated block IDs share one collision registry. Explicit IDs and slugs may contain ASCII letters, digits, dots, underscores, and hyphens.
Generated markers are empty, file-backed elements contained on one source
line. data-src is relative to the article directory. Missing
or invalid sources render visible missing blocks.
data-title changes the display title;
data-note adds a qualifier; and data-open
values 0, false, no,
closed, and collapsed close the block initially.
Other values leave it open. data-header="false" emits
always-visible content without a summary. A headerless block has no
footer unless data-footer="true" is explicit.
For normal blocks, an omitted data-footer hides the footer
when the source line count is at or below
CODE_FOOTER_LINES. Explicit true or false values override
that threshold. Raw links and sizes refer to the source file, whose
contents are HTML-escaped.
A download marker names exactly one file. data-title changes
only its display title and data-note adds a qualifier. The
link continues to target data-src. The block shows the raw
size and, when a supported checksum program is available, its SHA256.
The obsolete data-downloads attribute is rejected; use one
data-src marker per file.
The generator article has exactly one marker carrying
data-release="generator". The release and full targets replace
that complete line with the validated current archive name; a normal
build leaves it unchanged.
data-alt supplies alternative text.
data-caption adds a caption; data-title and
data-note label the header. data-open,
data-header, and data-footer behave as for code
blocks.
data-scale accepts small, medium,
large, or full and caps inline size at 20rem,
32rem, 48rem, or the article width. full is the default.
Images retain their aspect ratio, do not upscale, and remain within the
viewport.
data-border accepts full, fit, or
none. full is the default. fit
shrink-wraps the frame. none removes it and suppresses the
header and footer.
data-align accepts start, center, or
end; center is the default.
Above 760px, following prose and text lists may flow beside a start- or end-aligned fit or borderless block. Such a block uses at most 55% of the article measure.
Headings, generated blocks, preformatted blocks, tables, horizontal rules, consecutive images, and section ends clear the flow. Centered, full-frame, and narrower layouts keep images on their own row. Other scale, border, and alignment values are fatal. Generated images use lazy loading and asynchronous decoding.
A missing or invalid source renders a missing block. A non-empty or multiline marker is fatal.
Pygments is the default. An omitted data-lang requests
filename inference. data-lang="auto" first uses filename
inference and may guess from content. An explicit value requests that
lexer.
Source-highlight uses tools/html-fragment.outlang. An omitted
or automatic language lets the program infer its input language. The
make alias is translated to makefile.
A missing program, unknown lexer, failed invocation, missing output
definition, or empty highlighted result for non-empty input falls back to
escaped raw source for that block. HIGHLIGHTER=none always
uses that path.
Successful highlighted output is filtered to unwrap whitespace-only
Pygments span.w and Source-highlight
span.sh-normal elements. Their whitespace remains in the
preformatted code content.
The build writes title, creation-date, and modification-date order lists.
ARTICLE_ORDER selects the initial list; CSS radio controls
select another.
In single-page mode, URL fragments and CSS
:target/:has() select articles, sections, and
subsections. The first listed article is visible without a target.
index.html embeds the generated navigation rules.
In multi-page mode, index.html contains the first listed
article and each article has slug.html. Each file contains one
article, its section index, and its generated navigation rules.
Title order is case-insensitive by title, then slug. Creation and modification orders are newest first by the corresponding source value, then slug.
Wide landscape layouts place article and section navigation in a vertical left pane. Narrow portrait layouts use independent horizontal article, section, and conditional subsection rows. Short and narrow layouts hide descriptive build metadata before hiding the generator identity, Contact, or license controls.
DEFAULT_THEME selects the initial exact variant.
DEFAULT_THEME_AUTO adds an Exact, Auto, Light, and Dark
header control, beside the Theme button when present, and initially
selects Auto. Exact applies the selected theme unchanged. The other modes
use its light/dark mapping; Auto follows the browser preference. An
unmapped theme remains fixed.
Both controls have equal height. The mode selector has no frame or selected background; its checked symbol uses the active heading colour.
DEFAULT_THEME_SELECTOR enables the selector from
tools/theme-menu.html. Single-page selections span all
articles until reload. Multi-page selections reset when another page
loads. The mode control is independent and appears only when
DEFAULT_THEME_AUTO is true.
Contact opens a native popover with an optional 254-character reply
address and a required 500-character message. The form submits GET to the
current page and targets contact-confirmation.
The first query item is a lowercase SITE_TITLE identifier
followed by _contact=1. Runs outside letters, digits, dots,
underscores, and hyphens become one underscore; edge underscores are
removed; an empty identifier becomes arachnopress. Defaults are
arachnopress_contact=1 for release and
arachnogoat_contact=1 for build and full.
HTTPS encrypts the request in transit. The address and message remain in the URL, browser history, and logs that record the query string. Do not submit confidential information. The static site provides no separate message delivery or storage.
The operator extracts and processes marked requests from the server log. arachnopress provides no log-processing component.
The license popover HTML-escapes and embeds
tools/license.txt. Its first non-blank line is the title.
THIRD_PARTY_NOTICES.txt maps bundled colour palettes to
notices below licenses/.
site/ with the
deployment files, every source article, and newly generated output.
Leaves release markers and archives unchanged.
site/,
creates arachnopress_GENERATOR_VERSION.tar.gz in the project
root, and updates the source marker. The archive excludes itself.
site/, and updates the source marker.
No clean, install, serve, or watch target is defined.
RELEASE_SITE_ENV defines release site defaults.
PUBLIC_SITE_ENV defines build and full site defaults.
BUILD_ENV defines shared defaults. Environment and
command-line make values override them.
arachnopress for release;
arachnogoat for build and full.
SITE_TITLE and rendered into the
generated SVG favicon. Defaults: U+4DD6 for release; U+4DEA
for build and full.
#rgb or #rrggbb.
When empty, the header icon follows the current article-title colour
and the generated favicon uses the SVG default text fill. It is unused
when SITE_ICON_PATH is set. Default: empty.
site/favicon.svg and uses it beside
SITE_TITLE. SITE_ICON and
SITE_ICON_COLOUR are then unused. Defaults: empty for
release;
articles/arachnopress/arachnogoatsundual.svg for
build and full. Direct
tools/build.sh execution defaults to empty. Set it to an
empty value to restore the generated text icon.
true embeds the SITE_ICON_PATH SVG in the
header and maps its colour-out and colour-in
classes to the current article background and title colours. The
favicon remains an unchanged copy. true requires
SITE_ICON_PATH. false uses the SVG as an external
header image. Defaults: false for release;
true for build and full.
arachnopress.
GENERATOR_LABEL and used in release archive names.
Maintainers change it for a new generator release. It must contain
dot-separated digits only. Default: 1.0.53.
tools/theme-menu.html, with or without
the theme- prefix. Defaults:
solarized-dark for release;
everforest-hard-dark for build and
full.
true renders Exact, Auto, Light, and
Dark header choices, beside the Theme button when present, and
initially selects Auto. Exact applies the selected theme unchanged. The
other choices use its data-auto-dark and
data-auto-light mapping; Auto follows the browser
preference. A theme without a mapping remains fixed.
false uses the selected exact variant and omits the
control. Defaults: false for release;
true for build and full.
true renders the selector in either
output mode; false fixes the selection to
DEFAULT_THEME. Default: true.
single-page writes all generated articles
to index.html. multi-page writes
index.html plus one slug.html per article.
Default: single-page.
true enables unlisted output
using the selected SITE_MODE; false excludes
unlisted articles from generated HTML and navigation. Defaults:
false for release; true for
build and full.
html retains .html links.
extensionless keeps generated .html files but
uses slug and ./ for multi-page navigation, home
links, and contact actions. Defaults: html for
release; extensionless for build
and full. Extensionless output requires a matching
web-server rewrite. Single-page output is unchanged.
title;
created, creation, or ctime; and
modified, modification, or
mtime. Default: title.
pygments, source-highlight, or
none. Default: pygments.
23.
static-site-build.* rendering
directories. Default: /tmp. Target staging uses
.site-build.* below the project root.
LC_ALL is set to C.
SOURCE_HIGHLIGHT_DATADIR is unset so Source-highlight uses
its installed data files and the project output definition.
Run make build from the project root. It defaults to
single-page output, includes unlisted articles, and enables the Theme and
Exact/Auto/Light/Dark controls. The extensionless URL setting has no
effect in single-page mode.
Set SITE_MODE=multi-page for per-article HTML files.
Set DEFAULT_THEME_AUTO=false or
DEFAULT_THEME_SELECTOR=false to omit either theme control.
Set SITE_MODE_UNLISTED=false to exclude unlisted articles.
Store the SVG below an included article and define
colour-out and colour-in classes. Clear
SITE_ICON_PATH to restore the generated text icon.
After updating GENERATOR_VERSION, run
make release from the project root. It renders the generator
download as missing and creates the root archive.
Run make full from the same project root after
make release. It requires the matching root archive and
installs it in the generated generator article. Both targets update the
source marker only after publication.
HIGHLIGHTER=none selects escaped source. Select either
installed highlighter explicitly to test its output.
Re-run the build after changing an article, an article-local file,
styles.css, a tool input, or a build setting. Generated
stylesheet and favicon URLs contain cache tokens, so rebuilding publishes
new URLs when those inputs change.
Correct the diagnostic and rerun the target. Before publication, a
validation, staging, or rendering failure leaves the previous
site/, source marker, source archives, and root release archive
unchanged.
A publication failure may leave site/ incomplete; rerun before
serving.
After all builds stop, remove files left by an untrappable termination. Inspect the wildcard expansions before removal.
No clean target is defined. Remove site/ without changing
maintained source. Release replaces the current-version root archive but
does not remove older root archives. Remove obsolete root archives by
exact name.
make in this directory.
SITE_ICON_PATH.
Its link contains a cache version token.
DEFAULT_THEME_AUTO=true and a reachable
theme has an automatic mapping. It contains light/dark rules derived
from styles.css and the mappings in
tools/theme-menu.html. Its link contains the shared
stylesheet cache token.
site/ and release archives.
site/ and release archives.
site/articles/<slug>/.
make release and
consumed by make full from the same project root. Its
top-level directory has the same name without the .tar.gz
suffix.
A target exits zero after its complete staged tree is published as
site/, after release packaging when applicable, and after
managed source cleanup. It exits non-zero on invalid settings or article
structure, missing required tool inputs, duplicate or invalid IDs, no
articles, or an unhandled command or filesystem failure.
Optional highlighting and checksum failures are not fatal. The build either emits escaped raw source or omits the checksum.
make release with the same generator version before
make full. Run both commands from the same project root, not
from site/.
tools/theme-menu.html. Define
data-auto-dark and data-auto-light together,
and include the source theme in its pair.
data-listed="false".
.svg file in the staged tree. A
themed icon must contain colour-out and
colour-in class tokens.
Missing or invalid generated block files appear as visible missing blocks. They do not produce these fatal diagnostics.
Generated documentation may be bundled with a project and opened directly
as site/index.html through file://. Single-page
output works directly; multi-page output requires
SITE_URL_STYLE=html. Contact submission is for HTTP or HTTPS
deployment.
Serve site/ without changing its relative paths. The Python 3
command provides HTTP only, creates no project files, and does not rewrite
extensionless URLs. Stop it with an interrupt.
Deploy site/ without changing its relative paths. Serve contact
forms over HTTPS. The access log must retain query strings for contact
messages to be available there.
The OpenBSD httpd(8) example serves the site and rewrites
extensionless article paths. Replace its host and document-root paths,
validate the configuration, and reload httpd.
Its final rule appends .html internally to a missing final
path component without a dot. Keep specific rules before it.
Article HTML and a themed SITE_ICON_PATH SVG are trusted
author content. The build escapes generated text and code, but does not
sanitize embedded article or SVG markup. Review both before building.
Single-page output contains every generated article and highlighted code
span. Large code-heavy collections increase HTML size and DOM cost. Use
multi-page mode, focused excerpts, raw downloads, or
HIGHLIGHTER=none when that cost becomes material.
CSS and popover support varies on older clients. No JavaScript compatibility layer is provided.
sh(1), make(1), awk(1),
sed(1), tar(1), and cksum(1). On OpenBSD,
see also httpd(8) for the optional deployment example.
arachnopress is distributed under the BSD 3-Clause license. See
tools/license.txt or the License control in the site metadata.
Bundled colour palettes retain their upstream values and third-party
licences; see
THIRD_PARTY_NOTICES.txt and licenses/.