The social focus timer. Start a room, share the link, focus together.
Every focus app is built for one person. Forest grows a tree. Yours, alone. Notion tracks tasks. Yours, alone. There is no app built around the fact that focusing with someone else is fundamentally different from focusing solo.
Bonfire is that app. Start a room, share the link. Your friend joins and sees the exact same second on the exact same timer. When the break hits, it hits for everyone. The accountability is real because the other person is actually there.
A live Three.js fire scene that reacts to your session state. The flame grows as you complete pomodoros and more participants join, dims to embers on short breaks, and goes near-dormant on long breaks, giving you a visual heartbeat of the room's energy.
The timer is clock-based using a startedAt Unix timestamp rather than a local countdown. Everyone in the room, regardless of when they joined or how bad their connection is, always sees the correct second. No drift, no skew.
Every room has three modes, switchable at any time:
- Host mode: only the host can start, pause, skip, or change settings. Everyone else follows along in sync.
- Jam mode: anyone in the room can control the timer. Great for study groups where everyone has equal say.
- Solo mode: private room, no sharing, no watchers. Just you and the timer.
The current mode is visible to all participants in real time.
Watchers can't change settings directly, but they can request a change. The host receives an inline card showing exactly what the watcher wants to change, with a diff of old vs. new values, and can accept or reject with one tap. If accepted, the settings apply immediately for everyone.
Four ambient sounds generated entirely by the Web Audio API. No CDN, no external files, no latency:
- Brown noise: deep, warm rumble. Like a distant waterfall.
- White noise: broad-spectrum static. Clinical focus.
- Pink noise: softer mid-range tone. Gentle background presence.
- Rain: gentle rainfall texture. Calm and grounding.
The panel is collapsible. A green pulse dot appears next to "Focus Music" when a sound is active.
See who's focusing alongside you via real-time presence. When someone joins or leaves, a floating activity message appears at the bottom of the screen. The same feed shows timer events: when someone starts, pauses, or skips, so the whole group stays in the loop without any chat.
No account needed. Guests are prompted to set a display name when they first join a room. The name is saved per-room in localStorage so it persists across page reloads. It shows up in the participant list and activity feed for everyone.
Fully configurable per-room:
- Focus, short break, and long break durations (in minutes)
- Long break interval (how many focus rounds before a long break)
- Auto-start breaks: break timer starts automatically when focus ends
- Auto-start pomodoros: focus timer restarts automatically after a break
- Light / Dark theme toggle
Settings are persisted to the database and broadcast to all participants when applied.
A built-in guide panel (press ? or click the ? button) covers every mode, the noise library, keyboard shortcuts, and how to request settings as a watcher. Available as a slide-out sidebar on desktop and a bottom sheet on mobile.
When the timer ends, a full-screen break overlay appears for all participants simultaneously. Browser push notifications fire at the same moment, useful if you've switched tabs. The overlay disappears as soon as the next round starts.
Authenticated users get a personal analytics dashboard at /profile/[username]:
- Total pomodoros and focus hours completed
- Current streak: consecutive days with at least one completed session
- Weekly bar chart: last 7 days of focus activity
- GitHub-style heatmap: 52-week calendar showing daily pomodoro counts
All data is logged to the pomodoro_logs table whenever a focus round completes.
Browse all live public rooms happening right now without needing a direct link. The explore page shows active rooms updated in the last 90 seconds, showing room name, host, and current mode. Click any card to join instantly.
The share panel lets you copy the room link or trigger the native OS share sheet on mobile. Guests can only share if the host has "Allow guests to invite" enabled in settings. The host controls whether the room is open or invite-only.
Theme toggles between dark and light, persisted per device. The app is installable as a PWA on mobile and desktop. The favicon and tab title update live with the current timer countdown (minutes only, always readable).
- Start: click "Start Room" on the home page
- Share: hit the Invite button and send the link to anyone
- Pick your mode: Host (you lead), Jam (everyone drives), or Solo (just you)
- Focus: hit Play. Everyone sees the same countdown, on the same second
- Break: timer ends, notifications fire, break overlay appears for everyone
No account needed. Start in under 30 seconds.
| Layer | Technology |
|---|---|
| Framework | Next.js 14 App Router |
| Language | TypeScript (strict) |
| Database | Supabase (PostgreSQL + Realtime) |
| Auth | Supabase Auth (GitHub + Google OAuth) |
| Styling | Tailwind CSS + CSS variables |
| Animation | Three.js + React Three Fiber |
| OG Images | @vercel/og |
| Audio | Web Audio API (no external deps) |
| Fonts | Plus Jakarta Sans + DM Sans + JetBrains Mono |
Prerequisites: Node.js 18+, a Supabase account (free), npm
1. Clone and install
git clone https://github.com/MinitJain/bonfire.git
cd bonfire
npm install2. Set up environment variables
cp .env.local.example .env.localFill in your Supabase credentials:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
NEXT_PUBLIC_APP_URL=http://localhost:3000
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
CRON_SECRET=your-random-secret3. Set up the database
Run the migrations in your Supabase SQL editor in order:
supabase/migrations/001_init.sql
supabase/migrations/002_jam_mode.sql
supabase/migrations/003_rls_sessions.sql
supabase/migrations/004_session_expiry.sql
supabase/migrations/005_log_pomodoros.sql
supabase/migrations/006_session_mode.sql
Or push via the Supabase CLI:
npx supabase db push4. Enable OAuth providers
Supabase → Authentication → Providers → enable GitHub and/or Google, add your Client ID and Secret.
5. Run locally
npm run devAfter deploying, complete these three steps or auth will break:
- Supabase → Authentication → URL Configuration → add your Vercel URL to Redirect URLs
- Google Cloud Console → OAuth client → add your Vercel domain to Authorized JavaScript origins
- Set
NEXT_PUBLIC_APP_URLin Vercel environment variables to your live URL (must includehttps://)
PRs are welcome. For major changes, open an issue first. This repo uses CodeRabbit for AI code review. Every PR gets reviewed automatically.
MIT