Docs: align WRITING.md and README with the implementation

- js: page-script paths are site-root-relative, not content-relative
  (AUDIT §7.1)
- directory-form standalone pages need a dedicated Site.hs rule; flat
  content/<page>.md is the generic form (§7.2)
- portal table: add the missing Photography row (§7.3)
- document the implemented-but-undocumented summary:, revised:, and
  keywords: fields, including a Revision dates section (§7.4)
- default citation style is Chicago Notes Bibliography, not
  Author-Date; hover previews come from popups.js, not the deleted
  citations.js (§7.5)
- history: entries may be authored in any order (sorted at build
  time); examples reordered newest-first (§3.5)
- README: make watch runs Hakyll's live-reload preview server (§7.5)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Levi Neuwirth 2026-06-10 09:43:25 -04:00
parent caa113e036
commit 8040be1aee
2 changed files with 88 additions and 25 deletions

View File

@ -9,14 +9,15 @@ with a custom build system in `build/` and a Haskell + JS + Python toolchain.
```sh ```sh
make build # one-shot production build into _site/ make build # one-shot production build into _site/
make dev # dev build (drafts visible) + local server on :8000 make dev # dev build (drafts visible) + local server on :8000
make watch # cabal-watch rebuild (drafts visible) make watch # Hakyll live-reload dev server (drafts visible)
make clean # cabal run site -- clean make clean # cabal run site -- clean
make deploy # clean → build → sign → push → rsync to VPS make deploy # clean → build → sign → push → rsync to VPS
``` ```
`make build` always runs `make clean` implicitly when invoked from `make deploy`. `make build` always runs `make clean` implicitly when invoked from `make deploy`.
For day-to-day work, prefer `make dev` (which serves the site on For day-to-day work, prefer `make dev` (which serves the site on
`http://localhost:8000`) or `make watch` (rebuilds on save without a server). `http://localhost:8000`) or `make watch` (Hakyll's live-reload preview server,
which rebuilds on save and serves the site locally).
**Run `make build` any time you add or replace binary assets** (JPEG/PNG **Run `make build` any time you add or replace binary assets** (JPEG/PNG
figures, PDFs, music assets). `make dev` and `make watch` skip the figures, PDFs, music assets). `make dev` and `make watch` skip the

View File

