Web-Mercator slippy projection for both tiles and rides (exact alignment), dark tint to keep the garden tone, label halos for legibility over imagery, required Esri attribution. Google tiles were ruled out (ToS requires the Maps JS API + key/billing). Co-Authored-By: Claude Fable 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).
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.