my website at ewancroft.uk
1# Configuration Guide
2
3This guide will walk you through configuring your AT Protocol-powered personal website. Follow these steps in order to set up your site correctly.
4
5## Table of Contents
6
71. [Prerequisites](#prerequisites)
82. [Environment Configuration](#environment-configuration)
93. [Publication Slug Mapping](#publication-slug-mapping)
104. [Static File Customization](#static-file-customization)
115. [Optional Features](#optional-features)
126. [Advanced Configuration](#advanced-configuration)
137. [Verification](#verification)
148. [Troubleshooting](#troubleshooting)
15
16---
17
18## Prerequisites
19
20Before you begin configuration, ensure you have:
21
22- **Node.js 18+** installed
23- **npm** package manager
24- An **AT Protocol DID** (Decentralized Identifier) from Bluesky
25- Basic knowledge of environment variables and JSON configuration
26
27### Finding Your DID
28
29Your DID is your unique identifier in the AT Protocol network.
30
31#### Using PDSls (Recommended)
32
331. Visit [PDSls](https://pdsls.dev/)
342. Enter your Bluesky handle (e.g., `username.bsky.social`)
353. Look for the `Repository` field - your DID will be in the format `did:plc:...` or `did:web:...`
364. Click the arrow to the right if the full DID is not visible
37
38**Example DID**: `did:plc:abcdef123456xyz`
39
40---
41
42## Environment Configuration
43
44### Step 1: Create Your Environment File
45
46Copy the example environment file:
47
48```bash
49cp .env.example .env.local
50```
51
52**Important**: Use `.env.local` for your personal configuration. This file is ignored by git and keeps your settings private.
53
54### Step 2: Configure Required Variables
55
56Edit `.env.local` and set these **required** values:
57
58```ini
59# Your AT Protocol DID (Required)
60PUBLIC_ATPROTO_DID=did:plc:your-actual-did-here
61
62# Site Metadata (Required)
63PUBLIC_SITE_TITLE="Your Site Name"
64PUBLIC_SITE_DESCRIPTION="A brief description of your website"
65PUBLIC_SITE_KEYWORDS="keywords, about, your, site"
66PUBLIC_SITE_URL="https://yourdomain.com"
67```
68
69**Critical**: Replace `your-actual-did-here` with your actual DID from the Prerequisites section.
70
71### Step 3: Configure Optional Variables
72
73Add these optional settings based on your needs:
74
75```ini
76# WhiteWind Support (Optional, default: false)
77# Set to "true" only if you use WhiteWind for blogging
78PUBLIC_ENABLE_WHITEWIND=false
79
80# Blog Fallback URL (Optional)
81# Where to redirect if a blog post isn't found
82# Leave empty to show a 404 error instead
83PUBLIC_BLOG_FALLBACK_URL=""
84
85# Slingshot Configuration (Optional)
86# For development with local Slingshot instance
87PUBLIC_LOCAL_SLINGSHOT_URL="http://localhost:3000"
88PUBLIC_SLINGSHOT_URL="https://slingshot.microcosm.blue"
89
90# CORS Configuration (Optional, but recommended)
91# Comma-separated list of domains allowed to access your API
92# Use "*" for development only (not secure for production)
93PUBLIC_CORS_ALLOWED_ORIGINS="https://yourdomain.com"
94```
95
96### Environment Variable Reference
97
98| Variable | Required | Default | Purpose |
99|----------|----------|---------|---------|
100| `PUBLIC_ATPROTO_DID` | ✅ Yes | - | Your AT Protocol identifier |
101| `PUBLIC_SITE_TITLE` | ✅ Yes | - | Website title for SEO |
102| `PUBLIC_SITE_DESCRIPTION` | ✅ Yes | - | Website description for SEO |
103| `PUBLIC_SITE_KEYWORDS` | ✅ Yes | - | SEO keywords |
104| `PUBLIC_SITE_URL` | ✅ Yes | - | Your website's URL |
105| `PUBLIC_ENABLE_WHITEWIND` | ❌ No | `false` | Enable WhiteWind blog support |
106| `PUBLIC_BLOG_FALLBACK_URL` | ❌ No | `""` | Fallback URL for missing posts |
107| `PUBLIC_LOCAL_SLINGSHOT_URL` | ❌ No | `""` | Local Slingshot instance URL |
108| `PUBLIC_SLINGSHOT_URL` | ❌ No | Public URL | Public Slingshot instance |
109| `PUBLIC_CORS_ALLOWED_ORIGINS` | ❌ No | `"*"` | CORS allowed origins |
110
111---
112
113## Publication Slug Mapping
114
115The slug mapping system allows you to access your Leaflet publications via friendly URLs.
116
117### Understanding Slugs
118
119- **Slug**: A friendly URL segment (e.g., `blog`, `essays`, `notes`)
120- **Publication Rkey**: The unique identifier of your Leaflet publication
121- **URL Format**: Your publications will be accessible at `https://yoursite.com/{slug}`
122
123### Step 1: Find Your Publication Rkeys
124
1251. Visit your Leaflet publication on [leaflet.pub](https://leaflet.pub/)
1262. Look at the URL format: `https://leaflet.pub/lish/{did}/{publication-rkey}`
1273. Copy the `{publication-rkey}` portion (e.g., `3m3x4bgbsh22k`)
128
129**Example URL**: `https://leaflet.pub/lish/did:plc:abc123/3m3x4bgbsh22k`
130
131- **Publication Rkey**: `3m3x4bgbsh22k`
132
133### Step 2: Configure Slugs
134
135Edit `src/lib/config/slugs.ts`:
136
137```typescript
138import type { SlugMapping } from '$lib/services/atproto';
139
140/**
141 * Maps friendly URL slugs to Leaflet publication rkeys
142 *
143 * Example usage:
144 * - { slug: 'blog', publicationRkey: '3m3x4bgbsh22k' }
145 * Accessible at: /blog
146 * - { slug: 'essays', publicationRkey: 'xyz789abc' }
147 * Accessible at: /essays
148 */
149export const slugMappings: SlugMapping[] = [
150 {
151 slug: 'blog',
152 publicationRkey: '3m3x4bgbsh22k' // Replace with your actual rkey
153 }
154 // Add more mappings as needed:
155 // {
156 // slug: 'essays',
157 // publicationRkey: 'your-essays-rkey'
158 // },
159 // {
160 // slug: 'notes',
161 // publicationRkey: 'your-notes-rkey'
162 // }
163];
164```
165
166### Step 3: Understand URL Structure
167
168Once configured, your publications are accessible via:
169
170- **Publication Homepage**: `/{slug}` → Redirects to Leaflet publication
171- **Individual Posts**: `/{slug}/{post-rkey}` → Redirects to specific post
172- **RSS Feed**: `/{slug}/rss` → RSS feed for the publication
173
174**Example**:
175
176- Configuration: `{ slug: 'blog', publicationRkey: '3m3x4bgbsh22k' }`
177- Homepage: `https://yoursite.com/blog`
178- Post: `https://yoursite.com/blog/3abc789xyz`
179- RSS: `https://yoursite.com/blog/rss`
180
181### Multiple Publications Example
182
183```typescript
184export const slugMappings: SlugMapping[] = [
185 {
186 slug: 'blog', // Main blog
187 publicationRkey: '3m3x4bgbsh22k'
188 },
189 {
190 slug: 'tech', // Tech articles
191 publicationRkey: 'xyz789tech'
192 },
193 {
194 slug: 'personal', // Personal writing
195 publicationRkey: 'abc456personal'
196 }
197];
198```
199
200---
201
202## Static File Customization
203
204Several static files need to be customized for your site.
205
206### Files to Update
207
208| File | Purpose | Action Required |
209|------|---------|-----------------|
210| `static/robots.txt` | SEO crawling rules | Update sitemap URL |
211| `static/sitemap.xml` | Site structure for SEO | Update with your pages |
212| `static/.well-known/*` | Domain verification | Replace or remove |
213| `static/favicon/*` | Site icons | Replace with your branding |
214
215### Step 1: Update robots.txt
216
217Edit `static/robots.txt`:
218
219```text
220User-agent: *
221Allow: /
222
223# Update this line with your actual domain
224Sitemap: https://yourdomain.com/sitemap.xml
225```
226
227### Step 2: Update sitemap.xml
228
229Edit `static/sitemap.xml`:
230
231```xml
232<?xml version="1.0" encoding="UTF-8"?>
233<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
234 <!-- Homepage -->
235 <url>
236 <loc>https://yourdomain.com/</loc>
237 <changefreq>daily</changefreq>
238 <priority>1.0</priority>
239 </url>
240
241 <!-- Add your publication slugs -->
242 <url>
243 <loc>https://yourdomain.com/blog</loc>
244 <changefreq>weekly</changefreq>
245 <priority>0.8</priority>
246 </url>
247
248 <!-- Add other important pages -->
249 <url>
250 <loc>https://yourdomain.com/site/meta</loc>
251 <changefreq>monthly</changefreq>
252 <priority>0.5</priority>
253 </url>
254</urlset>
255```
256
257### Step 3: Update Favicon
258
259Replace files in `static/favicon/`:
260
2611. Generate favicons using [RealFaviconGenerator](https://realfavicongenerator.net/)
2622. Replace all files in `static/favicon/` with your generated icons
2633. Ensure these files are present:
264 - `favicon.ico`
265 - `apple-touch-icon.png`
266 - `favicon-16x16.png`
267 - `favicon-32x32.png`
268 - `site.webmanifest`
269
270### Step 4: Update or Remove .well-known Files
271
272The `static/.well-known/` directory contains domain verification files.
273
274#### Option A: Replace with your own
275
276```bash
277rm -rf static/.well-known/*
278# Add your own verification files here
279```
280
281#### Option B: Remove entirely (if you don't need verification)
282
283```bash
284rm -rf static/.well-known/
285```
286
287Common `.well-known` files:
288
289- `atproto-did` - AT Protocol domain verification
290- `security.txt` - Security contact information
291- Domain verification files for various services
292
293---
294
295## Optional Features
296
297### WhiteWind Blog Support
298
299**When to enable**: If you publish blog posts on WhiteWind (`com.whtwnd.blog.entry` records).
300
301**Configuration**:
302
303```ini
304# In .env.local
305PUBLIC_ENABLE_WHITEWIND=true
306```
307
308**Behavior**:
309
310- With WhiteWind **disabled** (default):
311 - Only Leaflet posts are fetched and displayed
312 - RSS feeds redirect to Leaflet's native feeds
313 - Post redirects only check Leaflet
314
315- With WhiteWind **enabled**:
316 - Both Leaflet and WhiteWind posts are displayed
317 - RSS feeds include links to WhiteWind posts
318 - Post redirects check Leaflet first, then WhiteWind
319 - Draft and non-public WhiteWind posts are filtered out
320
321**Note**: Most users should keep WhiteWind disabled unless they specifically use it.
322
323### Custom Blog Fallback
324
325Redirect users to an archive or external blog when posts aren't found.
326
327```ini
328# In .env.local
329PUBLIC_BLOG_FALLBACK_URL="https://archive.yourdomain.com"
330```
331
332**Behavior**:
333
334- If a post isn't found on Leaflet (or WhiteWind)
335- AND `PUBLIC_BLOG_FALLBACK_URL` is set
336- Then redirect to: `{FALLBACK_URL}/{slug}/{rkey}`
337
338**Example**:
339
340- Missing post: `/blog/3abc789`
341- Redirects to: `https://archive.yourdomain.com/blog/3abc789`
342
343### CORS Configuration
344
345Control which domains can access your API endpoints.
346
347**Development** (allow all):
348
349```ini
350PUBLIC_CORS_ALLOWED_ORIGINS="*"
351```
352
353**Production** (specific domains):
354
355```ini
356# Single domain
357PUBLIC_CORS_ALLOWED_ORIGINS="https://yourdomain.com"
358
359# Multiple domains
360PUBLIC_CORS_ALLOWED_ORIGINS="https://yourdomain.com,https://app.yourdomain.com,https://www.yourdomain.com"
361```
362
363**Security Note**: Always use specific domain lists in production, never use `*`.
364
365---
366
367## Advanced Configuration
368
369### Custom Lexicon Support
370
371The site automatically displays data from these AT Protocol lexicons:
372
373#### Site Information (`uk.ewancroft.site.info`)
374
375- Technology stack
376- Privacy statements
377- Credits and licenses
378- No configuration needed - automatically fetched
379
380#### Music Status (`fm.teal.alpha.*`)
381
382- Current playing status via teal.fm
383- Automatic album artwork from MusicBrainz
384- Scrobbles from Last.fm, Spotify, etc.
385- No configuration needed
386
387#### Mood Status (`social.kibun.status`)
388
389- Current mood/feeling via kibun.social
390- Emoji and text display
391- No configuration needed
392
393#### Link Board (`blue.linkat.board`)
394
395- Curated link collections from Linkat
396- Emoji icons for each link
397- No configuration needed
398
399#### Tangled Repositories (`sh.tangled.repo`)
400
401- Code repository display
402- Descriptions, labels, creation dates
403- No configuration needed
404
405**All lexicons are automatically fetched using your `PUBLIC_ATPROTO_DID`**
406
407### Slingshot Configuration
408
409Slingshot is an AT Protocol data aggregator for faster queries.
410
411```ini
412# Local development instance (optional)
413PUBLIC_LOCAL_SLINGSHOT_URL="http://localhost:3000"
414
415# Public instance (default fallback)
416PUBLIC_SLINGSHOT_URL="https://slingshot.microcosm.blue"
417```
418
419**Default Behavior**:
420
4211. Try local Slingshot (if URL is set and reachable)
4222. Fallback to public Slingshot
4233. Fallback to user's PDS
4244. Fallback to Bluesky public API
425
426**Note**: Most users can leave these at their defaults.
427
428### Theme Customization
429
430The site uses Tailwind CSS with custom semantic colors. To customize:
431
4321. Edit `src/app.css` for global color scheme:
433
434```css
435@theme {
436 --color-canvas: /* Background color */;
437 --color-ink: /* Text color */;
438 --color-primary: /* Accent color */;
439}
440```
441
4421. Dark mode colors are automatically adjusted via Tailwind's `dark:` variants
443
4441. Wolf mode and theme toggle work automatically with any color scheme
445
446---
447
448## Verification
449
450After configuration, verify everything works:
451
452### Step 1: Install Dependencies
453
454```bash
455npm install
456```
457
458### Step 2: Start Development Server
459
460```bash
461npm run dev
462```
463
464Visit `http://localhost:5173`
465
466### Step 3: Check Core Features
467
468Verify these elements appear correctly:
469
470- [ ] **Profile Card**: Shows your Bluesky profile information
471 - Avatar and banner image
472 - Display name and handle
473 - Bio text
474 - Follower/following counts
475
476- [ ] **Site Metadata**: Check `http://localhost:5173/site/meta`
477 - Site information loads correctly
478 - Credits, tech stack, privacy info display
479
480- [ ] **Blog Access**: Test your slug configuration
481 - Visit `http://localhost:5173/{your-slug}`
482 - Should redirect to your Leaflet publication
483 - RSS feed works at `http://localhost:5173/{your-slug}/rss`
484
485- [ ] **Optional Features** (if enabled):
486 - Music status card (if you use teal.fm)
487 - Mood status card (if you use kibun.social)
488 - Link board (if you use Linkat)
489 - Repositories (if you use Tangled)
490 - Latest Bluesky post
491
492### Step 4: Check Browser Console
493
494Open browser DevTools (F12) and check for:
495
496- ✅ No error messages in Console tab
497- ✅ Successful API responses in Network tab
498- ✅ No 404 errors for static files
499
500### Step 5: Test Responsive Design
501
502Check the site at different screen sizes:
503
504- Mobile (375px width)
505- Tablet (768px width)
506- Desktop (1280px+ width)
507
508### Step 6: Verify SEO Metadata
509
510View page source and check for:
511
512- `<title>` tag with your site title
513- `<meta name="description">` with your description
514- Open Graph tags (`og:title`, `og:description`, etc.)
515- Twitter Card tags (`twitter:card`, `twitter:title`, etc.)
516
517---
518
519## Troubleshooting
520
521### Profile Data Not Loading
522
523**Symptom**: Profile card shows "Profile not found" or loading state persists
524
525**Solutions**:
526
5271. Verify `PUBLIC_ATPROTO_DID` is correct in `.env.local`
5282. Check your DID format: should be `did:plc:...` or `did:web:...`
5293. Ensure your Bluesky account is active and public
5304. Check browser console for specific error messages
5315. Clear cache and hard refresh (Ctrl+Shift+R / Cmd+Shift+R)
532
533### Publications Not Found
534
535**Symptom**: Blog pages show 404 or "Not Found" errors
536
537**Solutions**:
538
5391. Verify publication rkey in `src/lib/config/slugs.ts` matches your Leaflet publication
5402. Visit your Leaflet publication URL and confirm the rkey is correct
5413. Ensure the publication is public (not draft/private)
5424. Check if documents exist in the publication
5435. If using WhiteWind, verify `PUBLIC_ENABLE_WHITEWIND=true` if needed
544
545### Music Status Not Showing
546
547**Symptom**: Music card doesn't appear or shows no data
548
549**Solutions**:
550
5511. Verify you have teal.fm configured with your Bluesky account
5522. Check if you have any scrobbles in your teal.fm history
5533. Ensure your scrobbler (e.g., piper) is running and connected
5544. Album artwork requires MusicBrainz IDs or blob storage
5555. Check browser console for MusicBrainz API errors
556
557### RSS Feeds Not Working
558
559**Symptom**: RSS feed shows errors or no posts
560
561**Solutions**:
562
5631. Check slug configuration in `src/lib/config/slugs.ts`
5642. Verify publication has published documents (not drafts)
5653. If using WhiteWind:
566 - Ensure `PUBLIC_ENABLE_WHITEWIND=true`
567 - Verify you have published WhiteWind posts
5684. Test feed URL directly: `http://localhost:5173/{slug}/rss`
5695. Check Content-Type header is `application/rss+xml`
570
571### Environment Variables Not Applied
572
573**Symptom**: Changes to `.env.local` don't take effect
574
575**Solutions**:
576
5771. Restart the development server (`npm run dev`)
5782. Verify variable names start with `PUBLIC_` for client-side access
5793. Check for typos in variable names
5804. Ensure `.env.local` is in the project root directory
5815. Clear `.svelte-kit` cache: `rm -rf .svelte-kit && npm run dev`
582
583### Build Errors
584
585**Symptom**: `npm run build` fails with errors
586
587**Solutions**:
588
589```bash
590# Clean build artifacts
591rm -rf .svelte-kit node_modules package-lock.json
592
593# Reinstall dependencies
594npm install
595
596# Try building again
597npm run build
598```
599
600### CORS Errors in Production
601
602**Symptom**: API requests fail with CORS errors
603
604**Solutions**:
605
6061. Add your production domain to `PUBLIC_CORS_ALLOWED_ORIGINS`
6072. Ensure the domain includes the protocol (`https://`)
6083. For multiple domains, separate with commas (no spaces)
6094. Avoid using `*` in production for security
6105. Check that the origin header matches exactly (including www or non-www)
611
612### TypeScript Errors
613
614**Symptom**: Type errors in development
615
616**Solutions**:
617
618```bash
619# Run type checking
620npm run check
621
622# Watch mode for continuous checking
623npm run check:watch
624
625# Clear and rebuild
626rm -rf .svelte-kit && npm run dev
627```
628
629### Dark Mode Not Working
630
631**Symptom**: Dark mode toggle doesn't change theme
632
633**Solutions**:
634
6351. Check if browser supports `prefers-color-scheme`
6362. Clear browser localStorage: `localStorage.clear()` in console
6373. Verify Tailwind's dark mode is configured in `tailwind.config.js`
6384. Check that dark mode classes are present in HTML (inspect element)
639
640### Wolf Mode Issues
641
642**Symptom**: Wolf mode toggle doesn't transform text
643
644**Solutions**:
645
6461. Ensure JavaScript is enabled in browser
6472. Check browser console for errors
6483. Verify the wolf mode store is imported correctly
6494. Test on different text elements to confirm it's working
6505. Remember: numbers and navigation are intentionally preserved
651
652---
653
654## Getting Help
655
656If you encounter issues not covered here:
657
6581. **Check Browser Console**: Press F12 and look for error messages
6592. **Review README**: See [README.md](../README.md) for detailed feature documentation
6603. **GitHub Issues**: Search existing issues or create a new one
6614. **AT Protocol Docs**: Visit [atproto.com](https://atproto.com/) for protocol details
6625. **SvelteKit Docs**: Check [kit.svelte.dev](https://kit.svelte.dev/) for framework help
663
664### Useful Debugging Commands
665
666```bash
667# Check environment variables are loaded
668npm run dev -- --debug
669
670# View detailed build output
671npm run build -- --verbose
672
673# Type-check without building
674npm run check
675
676# Format code (may fix some issues)
677npm run format
678```
679
680### Log Collection for Bug Reports
681
682When reporting issues, include:
683
6841. Browser console errors (F12 → Console tab)
6852. Network tab showing failed requests (F12 → Network tab)
6863. Your `.env.local` configuration (remove sensitive data like DIDs)
6874. Node.js and npm versions: `node --version && npm --version`
6885. Operating system and browser version
689
690---
691
692## Next Steps
693
694After completing configuration:
695
6961. **Customize Content**:
697 - Update your Bluesky profile bio and banner
698 - Publish posts to your Leaflet publications
699 - Add site information via AT Protocol records
700
7012. **Deploy Your Site**:
702 - See [README.md](../README.md#-deployment) for deployment options
703 - Choose a platform (Vercel, Netlify, Cloudflare Pages, etc.)
704 - Configure production environment variables
705 - Set up custom domain
706
7073. **Enhance Your Site**:
708 - Add custom styling in `src/app.css`
709 - Create new components in `src/lib/components/`
710 - Extend functionality with new AT Protocol lexicons
711 - Customize layouts and pages
712
7134. **Monitor and Maintain**:
714 - Check RSS feeds regularly
715 - Update dependencies: `npm update`
716 - Monitor browser console for errors
717 - Keep AT Protocol records up to date
718
719---
720
721## Configuration Checklist
722
723Use this checklist to track your configuration progress:
724
725### Required Configuration
726
727- [ ] Set `PUBLIC_ATPROTO_DID` in `.env.local`
728- [ ] Set `PUBLIC_SITE_TITLE` in `.env.local`
729- [ ] Set `PUBLIC_SITE_DESCRIPTION` in `.env.local`
730- [ ] Set `PUBLIC_SITE_KEYWORDS` in `.env.local`
731- [ ] Set `PUBLIC_SITE_URL` in `.env.local`
732- [ ] Configure slug mappings in `src/lib/config/slugs.ts`
733- [ ] Update `static/robots.txt` with your domain
734- [ ] Update `static/sitemap.xml` with your pages
735
736### Optional Configuration
737
738- [ ] Enable WhiteWind support (if needed)
739- [ ] Configure blog fallback URL (if desired)
740- [ ] Set CORS allowed origins for production
741- [ ] Replace favicon files with your branding
742- [ ] Update or remove `.well-known` files
743- [ ] Configure Slingshot URLs (if using local instance)
744
745### Verification (Checklist)
746
747- [ ] Development server starts without errors
748- [ ] Profile card loads correctly
749- [ ] Blog slug redirects work
750- [ ] RSS feeds generate successfully
751- [ ] Optional features display (if enabled)
752- [ ] SEO metadata is correct in page source
753- [ ] Site works on mobile, tablet, and desktop
754- [ ] Dark mode and wolf mode toggles work
755
756### Deployment Preparation
757
758- [ ] Test production build: `npm run build`
759- [ ] Preview production build: `npm run preview`
760- [ ] Configure production environment variables
761- [ ] Choose and configure deployment platform
762- [ ] Set up custom domain (if applicable)
763- [ ] Configure SSL certificate (handled by most platforms)
764
765---
766
767**Configuration complete!** Your AT Protocol-powered personal website is ready to use. For detailed feature documentation, see [README.md](../README.md).