Claude Code Plugins

Community-maintained marketplace

Feedback

convex-game-management

@violabg/pictionary-game
0
0

Manage game lifecycle, player turns, round rotation, scoring, and game state transitions. Use when implementing game creation, turn management, score updates, and game completion flows in PictionAI.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name convex-game-management
description Manage game lifecycle, player turns, round rotation, scoring, and game state transitions. Use when implementing game creation, turn management, score updates, and game completion flows in PictionAI.
compatibility Requires Convex backend with mutations and queries, React hooks (useQuery, useMutation)
metadata [object Object]

Convex Game Management

Overview

This skill handles the complete game lifecycle for PictionAI's multiplayer Pictionary game, including game creation, player management, turn-based rotation, atomic turn completion with scoring, and game state transitions.

Core Concepts

Game States

  • waiting - Game created, players joining in lobby
  • started - Game in progress, turns rotating
  • finished - All rounds complete, winner determined

Turn States

  • drawing - Active turn, timer running (60-120 seconds)
  • completed - Turn finished with correct guess
  • time_up - Timer expired, no points awarded

Atomic Turn System

Turns are completed atomically to ensure data consistency:

  1. Start Turn: Drawer calls startNewTurn mutation
  2. Draw & Guess Phase: Real-time canvas sync, players submit guesses
  3. Turn Completion: Three atomic scenarios:
    • ✅ Correct guess → Both guesser and drawer earn points
    • 🏆 Manual winner selection → Drawer selects winner from guessers
    • ⏱️ Time up → No points, proceed to next turn
  4. Score Updates: Dual scoring system (guesser time bonus + drawer base score)
  5. Next Turn: Auto round-robin rotation to next player

Scoring System

Guess Scoring (Correct Answer)

  • Guesser: Base 50 points + time bonus (50 - elapsed_seconds, min 5 points)
  • Drawer: 25% of guesser's score, minimum 10 points

Drawer Scoring (Manual Winner)

  • Selected Guesser: 30 points
  • Drawer: 25 points

Key Mutations

startNewTurn

Start a new drawing turn, assign card, initialize timer.

mutation startNewTurn {
  args: {
    game_id: Id<"games">
  }
  // Returns: {
  //   turn_id: Id<"turns">,
  //   card: { word: string, category: string },
  //   drawer_id: Id<"users">,
  //   time_limit: number
  // }
}

submitGuessAndCompleteTurn

Submit a guess and complete the turn with atomic scoring.

mutation submitGuessAndCompleteTurn {
  args: {
    game_id: Id<"games">,
    turn_id: Id<"turns">,
    guesser_id: Id<"users">,
    guess: string,
    elapsed_time: number,
    is_correct?: boolean
  }
  // Handles three scenarios atomically:
  // 1. Correct guess → Award points to both
  // 2. Manual selection → Drawer chooses winner
  // 3. Time up → Skip to next turn
}

selectWinner (Manual Selection)

Drawer selects a guesser as the winner when time expires.

mutation selectWinner {
  args: {
    turn_id: Id<"turns">,
    selected_guesser_id: Id<"users">
  }
  // Awards 30 points to guesser, 25 to drawer
}

Key Queries

getGame

Fetch complete game state with players, current turn, scores.

query getGame {
  args: { game_id: Id<"games"> }
  // Returns full game with nested players, turns, scores
}

getGameTurns

Get all turns in a game with guesses and results.

query getGameTurns {
  args: { game_id: Id<"games"> }
  // Returns array of turns with scoring details
}

React Integration

// Start a new turn
const startTurn = useMutation(api.mutations.game.startNewTurn);
await startTurn({ game_id: gameId });

// Submit guess and complete turn
const submitGuess = useMutation(api.mutations.game.submitGuessAndCompleteTurn);
await submitGuess({
  game_id: gameId,
  turn_id: turnId,
  guesser_id: userId,
  guess: "elephant",
  elapsed_time: 45,
});

// Fetch game state
const game = useQuery(api.queries.games.getGame, { game_id: gameId });

Database Schema References

// Games table
games: defineTable({
  code: v.string(), // Unique game code
  creator_id: v.id("users"),
  players: v.array(
    v.object({
      user_id: v.id("users"),
      score: v.number(),
      is_drawer: v.boolean(),
    })
  ),
  state: v.union(
    v.literal("waiting"),
    v.literal("started"),
    v.literal("finished")
  ),
  current_turn_index: v.number(),
  created_at: v.optional(v.number()),
  round_count: v.number(),
});

// Turns table
turns: defineTable({
  game_id: v.id("games"),
  drawer_id: v.id("users"),
  card_id: v.id("cards"),
  state: v.union(
    v.literal("drawing"),
    v.literal("completed"),
    v.literal("time_up")
  ),
  timer_started_at: v.number(),
  time_limit: v.number(),
  correct_guesser_id: v.optional(v.id("users")),
  guesses: v.array(
    v.object({
      guesser_id: v.id("users"),
      guess: v.string(),
      timestamp: v.number(),
      is_correct: v.optional(v.boolean()),
    })
  ),
});

Common Patterns

Monitor active turn

const game = useQuery(api.queries.games.getGame, { game_id });
const currentTurn = game?.turns[game.current_turn_index];
const isMyTurn = currentTurn?.drawer_id === userId;

Handle turn completion

// When drawer completes turn with guess result
const completeWithCorrect = useMutation(
  api.mutations.game.submitGuessAndCompleteTurn
);
await completeWithCorrect({
  game_id: gameId,
  turn_id: turnId,
  guesser_id: guesserId,
  guess: "elephant",
  elapsed_time: 30,
  is_correct: true,
});

Automatic next turn

The mutation automatically:

  1. Rotates drawer (round-robin through players)
  2. Assigns new card
  3. Starts timer
  4. Updates game state

Edge Cases

  • Multiple guesses per player: Allowed, only latest is scored
  • Guess submitted after timer: System checks elapsed time on server
  • Late guess arrival: Real-time subscription updates guess feed
  • Manual selection ambiguity: Drawer must explicitly select one winner
  • Game with 2 players: Drawer rotation still works with round-robin

See Also

  • TURN_MANAGEMENT_ANALYSIS.md - Detailed atomic turn analysis
  • convex/mutations/game.ts - Complete mutation implementations
  • components/game/game-board.tsx - UI integration