Meme search and management app with semantic search. Built for homelab.
Inspired by meme-search.
| Grid | Detail | Editor |
|---|---|---|
![]() |
![]() |
![]() |
bun install && bun run dev # Development
docker compose up # Production- Semantic Search: Vector embeddings (all-MiniLM-L6-v2) + filename matching
- AI Descriptions: Ollama vision model describes memes automatically
- Meme Editor: Add text overlays, choose fonts/colors
- Zipline Sharing: One-click upload edited memes to Zipline
- Multi-Directory: Mount multiple meme collections
- Mobile Friendly: Responsive layout for phone/tablet
Generates searchable descriptions for memes using vision AI.
- Run Ollama with a vision model:
ollama pull llava:7b - Set
OLLAMA_URL(default:http://localhost:11434) - Click "Generate" on a meme or use batch generate in Settings
The model analyzes each image and creates a text description used for semantic search.
Share edited memes to your Zipline instance.
- Set
ZIPLINE_URLto your Zipline upload endpoint - Set
ZIPLINE_TOKENto your API token - Edit a meme → click "Share to Zipline" → URL copied to clipboard
Drag & drop or click to upload images via the UI. Files save to UPLOAD_DIR (default /data/memes/uploads) and are automatically added to the database with "pending" status.
Scan directories to import existing meme collections:
curl -X POST http://localhost:3000/api/scan \
-H 'Content-Type: application/json' \
-d '{"directory": "/data/memes"}'The scanner recursively finds images (jpg, png, gif, webp, avif), adds them to the database, and extracts titles from filenames. Use Settings UI to trigger scans or batch-generate AI descriptions.
| File | Purpose |
|---|---|
index.ts |
All backend: Hono server, API routes, DB, embeddings, scanner |
index.html |
All frontend: vanilla JS/CSS, grid, modals, meme editor |
schema.sql |
PostgreSQL + pgvector schema |
docker-compose.yml |
App + PostgreSQL containers |
- Runtime: Bun
- Server: Hono
- Database: PostgreSQL 17 + pgvector
- Embeddings: Xenova all-MiniLM-L6-v2
- Vision AI: Ollama llava:7b (optional)
- Frontend: Vanilla JS
DATABASE_URL=postgres://postgres:postgres@localhost:5432/shitpostr
OLLAMA_URL=http://localhost:11434
OLLAMA_MODEL=llava:7b
UPLOAD_DIR=/data/memes/uploads
PORT=3000
# Zipline (optional)
ZIPLINE_URL=https://your-zipline.com
ZIPLINE_TOKEN=your-token
# Multiple source directories (comma-separated)
STATIC_DIRS=/data/memes,/data/imgflipMount multiple meme collections as separate Docker volumes:
services:
shitpostr:
environment:
- STATIC_DIRS=/data/memes,/data/imgflip
volumes:
- meme-data:/data/memes
- imgflip-data:/data/imgflipThen scan each directory:
curl -X POST http://localhost:3000/api/scan \
-H 'Content-Type: application/json' \
-d '{"directory": "/data/imgflip"}'Built with Claude Code.
MIT


