feat: Initial project structure for WebTriviasMulti
- Backend: FastAPI + Python-SocketIO + SQLAlchemy - Models for categories, questions, game sessions, events - AI services for answer validation and question generation (Claude) - Room management with Redis - Game logic with stealing mechanics - Admin API for question management - Frontend: React + Vite + TypeScript + Tailwind - 5 visual themes (DRRR, Retro, Minimal, RGB, Anime 90s) - Real-time game with Socket.IO - Achievement system - Replay functionality - Sound effects per theme - Docker Compose for deployment - Design documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
90
frontend/src/stores/soundStore.ts
Normal file
90
frontend/src/stores/soundStore.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { create } from 'zustand'
|
||||
import { persist } from 'zustand/middleware'
|
||||
import type { ThemeName } from '../types'
|
||||
|
||||
type SoundEffect =
|
||||
| 'correct'
|
||||
| 'incorrect'
|
||||
| 'steal'
|
||||
| 'timer_tick'
|
||||
| 'timer_urgent'
|
||||
| 'victory'
|
||||
| 'defeat'
|
||||
| 'select'
|
||||
|
||||
interface SoundState {
|
||||
volume: number
|
||||
muted: boolean
|
||||
setVolume: (volume: number) => void
|
||||
setMuted: (muted: boolean) => void
|
||||
toggleMute: () => void
|
||||
}
|
||||
|
||||
export const useSoundStore = create<SoundState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
volume: 0.7,
|
||||
muted: false,
|
||||
setVolume: (volume) => set({ volume }),
|
||||
setMuted: (muted) => set({ muted }),
|
||||
toggleMute: () => set((state) => ({ muted: !state.muted })),
|
||||
}),
|
||||
{
|
||||
name: 'trivia-sound',
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
// Sound file paths per theme
|
||||
export const soundPaths: Record<ThemeName, Record<SoundEffect, string>> = {
|
||||
drrr: {
|
||||
correct: '/sounds/drrr/correct.mp3',
|
||||
incorrect: '/sounds/drrr/incorrect.mp3',
|
||||
steal: '/sounds/drrr/steal.mp3',
|
||||
timer_tick: '/sounds/drrr/tick.mp3',
|
||||
timer_urgent: '/sounds/drrr/urgent.mp3',
|
||||
victory: '/sounds/drrr/victory.mp3',
|
||||
defeat: '/sounds/drrr/defeat.mp3',
|
||||
select: '/sounds/drrr/select.mp3',
|
||||
},
|
||||
retro: {
|
||||
correct: '/sounds/retro/correct.mp3',
|
||||
incorrect: '/sounds/retro/incorrect.mp3',
|
||||
steal: '/sounds/retro/steal.mp3',
|
||||
timer_tick: '/sounds/retro/tick.mp3',
|
||||
timer_urgent: '/sounds/retro/urgent.mp3',
|
||||
victory: '/sounds/retro/victory.mp3',
|
||||
defeat: '/sounds/retro/defeat.mp3',
|
||||
select: '/sounds/retro/select.mp3',
|
||||
},
|
||||
minimal: {
|
||||
correct: '/sounds/minimal/correct.mp3',
|
||||
incorrect: '/sounds/minimal/incorrect.mp3',
|
||||
steal: '/sounds/minimal/steal.mp3',
|
||||
timer_tick: '/sounds/minimal/tick.mp3',
|
||||
timer_urgent: '/sounds/minimal/urgent.mp3',
|
||||
victory: '/sounds/minimal/victory.mp3',
|
||||
defeat: '/sounds/minimal/defeat.mp3',
|
||||
select: '/sounds/minimal/select.mp3',
|
||||
},
|
||||
rgb: {
|
||||
correct: '/sounds/rgb/correct.mp3',
|
||||
incorrect: '/sounds/rgb/incorrect.mp3',
|
||||
steal: '/sounds/rgb/steal.mp3',
|
||||
timer_tick: '/sounds/rgb/tick.mp3',
|
||||
timer_urgent: '/sounds/rgb/urgent.mp3',
|
||||
victory: '/sounds/rgb/victory.mp3',
|
||||
defeat: '/sounds/rgb/defeat.mp3',
|
||||
select: '/sounds/rgb/select.mp3',
|
||||
},
|
||||
anime: {
|
||||
correct: '/sounds/anime/correct.mp3',
|
||||
incorrect: '/sounds/anime/incorrect.mp3',
|
||||
steal: '/sounds/anime/steal.mp3',
|
||||
timer_tick: '/sounds/anime/tick.mp3',
|
||||
timer_urgent: '/sounds/anime/urgent.mp3',
|
||||
victory: '/sounds/anime/victory.mp3',
|
||||
defeat: '/sounds/anime/defeat.mp3',
|
||||
select: '/sounds/anime/select.mp3',
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user