The same 9,194 passages arranged by seven embedding models, switchable. Every
model's coordinates are Procrustes-aligned to nomic, without which the toggle
would be seven unrelated arrangements and the motion between them meaningless.
⚠️ The page states the NEIGHBOUR-AGREEMENT number, not the animation, and the
distinction is load-bearing. Every projection of 1024 dimensions into 3 is lossy
in a way that shapes what you see: measured directly, PCA and UMAP disagreed by
10x about whether whole books move together, each reporting its own arithmetic.
So the claim is computed on the raw embeddings where there is no projection to
be an artifact of (models share ~50% of each passage's 15 nearest neighbours),
and the picture illustrates that number rather than being the evidence for it.
The page says so in as many words.
Renderer gains setCoordinates(), driven from the existing render loop rather
than its own rAF so a morph cannot outlive the scene or run while scrolled away.
It writes through the single `xyz` buffer the nebula, signal and trace all read
from, so every layer moves together and nothing drifts out of registration.
`trace` is now optional. The banner and explorer always carry one; a comparison
payload legitimately does not — its subject is where passages MOVE between
models, not the order they were highlighted in.
Payload is split: a 44 KB manifest with everything shared, plus one ~145 KB
coordinate file per model fetched on demand. The per-node book/kind arrays are
identical across models, so carrying them seven times is waste, and eager
loading would be ~1.1 MB before first paint.
auto-build.sh now watches public/reading_*.json as ONE glob. The previous
OR-chain was subtly broken — with `-o` the `-printf` binds only to the last
clause, so earlier matches printed in a different format and the signature was
not stable. The glob also picks up future payloads without an edit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
library-rag-export.service now regenerates reading_umap.json on cyrion
whenever the corpus or its located highlights move, writing straight into this
checkout. Keeping it tracked would defeat that: a generated file that changes
under git dirties the tree, which both flips auto-build.sh's change signature
and breaks the `git pull` at the top of every build tick — the reason
notebooks-export/ is already ignored, in that file's own words.
So it joins them: ignored, plus a find line in the signature block so the
5-minute tick still notices a new projection.
The cost is that a fresh checkout has no map until the service runs — on
cyrion that is within the hour, anywhere else never. ReadingMap.astro says so
where someone would hit it.
Notebooks from the marimo server can now appear in the garden. A notebook
opts in with an HTML comment in one of its markdown cells — invisible when
rendered, greppable in the .py source:
<!-- garden:publish
title: Dream of Spotification
order: 30
-->
Default-deny on purpose: garden.c0smere.net is public and the export bakes
each notebook's executed output into the page, not just its code.
export-notebooks.py also carries a NEVER_PUBLISH list (genome_*, coursework)
so a marker pasted into one of those refuses loudly instead of publishing.
Pipeline: export-notebooks.py runs each marked notebook in a one-shot
marimo container (same image/env/GPU as the live server, so it hits the real
databases) into notebooks-export/ + index.json; copy-notebooks.mjs stages
those to public/nb/; Astro reads index.json to build the pages and the
sidebar section.
Isolation choices worth keeping:
- Own timer and own lock, separate from the 5-min garden build — executing a
notebook takes minutes and must never hold up a build tick.
- Cached on notebook content; both index.json and .cache.json go through
write_if_changed, since auto-build.sh hashes mtimes under notebooks-export/
and an unconditional rewrite would force a full rebuild every 30 minutes.
- Per-notebook timeout; a failure keeps the previous export and continues.
- Runs against a throwaway copy of the notebook dir, so notebooks that write
scratch files don't dirty the notebooks repo.
- Notebooks are NOT injected into the garden collection — they aren't vault
notes, and doing so would move noteCount and the sitemap.
build.format:'file' makes the listing a file (notebooks.html) beside a
directory of detail pages. Verified against the running nginx: /notebooks and
/notebooks/<slug> resolve through the generic try_files but /notebooks/ does
not, so nginx.conf gets an explicit location for the trailing-slash form.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- deploy/rebuild-hook.py: tiny stdlib HTTP service (:18101) — button
page for the Homepage dashboard iframe, POST /rebuild runs
auto-build.sh --force, /status + /healthz for feedback/monitoring
- auto-build.sh: --force flag + flock so timer and manual builds
serialize
- [...slug].astro: skip the synthetic h1 when the note body already
opens with an identical h1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- deploy/auto-build.sh: git pull + rebuild only when the repo HEAD or any
vault file mtime changed (sha256 signature in .build_state); replaces
the Quartz update_quartz_docker.sh loop
- systemd user units (5-min cadence, matching the old Quartz timer)
- compose service/container renamed garden-next -> garden
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>