Meme Museum #
An independent Atmosphere app for curating a personal collection of memes — still images, animated images, and short video clips — and posting them to Bluesky with a couple of clicks. Your memes live in your own PDS, with enough metadata attached to find the right one fast and to credit where it came from.
Status #
Phases 0–3 are done (library MVP, compose/post, and external source import), and the app is deployed. PWA/share-sheet polish is paused, outside the numbered sequence. Phase 4 (cross-user AppView) is in early exploration, not built. See docs/plan.md for the phased build plan.
Getting Started #
Prerequisites: Node 20+, pnpm. Then pnpm install.
Run against public Bluesky (simplest) #
pnpm dev
Open the printed localhost URL and sign in with a real Bluesky handle via
OAuth. No extra setup required.
Run against the local devnet #
Use this to test writes (posting, uploads) without touching a real Bluesky
account. One-time setup — Docker Desktop, mkcert, an /etc/hosts entry, and
a sibling clone of atproto-devnet — is documented in
docs/atproto-devnet.md.
# 1. Make sure Docker Desktop is running
# 2. Start the devnet stack (postgres, PDS, PLC directory, Caddy, mail)
./scripts/devnet-up.sh
# 3. Run the app pointed at the devnet
pnpm dev:devnet
One gap: the devnet has no video service, so video memes fall back to a plain PDS blob upload — everything except the transcode and the resulting post embed works locally, and only mp4 is accepted there. See docs/plan.md.
Sign in with a seeded account: alice.devnet.test / alice-devnet-pass
(or bob.devnet.test / bob-devnet-pass). These accounts start out empty —
to populate alice's library with placeholder memes and collections:
node scripts/seed-devnet.mjs
devnet-up.sh is safe to re-run any time, including after a reboot — it's
idempotent. Existing data (Postgres, PDS records, seeded accounts) is left
alone; it only (re)starts containers and skips steps that are already done
(cert generation, account seeding). If containers aren't running yet (e.g.
after your Mac restarted), just make sure Docker Desktop is open and run it
again.
When you actually want a clean slate (not just a restart):
./scripts/devnet-down.sh
This deletes the Docker volumes (Postgres, PDS data) and the seeded-account
files — a full wipe, on purpose. The next devnet-up.sh starts from
scratch and reseeds alice/bob with fresh accounts.
Deployment #
pnpm deploy
Builds to dist/ and pushes it to wisp.place, which serves
meme-museum.at.
Routing is path-based (/library, /share, /about, /meme/:actor/:rkey,
…), so the host has to serve index.html for unmatched paths or every
deep link and reload 404s. /meme/:actor/:rkey is the one that matters
most: it's the public share link, so it arrives cold from someone else's
chat window rather than from a click inside the app.
public/_redirects is what tells wisp.place to do
that; anything that replaces it — a different host, a rewritten build step
— has to keep an equivalent SPA fallback.
Documents #
| Doc | Contents |
|---|---|
| docs/brief.md | Product brief: what this is, who it's for, design direction, v1 scope |
| docs/data-model.md | The meme/collection lexicon design, and how it handles sharing, provenance, and external sources |
| docs/plan.md | Phased build plan — what ships as a plain PWA vs. what needs an AppView later |
| docs/appview-exploration.md | Working notes on the Phase 4 AppView: framework choice, moderation, anonymous search, testing — not yet a committed design |
| docs/atproto-devnet.md | Local ATProto devnet setup, adapted from timeline-ng |
| lexicons/ | Lexicon JSON schemas for the at.meme-museum.* record types (source of truth for codegen) |
| art/ | Icon source (icon-source.svg, which every public/icons/ PNG is rendered from) and the retired gallery illustration |
Contributors #
This started as a solo project and stays small, but it isn't solo-only — pull requests are welcome at tangled.org/meme-museum.at/meme-museum.
- Joe Germuska — original author and maintainer
- zzstoatzz — the public meme detail
page at
/meme/:actor/:rkey(pull #1)