The banner draws all 9,194 chunks in one flat colour. `nodes.book` was in the
payload but only ever reached the tooltip, so nothing on screen said which book
or which region you were looking at.
This adds /reading: the same corpus at the pre-flight's 15/0.1 instead of the
banner's 50/0.8, coloured by kind of book, with any single title isolatable.
The two projections are NOT interchangeable, and that is why this is a separate
page rather than a mode of the banner. 50/0.8 was chosen *because* it blurs book
territory into something that reads as a cloud; showing that territory is the one
thing this page exists to do.
Renderer notes:
• Explorer mode turns on only when the payload actually carries a `kind`
layer, not when the caller asks for it — a page pointed at the banner's
file degrades to the flat cloud instead of throwing.
• Smaller and denser points (0.032/0.62 vs 0.055/0.3). Three hues piling up
in one volume average toward grey; that pairing is what keeps each one's
hue, and it is not cosmetic.
• Isolation dims to 8.5% rather than hiding. Against an empty frame you learn
where a book's chunks are and lose the only question worth asking, which is
where they sit relative to everything else.
• `nebulaBase` keeps a pristine copy of the vertex colours; dimming from an
already-dimmed buffer compounds and the cloud would fade on every hover.
Kind colours are slots 1-3 of the validated categorical palette, checked
ALL-PAIRS against this file's own #0b0d12 — a point cloud has no series order,
so the adjacent-pairs default that suits stacks and lines is the wrong test.
Worst pair CVD dE 9.4, worst normal-vision dE 20.9.
⚠️ `--map-kind-narrative` (aqua) sits near `--map-trace` (the garden green).
Tolerable only because form separates them absolutely — diffuse points versus
one continuous line — and nothing is encoded by the similarity. If the trace
ever becomes points, re-measure that pair.
The payload is gitignored for the same reason the banner's is: a tracked
generated file dirties the tree and breaks the `git pull` at the top of every
build tick. auto-build.sh's signature now watches both, or a corpus change
would rebuild one page and leave the other on yesterday's cloud.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
garden-astro
Astro rebuild of the digital garden at garden.c0smere.net, replacing
Quartz v4. Content stays in the Obsidian vault (Digital_Garden/ folder);
this repo is only the rendering pipeline.
URL compatibility
Built to be a drop-in replacement — every URL on the live Quartz site resolves identically here (verified against the live sitemap, 102/102):
- case preserved, spaces become
-, hyphens/em-dashes kept - leaf pages:
/Folder/Note-Name(build.format: 'file'+ nginxtry_files $uri $uri.html) - folder indexes:
/Folder/(fromFolder/index.md, or a synthetic listing page when no index exists)
Obsidian compatibility (src/lib/remark-obsidian.mjs)
[[wikilinks]]with aliases/anchors, resolved vault-path-first then by basename; unresolved links degrade to plain text![[image embeds]]and relativeboth rewrite to flat/assets/<name>URLs;scripts/copy-assets.mjsresolves the files (Digital_Garden first, then vault-wide) and copies them in at build time> [!type]callouts, KaTeX math, mermaid (lazy-loaded client-side only on pages that use it), shiki dual light/dark themesdraft:frontmatter excluded, including Quartz-style quoted"true"
Build
GARDEN_CONTENT=/path/to/vault/Digital_Garden npm run build
Defaults to the kotov vault copy. On cyrion use deploy/build.sh
(containerized node:24, vault mounted read-only), then
docker compose -f deploy/docker-compose.yml up -d serves dist/ on
port 18100, proxied as garden.c0smere.net (NPM public + Caddy internal).
marimo notebooks (/notebooks)
Notebooks from the marimo server (/home/nox/docker/marimo/notebooks/) can
be published into the garden. A notebook publishes only if it opts in, by
carrying this HTML comment in one of its markdown cells — invisible in the
rendered page, greppable in the .py source:
<!-- garden:publish
title: Dream of Spotification
description: A decade of Spotify history, worked two ways.
order: 30
-->
Only the garden:publish line is required. Optional keys: title,
description, order (sort weight, default 100), slug (URL override,
default derived from the filename), timeout (export seconds, default 600).
Delete the marker to unpublish — the next export run removes the page.
This is deliberately default-deny: garden.c0smere.net is public and the
export bakes each notebook's executed output into the page, not just its
code. deploy/export-notebooks.py also carries a NEVER_PUBLISH list
(genome_*, coursework) as a second latch, so a marker pasted into one of
those refuses loudly instead of publishing.
Pipeline:
deploy/export-notebooks.py(own timer,garden-notebooks-export.timer, every 30 min; own lock) scans for markers and runs each opted-in notebook in a one-shotmarimo:latestcontainer — same image and.envas the live server, so it hits the real databases. Output lands innotebooks-export/<slug>.htmlplus anindex.json.- Cached on notebook content: a run after no edits does no work.
- Per-notebook timeout, and a failure keeps the previous export and continues. A broken notebook can't take the garden down.
- It runs against a throwaway copy of the notebook dir, so notebooks that write scratch files don't dirty the notebooks git repo.
scripts/copy-notebooks.mjsstages those intopublic/nb/<slug>.html.- Astro reads
index.json(src/lib/notebooks.mjs) to build/notebooksand/notebooks/<slug>, which wrap the raw export in an iframe with the garden chrome, plus the sidebar section.
The raw export is at /nb/<slug>.html, deliberately not under
/notebooks — with build.format: 'file' the page and the raw file would
collide on the same URL.
URL shapes here are worth knowing, since build.format: 'file' makes the
listing a file (dist/notebooks.html) that sits beside a directory of
detail pages (dist/notebooks/<slug>.html). Verified against the running
nginx: /notebooks and /notebooks/<slug> resolve through the generic
try_files, but /notebooks/ does not — a bare directory has no
index.html. deploy/nginx.conf carries an explicit location = /notebooks/
so the trailing-slash form works like every other folder URL on the site.
Both notebooks-export/ and public/nb/ are gitignored: tracking them would
make every export dirty the tree, which flips auto-build.sh's change
signature and breaks the git pull at the top of each build tick. The
signature hashes notebooks-export/ separately instead.
Force a full re-export with deploy/export-notebooks.py --force.
Layout extras
Every page carries a left sidebar tree of the whole garden (folders
collapsible, current page highlighted; flows after the footer on narrow
screens) and the bandwidth odometer in the footer, fed by
https://api.c0smere.net/bandwidth/odometer. The widget animates at the
lifetime average rate from a fetched baseline — it never reflects live
throughput, and hides itself if the API is down.