interactive intro to open social
at-me.zzstoatzz.io
real-time updates via firehose#
at-me visualizes your atproto activity in real-time using the jetstream firehose.
what is the firehose?#
the atproto firehose is a WebSocket stream of all repository events across the network. when you create, update, or delete records in your PDS, these events flow through the firehose.
we use jetstream, a more efficient firehose consumer that filters and transforms events.
architecture#
backend: rust + server-sent events#
firehose manager (src/firehose.rs)
- maintains WebSocket connections to jetstream
- one broadcaster per DID being watched
- smart reconnection with exponential backoff
- thread-safe using
tokioandArc<Mutex>
dynamic collection registration
- when you click "watch live", we fetch your repo's collections via
com.atproto.repo.describeRepo - registers event ingesters for ALL collections (not just bluesky)
- this means whitewind, tangled, guestbook, and any future app automatically work
event broadcasting (src/routes.rs:firehose_watch)
- server-sent events (SSE) endpoint at
/api/firehose/watch?did=<your-did> - filters jetstream events to only those matching your DID and collections
- broadcasts as JSON:
{action, collection, namespace, did, rkey}
frontend: particles + circles#
WebSocket to SSE bridge (static/app.js)
EventSourceconnects to SSE endpoint- parses incoming events
- creates particle animations
- shows toast notifications
particle system
- creates colored particles (green=create, blue=update, red=delete)
- animates from app circle → identity (your PDS)
- uses
requestAnimationFramefor smooth 60fps - easing with cubic bezier for natural motion
dynamic circle management
- new app? →
addAppCircle()creates it on the fly - delete event? →
removeAppCircle()cleans up when particle completes - circles automatically reposition to maintain even spacing
event flow#
1. you create a post in bluesky
2. bluesky writes to your PDS
3. your PDS emits event to firehose
4. jetstream filters and forwards to our backend
5. backend matches your DID + collection
6. SSE pushes event to your browser
7. particle animates from bluesky circle to center
8. identity pulses when particle arrives
9. toast shows "created post: hello world..."
why it works for any app#
traditional approaches hardcode collections like app.bsky.feed.post. we don't.
instead, we:
- call
describeRepoto get YOUR actual collections - register ingesters for everything you have
- dynamically create/remove app circles as events flow
this means if you use:
- whitewind → see blog posts flow in
- tangled → see commits flow in
- at-me guestbook → see signatures flow in
- future apps → automatically supported
performance notes#
- caching: DID resolution cached for 1 hour (
constants::CACHE_TTL) - buffer: broadcast channel with 100-event buffer
- reconnection: 5-second delay between retries
- cleanup: connections close when SSE client disconnects
code references#
- firehose manager:
src/firehose.rs - SSE endpoint:
src/routes.rs:951(firehose_watch) - dynamic registration:
src/routes.rs:985(fetch collections viadescribeRepo) - particle animation:
static/app.js:1037(animateFirehoseParticles) - circle lifecycle:
static/app.js:1419(addAppCircle),static/app.js:1646(removeAppCircle)