where words drift freely
A minimal, beautifully dark website for anonymous poem submission and random discovery. No accounts. No algorithms. Just poems, floating in a shared pool.
- Submit a Poem — anonymous or named, up to 2000 characters, protected by Cloudflare Turnstile
- Discover — a random poem from the shared pool, with a "This moved me" button
- Poems That Moved People — poems gently elevated by appreciation signals
- Your Poems — poems you've submitted, stored in
localStorageper device - Unique shareable URLs — each poem gets a
/p/{slug}permalink - Permanently stored in Supabase Postgres
- Next.js 15 (App Router, TypeScript)
- Tailwind CSS
- Supabase (Postgres)
- Cloudflare Turnstile (spam protection)
- nanoid (slug generation)
- Deploy on Vercel
git clone https://github.com/jjm578/PoetryPond.git
cd PoetryPond
npm install- Create a Supabase project
- Go to SQL Editor and run the contents of
supabase/schema.sql - Copy your project URL and keys
- Go to Cloudflare Turnstile and create a widget
- Set the site key and secret key in your environment variables
Copy .env.local.example to .env.local and fill in your values:
cp .env.local.example .env.localNEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
# Optional — omit to disable captcha in development
NEXT_PUBLIC_TURNSTILE_SITE_KEY=your-site-key
TURNSTILE_SECRET_KEY=your-secret-keynpm run devOpen http://localhost:3000.
-- poems table
id uuid primary key
slug text unique (used in /p/{slug} URLs)
text text max 2000 chars
author_name text nullable
is_anonymous boolean
created_at timestamptz
-- poem_appreciations table
id uuid primary key
poem_id uuid → poems.id
session_id text (browser-generated anonymous identifier)
created_at timestamptz
-- unique(poem_id, session_id) prevents duplicate appreciations- Push to GitHub and import the repo in Vercel
- Add the environment variables in Vercel's project settings
- Deploy!
| Method | Path | Description |
|---|---|---|
POST |
/api/poems |
Submit a new poem |
GET |
/api/poems/random |
Get a random poem |
GET |
/api/poems/:slug |
Get a poem by slug |
POST |
/api/poems/:slug/appreciate |
Record "moved me" for a poem |
GET |
/api/poems/moved |
Get poems with appreciations |
MIT
