All files / web/src/arcade-games/know-your-world/utils celebration.ts

0% Statements 0/90
0% Branches 0/1
0% Functions 0/1
0% Lines 0/90

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                                                                                                                                                                                     
/**
 * Celebration Classification Utility
 *
 * Determines the type of celebration based on how the user found the region.
 * Uses search metrics from the hot/cold feedback system to classify:
 * - Lightning: Fast and direct find
 * - Standard: Normal discovery
 * - Hard-earned: Extensive searching, shows perseverance
 */

import type { SearchMetrics } from '../hooks/useHotColdFeedback'
import type { CelebrationType } from '../Provider'

// Thresholds for classification
const LIGHTNING_TIME_MS = 3000 // Under 3 seconds
const LIGHTNING_EFFICIENCY = 0.7 // Very direct path

const HARD_EARNED_TIME_MS = 20000 // Over 20 seconds
const HARD_EARNED_EFFICIENCY = 0.3 // Wandered a lot
const HARD_EARNED_REVERSALS = 10 // Many direction changes
const HARD_EARNED_NEAR_MISSES = 2 // Got close multiple times

/**
 * Classify the celebration type based on search metrics.
 *
 * @param metrics - Search metrics from useHotColdFeedback
 * @returns The celebration type: 'lightning', 'standard', or 'hard-earned'
 */
export function classifyCelebration(metrics: SearchMetrics): CelebrationType {
  // Lightning: Fast and direct
  // Kid knew exactly where to look - reward the speed!
  if (metrics.timeToFind < LIGHTNING_TIME_MS && metrics.searchEfficiency > LIGHTNING_EFFICIENCY) {
    return 'lightning'
  }

  // Hard-earned: Any of these indicate real effort
  // Kid really worked for it - acknowledge the perseverance!
  if (
    metrics.timeToFind > HARD_EARNED_TIME_MS ||
    metrics.searchEfficiency < HARD_EARNED_EFFICIENCY ||
    metrics.directionReversals > HARD_EARNED_REVERSALS ||
    metrics.nearMissCount > HARD_EARNED_NEAR_MISSES
  ) {
    return 'hard-earned'
  }

  // Standard: Normal discovery
  return 'standard'
}

// Celebration timing configuration
export const CELEBRATION_TIMING = {
  lightning: {
    flashDuration: 400,
    confettiDuration: 600,
    soundDuration: 200,
    totalDuration: 600,
  },
  standard: {
    flashDuration: 600,
    confettiDuration: 1000,
    soundDuration: 400,
    totalDuration: 1000,
  },
  'hard-earned': {
    flashDuration: 800,
    confettiDuration: 1500,
    soundDuration: 600,
    totalDuration: 1500,
  },
} as const

// Confetti configuration per celebration type
export const CONFETTI_CONFIG = {
  lightning: {
    count: 12,
    spread: 60,
    colors: ['#fbbf24', '#fcd34d', '#fef3c7'], // Gold sparkles
  },
  standard: {
    count: 20,
    spread: 90,
    colors: ['#fbbf24', '#22c55e', '#3b82f6', '#f472b6'], // Colorful mix
  },
  'hard-earned': {
    count: 35,
    spread: 120,
    colors: ['#fbbf24', '#22c55e', '#8b5cf6', '#ec4899', '#f97316'], // Big party!
  },
} as const