This is a 2025 holiday break exploration in vibe-coding.
This is a party game whose rules are as follows:
- Each game has one leader, and everyone else is a guesser. The leader selects how many rounds of guessing the game will involve (1-3).
- At the start of the game, the leader is assigned and shown a color swatch chosen from the 4096-color RGB space defined by 4-bits per channel (16^3 = 4096), i.e. the range #000 to #fff
- Each guesser is shown a palette of swatches, covering the full color space.
- The leader provides hints (verbally, out of band).
- Each guesser, after hearing the hints, selects the swatch which they feel is best indicated by the given hints.
- Once all the guesses are in, the round of guessing is completed.
- If the round is not the final round, guessing resumes. The leader reviews the guesses and gives more refined hints to move guessers closer to the target.
- If the round is the final round, the game is completed. The guesser whose match is nearest to the target color is the winner.
coloranintin the range [0, 4096)gamea compound object whose fields are:game_id:uuidthe game's ID, used to construct backend endpointsopen:boolthe game is open to inviteescurrent_round:int | nullthe current round, if the game has begun alreadytotal_rounds:intthe number of rounds totalfinished:boolthe game is either finished, or still pending guessesplayers:list[str]a list of player names, representing those who have joinedguessed_players:list[str]players who have submitted guesses in the current roundwinner:str | nullthe player who won, if the game has completedwinning_guess:color | nullthe winner's guess, if the game has completedwinning_distance:float | nullthe Euclidean distance from the winning guess and the target, if the game has completedtarget:color | nullthe target color to guess
The project is implemented as a FastAPI web application. The structure of the application is given here:
GET /game/newbegins a new game. It is expected that the first leader player is the one who requests the new game.GET /game/{game_id}/joinonce the game is begun, this URL should be provided to the leader to share with each guesser, who should use this URL to join the game.POST /game/{game_id}/joinaccepts the player's registration and joins the player to the game.name:strthe player's name
POST /game/{game_id}/startthe leader POSTs to this endpoint when they are ready to start the gametargetcolorthe color in #000 - #fff to guess
POST /game/{game_id}/guesswhen a player is ready to submit a guess, this endpoint accepts itcolor:stra 3-digit hex-code in the space #000 - #fff
GET /game/{game_id}/statusused for various UI functions to determine the state of the gamegame: a JSON object of typegame(see Types section above)
The frontend is a React application with a two modes, leader and guesser, each comprising a number of screens. The screens are all designed with a phone user in mind.
The leader mode has the following screens, whose components are listed below each screen:
inviting- a link to share (out of band) with invitees
- the list of users who have joined
- a button to close invitation and begin, which triggers the transition to
guessing, and causesopen = false
guessing- the target swatch
- the list of users who have submitted guesses
- once all guessers have submitted entries,
- if there is another round, show each player's guess to the leader, present a button to start the next round, which restarts the
guessingstate - if this was the final round, transition to
result
- if there is another round, show each player's guess to the leader, present a button to start the next round, which restarts the
result- the person whose guess is the nearest (using Euclidean distance) to the target wins, and their name is shown
- the winning guess and the target swatches are shown side by side and labeled appropriately
The guesser mode has the following screens and components:
waiting- the list of users who have joined
- once the game's status becomes
open = falsethen transitions toguessing
guessing- a scrollable grid of sorted swatches representing each color in the color space, each swatch being selectable, and the entire grid having the property that only one swatch can be selected at a time
- a button anchored to the bottom of the screen (so superimposed above the grid of swatches) whose color changes to the color selected, bearing the label "Submit Guess"
- when that button is pressed, POSTs to
/game/{game_id}/guessand transitions towaiting
waiting- if this was not the final round, waits for the next round to start (
current_roundincremented by 1), then returns toguessing - if this was the final round, waits for
finished = truei.e. for all guesses to be submitted
- if this was not the final round, waits for the next round to start (
result- this screen is the same for the leader, see the leader's
resultscreen - if the user has the winning guess, they will see a button to start a new game, which when pressed, transitions them to the leader's
invitingscreen
- this screen is the same for the leader, see the leader's
- This game is expected to be hosted in uvicorn
- This game uses redis as a data store
- Any services on which this project depends should be defined in
process-compose.yamland run withprocess-compose up - The developer environment is provided through a devshell defined in a Nix flake