- TypeScript 54%
- Astro 39%
- CSS 6%
- Nix 1%
tynanpurdy.com #
A personal website entirely powered by the AT Protocol. All content is stored as AT Protocol records and automatically displayed on the site without requiring manual rebuilds.
Features #
- ✅ AT Protocol Native: All content comes from AT Protocol records
- ✅ Blog System: Write blog posts as AT Proto records with Bluesky comments integration
- ✅ Standard.site Integration: Automatically display publications and documents
- ✅ Guestbook: Visitors can sign with their Bluesky accounts
- ✅ OAuth Authentication: Secure user interactions via AT Protocol OAuth
- ✅ Web Components: Lightweight, reusable UI components
- ✅ Universal CSS System: Consistent styling with CSS custom properties
- 🚧 Live Updates: Real-time content updates (using Astro experimental features)
Tech Stack #
- Framework: Astro
- Protocol: AT Protocol
- Styling: CSS + Web Components
- Authentication: AT Protocol OAuth
- Package Manager: pnpm
- Development Environment: Nix flakes
Getting Started #
Prerequisites #
- Nix with flakes enabled
Setup #
-
Clone the repository and enter the directory
-
Activate the Nix development environment:
nix developOr use direnv for automatic activation:
direnv allow -
Install dependencies:
pnpm install -
Configure your AT Protocol identity:
cp .env.example .envEdit
.envand add your:PUBLIC_ATPROTO_DID: Your DID (e.g.,did:plc:...)PUBLIC_ATPROTO_HANDLE: Your handle (e.g.,you.bsky.social)PUBLIC_ATPROTO_NAMESPACE: Your custom namespace (e.g.,com.yourname)- OAuth credentials (for user interactions)
-
Update the configuration in
src/lib/atproto.ts:export const SITE_CONFIG: ATProtoConfig = { did: 'your-did-here', handle: 'your-handle.bsky.social', }; -
Start the development server:
pnpm dev -
Visit
http://localhost:4321
Project Structure #
/
├── src/
│ ├── components/ # Web Components
│ │ ├── avatar.ts
│ │ ├── button.ts
│ │ └── card.ts
│ ├── layouts/ # Page layouts
│ │ └── BaseLayout.astro
│ ├── lib/ # Utility functions
│ │ ├── atproto.ts # AT Protocol API wrappers
│ │ ├── blog.ts # Blog functionality
│ │ ├── guestbook.ts # Guestbook functionality
│ │ └── oauth.ts # OAuth authentication
│ ├── pages/ # Routes
│ │ ├── blog/
│ │ │ ├── index.astro
│ │ │ └── [slug].astro
│ │ ├── oauth/
│ │ │ └── callback.astro
│ │ ├── guestbook.astro
│ │ ├── index.astro
│ │ └── publications.astro
│ └── styles/
│ └── global.css # Universal design system
├── public/ # Static assets
├── astro.config.mjs # Astro configuration
├── flake.nix # Nix development environment
└── package.json
Creating Content #
Blog Posts #
Create blog post records in your AT Protocol repository using the collection:
{namespace}.blog.post
Example record structure:
{
"$type": "com.tynanpurdy.blog.post",
"title": "My First Post",
"text": "Post content here...",
"tags": ["atproto", "blog"],
"blueskyUri": "at://did:plc:.../app.bsky.feed.post/...",
"createdAt": "2026-02-13T00:00:00.000Z"
}
The blueskyUri field links to a Bluesky post for comments and engagement.
Guestbook Entries #
Guestbook entries are automatically created when users sign via OAuth. They use the collection:
{namespace}.guestbook.entry
Publications #
Standard.site publications are automatically fetched from:
pub.standard.publication
pub.standard.document
Customization #
Styling #
Edit src/styles/global.css to customize the design system. All colors, spacing, typography, and other design tokens are defined as CSS custom properties at the root level.
Components #
Web Components are defined in src/components/. They use Shadow DOM and CSS custom properties for styling.
AT Protocol Collections #
Update the namespace in .env and throughout the codebase to use your own custom collections.
Building for Production #
pnpm build
The built site will be in the dist/ directory.
Roadmap #
Resources #
- AT Protocol Documentation
- Astro Documentation
- Standard.site Documentation
- Bluesky Comments Reference
License #
MIT