An anonymous starry space for emotional release.
A full-stack emotional whisper-sharing platform where anonymous souls can release unspoken feelings into the void — and receive gentle AI-powered reflections in return.
Whisper.txt is a quiet, beautiful space to:
- Release whispers — anonymous feelings, secrets, or quiet hopes (up to 300 characters)
- Tag a mood — Sad, Anxious, Lonely, Grateful, Numb, or Hopeful
- React to others' whispers with "I felt this 🫂" or "Released 🌙"
- Seek a reflection — Gemini AI generates a gentle 2-3 sentence emotional response
- Filter by mood — browse whispers by emotional echo
- Track your own — your released whispers are remembered locally in your browser session
No accounts. No tracking. No IP logs. Just the void, and the stars.
| Layer | Technology |
|---|---|
| Frontend | React 19 + TypeScript + Vite |
| Styling | Tailwind CSS v4 |
| Animations | Motion (Framer Motion) |
| Backend | Node.js + Express |
| AI | Google Gemini 2.5 Flash |
| Database | JSON flat file (whispers.json) |
| Icons | Lucide React |
whisper.txt/
├── server.ts # Express backend (API + Vite middleware)
├── whispers.json # Flat-file database (auto-created on first run)
├── index.html # HTML entry point
├── vite.config.ts # Vite configuration
├── tsconfig.json # TypeScript configuration
├── package.json # Dependencies and scripts
├── .env # Environment variables (see setup below)
└── src/
├── main.tsx # React entry point
├── App.tsx # Root component (layout, state, API calls)
├── index.css # Global styles
├── types.ts # TypeScript interfaces (Whisper, MoodType)
└── components/
├── StarryBackground.tsx # Animated canvas starfield
├── WhisperForm.tsx # Whisper submission form
├── WhisperCard.tsx # Individual whisper display + reactions
└── MoodSelector.tsx # Mood pill selector
git clone https://github.com/your-username/whisper-txt.git
cd whisper-txt
npm install# Copy the example file
cp .env.example .envOpen .env and add your Gemini API key:
GEMINI_API_KEY=your_gemini_api_key_here
PORT=3000
NODE_ENV=developmentGet a free Gemini API key at aistudio.google.com.
Note: The app works without a Gemini key — AI reflections fall back to handcrafted mood-based responses automatically.
npm run devVisit http://localhost:3000
Returns a randomized set of whispers.
| Query Param | Type | Description |
|---|---|---|
mood |
string | Filter by mood (sad, anxious, lonely, grateful, numb, hopeful, all) |
limit |
number | Number of whispers to return (default: 9, max: 20) |
Creates a new whisper.
{
"content": "I've been carrying this for months.",
"mood": "lonely"
}Adds a reaction to a whisper.
{
"id": "w-1234567890-abc123",
"type": "felt"
}type must be "felt" or "release".
Generates (or returns cached) an AI emotional reflection for a whisper.
{
"id": "w-1234567890-abc123"
}Returns:
{
"reflection": "Your feelings are valid and held gently here. 🌙",
"isFallback": false
}Render is the recommended platform — the Express + Vite setup maps directly to a Render Web Service.
-
Push your project to GitHub
-
Create a new Web Service on render.com
-
Connect your GitHub repo and set:
| Setting | Value |
|---|---|
| Build Command | npm install && npm run build |
| Start Command | npm run start |
| Node Version | 20+ |
- Add environment variables in the Render dashboard:
GEMINI_API_KEY=your_key_here
NODE_ENV=production
- Deploy — that's it.
Important:
whispers.jsonwill reset on every Render redeploy since the filesystem is ephemeral. For persistent data, migrate to a database (Turso, MongoDB Atlas, or Render's managed PostgreSQL — all have free tiers).
- Flat file database —
whispers.jsonis not suitable for high traffic or persistent production use. Fine for demos and portfolios. - No authentication — fully anonymous by design; no moderation tools.
- Rate limiting — 20 requests per 15 minutes per IP across all
/api/routes. - Data resets on redeploy — inherent to ephemeral filesystems on platforms like Render.
The dev server runs Express + Vite together on port 3000. Hot module replacement (HMR) is enabled by default in development. The whispers.json database is created automatically on first run with 5 sample whispers.