Inspiration

After seeing the examples given to us of bad UI during the opening ceremony, we were inspired to make a "fake-out" site to prank users into being frustrated at an annoying sign up form, before the penny drops and they are introduced to the actual purpose of the site: a snake game!

What it does

SnekUp is a counter-intuitive sign-up experience that gamifies form submission. Instead of filling out fields passively, users steer a pixel-art snake with arrow keys to "eat" fleeing form fields (Name, Email, Password). Each capture freezes the game momentarily for input, and users race against a 120-second countdown. To punish the user, every keystroke costs a second, and bad input deducts 5 seconds. Completions are ranked on a persistent leaderboard, sorted by speed and death count. It's a hilariously frustrating take on user sign-up — form fields that don't want to be filled.

How we built it

Frontend: React + Vite with a DOM-based game rendering engine (no Canvas). The game loop runs outside React's render cycle via custom hooks (useGameLoop, useKeyboard, useSnakeGame), keeping it performant. Fields flee intelligently toward the snake using AI collision detection; captured fields trigger a smooth morph animation (form positions → game grid) and cross-fade into the game world. We designed the UI in AllocateMe's pixel-art palette using Tailwind CSS and shadcn/ui components.

Backend: Node.js + Express serves a minimal REST API: - POST /api/submit — validates input, SHA-256 hashes emails (never stored plaintext), inserts to SQLite, calculates rank

  • GET /api/leaderboard — returns top 10 ranked players - PATCH /api/submit/:id/* — one-time display name edit & frame colour customization

Database: SQLite (better-sqlite3) for simplicity and portability; schema auto-initializes on server startup.

Polish: Progressive password rules (≥8 chars → uppercase → digit sum → emoji → prime number), death-penalty 3-2-1 countdowns, animated fire border around the game board, penalty flashes on timer deduction, and top-3 leaderboard entries get rainbow name animations + dual-colour gradient borders

Challenges we ran into

  1. Game loop timing: Decoupling the pure-JS game engine from React's render cycle was tricky. We solved it with a custom useGameLoop hook that exposes game state via React state only on discrete events (field captured, death, game over), not every tick.
  2. Form-to-game animation: Transitioning field positions from the pre-game form to scattered game grid positions required careful timing. Fields start in form layout, spiral/scatter to random game positions (2s ease-in-quintic), then the snake pursues them. Getting the morph animation to sync with game start was finicky.
  3. Snake respawning collision: After death, the snake resets to centre, but sometimes immediately re-collides with walls. Fixed by ensuring a brief invulnerability window or better spawn detection.
    1. Keyboard event leakage: Players typing in the input overlay could accidentally trigger snake direction changes. Solved by guarding input handlers against INPUT/TEXTAREA target elements.

Accomplishments that we're proud of

  • End-to-end flow: From landing page → sign-up form → game → leaderboard, all working and polished in a single sprint.
  • AI field flee: Fields detect the snake's proximity and intelligently dodge, staying just catchable but challenging. Locked password field (until Name+Email captured) flees even more aggressively.
  • Punishment mechanics: Typing costs time; bad validation costs time; deaths spawn countdowns. The game actively discourages completion, which is the whole joke.
  • Visual design: Pixel-art, animated blob backgrounds, fire borders, glitch effects, and rainbow leaderboard animations create a cohesive, playful brand.
  • Solid backend: Proper email hashing, rank calculation, leaderboard API, and one-time name/frame customization. Data is persistent and ranked fairly.
  • Accessibility of complexity: Despite 7+ stages of features, the core mechanic is immediately understandable: catch the fields, type your info, beat the clock.

What we learned

  • Separating concerns: Pure-JS game engines + React state management can coexist beautifully if callbacks are the bridge.
  • Timing animation sync for good UX using CSS and JS is... an experience
  • Constraints breed creativity
  • User psychology make punishment feel fair and fun, not frustrating.

What's next for SnekUp!

  1. Mobile support: On-screen D-pad or swipe controls so it works on tablets/phones.
  2. Personal best tracking: If the same player (matched by email hash) beats their previous score, replace the leaderboard entry and show a "New Personal Best!" badge.
  3. Difficulty tiers: After each game, let players attempt "Hard Mode" with faster flee radius or tighter time limits.
  4. Multiplayer: Two players race on the same board with WebSockets — last to finish loses.
  5. Easter eggs: Per-field surprises (password field grows spikes, emoji field plays a secret sound, etc.) and leaderboard milestones.

Built With

Share this project:

Updates