Technical reference
arachnopress
Build a zero-JS static article site from hand-written HTML fragments.
DESCRIPTION
arachnopress reads articles/slug/article.html files and builds
a single-page or multi-page static article site in site/.
make build is the normal interface.
It runs in POSIX-like BSD, Linux, and macOS environments. Generated output
is served as static files and may also be opened through
file://. It requires no server-side processing.
FEATURES
- File-backed code, download, and image blocks with raw links, checksums, image sizing, framing, alignment, text flow, and native enlarged-image popovers.
- Pygments or Source-highlight syntax highlighting with escaped-source fallback and reduced span markup.
- Minimal, hand-edited article fragments with arbitrary HTML; no Markdown or template pipeline.
- Single-page or per-article output, optional unlisted articles, and HTML or extensionless internal URLs.
- Opt-in Atom entries for articles or sections, with summaries, updated dates, and section/subsection links.
- Responsive CSS navigation, sortable title and date indexes, and article creation and modification metadata.
- Selectable upstream colour palettes with Exact, Auto, Light, and Dark modes.
- SVG logo and favicon support, theme-aware inline SVG, and optional fixed or randomised SVG backdrops. A single Unicode symbol supplies the logo/favicon fallback when no SVG icon is configured.
- An HTML and CSS interface without JavaScript, cookies, browser storage, or server-side processing.
- Native theme, contact, and license popovers; marked GET contact requests for access-log collection.
-
POSIX-style
shandmakebuilds for BSD, Linux, and macOS, with optional versioned release packaging.
DOWNLOADS
arachnopress_1.0.65.tar.gzgzipped source archive
SYNOPSIS
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.
Do not store source files in or run make from
site/; each successful build replaces it.
REQUIREMENTS
Required utilities
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 maintainer targets additionally require cmp,
tar, and gzip support in tar.
mktemp is widely available but is not specified by POSIX.
Optional utilities
- pygmentize
- Provides Pygments syntax highlighting. This is the default highlighter when the command is available.
- source-highlight
- Provides GNU Source-highlight syntax highlighting when selected.
- sha256, sha256sum, shasum, or openssl
- Provides SHA256 values for download blocks. The first successful implementation is used. Downloads remain usable without a checksum.
Browser features
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. The
optional randomised article backdrop requires CSS random();
unsupported browsers retain the SVG's base fit. The bundled backdrop uses
a centred cover fit.
SOURCE LAYOUT
Maintained files
- Makefile
-
Defines
build,release, andfull, their defaults, and their explicit inclusion lists. - styles.css
- Defines layout, themes, syntax colours, responsive behaviour, popovers, and generated block presentation. Targets copy it into their fresh site output but do not modify it.
- THIRD_PARTY_NOTICES.txt
- Identifies the upstream colour schemes, sources, authors, and licences. The license popover and optional Theme popover link to this file.
- licenses/
- Contains the retained third-party copyright and licence notices.
- tools/build.sh
-
Discovers, validates, orders, and renders articles. It generates
the selected page layout, optional Atom feed,
favicon.svg, automatic-theme rules, and embedded navigation rules in the selected build root. - tools/build-profile.sh
- Stages, builds, publishes, cleans, and packages target output.
- tools/theme-menu.html
-
Supplies theme controls and optional
data-auto-darkanddata-auto-lightpair mappings. Its IDs are reserved as page anchors. - tools/license.txt
- Supplies the authoritative static project-license text. Its first non-blank line is the displayed title.
- tools/html-fragment.outlang
- Configures Source-highlight to emit an HTML fragment.
- articles/<slug>/article.html
- Supplies one article. The directory name is the article slug and must match the article element ID.
- articles/<slug>/*
-
Supplies article-local code, download, and image files. These paths are
copied below
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
example contains only the arachnopress article.
Example project and build outputraw↓
.
|-- Makefile
|-- README.arachnopress
|-- THIRD_PARTY_NOTICES.txt
|-- articles
| `-- arachnopress
| |-- article.html
| `-- ...
|-- licenses
| |-- mit.txt
| `-- oksolar-cc0.txt
|-- site
| |-- THIRD_PARTY_NOTICES.txt
| |-- articles
| | `-- arachnopress
| | |-- article.html
| | `-- ...
| |-- favicon.svg
| |-- feed.atom
| |-- index.html
| |-- licenses
| | |-- mit.txt
| | `-- oksolar-cc0.txt
| |-- styles.css
| `-- theme-auto.css
|-- styles.css
`-- tools
|-- build-profile.sh
|-- build.sh
|-- html-fragment.outlang
|-- license.txt
`-- theme-menu.html
BUILD MODEL
make build copies the configured files and articles into a
private staging tree, renders the complete site, then replaces
site/. A failure before publication preserves the previous
output.
site/ is generated output. All targets replace the same
directory and must not run concurrently. The maintainer release targets
also manage the generator download marker and versioned archive.
ARTICLE FORMAT
Root metadata
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.
Use double-quoted values for attributes read by the generator.
data-created and data-modified accept a value
beginning with a valid YYYY-MM-DD date or auto:
-
data-created: missing, empty, orautouses the current UTC build date. -
data-modified: missing or empty uses the resolved creation date;autouses the build date. - Explicit dates remain unchanged. Use explicit dates on published articles and dated headings to keep metadata and 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.
data-feed-sections selects none, h1,
h2, or h3. Unset or empty means none.
See Atom feed modes under NAVIGATION AND THEMES.
Unlisted output:
- Single-page: embedded after listed articles, absent from article indexes, and accessible through article, section, and subsection fragments.
-
Multi-page: written as
slug.html, absent from listed-page indexes, and included only in its own index. Its document hasnoindex, nofollow. -
Single-page articles share
index.htmland have no separate robots directive. -
Unlisted output remains publicly accessible. Targets still copy
included article directories to
site/articles/. -
At least one listed article is required. Multi-page mode reserves
index.
articles/getting-started/article.htmlComplete example articleraw
<article class="article" id="getting-started" data-title="Getting Started" data-created="2026-07-09" data-modified="2026-07-09" data-feed-sections="h1">
<header class="article-header">
<p class="kicker">Guide</p>
<h1>Getting Started</h1>
<p class="summary">
A short article built from one editable HTML fragment.
</p>
</header>
<section>
<h2>Example</h2>
<p>Article text is normal HTML.</p>
<h3>Subsection</h3>
<p>Plain one-line h3 headings appear under their preceding section.</p>
</section>
</article>
Header metadata
The source header contains an h1 and summary. The build inserts
Created and a time element before its closing tag. Updated is
the newest resolved article or heading date and appears when it differs
from Created. Unlisted articles are prefixed with Unlisted; fields use
middle-dot separators.
Indexed headings
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.
Every source h2 and h3 is indexed. IDs on other
author-supplied elements are preserved but are not registered; keep them
unique and clear of generated IDs.
Indexable headings may use data-created and
data-modified. Values follow the article-date format and may
use auto. Their resolved dates contribute to Updated metadata,
modification ordering, and Atom dates. They do not reorder section or
subsection indexes.
Indexed heading formsraw
<h2 data-created="2026-07-09">BUILD</h2>
<h3>Requirements</h3>
<h3 id="custom-subsection" data-modified="2026-07-10">Explicit Subsection Anchor</h3>
<h2 id="custom-anchor" data-created="2026-07-09" data-modified="2026-07-10">Explicit Anchor</h2>
GENERATED BLOCKS
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. Use double-quoted
marker attributes.
File paths (data-src, SITE_ICON_PATH,
SITE_BACKGROUND_PATH):
- Relative, slash-separated paths; each component contains only ASCII letters, digits, dots, underscores, and hyphens.
- Empty,
.and..components and symlinks are rejected.
Code blocks
-
data-title: display title.data-note: header qualifier. data-open="false": initially closed.data-header="false": always visible, without a summary.-
data-footer:trueorfalseoverrides the default. Normal blocks hide the footer for source line counts at or belowCODE_FOOTER_LINES; headerless blocks hide it unless explicitly enabled.
Raw links and sizes refer to the original file. Only the rendered code is HTML-escaped.
Code block markersKeep each marker on one lineraw
<pre class="code-block" data-src="src/example.c" data-title="example.c" data-note="A short C example" data-lang="c"></pre>
<pre class="code-block" data-src="build.sh" data-lang="sh" data-open="false" data-footer="false"></pre>
<pre class="code-block" data-src="output.txt" data-lang="text" data-header="false"></pre>
<pre class="code-block" data-src="output.txt" data-title="output.txt" data-lang="text" data-header="false" data-footer="true"></pre>
Download blocks
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.
Download block markersOne source file per markerraw
<div class="article-downloads" data-src="release.tar.gz" data-title="release.tar.gz" data-note="Source archive"></div>
Image blocks
-
data-alt: alternative text.data-caption: caption. data-titleanddata-note: header labels.data-openanddata-header: as for code blocks.-
data-footer: shown with a normal header unlessfalse; a headerless image requirestrueto show it. -
data-scalecaps inline size:small(20rem),medium(32rem),large(48rem), orfull(article width, default). Images retain their aspect ratio, do not upscale, and remain within the viewport. -
data-border:full(default),fit, ornone.fitshrink-wraps the block with one width for its header, image border, and footer.noneremoves the frame, uses the opaque article background, and suppresses both bars. -
data-align:start,center(default), orend. - Other scale, border, and alignment values are fatal.
- Images use lazy loading and asynchronous decoding.
Text flow:
- Above 760px, following prose and text lists may flow beside start- or end-aligned fit or borderless blocks, capped at 55% of the containing section's width and by the configured size limit.
- 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.
Image viewer:
- Selecting an image opens a themed viewer over the article pane.
- Intrinsic size and aspect ratio are retained, scaling down to fit.
- The enlarged image, X button, Escape, or light dismissal closes it.
- Missing images have no viewer.
Image block markersraw
<figure class="image-block" data-src="images/diagram.png" data-title="Diagram" data-note="Article-local image path" data-alt="Build flow diagram" data-caption="Article-local image"></figure>
<figure class="image-block" data-src="images/icon.png" data-title="Icon" data-alt="Small icon" data-scale="small" data-border="fit" data-align="start" data-header="false" data-footer="true"></figure>
<figure class="image-block" data-src="images/plain.png" data-alt="Borderless image" data-scale="small" data-border="none" data-align="end"></figure>
Missing sources
A missing or invalid source renders a missing block. A non-empty or multiline marker is fatal.
SYNTAX HIGHLIGHTING
HIGHLIGHTER selects pygments,
source-highlight, or none. Use an explicit
data-lang for predictable lexer selection, or omit it for
automatic selection.
Pygments
Pygments is the default. An omitted data-lang requests
filename inference. data-lang="auto" may also guess from
content.
Source-highlight
Source-highlight uses tools/html-fragment.outlang. An omitted
or automatic language lets the program infer its input language.
Fallback and optimisation
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.
NAVIGATION AND THEMES
Article and section selection
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. A slug
page title is its article title followed by SITE_TITLE; the
index page title is SITE_TITLE.
Title order is case-insensitive by title, then slug. Creation order uses the resolved article creation date. Modification order uses the newest resolved article or heading date. Date orders are newest first, then slug. Article-title links provide the article summary and resolved Created and Updated dates as native hover text, with the dates on the final line. If a summary cannot be reduced to clean text, the hover text contains only the dates.
Responsive index
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 while retaining the generator identity, Contact, and license controls.
Theme state
DEFAULT_THEME selects the initial exact variant.
DEFAULT_THEME_MODE selects the initial mode:
-
off: omit the mode control; applyDEFAULT_THEMEunchanged. exact: apply the selected theme unchanged.auto: select the mapped variant using the browser preference.-
lightordark: select the corresponding mapped variant.
Every value except off renders all four choices. An
unmapped theme remains fixed in every mode.
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 of the Theme selector.
Light and dark pairs are the data-auto-light and
data-auto-dark attributes in
tools/theme-menu.html. Edit those attributes to change a
pairing.
tools/theme-menu.htmlComplete theme menuraw↓
<div class="theme-menu" id="theme-popover" popover>
<div class="theme-head">
<h2>Theme</h2>
<button class="theme-close" type="button" popovertarget="theme-popover" popovertargetaction="hide" aria-label="Close theme menu">X</button>
</div>
<form class="theme-list" aria-label="Theme">
<fieldset>
<legend>Solarized</legend>
<input type="radio" name="theme" id="theme-solarized-dark" data-auto-dark="theme-solarized-dark" data-auto-light="theme-solarized-light" checked>
<label for="theme-solarized-dark">Dark</label>
<input type="radio" name="theme" id="theme-solarized-light" data-auto-dark="theme-solarized-dark" data-auto-light="theme-solarized-light">
<label for="theme-solarized-light">Light</label>
</fieldset>
<fieldset>
<legend>Selenized</legend>
<input type="radio" name="theme" id="theme-selenized-dark" data-auto-dark="theme-selenized-dark" data-auto-light="theme-selenized-light">
<label for="theme-selenized-dark">Dark</label>
<input type="radio" name="theme" id="theme-selenized-black" data-auto-dark="theme-selenized-black" data-auto-light="theme-selenized-white">
<label for="theme-selenized-black">Black</label>
<input type="radio" name="theme" id="theme-selenized-light" data-auto-dark="theme-selenized-dark" data-auto-light="theme-selenized-light">
<label for="theme-selenized-light">Light</label>
<input type="radio" name="theme" id="theme-selenized-white" data-auto-dark="theme-selenized-black" data-auto-light="theme-selenized-white">
<label for="theme-selenized-white">White</label>
</fieldset>
<fieldset>
<legend>OKSolar</legend>
<input type="radio" name="theme" id="theme-oksolar-dark" data-auto-dark="theme-oksolar-dark" data-auto-light="theme-oksolar-light">
<label for="theme-oksolar-dark">Dark</label>
<input type="radio" name="theme" id="theme-oksolar-light" data-auto-dark="theme-oksolar-dark" data-auto-light="theme-oksolar-light">
<label for="theme-oksolar-light">Light</label>
</fieldset>
<fieldset>
<legend>Gruvbox Material</legend>
<input type="radio" name="theme" id="theme-gruvbox-material-hard-dark" data-auto-dark="theme-gruvbox-material-hard-dark" data-auto-light="theme-gruvbox-material-hard-light">
<label for="theme-gruvbox-material-hard-dark">Hard Dark</label>
<input type="radio" name="theme" id="theme-gruvbox-material-hard-light" data-auto-dark="theme-gruvbox-material-hard-dark" data-auto-light="theme-gruvbox-material-hard-light">
<label for="theme-gruvbox-material-hard-light">Hard Light</label>
<input type="radio" name="theme" id="theme-gruvbox-material-medium-dark" data-auto-dark="theme-gruvbox-material-medium-dark" data-auto-light="theme-gruvbox-material-medium-light">
<label for="theme-gruvbox-material-medium-dark">Medium Dark</label>
<input type="radio" name="theme" id="theme-gruvbox-material-medium-light" data-auto-dark="theme-gruvbox-material-medium-dark" data-auto-light="theme-gruvbox-material-medium-light">
<label for="theme-gruvbox-material-medium-light">Medium Light</label>
<input type="radio" name="theme" id="theme-gruvbox-material-soft-dark" data-auto-dark="theme-gruvbox-material-soft-dark" data-auto-light="theme-gruvbox-material-soft-light">
<label for="theme-gruvbox-material-soft-dark">Soft Dark</label>
<input type="radio" name="theme" id="theme-gruvbox-material-soft-light" data-auto-dark="theme-gruvbox-material-soft-dark" data-auto-light="theme-gruvbox-material-soft-light">
<label for="theme-gruvbox-material-soft-light">Soft Light</label>
</fieldset>
<fieldset>
<legend>Tomorrow</legend>
<input type="radio" name="theme" id="theme-tomorrow" data-auto-dark="theme-tomorrow-night" data-auto-light="theme-tomorrow">
<label for="theme-tomorrow">Light</label>
<input type="radio" name="theme" id="theme-tomorrow-night" data-auto-dark="theme-tomorrow-night" data-auto-light="theme-tomorrow">
<label for="theme-tomorrow-night">Night</label>
<input type="radio" name="theme" id="theme-tomorrow-eighties" data-auto-dark="theme-tomorrow-eighties" data-auto-light="theme-tomorrow">
<label for="theme-tomorrow-eighties">Eighties</label>
<input type="radio" name="theme" id="theme-tomorrow-blue" data-auto-dark="theme-tomorrow-blue" data-auto-light="theme-tomorrow">
<label for="theme-tomorrow-blue">Blue</label>
<input type="radio" name="theme" id="theme-tomorrow-bright" data-auto-dark="theme-tomorrow-bright" data-auto-light="theme-tomorrow">
<label for="theme-tomorrow-bright">Bright</label>
</fieldset>
<fieldset>
<legend>Nord</legend>
<input type="radio" name="theme" id="theme-nord">
<label for="theme-nord">Dark</label>
</fieldset>
<fieldset>
<legend>Everforest</legend>
<input type="radio" name="theme" id="theme-everforest-hard-dark" data-auto-dark="theme-everforest-hard-dark" data-auto-light="theme-everforest-hard-light">
<label for="theme-everforest-hard-dark">Hard Dark</label>
<input type="radio" name="theme" id="theme-everforest-hard-light" data-auto-dark="theme-everforest-hard-dark" data-auto-light="theme-everforest-hard-light">
<label for="theme-everforest-hard-light">Hard Light</label>
<input type="radio" name="theme" id="theme-everforest-dark" data-auto-dark="theme-everforest-dark" data-auto-light="theme-everforest-light">
<label for="theme-everforest-dark">Medium Dark</label>
<input type="radio" name="theme" id="theme-everforest-light" data-auto-dark="theme-everforest-dark" data-auto-light="theme-everforest-light">
<label for="theme-everforest-light">Medium Light</label>
<input type="radio" name="theme" id="theme-everforest-soft-dark" data-auto-dark="theme-everforest-soft-dark" data-auto-light="theme-everforest-soft-light">
<label for="theme-everforest-soft-dark">Soft Dark</label>
<input type="radio" name="theme" id="theme-everforest-soft-light" data-auto-dark="theme-everforest-soft-dark" data-auto-light="theme-everforest-soft-light">
<label for="theme-everforest-soft-light">Soft Light</label>
</fieldset>
<fieldset>
<legend>Edge</legend>
<input type="radio" name="theme" id="theme-edge-dark" data-auto-dark="theme-edge-dark" data-auto-light="theme-edge-light">
<label for="theme-edge-dark">Dark</label>
<input type="radio" name="theme" id="theme-edge-aura" data-auto-dark="theme-edge-aura" data-auto-light="theme-edge-light">
<label for="theme-edge-aura">Aura</label>
<input type="radio" name="theme" id="theme-edge-neon" data-auto-dark="theme-edge-neon" data-auto-light="theme-edge-light">
<label for="theme-edge-neon">Neon</label>
<input type="radio" name="theme" id="theme-edge-aura-dim" data-auto-dark="theme-edge-aura-dim" data-auto-light="theme-edge-light">
<label for="theme-edge-aura-dim">Aura Dim</label>
<input type="radio" name="theme" id="theme-edge-light" data-auto-dark="theme-edge-dark" data-auto-light="theme-edge-light">
<label for="theme-edge-light">Light</label>
</fieldset>
<fieldset>
<legend>Sonokai</legend>
<input type="radio" name="theme" id="theme-sonokai">
<label for="theme-sonokai">Default</label>
<input type="radio" name="theme" id="theme-sonokai-atlantis">
<label for="theme-sonokai-atlantis">Atlantis</label>
<input type="radio" name="theme" id="theme-sonokai-andromeda">
<label for="theme-sonokai-andromeda">Andromeda</label>
<input type="radio" name="theme" id="theme-sonokai-shusia">
<label for="theme-sonokai-shusia">Shusia</label>
<input type="radio" name="theme" id="theme-sonokai-maia">
<label for="theme-sonokai-maia">Maia</label>
<input type="radio" name="theme" id="theme-sonokai-espresso">
<label for="theme-sonokai-espresso">Espresso</label>
</fieldset>
<fieldset>
<legend>Spring Night</legend>
<input type="radio" name="theme" id="theme-spring-night">
<label for="theme-spring-night">Normal</label>
<input type="radio" name="theme" id="theme-spring-night-high-contrast">
<label for="theme-spring-night-high-contrast">High Contrast</label>
</fieldset>
<fieldset>
<legend>Ayu</legend>
<input type="radio" name="theme" id="theme-ayu-dark" data-auto-dark="theme-ayu-dark" data-auto-light="theme-ayu-light">
<label for="theme-ayu-dark">Dark</label>
<input type="radio" name="theme" id="theme-ayu-mirage" data-auto-dark="theme-ayu-mirage" data-auto-light="theme-ayu-light">
<label for="theme-ayu-mirage">Mirage</label>
<input type="radio" name="theme" id="theme-ayu-light" data-auto-dark="theme-ayu-dark" data-auto-light="theme-ayu-light">
<label for="theme-ayu-light">Light</label>
</fieldset>
<fieldset>
<legend>Catppuccin</legend>
<input type="radio" name="theme" id="theme-catppuccin-latte" data-auto-dark="theme-catppuccin-mocha" data-auto-light="theme-catppuccin-latte">
<label for="theme-catppuccin-latte">Latte</label>
<input type="radio" name="theme" id="theme-catppuccin-frappe" data-auto-dark="theme-catppuccin-frappe" data-auto-light="theme-catppuccin-latte">
<label for="theme-catppuccin-frappe">Frappe</label>
<input type="radio" name="theme" id="theme-catppuccin-macchiato" data-auto-dark="theme-catppuccin-macchiato" data-auto-light="theme-catppuccin-latte">
<label for="theme-catppuccin-macchiato">Macchiato</label>
<input type="radio" name="theme" id="theme-catppuccin-mocha" data-auto-dark="theme-catppuccin-mocha" data-auto-light="theme-catppuccin-latte">
<label for="theme-catppuccin-mocha">Mocha</label>
</fieldset>
<fieldset>
<legend>Rose Pine</legend>
<input type="radio" name="theme" id="theme-rose-pine" data-auto-dark="theme-rose-pine" data-auto-light="theme-rose-pine-dawn">
<label for="theme-rose-pine">Main</label>
<input type="radio" name="theme" id="theme-rose-pine-moon" data-auto-dark="theme-rose-pine-moon" data-auto-light="theme-rose-pine-dawn">
<label for="theme-rose-pine-moon">Moon</label>
<input type="radio" name="theme" id="theme-rose-pine-dawn" data-auto-dark="theme-rose-pine" data-auto-light="theme-rose-pine-dawn">
<label for="theme-rose-pine-dawn">Dawn</label>
</fieldset>
<p class="theme-third-party">Theme sources and licences: <a href="THIRD_PARTY_NOTICES.txt">third-party notices</a></p>
</form>
</div>
Atom feed
SITE_FEED=true writes feed.atom, feed discovery
metadata, and a text-form Atom link before the Theme control. Listed
articles opt in through data-feed-sections:
- none
- No entries. Also the default when unset or empty.
- h1
- One entry with the article title, link, and plain-text summary.
- h2
-
One entry per
h2, titled "Article title - Section heading", with a link to that section instead of the article summary. - h3
-
As
h2, with a linked list of itsh3headings in each entry body.
Feed rules:
-
h2andh3fall back toh1withouth2headings. Inh3mode, anh2without child headings has the same content ash2mode. - Section bodies contain generated HTML links, not article prose.
- Unlisted articles never enter the feed. Other mode values are fatal.
-
An
h1entry uses the newest article or heading date. Anh2entry uses itsdata-modified, then itsdata-created, then the article's resolved modification date. -
A dated
h3updates its parent entry when newer. An undatedh3has no effect. Article-levelautorolls intoh1entries; in section modes it is only the fallback for an undatedh2. Feed dates use midnight UTC. - Article groups are ordered by their newest entry. Sections and linked subsections retain source order. An empty feed uses the UTC build date.
- The feed identifies the generator and uses the versioned site favicon.
-
Links follow
SITE_MODEandSITE_URL_STYLE. IDs remainSITE_URL/#article-idorSITE_URL/#section-id, independent of dates and output mode. -
Explicit heading IDs are optional and preserve identity across renames
and reordering of duplicate headings. New
h2headings create entries; section edits and addedh3links retain the parent entry ID. - Enabling section entries introduces existing sections as new entries. Revisions retain their IDs; read/unread state is reader-controlled.
Branding and backdrop
SITE_ICON supplies the Unicode header logo and generated
favicon when SITE_ICON_PATH is empty.
SITE_ICON_PATH supplies an SVG copied unchanged as the
favicon and used as the header logo.
SITE_ICON_PATH_THEME=true embeds the header copy and maps its
colour-out and
colour-in classes to the current article background and title
colours. See Custom site icon under BUILD for class assignment.
SITE_BACKGROUND enables a fixed article-pane SVG backdrop.
SITE_BACKGROUND_RANDOM lets supporting browsers select its
scale and crop with CSS random() when loading the document.
Other browsers retain the SVG's base fit. The bundled SVG uses a centred
cover crop. Its colour-out class is not painted;
colour-in uses the panel background colour at 25% opacity.
Code, download, and image block surfaces remain opaque.
CONTACT AND LICENSE
Contact request
Contact opens a native popover:
- Reply address: optional, at most 254 characters.
- Message: required, at most 500 characters.
-
Submission: GET to the current page, targeting
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. Identifiers without ASCII letters or digits become
arachnopress. Defaults are
arachnopress_contact=1 for release and
arachnogoat_contact=1 for build and full.
Contact request shapeValues are URL-encoded by the browserraw
Browser URL with SITE_TITLE="Example Site":
https://host.example/?example_site_contact=1&reply=operator%40example.com&message=Short+message#contact-confirmation
HTTP request target logged by a server that retains query strings:
GET /?example_site_contact=1&reply=operator%40example.com&message=Short+message
Contact privacy
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.
Project license
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/.
TARGETS
- build
-
Routine site-generation target. Replaces
site/with the deployment files, every source article, and newly generated output. Leaves release markers and archives unchanged. - release
-
Maintainer target for a generator release. Builds only the arachnopress
article, marks its archive download as missing, and replaces
site/. It creates the versioned archive in the project root, removes allarachnopress_*.tar.gzsource article archives, and updates the source marker. - full
-
Optional maintainer target that installs the matching root release
archive in a full staged site. It replaces
site/, removes allarachnopress_*.tar.gzsource article archives, and updates the source marker.
No clean, install, serve, or watch target is defined.
VARIABLES
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.
Site identity
- SITE_TITLE
-
Page title and displayed brand. It also forms the contact request marker
prefix. Defaults:
arachnopressforreleaseand directtools/build.shuse;arachnogoatforbuildandfull. - SITE_FEED
-
truewritesfeed.atom, its discovery metadata, and a header link. Listed articles opt in withdata-feed-sections.falseomits them. Defaults:falseforreleaseand directtools/build.shuse;trueforbuildandfull. - SITE_URL
-
Canonical site root used for Atom links.
SITE_FEED=truerequires an absolute HTTP or HTTPS URL without a query or fragment. A trailing slash is removed. Defaults: empty forreleaseand directtools/build.shuse;https://arachnogoat.comforbuildandfull. - SITE_AUTHOR
-
Atom feed author. Defaults:
SITE_TITLEforreleaseand directtools/build.shuse;musol@arachnogoat.comforbuildandfull. - SITE_ICON
-
Character shown beside
SITE_TITLEand rendered into the generated SVG favicon. Defaults: U+4DD6 forreleaseand directtools/build.shuse; U+4DEA forbuildandfull. - SITE_ICON_COLOUR
-
Optional fixed colour for the Unicode header icon and generated
favicon. The value must be
#rgbor#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 whenSITE_ICON_PATHis set. Default: empty. - SITE_ICON_PATH
-
Optional relative path to an SVG in the selected build tree. The build
copies it unchanged to
site/favicon.svgand uses it besideSITE_TITLE.SITE_ICONandSITE_ICON_COLOURare then unused. The path must not name the generatedfavicon.svg. Defaults: empty forrelease;articles/arachnopress/arachnogoatsundual.svgforbuildandfull. Directtools/build.shexecution defaults to empty. Restore the text icon withSITE_ICON_PATH=andSITE_ICON_PATH_THEME=false. - SITE_ICON_PATH_THEME
-
trueembeds theSITE_ICON_PATHSVG in the header and maps itscolour-outandcolour-inclasses to the current article background and title colours. The favicon remains an unchanged copy.truerequiresSITE_ICON_PATH.falseuses the SVG as an external header image. Defaults:falseforreleaseand directtools/build.shuse;trueforbuildandfull. - SITE_BACKGROUND
-
Article-pane backdrop.
trueembeds theSITE_BACKGROUND_PATHSVG. The bundled SVG uses a centred cover crop; a replacement's root SVG attributes determine its base fit. Defaults:falseforreleaseand directtools/build.shexecution;trueforbuildandfull. - SITE_BACKGROUND_RANDOM
-
Backdrop crop.
truelets browsers with CSSrandom()support select a scale and crop on page load; unsupported browsers retain the base fit.falsealways uses the base fit. Default:true. - SITE_BACKGROUND_PATH
-
Relative path to the backdrop SVG in the selected build tree. When
SITE_BACKGROUND=true, the file must definecolour-outandcolour-inclasses. The former is not painted; the latter uses the active theme's panel background colour at 25% opacity. Default:articles/arachnopress/arachnogoatsundual.svg. UsepreserveAspectRatio="xMidYMid slice"for a centred cover fit. - GENERATOR_LABEL
-
Maintainer setting for the generator name displayed in site metadata
and the Atom feed. Default:
arachnopress. - GENERATOR_VERSION
-
Maintainer setting displayed after
GENERATOR_LABELand used in release archive names and Atom generator metadata. It contains dot-separated digits. Default:1.0.64.
Navigation and rendering
- DEFAULT_THEME
-
Exact input ID from
tools/theme-menu.html, with or without thetheme-prefix. Defaults:solarized-darkforreleaseand directtools/build.shuse;everforest-hard-darkforbuildandfull. - DEFAULT_THEME_MODE
-
Theme mode.
offomits the control and appliesDEFAULT_THEMEunchanged.exact,auto,light, ordarkrender all four choices and select that initial mode. Auto follows the browser preference; Light and Dark use the selected theme's mapping. An unmapped theme remains fixed. Defaults:offforreleaseand directtools/build.shuse;exactforbuildandfull. - DEFAULT_THEME_SELECTOR
-
Theme selector state.
truerenders the selector in either output mode;falsefixes the selection toDEFAULT_THEME. Default:true. - SITE_MODE
-
Output layout.
single-pagewrites all generated articles toindex.html.multi-pagewritesindex.htmlplus oneslug.htmlper article. Default:single-page. - SITE_MODE_UNLISTED
-
Unlisted article generation.
trueenables unlisted output using the selectedSITE_MODE;falseexcludes unlisted articles from generated HTML and navigation. Defaults:falseforreleaseand directtools/build.shuse;trueforbuildandfull. - SITE_URL_STYLE
-
Page-link format.
htmlretains.htmllinks.extensionlesskeeps generated.htmlfiles but usesslugand./for multi-page navigation, home links, and contact actions. Defaults:htmlforreleaseand directtools/build.shuse;extensionlessforbuildandfull. Extensionless output requires a matching web-server rewrite. Single-page output is unchanged. - ARTICLE_ORDER
-
Initial order:
title,created, ormodified. Default:title. - HIGHLIGHTER
-
pygments,source-highlight, ornone. Default:pygments. - CODE_FOOTER_LINES
-
Non-negative line threshold for automatically hiding code block
footers. Default:
23.
ENVIRONMENT
- PATH
- Locates required utilities and optional highlighters and checksum programs.
- TMPDIR
-
Parent for private
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.
BUILD
Routine site build
make build is the normal target. Run it from the project root
after changing articles, assets, styles, tool inputs, or build settings.
Routine build profilesRun from the project rootraw
make build
# Per-article pages with system light/dark selection and no theme menu.
make build SITE_MODE=multi-page DEFAULT_THEME_MODE=auto \
DEFAULT_THEME_SELECTOR=false
# Per-article files for file:// navigation, using a fixed theme.
make build SITE_MODE=multi-page SITE_URL_STYLE=html \
DEFAULT_THEME=solarized-dark DEFAULT_THEME_MODE=off \
DEFAULT_THEME_SELECTOR=false
# Published articles only, without theme controls or an article backdrop.
make build SITE_MODE_UNLISTED=false SITE_BACKGROUND=false \
DEFAULT_THEME_MODE=off DEFAULT_THEME_SELECTOR=false
# Override the public Atom feed identity.
make build SITE_FEED=true SITE_URL=https://example.com \
SITE_AUTHOR='Example Author'
Custom site icon
Store the SVG below an included article. For theme colouring, assign
colour-out and colour-in classes to its drawable
elements or groups. Edit the class attributes directly or with Inkscape's
XML Editor. Restore the Unicode icon with SITE_ICON_PATH=
and SITE_ICON_PATH_THEME=false.
Custom site icon buildReplace article-slug after adding an SVGraw
# Run each command separately from the project root.
# Custom SVG after adding the required classes.
make build SITE_ICON_PATH=articles/article-slug/site-icon.svg \
SITE_ICON_PATH_THEME=true
# Restore the Unicode icon.
make build SITE_ICON_PATH= SITE_ICON_PATH_THEME=false
Generator release
Maintainers changing the generator update GENERATOR_VERSION
and run make release. This builds only the arachnopress
article and creates the root archive. Copy that archive into
articles/arachnopress/, then use make build for a
normal site. The optional make full target performs the
archive integration within its staged output.
Highlighter variants
HIGHLIGHTER=none selects escaped source. Select either
installed highlighter explicitly to test its output.
Highlighter buildsRun separately from the project rootraw
# Run each command separately from the project root.
make build HIGHLIGHTER=none
make build HIGHLIGHTER=pygments
make build HIGHLIGHTER=source-highlight
REBUILD AND RECOVERY
-
Re-run
make buildafter changing maintained input. Stylesheet and favicon cache tokens change with their resources. - After failure or interruption, correct the diagnostic and rerun the target. Normal failure and signal handling remove unpublished temporary files and preserve the previous site before publication.
-
After an untrappable termination, wait until no build is running.
Inspect
.site-build.*below the project root andstatic-site-build.*belowTMPDIRbefore removing leftovers.
Remove generated output
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.
Remove generated outputRun from the project rootraw
# Run from the project root when no build is running.
rm -rf site
FILES
- site/
-
Fresh published output from the most recent target. Do not store
maintained articles or run
makein this directory. - site/index.html
- Generated entry point. It contains every generated article in single-page mode or the first listed article in multi-page mode.
- site/<slug>.html
- Multi-page output for each listed article and each enabled unlisted article.
- site/favicon.svg
-
Generated fallback or unchanged copy of
SITE_ICON_PATH. Its link contains a cache version token. - site/feed.atom
-
Site-wide Atom feed generated when
SITE_FEED=true. - site/theme-auto.css
-
Generated when
DEFAULT_THEME_MODEis notoffand a reachable theme has an automatic mapping. It contains light/dark rules derived fromstyles.cssand the mappings intools/theme-menu.html. Its link contains the shared stylesheet cache token. - site/styles.css
- Copied site stylesheet.
- THIRD_PARTY_NOTICES.txt
-
Maintained notice for bundled colour palettes. Targets copy it into
site/and release archives. - licenses/
-
Retained third-party licence notices. Targets copy the directory into
site/and release archives. - articles/<slug>/*
-
Maintained article source and published raw, download, and image assets.
Targets copy them to
site/articles/<slug>/. - arachnopress_GENERATOR_VERSION.tar.gz
-
Maintainer release archive produced by
make releaseand consumed bymake fullfrom the same project root. Its top-level directory has the same name without the.tar.gzsuffix. - README.arachnopress
- The compact operator and interface reference.
EXIT STATUS
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.
DIAGNOSTICS
- Missing release archive
-
Run
make releasewith the same generator version beforemake full. Run both commands from the same project root, not fromsite/. - DEFAULT_THEME does not exist in theme menu / Automatic theme mapping must name a theme option
-
Use theme radio IDs from
tools/theme-menu.html. Definedata-auto-darkanddata-auto-lighttogether, and include the source theme in its pair. - No listed articles found
-
Add or select at least one article not marked
data-listed="false". - Extensionless article directory names must not contain dots / Extensionless article URL conflicts with a site root path
- Rename the article directory and matching article ID. The slug must not contain a dot or match another generated root path.
- Unsafe SITE_ICON_PATH / SITE_ICON_PATH_THEME requires SVG class
-
Use a readable relative
.svgfile in the staged tree. A themed icon must containcolour-outandcolour-inclass tokens. - Unsafe SITE_BACKGROUND_PATH / SITE_BACKGROUND requires SVG class
-
Enable the backdrop with a readable relative
.svgfile in the staged tree containingcolour-outandcolour-inclass tokens. - Article, heading, or generated-marker format error
- Apply the ARTICLE FORMAT and GENERATED BLOCKS rules. Keep indexed headings and empty generated markers on one source line.
Missing or invalid generated block files appear as visible missing blocks. They do not produce these fatal diagnostics.
SERVING
Deploy site/ as static files without changing its relative
paths. It may instead be opened as site/index.html through
file://; multi-page file access requires
SITE_URL_STYLE=html.
Contact submission is for HTTP or HTTPS deployment. Serve contact forms over HTTPS and retain query strings in the access log to receive their contents.
OpenBSD httpd example
The OpenBSD httpd(8) example serves .atom as
application/atom+xml 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.
/etc/httpd.confReplace host, certificate, and document-root pathsraw↓
types {
include "/usr/share/misc/mime.types"
application/atom+xml atom
}
server "arachnogoat.com" {
listen on * port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
request strip 2
}
location * {
block return 301 "https://$HTTP_HOST$REQUEST_URI"
}
}
server "arachnogoat.com" {
listen on * tls port 443
tls {
certificate "/etc/ssl/arachnogoat.com.fullchain.pem"
key "/etc/ssl/private/arachnogoat.com.key"
}
root "/htdocs/arachnogoat.com"
# Required when arachnopress uses SITE_URL_STYLE=extensionless.
location not found match "/[^./]+$" {
request rewrite "$DOCUMENT_URI.html"
}
}
CAVEATS
Trusted input
Article HTML, a SITE_ICON_PATH SVG embedded by
SITE_ICON_PATH_THEME, and a
SITE_BACKGROUND_PATH SVG are trusted author content. The
build escapes generated text and code, but does not sanitize author HTML
or embedded SVG markup. Review them before building. The zero-JS
guarantee applies to the generated interface; author HTML may add its own
active content or external dependencies.
Single-page scale
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.
Browser compatibility
Older clients may not support every CSS or popover feature. See REQUIREMENTS.
LICENSE
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/.