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
make build # one-shot production build into _site/
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 deploy # clean → build → sign → push → rsync to VPS
```
`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
`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
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` |
| Composition | `content/music/{slug}/index.md` | `/music/{slug}/` |
| 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) |
File names become URL slugs. Use lowercase, hyphen-separated words.
If a standalone page embeds co-located SVG score fragments or other relative assets,
place it in its own directory (`content/my-page/index.md`) rather than as a flat file.
Score fragment paths are resolved relative to the source file's directory; a flat
`content/my-page.md` would resolve them from `content/`, which is wrong.
Flat `content/<page>.md` is the generic standalone form — any flat file dropped
into `content/` builds automatically. Directory-form standalone pages
(`content/my-page/index.md`) are **not** picked up by the generic rule; each one
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
abstract: > # optional; shown in the metadata block and link previews
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
- nonfiction
- nonfiction/philosophy
keywords: [lattices, simd] # optional; links to /bibliography/<keyword>/ pages (list or comma-separated string)
authors: # optional; overrides the default "Levi Neuwirth" link
- "Levi Neuwirth | /me.html"
- "Collaborator | https://their.site"
@ -79,7 +89,7 @@ further-reading: # optional; see Citations section
- someKey
- anotherKey
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
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)
@ -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
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:
- date: 2026-03-01 # ISO date; unquoted is fine (the Haskell YAML parser keeps it as a string)
note: Initial draft
- date: 2026-03-14
- date: 2026-03-14 # ISO date; unquoted is fine (the Haskell YAML parser keeps it as a string)
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/` |
| Music | `/music/` |
| Nonfiction | `/nonfiction/` |
| Photography | `/photography/` |
| Poetry | `/poetry/` |
| Research | `/research/` |
| Tech | `/tech/` |
@ -265,7 +284,8 @@ The URL part is optional.
## 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
`bibliography` and `csl`.
@ -278,7 +298,7 @@ Multiple sources agree.[@jones2019; @brown2021]
```
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.
### Further reading
@ -754,9 +774,8 @@ at the top of the catalog.
## Page scripts
For pages that need custom JavaScript (interactive widgets, visualisations, etc.),
place the JS file alongside the content and reference it via the `js:` frontmatter
key. The file is copied to `_site/` and injected as a deferred `<script>` at the
bottom of `<body>`.
reference the JS file via the `js:` frontmatter key. The file is injected as a
deferred `<script>` at the bottom of `<body>`.
```yaml
js: scripts/memento-mori.js # single file
@ -770,12 +789,18 @@ js:
- scripts/widget-b.js
```
Paths are relative to the content file. A composition at
`content/music/symphony/index.md` with `js: scripts/widget.js` serves the
script at `/music/symphony/scripts/widget.js`.
Paths are **site-root-relative**, not relative to the content file: the template
emits the value verbatim with a leading `/` prepended. Write the path without a
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
copies all JS files from `content/` to `_site/` automatically.
The script file must live where the build serves that URL. The `content/**/*.js`
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:
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`.
Entries have no message (date only).
3. **`date:` frontmatter** — if git has no commits for the file, falls back to
@ -910,14 +936,50 @@ descriptive:
```yaml
history:
- date: 2026-03-01
note: Initial draft
- date: 2026-03-14
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
Applied automatically at build time; no markup needed.