Files
README.md

bs-farm #

An isometric idle-farm visualization of a Bluesky user's activity and social graph. Type in a handle, pick some neighbors, and watch their last few months of posting grow into a tile-based landscape — each user gets a crop, every post sprouts a cell, replies and reposts grow toward the people they engage with, and tiles decay the further they get from the root.

Live at farm.cee.wtf.

preview

Cell rules #

  • Posts sprout a fresh tile on your farm.
  • Replies & reposts create a cell on your farm in the direction of the recipient.
  • Likes bump the maturity of the tile they're on — and every ancestor up the reply chain.
  • Tiles decay the further they sit from a farm's root. Keep posting to keep growing.
  • Each user gets one crop type hashed from their handle. Tile colors come from their avatar.

Run it locally #

pip install -r requirements.txt
python server.py            # http://localhost:8920
python server.py --port 9000

Static files (everything under static/) are served live — edit JS/CSS/HTML and hard-reload (Ctrl+Shift+R). Restart is only needed when sim/rules.py or sim/world.py change (those are what /api/config returns).

What's in the box #

  • static/ — the actual app. 13 JS files, no bundler. Loaded in dependency order from index.html.
  • sim/, fetcher/ — Python sim + repo fetcher. Mostly vestigial; the shipped app does sim + fetch entirely in the browser. Kept around for offline experiments.
  • server.py, wsgi.py — Flask shell. Serves /api/config (default tunables) + static files. That's the critical path.
  • design.md — the original design doc. Read it for the "why" behind the mechanics.
  • CLAUDE.md — architecture notes for AI assistants (also useful for humans).

Tech #

Pure-browser sim + fetch. Talks to Bluesky's public AppView + per-user PDS directly via com.atproto.repo.listRecords, caches parsed events per-DID in IndexedDB, then runs the replay in a vanilla canvas with a pre-rendered sprite cache. The Flask side mostly just hands out defaults.