Configuration Guide#
This guide will walk you through configuring your AT Protocol-powered personal website. Follow these steps in order to set up your site correctly.
Table of Contents#
- Prerequisites
- Environment Configuration
- Publication Slug Mapping
- Static File Customization
- Optional Features
- Advanced Configuration
- Verification
- Troubleshooting
Prerequisites#
Before you begin configuration, ensure you have:
- Node.js 18+ installed
- npm package manager
- An AT Protocol DID (Decentralized Identifier) from Bluesky
- Basic knowledge of environment variables and JSON configuration
Finding Your DID#
Your DID is your unique identifier in the AT Protocol network.
Using PDSls (Recommended)#
- Visit PDSls
- Enter your Bluesky handle (e.g.,
username.bsky.social) - Look for the
Repositoryfield - your DID will be in the formatdid:plc:...ordid:web:... - Click the arrow to the right if the full DID is not visible
Example DID: did:plc:abcdef123456xyz
Environment Configuration#
Step 1: Create Your Environment File#
Copy the example environment file:
cp .env.example .env.local
Important: Use .env.local for your personal configuration. This file is ignored by git and keeps your settings private.
Step 2: Configure Required Variables#
Edit .env.local and set these required values:
# Your AT Protocol DID (Required)
PUBLIC_ATPROTO_DID=did:plc:your-actual-did-here
# Site Metadata (Required)
PUBLIC_SITE_TITLE="Your Site Name"
PUBLIC_SITE_DESCRIPTION="A brief description of your website"
PUBLIC_SITE_KEYWORDS="keywords, about, your, site"
PUBLIC_SITE_URL="https://yourdomain.com"
Critical: Replace your-actual-did-here with your actual DID from the Prerequisites section.
Step 3: Configure Optional Variables#
Add these optional settings based on your needs:
# WhiteWind Support (Optional, default: false)
# Set to "true" only if you use WhiteWind for blogging
PUBLIC_ENABLE_WHITEWIND=false
# Blog Fallback URL (Optional)
# Where to redirect if a blog post isn't found
# Leave empty to show a 404 error instead
PUBLIC_BLOG_FALLBACK_URL=""
# Slingshot Configuration (Optional)
# For development with local Slingshot instance
PUBLIC_LOCAL_SLINGSHOT_URL="http://localhost:3000"
PUBLIC_SLINGSHOT_URL="https://slingshot.microcosm.blue"
# CORS Configuration (Optional, but recommended)
# Comma-separated list of domains allowed to access your API
# Use "*" for development only (not secure for production)
PUBLIC_CORS_ALLOWED_ORIGINS="https://yourdomain.com"
Environment Variable Reference#
| Variable | Required | Default | Purpose |
|---|---|---|---|
PUBLIC_ATPROTO_DID |
✅ Yes | - | Your AT Protocol identifier |
PUBLIC_SITE_TITLE |
✅ Yes | - | Website title for SEO |
PUBLIC_SITE_DESCRIPTION |
✅ Yes | - | Website description for SEO |
PUBLIC_SITE_KEYWORDS |
✅ Yes | - | SEO keywords |
PUBLIC_SITE_URL |
✅ Yes | - | Your website's URL |
PUBLIC_ENABLE_WHITEWIND |
❌ No | false |
Enable WhiteWind blog support |
PUBLIC_BLOG_FALLBACK_URL |
❌ No | "" |
Fallback URL for missing posts |
PUBLIC_LOCAL_SLINGSHOT_URL |
❌ No | "" |
Local Slingshot instance URL |
PUBLIC_SLINGSHOT_URL |
❌ No | Public URL | Public Slingshot instance |
PUBLIC_CORS_ALLOWED_ORIGINS |
❌ No | "*" |
CORS allowed origins |
Publication Slug Mapping#
The slug mapping system allows you to access your Leaflet publications via friendly URLs.
Understanding Slugs#
- Slug: A friendly URL segment (e.g.,
blog,essays,notes) - Publication Rkey: The unique identifier of your Leaflet publication
- URL Format: Your publications will be accessible at
https://yoursite.com/{slug}
Step 1: Find Your Publication Rkeys#
- Visit your Leaflet publication on leaflet.pub
- Look at the URL format:
https://leaflet.pub/lish/{did}/{publication-rkey} - Copy the
{publication-rkey}portion (e.g.,3m3x4bgbsh22k)
Example URL: https://leaflet.pub/lish/did:plc:abc123/3m3x4bgbsh22k
- Publication Rkey:
3m3x4bgbsh22k
Step 2: Configure Slugs#
Edit src/lib/config/slugs.ts:
import type { SlugMapping } from '$lib/services/atproto';
/**
* Maps friendly URL slugs to Leaflet publication rkeys
*
* Example usage:
* - { slug: 'blog', publicationRkey: '3m3x4bgbsh22k' }
* Accessible at: /blog
* - { slug: 'essays', publicationRkey: 'xyz789abc' }
* Accessible at: /essays
*/
export const slugMappings: SlugMapping[] = [
{
slug: 'blog',
publicationRkey: '3m3x4bgbsh22k' // Replace with your actual rkey
}
// Add more mappings as needed:
// {
// slug: 'essays',
// publicationRkey: 'your-essays-rkey'
// },
// {
// slug: 'notes',
// publicationRkey: 'your-notes-rkey'
// }
];
Step 3: Understand URL Structure#
Once configured, your publications are accessible via:
- Publication Homepage:
/{slug}→ Redirects to Leaflet publication - Individual Posts:
/{slug}/{post-rkey}→ Redirects to specific post - RSS Feed:
/{slug}/rss→ RSS feed for the publication
Example:
- Configuration:
{ slug: 'blog', publicationRkey: '3m3x4bgbsh22k' } - Homepage:
https://yoursite.com/blog - Post:
https://yoursite.com/blog/3abc789xyz - RSS:
https://yoursite.com/blog/rss
Multiple Publications Example#
export const slugMappings: SlugMapping[] = [
{
slug: 'blog', // Main blog
publicationRkey: '3m3x4bgbsh22k'
},
{
slug: 'tech', // Tech articles
publicationRkey: 'xyz789tech'
},
{
slug: 'personal', // Personal writing
publicationRkey: 'abc456personal'
}
];
Static File Customization#
Several static files need to be customized for your site.
Files to Update#
| File | Purpose | Action Required |
|---|---|---|
static/robots.txt |
SEO crawling rules | Update sitemap URL |
static/sitemap.xml |
Site structure for SEO | Update with your pages |
static/.well-known/* |
Domain verification | Replace or remove |
static/favicon/* |
Site icons | Replace with your branding |
Step 1: Update robots.txt#
Edit static/robots.txt:
User-agent: *
Allow: /
# Update this line with your actual domain
Sitemap: https://yourdomain.com/sitemap.xml
Step 2: Update sitemap.xml#
Edit static/sitemap.xml:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<!-- Homepage -->
<url>
<loc>https://yourdomain.com/</loc>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<!-- Add your publication slugs -->
<url>
<loc>https://yourdomain.com/blog</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<!-- Add other important pages -->
<url>
<loc>https://yourdomain.com/site/meta</loc>
<changefreq>monthly</changefreq>
<priority>0.5</priority>
</url>
</urlset>
Step 3: Update Favicon#
Replace files in static/favicon/:
- Generate favicons using RealFaviconGenerator
- Replace all files in
static/favicon/with your generated icons - Ensure these files are present:
favicon.icoapple-touch-icon.pngfavicon-16x16.pngfavicon-32x32.pngsite.webmanifest
Step 4: Update or Remove .well-known Files#
The static/.well-known/ directory contains domain verification files.
Option A: Replace with your own#
rm -rf static/.well-known/*
# Add your own verification files here
Option B: Remove entirely (if you don't need verification)#
rm -rf static/.well-known/
Common .well-known files:
atproto-did- AT Protocol domain verificationsecurity.txt- Security contact information- Domain verification files for various services
Optional Features#
WhiteWind Blog Support#
When to enable: If you publish blog posts on WhiteWind (com.whtwnd.blog.entry records).
Configuration:
# In .env.local
PUBLIC_ENABLE_WHITEWIND=true
Behavior:
-
With WhiteWind disabled (default):
- Only Leaflet posts are fetched and displayed
- RSS feeds redirect to Leaflet's native feeds
- Post redirects only check Leaflet
-
With WhiteWind enabled:
- Both Leaflet and WhiteWind posts are displayed
- RSS feeds include links to WhiteWind posts
- Post redirects check Leaflet first, then WhiteWind
- Draft and non-public WhiteWind posts are filtered out
Note: Most users should keep WhiteWind disabled unless they specifically use it.
Custom Blog Fallback#
Redirect users to an archive or external blog when posts aren't found.
# In .env.local
PUBLIC_BLOG_FALLBACK_URL="https://archive.yourdomain.com"
Behavior:
- If a post isn't found on Leaflet (or WhiteWind)
- AND
PUBLIC_BLOG_FALLBACK_URLis set - Then redirect to:
{FALLBACK_URL}/{slug}/{rkey}
Example:
- Missing post:
/blog/3abc789 - Redirects to:
https://archive.yourdomain.com/blog/3abc789
CORS Configuration#
Control which domains can access your API endpoints.
Development (allow all):
PUBLIC_CORS_ALLOWED_ORIGINS="*"
Production (specific domains):
# Single domain
PUBLIC_CORS_ALLOWED_ORIGINS="https://yourdomain.com"
# Multiple domains
PUBLIC_CORS_ALLOWED_ORIGINS="https://yourdomain.com,https://app.yourdomain.com,https://www.yourdomain.com"
Security Note: Always use specific domain lists in production, never use *.
Advanced Configuration#
Custom Lexicon Support#
The site automatically displays data from these AT Protocol lexicons:
Site Information (uk.ewancroft.site.info)#
- Technology stack
- Privacy statements
- Credits and licenses
- No configuration needed - automatically fetched
Music Status (fm.teal.alpha.*)#
- Current playing status via teal.fm
- Automatic album artwork from MusicBrainz
- Scrobbles from Last.fm, Spotify, etc.
- No configuration needed
Mood Status (social.kibun.status)#
- Current mood/feeling via kibun.social
- Emoji and text display
- No configuration needed
Link Board (blue.linkat.board)#
- Curated link collections from Linkat
- Emoji icons for each link
- No configuration needed
Tangled Repositories (sh.tangled.repo)#
- Code repository display
- Descriptions, labels, creation dates
- No configuration needed
All lexicons are automatically fetched using your PUBLIC_ATPROTO_DID
Slingshot Configuration#
Slingshot is an AT Protocol data aggregator for faster queries.
# Local development instance (optional)
PUBLIC_LOCAL_SLINGSHOT_URL="http://localhost:3000"
# Public instance (default fallback)
PUBLIC_SLINGSHOT_URL="https://slingshot.microcosm.blue"
Default Behavior:
- Try local Slingshot (if URL is set and reachable)
- Fallback to public Slingshot
- Fallback to user's PDS
- Fallback to Bluesky public API
Note: Most users can leave these at their defaults.
Theme Customization#
The site uses Tailwind CSS with custom semantic colors. To customize:
- Edit
src/app.cssfor global color scheme:
@theme {
--color-canvas: /* Background color */;
--color-ink: /* Text color */;
--color-primary: /* Accent color */;
}
-
Dark mode colors are automatically adjusted via Tailwind's
dark:variants -
Wolf mode and theme toggle work automatically with any color scheme
Verification#
After configuration, verify everything works:
Step 1: Install Dependencies#
npm install
Step 2: Start Development Server#
npm run dev
Visit http://localhost:5173
Step 3: Check Core Features#
Verify these elements appear correctly:
-
Profile Card: Shows your Bluesky profile information
- Avatar and banner image
- Display name and handle
- Bio text
- Follower/following counts
-
Site Metadata: Check
http://localhost:5173/site/meta- Site information loads correctly
- Credits, tech stack, privacy info display
-
Blog Access: Test your slug configuration
- Visit
http://localhost:5173/{your-slug} - Should redirect to your Leaflet publication
- RSS feed works at
http://localhost:5173/{your-slug}/rss
- Visit
-
Optional Features (if enabled):
- Music status card (if you use teal.fm)
- Mood status card (if you use kibun.social)
- Link board (if you use Linkat)
- Repositories (if you use Tangled)
- Latest Bluesky post
Step 4: Check Browser Console#
Open browser DevTools (F12) and check for:
- ✅ No error messages in Console tab
- ✅ Successful API responses in Network tab
- ✅ No 404 errors for static files
Step 5: Test Responsive Design#
Check the site at different screen sizes:
- Mobile (375px width)
- Tablet (768px width)
- Desktop (1280px+ width)
Step 6: Verify SEO Metadata#
View page source and check for:
<title>tag with your site title<meta name="description">with your description- Open Graph tags (
og:title,og:description, etc.) - Twitter Card tags (
twitter:card,twitter:title, etc.)
Troubleshooting#
Profile Data Not Loading#
Symptom: Profile card shows "Profile not found" or loading state persists
Solutions:
- Verify
PUBLIC_ATPROTO_DIDis correct in.env.local - Check your DID format: should be
did:plc:...ordid:web:... - Ensure your Bluesky account is active and public
- Check browser console for specific error messages
- Clear cache and hard refresh (Ctrl+Shift+R / Cmd+Shift+R)
Publications Not Found#
Symptom: Blog pages show 404 or "Not Found" errors
Solutions:
- Verify publication rkey in
src/lib/config/slugs.tsmatches your Leaflet publication - Visit your Leaflet publication URL and confirm the rkey is correct
- Ensure the publication is public (not draft/private)
- Check if documents exist in the publication
- If using WhiteWind, verify
PUBLIC_ENABLE_WHITEWIND=trueif needed
Music Status Not Showing#
Symptom: Music card doesn't appear or shows no data
Solutions:
- Verify you have teal.fm configured with your Bluesky account
- Check if you have any scrobbles in your teal.fm history
- Ensure your scrobbler (e.g., piper) is running and connected
- Album artwork requires MusicBrainz IDs or blob storage
- Check browser console for MusicBrainz API errors
RSS Feeds Not Working#
Symptom: RSS feed shows errors or no posts
Solutions:
- Check slug configuration in
src/lib/config/slugs.ts - Verify publication has published documents (not drafts)
- If using WhiteWind:
- Ensure
PUBLIC_ENABLE_WHITEWIND=true - Verify you have published WhiteWind posts
- Ensure
- Test feed URL directly:
http://localhost:5173/{slug}/rss - Check Content-Type header is
application/rss+xml
Environment Variables Not Applied#
Symptom: Changes to .env.local don't take effect
Solutions:
- Restart the development server (
npm run dev) - Verify variable names start with
PUBLIC_for client-side access - Check for typos in variable names
- Ensure
.env.localis in the project root directory - Clear
.svelte-kitcache:rm -rf .svelte-kit && npm run dev
Build Errors#
Symptom: npm run build fails with errors
Solutions:
# Clean build artifacts
rm -rf .svelte-kit node_modules package-lock.json
# Reinstall dependencies
npm install
# Try building again
npm run build
CORS Errors in Production#
Symptom: API requests fail with CORS errors
Solutions:
- Add your production domain to
PUBLIC_CORS_ALLOWED_ORIGINS - Ensure the domain includes the protocol (
https://) - For multiple domains, separate with commas (no spaces)
- Avoid using
*in production for security - Check that the origin header matches exactly (including www or non-www)
TypeScript Errors#
Symptom: Type errors in development
Solutions:
# Run type checking
npm run check
# Watch mode for continuous checking
npm run check:watch
# Clear and rebuild
rm -rf .svelte-kit && npm run dev
Dark Mode Not Working#
Symptom: Dark mode toggle doesn't change theme
Solutions:
- Check if browser supports
prefers-color-scheme - Clear browser localStorage:
localStorage.clear()in console - Verify Tailwind's dark mode is configured in
tailwind.config.js - Check that dark mode classes are present in HTML (inspect element)
Wolf Mode Issues#
Symptom: Wolf mode toggle doesn't transform text
Solutions:
- Ensure JavaScript is enabled in browser
- Check browser console for errors
- Verify the wolf mode store is imported correctly
- Test on different text elements to confirm it's working
- Remember: numbers and navigation are intentionally preserved
Getting Help#
If you encounter issues not covered here:
- Check Browser Console: Press F12 and look for error messages
- Review README: See README.md for detailed feature documentation
- GitHub Issues: Search existing issues or create a new one
- AT Protocol Docs: Visit atproto.com for protocol details
- SvelteKit Docs: Check kit.svelte.dev for framework help
Useful Debugging Commands#
# Check environment variables are loaded
npm run dev -- --debug
# View detailed build output
npm run build -- --verbose
# Type-check without building
npm run check
# Format code (may fix some issues)
npm run format
Log Collection for Bug Reports#
When reporting issues, include:
- Browser console errors (F12 → Console tab)
- Network tab showing failed requests (F12 → Network tab)
- Your
.env.localconfiguration (remove sensitive data like DIDs) - Node.js and npm versions:
node --version && npm --version - Operating system and browser version
Next Steps#
After completing configuration:
-
Customize Content:
- Update your Bluesky profile bio and banner
- Publish posts to your Leaflet publications
- Add site information via AT Protocol records
-
Deploy Your Site:
- See README.md for deployment options
- Choose a platform (Vercel, Netlify, Cloudflare Pages, etc.)
- Configure production environment variables
- Set up custom domain
-
Enhance Your Site:
- Add custom styling in
src/app.css - Create new components in
src/lib/components/ - Extend functionality with new AT Protocol lexicons
- Customize layouts and pages
- Add custom styling in
-
Monitor and Maintain:
- Check RSS feeds regularly
- Update dependencies:
npm update - Monitor browser console for errors
- Keep AT Protocol records up to date
Configuration Checklist#
Use this checklist to track your configuration progress:
Required Configuration#
- Set
PUBLIC_ATPROTO_DIDin.env.local - Set
PUBLIC_SITE_TITLEin.env.local - Set
PUBLIC_SITE_DESCRIPTIONin.env.local - Set
PUBLIC_SITE_KEYWORDSin.env.local - Set
PUBLIC_SITE_URLin.env.local - Configure slug mappings in
src/lib/config/slugs.ts - Update
static/robots.txtwith your domain - Update
static/sitemap.xmlwith your pages
Optional Configuration#
- Enable WhiteWind support (if needed)
- Configure blog fallback URL (if desired)
- Set CORS allowed origins for production
- Replace favicon files with your branding
- Update or remove
.well-knownfiles - Configure Slingshot URLs (if using local instance)
Verification (Checklist)#
- Development server starts without errors
- Profile card loads correctly
- Blog slug redirects work
- RSS feeds generate successfully
- Optional features display (if enabled)
- SEO metadata is correct in page source
- Site works on mobile, tablet, and desktop
- Dark mode and wolf mode toggles work
Deployment Preparation#
- Test production build:
npm run build - Preview production build:
npm run preview - Configure production environment variables
- Choose and configure deployment platform
- Set up custom domain (if applicable)
- Configure SSL certificate (handled by most platforms)
Configuration complete! Your AT Protocol-powered personal website is ready to use. For detailed feature documentation, see README.md.