@ -17,15 +17,22 @@ frontmatter fields, and every authoring feature available in the Markdown source
| Fiction | `content/fiction/my-story.md` | `/fiction/my-story.html` | | Fiction | `content/fiction/my-story.md` | `/fiction/my-story.html` |
| Composition | `content/music/{slug}/index.md` | `/music/{slug}/` | | Composition | `content/music/{slug}/index.md` | `/music/{slug}/` |
| Standalone page | `content/my-page.md` | `/my-page.html` | | Standalone page | `content/my-page.md` | `/my-page.html` |
| Standalone page (with co-located assets) | `content/my-page/index.md` | `/my-page.html` | | Standalone page (with co-located assets; needs a dedicated rule) | `content/me/index.md` | `/me.html` |
| Draft essay | `content/drafts/essays/my-draft.md` | `/drafts/essays/my-draft.html` (dev only) | | Draft essay | `content/drafts/essays/my-draft.md` | `/drafts/essays/my-draft.html` (dev only) |
File names become URL slugs. Use lowercase, hyphen-separated words. File names become URL slugs. Use lowercase, hyphen-separated words.
If a standalone page embeds co-located SVG score fragments or other relative assets, Flat `content/<page>.md` is the generic standalone form — any flat file dropped
place it in its own directory (`content/my-page/index.md`) rather than as a flat file. into `content/` builds automatically. Directory-form standalone pages
Score fragment paths are resolved relative to the source file's directory; a flat (`content/my-page/index.md`) are **not** picked up by the generic rule; each one
`content/my-page.md` would resolve them from `content/`, which is wrong. requires its own dedicated `match` rule in `build/Site.hs`. The two existing
ones are `content/me/index.md` and `content/memento-mori/index.md` — follow
their pattern when adding another.
The directory form exists for pages that embed co-located SVG score fragments
or other relative assets: score fragment paths are resolved relative to the
source file's directory, and a flat `content/my-page.md` would resolve them
from `content/`, which is wrong.
--- ---
@ -65,9 +72,12 @@ subtitle: "An Optional Secondary Line" # optional; rendered below the title in
date: 2026-03-15 # required; used for ordering, feed, and display date: 2026-03-15 # required; used for ordering, feed, and display
abstract: > # optional; shown in the metadata block and link previews abstract: > # optional; shown in the metadata block and link previews
A one-paragraph description of the piece. A one-paragraph description of the piece.
summary: | # optional; rendered in a "Summary" box near the abstract
A structured summary. **Markdown allowed** — bold, lists, multiple paragraphs.
tags: # optional; see Tags section tags: # optional; see Tags section
- nonfiction - nonfiction
- nonfiction/philosophy - nonfiction/philosophy
keywords: [lattices, simd] # optional; links to /bibliography/<keyword>/ pages (list or comma-separated string)
authors: # optional; overrides the default "Levi Neuwirth" link authors: # optional; overrides the default "Levi Neuwirth" link
- "Levi Neuwirth | /me.html" - "Levi Neuwirth | /me.html"
- "Collaborator | https://their.site" - "Collaborator | https://their.site"
@ -79,7 +89,7 @@ further-reading: # optional; see Citations section
- someKey - someKey
- anotherKey - anotherKey
bibliography: data/custom.bib # optional; overrides data/bibliography.bib bibliography: data/custom.bib # optional; overrides data/bibliography.bib
csl: data/custom.csl # optional; overrides Chicago Author-Date csl: data/custom.csl # optional; overrides Chicago Notes Bibliography
no-collapse: true # optional; disables collapsible h2/h3 sections no-collapse: true # optional; disables collapsible h2/h3 sections
repository: https://git.levineuwirth.org/levi/repo # optional; "Repository" link in metadata repository: https://git.levineuwirth.org/levi/repo # optional; "Repository" link in metadata
preprint: /papers/my-essay.pdf # optional; "Preprint" link in metadata (typeset PDF version) preprint: /papers/my-essay.pdf # optional; "Preprint" link in metadata (typeset PDF version)
@ -101,12 +111,20 @@ confidence-history: # list of integers; trend arrow derived from last two
peer-status: under-review # optional; unreviewed (default) | under-review | peer-reviewed | published | retracted peer-status: under-review # optional; unreviewed (default) | under-review | peer-reviewed | published | retracted
result-shape: mixed # optional; positive | negative | mixed | comparative | descriptive result-shape: mixed # optional; positive | negative | mixed | comparative | descriptive
# Version history — optional; falls back to git log, then to date frontmatter # Version history — optional; falls back to git log, then to date frontmatter.
# Entries may be listed in any order — they are sorted by date at build time.
history: history:
- date: 2026-03-01 # ISO date; unquoted is fine (the Haskell YAML parser keeps it as a string) - date: 2026-03-14 # ISO date; unquoted is fine (the Haskell YAML parser keeps it as a string)
note: Initial draft
- date: 2026-03-14
note: Expanded typography section; added citations note: Expanded typography section; added citations
- date: 2026-03-01
note: Initial draft
# Revision log — optional; drives the date shown on cards and list pages
# (see Revision dates section)
revised:
- date: "2026-04-10"
note: "expanded the section on typography"
- date: "2026-03-20" # note is optional per-entry
--- ---
``` ```
@ -226,6 +244,7 @@ The top-level segment maps to a **portal** in the nav:
| Miscellany | `/miscellany/` | | Miscellany | `/miscellany/` |
| Music | `/music/` | | Music | `/music/` |
| Nonfiction | `/nonfiction/` | | Nonfiction | `/nonfiction/` |
| Photography | `/photography/` |
| Poetry | `/poetry/` | | Poetry | `/poetry/` |
| Research | `/research/` | | Research | `/research/` |
| Tech | `/tech/` | | Tech | `/tech/` |
@ -265,7 +284,8 @@ The URL part is optional.
## Citations ## Citations
The citation pipeline uses Chicago Author-Date style. The bibliography lives at The citation pipeline uses Chicago Notes Bibliography style
(`data/chicago-notes.csl`). The bibliography lives at
`data/bibliography.bib` (BibLaTeX format) by default; override per-page with `data/bibliography.bib` (BibLaTeX format) by default; override per-page with
`bibliography` and `csl`. `bibliography` and `csl`.
@ -278,7 +298,7 @@ Multiple sources agree.[@jones2019; @brown2021]
``` ```
Inline citations render as numbered superscripts `[1]`, `[2]`, etc. The Inline citations render as numbered superscripts `[1]`, `[2]`, etc. The
bibliography section appears automatically in the page footer. `citations.js` bibliography section appears automatically in the page footer. `popups.js`
adds hover previews showing the full reference. adds hover previews showing the full reference.
### Further reading ### Further reading
@ -754,9 +774,8 @@ at the top of the catalog.
## Page scripts ## Page scripts
For pages that need custom JavaScript (interactive widgets, visualisations, etc.), For pages that need custom JavaScript (interactive widgets, visualisations, etc.),
place the JS file alongside the content and reference it via the `js:` frontmatter reference the JS file via the `js:` frontmatter key. The file is injected as a
key. The file is copied to `_site/` and injected as a deferred `<script>` at the deferred `<script>` at the bottom of `<body>`.
bottom of `<body>`.
```yaml ```yaml
js: scripts/memento-mori.js # single file js: scripts/memento-mori.js # single file
@ -770,12 +789,18 @@ js:
- scripts/widget-b.js - scripts/widget-b.js
``` ```
Paths are relative to the content file. A composition at Paths are **site-root-relative**, not relative to the content file: the template
`content/music/symphony/index.md` with `js: scripts/widget.js` serves the emits the value verbatim with a leading `/` prepended. Write the path without a
script at `/music/symphony/scripts/widget.js`. leading slash. `js: scripts/widget.js` loads `/scripts/widget.js` regardless of
where the page lives — a composition at `content/music/symphony/index.md` with
that value does *not* get `/music/symphony/scripts/widget.js`.
No changes to the build system are needed — the `content/**/*.js` glob rule The script file must live where the build serves that URL. The `content/**/*.js`
copies all JS files from `content/` to `_site/` automatically. glob rule copies JS files to `_site/` with the `content/` prefix stripped, so
`content/scripts/widget.js` is served at `/scripts/widget.js` — this is the
current convention (the memento-mori page keeps its script at
`content/scripts/memento-mori.js` and references it as
`js: scripts/memento-mori.js`).
--- ---
@ -896,7 +921,8 @@ should copy and adapt it; the file documents the §2.2 visual contract
The version history footer section uses a three-tier fallback: The version history footer section uses a three-tier fallback:
1. **`history:` frontmatter** — your authored notes, shown exactly as written. 1. **`history:` frontmatter** — your authored notes. Entries may be listed in
any order — they are sorted by date at build time.
2. **Git log** — if no `history:` key, dates are extracted from `git log --follow`. 2. **Git log** — if no `history:` key, dates are extracted from `git log --follow`.
Entries have no message (date only). Entries have no message (date only).
3. **`date:` frontmatter** — if git has no commits for the file, falls back to 3. **`date:` frontmatter** — if git has no commits for the file, falls back to
@ -910,14 +936,50 @@ descriptive:
```yaml ```yaml
history: history:
- date: 2026-03-01
note: Initial draft
- date: 2026-03-14 - date: 2026-03-14
note: Expanded section 3; incorporated feedback from peer review note: Expanded section 3; incorporated feedback from peer review
- date: 2026-03-01
note: Initial draft
``` ```
--- ---
## Revision dates
The `revised:` key records substantive revisions and drives the date shown on
item cards and list pages. Two accepted shapes:
```yaml
revised: "2026-04-10" # scalar shorthand — one revision, no note
revised: # canonical list of objects
- date: "2026-04-10"
note: "expanded the section on Shestov"
- date: "2025-12-03" # note is optional per-entry
```
Dates are ISO `YYYY-MM-DD` strings. Entries may be listed in any order — they
are sorted by date at build time, most recent first. Entries missing `date:`
or carrying non-string values are silently dropped; the build never fails on
a malformed `revised:` block.
Effects:
- **`$date-display$` / `$date-iso$`** — cards and list pages show the
most-recent revision date instead of the creation date.
- **Sort order** — revision-aware lists (`/new.html`, tag pages, the library)
sort by the display date, so a freshly revised piece moves to the top.
- **`$date-original$`** — when the latest revision date differs from the
creation date, the card adds a "revised from …" annotation showing the
original date.
- **`$revision-note$`** — the note on the most-recent entry renders as an
italicized line under the abstract on the card.
`revised:` is independent of `history:` (the version-history footer above);
add a matching `history:` entry if the revision should appear there too.
---
## Typography features ## Typography features
Applied automatically at build time; no markup needed. Applied automatically at build time; no markup needed.