All files / web/src/arcade-games/music-matching variant.ts

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

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                                                                                                                                                         
/**
 * Music Matching Game — Full Variant Definition (Client-Side)
 *
 * Extends the server-safe variant with React components for rendering.
 * This file imports .tsx components and should only be used on the client.
 */

import type { MatchingPairsVariant } from '@/lib/arcade/matching-pairs-framework'
import { MusicCardFront } from './components/MusicCardFront'
import { MusicSetupContent } from './components/MusicSetupContent'
import type { MusicCard, MusicConfig } from './types'
import { musicVariantServer } from './variant-server'

export const musicVariant: MatchingPairsVariant<MusicCard, MusicConfig> = {
  ...musicVariantServer,

  CardFront: MusicCardFront,

  getCardBackStyle: (card, isMatched) => {
    if (isMatched) {
      return { gradient: 'linear-gradient(135deg, #48bb78, #38a169)', icon: '✓' }
    }
    if (card.type === 'staff-note') {
      return {
        gradient: 'linear-gradient(135deg, #2c3e80, #4a69bd)',
        icon: '𝄞',
      }
    }
    // note-name cards — warm orange/amber to contrast the cool blue staff cards
    return {
      gradient: 'linear-gradient(135deg, #e17055, #fdcb6e)',
      icon: 'A♯',
    }
  },

  shouldDimCard: (card, firstFlippedCard) => {
    // note-name flipped → dim other note-name cards (staff-to-name mode)
    if (firstFlippedCard.type === 'note-name' && card.type === 'note-name') {
      return true
    }

    // staff-note flipped → behaviour depends on what the candidate card is
    if (firstFlippedCard.type === 'staff-note') {
      // Dim note-name cards? No — those are the match target in staff-to-name
      if (card.type === 'note-name') {
        return false
      }

      // Both are staff-note: dim if same clef (treble-to-bass mode),
      // or dim if candidate has no clef differentiation (staff-to-name mode:
      // the match target is a note-name card, so other staff-note cards are wrong)
      if (card.type === 'staff-note') {
        // If clefs differ, keep it available (treble-to-bass: it's the match target)
        if (card.clef && firstFlippedCard.clef && card.clef !== firstFlippedCard.clef) {
          return false
        }
        // Same clef or no clef → dim
        return true
      }
    }

    return false
  },

  SetupContent: MusicSetupContent,

  getNavInfo: (config) => ({
    title: config.gameType === 'staff-to-name' ? 'Note Match' : 'Clef Match',
    emoji: '🎵',
  }),

  getQuickTip: (config) =>
    config.gameType === 'staff-to-name'
      ? 'Match notes on the staff to their names'
      : 'Match the same pitch across clefs',
}