πΊοΈ The Big Picture
EmojiLab is a multi-page web app. Players spin emoji reels, get an AI-generated nickname read aloud, vote on each other's nicknames in a live feed, and compete on a daily leaderboard. A standalone prototype called the Avatar Generator lets players turn a nickname into a personalised PokΓ©mon-style creature card.
All the pages are static HTML files β just files your browser downloads and runs. All the server-side logic lives in two Cloudflare Workers.
π§± The Three Layers of Every Web Page
All three live inside each HTML file β CSS between <style> tags, JavaScript between <script> tags, structure between the <body> tags.
π° The Reel System
Each reel is an instance of the Reel class β a tall scrolling strip of emojis inside a window that only shows 3 at a time:
The strip is actually 16Γ longer than it appears β it repeats the emoji list 16 times so you can scroll endlessly without running out. When you flick fast, a momentum/friction loop keeps it moving and snaps to the nearest slot. The 3D cylinder effect is pure CSS: emojis near the edges are scaled down and rotated on the X axis to look like they're curling around a drum.
Every page load picks 12 random animals from a pool of 35 using a Fisher-Yates shuffle, so the reels feel fresh on every visit.
π£ Step-by-Step: Making a Nickname
The app uses the Pointer Events API (pointerdown, pointermove, pointerup) which works identically on touchscreens and desktop. Dragging slowly gives precise control; flicking fast gives a momentum spin.
const animal = reels[0].selectedEmoji; // e.g. π¦
const color = reels[1].selectedEmoji; // e.g. π
const vibe = reels[2].selectedEmoji; // e.g. β‘
The nickname pops up with a bounce animation and confetti. The Web Speech API reads it aloud β each word highlights yellow as it's spoken so early readers can follow along.
A coin-drop animation plays, then the app navigates to feed.html where the new nickname appears at the top, encouraging the player to vote on others.
π€ The AI Prompt System
The Worker builds the nickname prompt using three layers that work together to keep results fresh and varied:
Layer 1 β Static ban list
Common adjectives like Happy, Silly, Cute, Golden, Brave are permanently banned so the AI never falls back on boring defaults.
Layer 2 β Global last-8 avoidance
The Worker queries D1 for the last 8 nicknames generated by anyone and appends them as words to avoid. This prevents the same word appearing twice in a row across all players.
Layer 3 β Rolling dynamic ban
The last 100 nicknames are analysed. Any word appearing 5% or more of the time is temporarily banned (max 8 words). Animal names are protected from this ban so the core nickname structure stays intact.
Prompt styles
The AI is given a randomly selected style instruction on each call. Honorific style (Dr. / Professor / Captain / Chef) is picked 3Γ more often than others because it produces the most interesting results. The style used is saved to D1 for analysis.
ποΈ The Database
Cloudflare D1 is a SQLite database built into Cloudflare Workers β no separate service to set up. The schema has five tables:
nicknamesβ every generated nickname, its emojis, creator, score, and prompt stylecreatorsβ player identities: UUID, transfer code, display namevotesβ one row per card per voter, preventing double votingdaily_leaderboardβ yesterday's champion snapshot (written by the midnight cron)alltime_leaderboardβ all-time top cards with days-on-board counter
π Creator Identity
Every visitor gets a UUID generated in their browser and stored in localStorage β no account or password required. This UUID is the creator_id sent with every API call.
On first nickname generation, the Worker creates a human-readable transfer code (e.g. SUNNY-FOX-4829) stored in both D1 and localStorage. Players use this code to restore their profile on a new device by visiting player.html#SUNNY-FOX-4829.
The player profile page shows stats, all past nicknames, and a QR code for easy device transfer.
π‘ The Live Feed
feed.html polls GET /api/feed every 10 seconds. When new cards arrive they animate in with a pivot-and-slide entrance:
- The card starts rotated at -55Β° with only the bottom third visible (like being slipped under a door)
- It rotates to flat while a wrapper slides it down into position with a gentle bounce
- The full animation takes about 1.1 seconds
When multiple cards arrive at once, the current player's card is sorted to enter first, the first three animate with 200ms stagger, and any additional cards appear instantly below.
π Leaderboards
The daily leaderboard shows the top cards created today in EST, ordered by net score (likes minus dislikes). It refreshes live β scores update in real time as people vote.
A cron job runs at midnight EST to snapshot the day's #1 card into daily_leaderboard. This becomes the "Card to Beat" shown at the top of the daily tab the next day β a permanent record of past champions.
The all-time leaderboard shows the top 25 cards by net score across all time, with a badge showing how many days each card has appeared on the board.
π΄ The Avatar Generator
The avatar generator (avatar.html) is a standalone prototype that creates PokΓ©mon-style creature cards. It uses a three-step AI pipeline:
Llama 3.1 8B generates 3 child-friendly sentences with blanks tailored to the creature β e.g. "My fox's most powerful ability is ___". Each blank has 4 emoji suggestions. The player picks one emoji per blank.
Llama writes a rich, detailed image generation prompt incorporating both the original emojis and the mad lib answers. The answers must visibly appear in the illustration β Llama is explicitly instructed to reflect them in the creature's design.
The prompt is sent to @cf/bytedance/stable-diffusion-xl-lightning on Cloudflare's free tier. Three images are generated with different random seeds so the player can pick their favourite. Each is rendered inside a holofoil PokΓ©mon-style card with type badges, HP, and AI-generated flavour text.
βοΈ What Is a Cloudflare Worker?
A Cloudflare Worker is a tiny piece of code that runs on Cloudflare's global network β only when called. No server to manage; it scales automatically and runs on demand. The free tier includes 100,000 requests per day.
This app uses two Workers:
- emojilab β handles all nickname generation, feed, votes, leaderboards, and player profiles. Uses Groq (for AI) and D1 (for storage).
- nickname-avatar β handles the avatar generator. Uses Cloudflare Workers AI for both the language model and the image model. No external API key needed.
Workers also handle CORS β a browser security rule requiring servers to explicitly allow requests from different domains. Since the frontend and Workers are on different domains, every Worker response includes the necessary headers.
π Text-to-Speech
After a nickname appears, the app reads it aloud using the browser's built-in Web Speech API β no external service needed. It speaks the intro phrase "Your nickname is" then each word individually, slowly and clearly. As each word is spoken, it highlights yellow on screen so early readers can follow along.
TTS also works on the feed, leaderboard, and player profile pages β tap any nickname card to hear it read aloud. The app prefers Samantha on iOS or Google US English in Chrome.
π How Deployment Works
Every push to main triggers three CI jobs in parallel:
Each Worker job has an isolated environment and an explicit --name flag to prevent the two Workers from being accidentally deployed to each other's slot.
π Ready to Go Deeper?
Each guide is written for curious beginners β no experience needed.