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 tokio and Arc<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)

  • EventSource connects 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 requestAnimationFrame for 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:

  1. call describeRepo to get YOUR actual collections
  2. register ingesters for everything you have
  3. 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 via describeRepo)
  • particle animation: static/app.js:1037 (animateFirehoseParticles)
  • circle lifecycle: static/app.js:1419 (addAppCircle), static/app.js:1646 (removeAppCircle)