spores.garden#
A digital garden that goes where you go.
spores.garden is a personal website builder powered by your AT Protocol data. Curate your records, pick layouts, customize your space. Your content stays in your PDS—the website is just a view.
Quick Start#
npm install
npm run dev
Then open your browser to:
http://127.0.0.1:5174(or the port shown in your terminal)
You will see a "Connect" button. Log in with your Bluesky/AT Protocol handle (e.g., user.bsky.social) to view and edit your garden.
You can also directly view gardens by URL:
http://127.0.0.1:5174/@your-handle.bsky.social(path-based with handle)http://127.0.0.1:5174/did:plc:your-did-here(path-based with DID)
How It Works#
- Load ALL records from your PDS - any lexicon
- Select record types to display
- Map to layouts (post, card, image, leaflet, etc.)
- Customize with themes and custom CSS
- Save config to your PDS
Lexicons#
Writes use the coop.hypha.spores.* namespace; reads fall back to garden.spores.* for legacy data.
Site Configuration:
coop.hypha.spores.site.config- Site configuration (title, subtitle)coop.hypha.spores.site.layout- Layout preferencescoop.hypha.spores.site.section- Individual section definitionscoop.hypha.spores.site.profile- Profile / about-me record
User Content:
coop.hypha.spores.content.text- Text content recordscoop.hypha.spores.content.image- Image content records
Social/Interactive:
coop.hypha.spores.social.flower- Flowers planted in gardenscoop.hypha.spores.social.takenFlower- Flowers collected from other gardenscoop.hypha.spores.item.specialSpore- Special spore items (capture-the-flag mechanic)
Generative (Client-Side Only):
- Themes and sections are generated deterministically from your DID on every load—never stored on PDS
Architecture#
Static Site → Slingshot (records) + Constellation (backlinks) → Your PDS
- Slingshot: Fast record fetching cache
- Constellation: Backlink indexing for flower interactions and special spore tracking
- atcute: OAuth for AT Protocol
Project Structure#
/src/components/- Web Componentssite-app.ts- Main application coordinatorsite-*.ts- Modular app components (Auth, Editor, Router, Renderer, Data, Interactions)section-block.ts- Content block rendering
/src/layouts/- Record rendering layouts/src/records/- AT Protocol record loading and field extraction/src/themes/- Theme engine and presets/lexicons/- AT Protocol lexicon definitions/docs/- Documentation
Layouts#
| Layout | Best For |
|---|---|
post |
Blog posts, articles |
card |
Short content |
image |
Photos, art |
link |
Single link preview |
links |
Link tree |
list |
Generic list |
profile |
About section |
raw |
Custom HTML |
leaflet |
Long-form articles from standard.site |
smoke-signal |
Events (hosting/attending) |
flower-bed |
Flower garden display |
collected-flowers |
Collected flowers display |
Layouts extract common fields (title, content, image, date, etc.) from any lexicon.
Special Spores#
Special spores are rare, gamified items that implement a capture-the-flag mechanic:
- Rarity: Only 1 in 10 new gardens receives a special spore (10% probability on first config)
- Capture Mechanics: Users can steal spores from gardens, but rapid re-steals are blocked for 1 minute
- Backlink-Based: All spore records reference the origin garden via backlinks, enabling full lineage tracking
- Timestamp Guardrail: Capture records with
createdAtmore than 5 minutes in the future are ignored - Evolution: Complete history of all captures is preserved and displayed chronologically
See Special Spore Documentation for detailed implementation and mechanics.
Themes#
Built-in presets: minimal, dark, bold, retro
Custom CSS supported for full control.
Testing#
npm test # Run tests in watch mode
npm run test:run # Run tests once
npm run test:ui # Run tests with UI
npm run typecheck # TypeScript type check
npm run check # Strict pre-launch gate (typecheck + tests + build)
npm run test:e2e # Playwright smoke tests (requires @playwright/test + browsers)
Debug Logging#
Verbose runtime logs are disabled by default. Enable them when debugging with either:
- query param:
?debug=1 - local storage:
localStorage.setItem('spores.garden.debug', '1')
Deployment Notes#
- Namespace behavior is now new-first by default:
- writes use
coop.hypha.spores.* - reads use
coop.hypha.spores.*with fallback togarden.spores.*
- writes use
- Copy
.env.exampleto.env.localfor local development overrides.
Developer Utilities#
node scripts/special-spore-probability.js did:plc:...to check deterministic spore assignment for a DID.scripts/special-spore-helper.htmlbrowser helper page for manual spore checks.npm run garden:backup/npm run garden:reset -- --dry-run|--yes/npm run garden:restore -- --from <file>for onboarding validation against real account data.
Documentation#
- Documentation Index - Entry point for project documentation
- Architecture Overview - Runtime architecture and module boundaries
- Layout System Developer Guide - Learn how to create custom layouts
- Special Spore Documentation - Special spore mechanics and implementation
- Contributing Guide - Development workflow and quality gates
- Security Policy - Vulnerability reporting and disclosure process
- Code of Conduct - Community participation expectations
License#
MIT