Hey DEV community! π
Sometimes, the internet feels a bit too serious, too algorithm-driven, and too full of paywalls or sign-up forms. I wanted to build something completely opposite: a low-friction, playful corner of the web where people can just be silly for a couple of minutes.
So, I built Draw a Fish.
It's a free online drawing game. You sketch a fish, hit "Make it Swim", and it instantly drops into a massive, shared virtual aquarium with fish drawn by people from all over the world.
π¨ How it works
The core loop is designed to be as frictionless as possible:
- Draw: You get a blank canvas and some basic colors. No account needed.
- Swim: Once you're done, the app names it, rates it, and releases it into the global tank.
- Feed & Grow: This is the multiplayer part. Anyone can click to "feed" any fish. Every feed adds weight, and the heaviest fish climb the global leaderboard.
- Claim (Optional): If you want to keep track of your masterpiece's growth, you can log in later to "claim" your fish.
π οΈ The Tech Stack
To bring this virtual aquarium to life, I kept the stack modern and real-time friendly:
- Frontend: [e.g., React / Vue / Vanilla JS + HTML5 Canvas]
- Backend: [e.g., Node.js with Express / Python FastAPI]
- Database: [e.g., Firebase / Supabase / MongoDB] to store the fish image data and handle the real-time feeding counter.
- Hosting: [e.g., Vercel / Netlify / Heroku]
π§ The Biggest Challenge: Frictionless Onboarding vs. Data Ownership
One of the biggest UX decisions I made was "No account needed to play."
If I asked users to log in before drawing, 90% of them would bounce. But if they don't log in, how do they track their fish on the leaderboard?
The Solution:
When a guest user draws a fish, I store a unique identifier (token) in their browser's localStorage. The fish is saved to the database linked to this anonymous token.
// Example pseudo-code for the guest logic
const generateGuestToken = () => {
let token = localStorage.getItem('guest_fish_token');
if (!token) {
token = crypto.randomUUID();
localStorage.setItem('guest_fish_token', token);
}
return token;
};
If the user later decides they love their fish and want to track it across devices, they can hit "Log In". The app then takes their guest_fish_token, finds all fish created under it, and officially assigns them to their new permanent account.
Itβs the best of both worlds: zero friction to start playing, but a clear path to user retention!
π What's Next?
Right now, it's just pure chaos and fun in the tank. I'm planning to add:
- [e.g., More drawing tools and colors]
- [e.g., Special food types or interactions]
- [e.g., A way to share your specific fish on Twitter/X]
π I need your help!
The aquarium needs more weird, beautiful, and hilarious fish!
I'd love for you to take 2 minutes, go draw a fish, and post a screenshot of what you created in the comments below! Let's see who can get to the top of the leaderboard today. π
Top comments (0)