I Built My Own Scrum Poker Because All Others Suck 🎴
Source: Dev.to
The Problem 😩
Sprint planning. Your team needs to estimate tasks. Someone shares a Planning Poker link. You click. You wait. Half the team can’t connect. The other half already went for coffee.
Sound familiar?
At AGG TEAM we tried everything:
- Planning Poker Online – laggy, ads, ancient UI
- Scrum Poker for Jira – expensive, requires Jira
- PlanITpoker – works, but missing OUR features
After the third crash mid‑estimation I thought: “Screw it, I’ll build my own.”
The Real Challenge: 6 Teams, 1 Room 🤯
We don’t have one scrum team – we have six departments:
- Frontend
- Backend
- DevOps
- QA
- Analytics
- Management
Everyone wants to do planning poker simultaneously in one room. It’s chaos – like playing six different card games at the same table. Existing tools say “Here’s one room, figure it out!” – not ideal.
What I Built
🎰 Multi‑Table Support (Up to 6!)
Core concept: one session, multiple independent tables.
interface Table {
id: string;
name: string; // "Frontend Squad", "Backend Ninjas"
revealed: boolean; // Are cards revealed for this table?
}
interface Player {
id: string;
name: string;
tableId: string; // Which table they're at
vote: string | null; // "5", "13", "?", "☕"
}- Host creates tables with custom names.
- Everyone picks their table.
- Each table votes independently.
- You see all tables plus an overall average.
Host powers: add, remove, rename tables on the fly; move people between tables if needed.
⚡ Real‑Time Sync
Used Supabase as backend with a simple polling approach:
useEffect(() => {
if (view === 'room' && roomId) {
fetchRoomState();
const interval = setInterval(fetchRoomState, 2000);
return () => clearInterval(interval);
}
}, [view, roomId]);WebSockets would be cooler, but for prototypes and ~50 users polling works great. If it grows I’ll switch.
Updates in real time:
- Someone joins → instant
- Someone votes → immediate
- Cards revealed → everyone sees results
- Emoji thrown → flies across screen
💓 Smart Disconnect Detection
Problem with other tools: people close tabs, but their avatars stay forever (ghost users).
My solution uses heartbeat + explicit disconnect:
// Send heartbeat every 10 seconds
const sendHeartbeat = async () => {
await fetch(`${API_URL}/rooms/${roomId}/heartbeat`, {
method: 'POST',
body: JSON.stringify({ playerId }),
});
};
// Explicit disconnect on page close
window.addEventListener('beforeunload', () => {
navigator.sendBeacon(
`${API_URL}/rooms/${roomId}/disconnect`,
JSON.stringify({ playerId })
);
});Result
- Page open but idle → stays as long as you want (no kicks)
- Close page/tab → instant disconnect (≈ 2 seconds)
No more ghosts. Clean rooms.
🎉 Emoji Attacks!
Click any participant, throw an emoji. It literally flies from your avatar to theirs with smooth animation.
Available emojis:
👍 👏 🎉 ❤️ 🚀 🔥 😂 🤔 💯 ✨ 👌 🙌
Use cases
- 👍 agree with estimate
- 🔥 someone makes a great point
- 😂 junior estimates a simple task at 89 points
- ☕ definitely coffee time
This made our plannings fun – people actually look forward to estimation meetings now!
🃏 Fibonacci + Special Cards
Classic series: 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
Plus special cards:
- ”?” – “I have no idea”
- ”☕” – “Need coffee before thinking”
You can change your vote even after reveal (most tools lock votes). During discussion you might realize 13 should actually be 8 – my tool allows it.
🧮 Auto‑Average Calculation
Each table shows its average. A grand total appears at the bottom across all tables.
const calculateAverage = (players: Player[], revealed: boolean) => {
if (!revealed) return null;
const numericVotes = players
.map(p => p.vote)
.filter(v => v && !isNaN(Number(v)))
.map(Number);
if (numericVotes.length === 0) return null;
return (numericVotes.reduce((a, b) => a + b) / numericVotes.length).toFixed(1);
};Perfect for answering “What’s the overall estimate across all teams?”
🌙 Dark Mode + 🌍 Multi‑Language
Toggle in the corner switches theme (light/dark) and language (EN/RU). Settings are saved to localStorage and applied automatically on next visit.
Because if your app doesn’t have dark mode in 2026… what are you even doing?
Tech Stack 🛠
Frontend
- React + TypeScript
- Tailwind CSS v4
- Lucide icons
Backend
- Supabase Edge Functions (Hono + Deno)
- Supabase KV Store (key‑value table)
Why Supabase?
- Fast setup – no server deployment
- Edge Functions let me write TypeScript backend logic
- Simple KV store for room state
- Free tier sufficient for prototypes
Challenges & Solutions 💡
Ghost Users
- Problem: Users close tabs, avatars linger.
- Solution: Heartbeat + explicit disconnect via
navigator.sendBeacon.
Z‑Index Wars
- Problem: Theme toggle covered modals.
- Solution: Defined a clear hierarchy (
z-30for buttons,z-40for modals).
State Management
- Problem: Keeping 6 tables + players in sync.
- Solution: Single source of truth in the backend; polling for updates.
How Planning Changed
Before
- “Wait, is everyone loaded?”
- “Refresh, I don’t see your vote.”
- “Who’s still here?”
- awkward waiting
After
- Create room (≈ 5 seconds)
- Everyone joins (instant)
- Vote → reveal → discuss
- Throw emojis for fun
- Finish on time
Real feedback
“Wait, planning poker can be smooth?”
“I love throwing fire emojis at people!”
“Finally a tool that doesn’t make me rage‑quit.”
What’s Next? 🚀
- Session history (who voted what)
- Optional voting timer
- Exportable reports (CSV/JSON)
- More language support
Built for six teams, one room, and a lot of coffee.
# Countdown
- Custom decks (T‑shirt sizes?)
- Sound effects (optional)
- Jira integration
---Key Takeaways 🧠
1. Build what you need
Stop waiting for the perfect tool. 80 % built in a weekend beats 100 % coming “eventually.”
2. Polling isn’t evil
WebSockets are cool, but polling works great for small teams. Don’t over‑engineer.
3. Small delights matter
The emoji feature took 2 hours. It’s everyone’s favorite. Little things make big differences.
4. Dark mode is mandatory
Seriously. It’s 2026.
Try It! 🎮
AGG POKER – Engage teams in collaborative estimation with an interactive Scrum poker tool, allowing users to join sessions and streamline project planning.
Use it, free
The Bottom Line
Sometimes a few evenings of coding saves months of frustration. Plus you learn something new. Win‑win.
If your team has the same planning‑poker pain—build your own! We have amazing frameworks, free hosting, and AI assistants now. There’s no excuse.
Questions? Ideas? Want to contribute? Drop a comment!
P.S. Yes, enterprise solutions exist. Mine costs $0, works perfectly for us, and was fun to build. 😄