nearly finalized, fix the questions

This commit is contained in:
2026-01-21 00:00:56 -06:00
parent 4c8a30b9f6
commit ac68d6c7b5
5 changed files with 432 additions and 115 deletions

View File

@@ -35,12 +35,15 @@
<div class="light player-4" id="light4"></div> <div class="light player-4" id="light4"></div>
</div> </div>
<div class="buzzed-player" id="buzzedPlayer"></div> <div class="buzzed-player" id="buzzedPlayer"></div>
<div class="timer-display" id="timerDisplay" style="display: none;">
Time: 5s
</div>
</div> </div>
<div class="question-section"> <div class="question-section">
<div class="question-header"> <div class="question-header">
<span class="question-category" id="questionCategory">CATEGORY</span> <span class="question-category" id="questionCategory">CATEGORY</span>
<span class="question-number">Question <span id="questionNum">1</span>/25</span> <span class="question-number">Question <span id="questionNum">1</span></span>
</div> </div>
<div class="question-text" id="questionText"> <div class="question-text" id="questionText">
Click "New Question" to start Click "New Question" to start
@@ -64,6 +67,21 @@
<button id="resetGame" class="control-btn warning">Reset Game</button> <button id="resetGame" class="control-btn warning">Reset Game</button>
</div> </div>
<div class="settings-section">
<div class="setting-group">
<h3>📚 Source Selection</h3>
<select id="sourceSelect" class="source-select">
<option value="">All Sources (Random)</option>
<option value="Official">Official Sample Sets</option>
<option value="CSUB">CSUB Regionals</option>
<option value="05Nats">2005 Nationals</option>
<option value="98Nats">1998 Nationals</option>
</select>
<input type="number" id="roundNumber" placeholder="Round # (optional)" min="1" max="25" class="round-input">
</div>
<div class="setting-group">
<h3>🔬 Category Filter</h3>
<div class="category-filter"> <div class="category-filter">
<label> <label>
<input type="checkbox" class="category-checkbox" value="PHYSICS" checked> Physics <input type="checkbox" class="category-checkbox" value="PHYSICS" checked> Physics
@@ -80,6 +98,23 @@
<label> <label>
<input type="checkbox" class="category-checkbox" value="EARTH SCIENCE" checked> Earth Science <input type="checkbox" class="category-checkbox" value="EARTH SCIENCE" checked> Earth Science
</label> </label>
<label>
<input type="checkbox" class="category-checkbox" value="EARTH AND SPACE" checked> Earth & Space
</label>
<label>
<input type="checkbox" class="category-checkbox" value="ASTRONOMY" checked> Astronomy
</label>
<label>
<input type="checkbox" class="category-checkbox" value="ENERGY" checked> Energy
</label>
<label>
<input type="checkbox" class="category-checkbox" value="GENERAL SCIENCE" checked> General Science
</label>
<label>
<input type="checkbox" class="category-checkbox" value="COMPUTER SCIENCE" checked> Computer Science
</label>
</div>
</div>
</div> </div>
</div> </div>

View File

@@ -7,9 +7,9 @@ const questionText = document.getElementById('questionText');
const questionCategory = document.getElementById('questionCategory'); const questionCategory = document.getElementById('questionCategory');
const questionNum = document.getElementById('questionNum'); const questionNum = document.getElementById('questionNum');
const correctAnswer = document.getElementById('correctAnswer'); const correctAnswer = document.getElementById('correctAnswer');
const playerAnswer = document.getElementById('playerAnswer');
const answerSection = document.getElementById('answerSection'); const answerSection = document.getElementById('answerSection');
const buzzedPlayer = document.getElementById('buzzedPlayer'); const buzzedPlayer = document.getElementById('buzzedPlayer');
const timerDisplay = document.getElementById('timerDisplay');
const newQuestionBtn = document.getElementById('newQuestion'); const newQuestionBtn = document.getElementById('newQuestion');
const activateBuzzerBtn = document.getElementById('activateBuzzer'); const activateBuzzerBtn = document.getElementById('activateBuzzer');
@@ -24,6 +24,64 @@ let currentQuestionNumber = 1;
let currentBuzzedPlayer = null; let currentBuzzedPlayer = null;
let speechSynthesis = window.speechSynthesis; let speechSynthesis = window.speechSynthesis;
let currentUtterance = null; let currentUtterance = null;
let voicesLoaded = false;
let isShowingBonus = false;
let timerInterval = null;
let timeRemaining = 0;
// Track used questions to avoid repeats
let usedQuestionIds = new Set();
let allQuestions = [];
let questionsLoaded = false;
// Load voices
function loadVoices() {
return new Promise((resolve) => {
let voices = speechSynthesis.getVoices();
if (voices.length > 0) {
voicesLoaded = true;
resolve(voices);
} else {
speechSynthesis.onvoiceschanged = () => {
voices = speechSynthesis.getVoices();
voicesLoaded = true;
resolve(voices);
};
}
});
}
loadVoices().then(() => {
console.log('Voices loaded:', speechSynthesis.getVoices().length);
});
// Load all questions once at startup
async function loadAllQuestions() {
if (questionsLoaded) return;
try {
console.log('Loading all questions from database...');
const response = await fetch(CORS_PROXY + encodeURIComponent('https://scibowldb.com/api/questions'), {
method: 'GET'
});
if (!response.ok) {
throw new Error('Failed to load questions');
}
const data = await response.json();
allQuestions = data.questions || data;
questionsLoaded = true;
console.log(`Loaded ${allQuestions.length} questions!`);
} catch (error) {
console.error('Error loading questions:', error);
alert('Could not load question database. Will use random API instead (may repeat questions).');
}
}
// Start loading questions immediately
loadAllQuestions();
// Initialize game state // Initialize game state
database.ref('gameState').set({ database.ref('gameState').set({
@@ -55,63 +113,148 @@ database.ref('gameState').on('value', (snapshot) => {
const playerNum = state.buzzer.playerId.replace('player', ''); const playerNum = state.buzzer.playerId.replace('player', '');
currentBuzzedPlayer = state.buzzer.playerId; currentBuzzedPlayer = state.buzzer.playerId;
// Light up the buzzer
document.querySelectorAll('.light').forEach(l => l.classList.remove('active')); document.querySelectorAll('.light').forEach(l => l.classList.remove('active'));
document.getElementById(`light${playerNum}`).classList.add('active'); document.getElementById(`light${playerNum}`).classList.add('active');
buzzedPlayer.textContent = `Player ${playerNum} buzzed in!`; buzzedPlayer.textContent = `Player ${playerNum} buzzed in!`;
// Stop reading when someone buzzes // Stop reading and timer when someone buzzes
if (currentUtterance) { if (currentUtterance && speechSynthesis.speaking) {
speechSynthesis.cancel(); speechSynthesis.cancel();
readQuestionBtn.textContent = '🔊 Read Question';
readQuestionBtn.disabled = false;
} }
stopTimer();
// Show grading buttons
markCorrectBtn.style.display = 'inline-block'; markCorrectBtn.style.display = 'inline-block';
markIncorrectBtn.style.display = 'inline-block'; markIncorrectBtn.style.display = 'inline-block';
showAnswerBtn.style.display = 'inline-block'; showAnswerBtn.style.display = 'inline-block';
} }
// Update player answer
if (state.playerAnswer) {
playerAnswer.textContent = state.playerAnswer.answer;
answerSection.style.display = 'block';
}
}); });
// Fetch new question // Timer functions
function startTimer(seconds) {
stopTimer();
timeRemaining = seconds;
timerDisplay.textContent = `Time: ${seconds}s`;
timerDisplay.style.display = 'block';
timerInterval = setInterval(() => {
timeRemaining--;
timerDisplay.textContent = `Time: ${timeRemaining}s`;
if (timeRemaining <= 0) {
stopTimer();
timerDisplay.textContent = 'Time\'s up!';
setTimeout(() => {
timerDisplay.style.display = 'none';
}, 2000);
}
}, 1000);
}
function stopTimer() {
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
}
// Get filtered questions based on user selection
function getFilteredQuestions() {
const categories = Array.from(document.querySelectorAll('.category-checkbox:checked'))
.map(cb => cb.value);
const source = document.getElementById('sourceSelect').value;
const roundNum = document.getElementById('roundNumber').value;
let filtered = allQuestions.filter(q => {
// Filter by category
if (categories.length > 0 && !categories.includes(q.category)) {
return false;
}
// Filter by source
if (source && !q.source.startsWith(source)) {
return false;
}
// Filter by round number
if (roundNum && !q.source.includes(`round${roundNum}`)) {
return false;
}
// Exclude already used questions
if (usedQuestionIds.has(q.id)) {
return false;
}
return true;
});
return filtered;
}
// Fetch new question with filtering
newQuestionBtn.addEventListener('click', async () => { newQuestionBtn.addEventListener('click', async () => {
const categories = Array.from(document.querySelectorAll('.category-checkbox:checked')) const categories = Array.from(document.querySelectorAll('.category-checkbox:checked'))
.map(cb => cb.value); .map(cb => cb.value);
try { if (categories.length === 0) {
// Just fetch a random question without filtering alert('Please select at least one category!');
const response = await fetch(CORS_PROXY + encodeURIComponent(API_URL), { return;
method: 'GET' // Changed to GET - simpler
});
if (!response.ok) {
throw new Error('API request failed');
} }
const data = await response.json(); // Wait for questions to load if not ready
if (!questionsLoaded) {
newQuestionBtn.textContent = 'Loading questions...';
newQuestionBtn.disabled = true;
await loadAllQuestions();
newQuestionBtn.textContent = 'New Question';
newQuestionBtn.disabled = false;
}
// The API returns the question directly, not wrapped try {
currentQuestion = data; const availableQuestions = getFilteredQuestions();
console.log('Fetched question:', currentQuestion); if (availableQuestions.length === 0) {
const shouldReset = confirm('No more unique questions available with these filters! Reset used questions?');
if (shouldReset) {
usedQuestionIds.clear();
newQuestionBtn.click();
return;
} else {
alert('Try changing your filters or reset the game.');
return;
}
}
// Pick a random question from available ones
const randomIndex = Math.floor(Math.random() * availableQuestions.length);
currentQuestion = availableQuestions[randomIndex];
// Mark this question as used
usedQuestionIds.add(currentQuestion.id);
isShowingBonus = false;
console.log('Selected question:', currentQuestion);
console.log('Questions remaining:', availableQuestions.length - 1);
questionText.textContent = currentQuestion.tossup_question; questionText.textContent = currentQuestion.tossup_question;
questionCategory.textContent = currentQuestion.category; questionCategory.textContent = `${currentQuestion.category} - TOSSUP`;
correctAnswer.textContent = currentQuestion.tossup_answer; correctAnswer.textContent = currentQuestion.tossup_answer;
questionNum.textContent = currentQuestionNumber; questionNum.textContent = currentQuestionNumber;
// Update Firebase // Show source info
if (currentQuestion.source) {
questionCategory.textContent = `${currentQuestion.category} - TOSSUP (${currentQuestion.source})`;
}
await database.ref('gameState').update({ await database.ref('gameState').update({
currentQuestion: currentQuestion, currentQuestion: currentQuestion,
buzzerActive: false, buzzerActive: false,
buzzer: null, buzzer: null,
playerAnswer: null,
questionNumber: currentQuestionNumber, questionNumber: currentQuestionNumber,
isReading: false isReading: false
}); });
@@ -119,6 +262,7 @@ newQuestionBtn.addEventListener('click', async () => {
// Reset UI // Reset UI
answerSection.style.display = 'none'; answerSection.style.display = 'none';
buzzedPlayer.textContent = ''; buzzedPlayer.textContent = '';
timerDisplay.style.display = 'none';
document.querySelectorAll('.light').forEach(l => l.classList.remove('active')); document.querySelectorAll('.light').forEach(l => l.classList.remove('active'));
markCorrectBtn.style.display = 'none'; markCorrectBtn.style.display = 'none';
markIncorrectBtn.style.display = 'none'; markIncorrectBtn.style.display = 'none';
@@ -132,50 +276,78 @@ newQuestionBtn.addEventListener('click', async () => {
} catch (error) { } catch (error) {
console.error('Error fetching question:', error); console.error('Error fetching question:', error);
alert('Error loading question. The API might be down. Check console for details.'); alert('Error loading question. Try refreshing the page.');
} }
}); });
// Read question aloud // Read question aloud
readQuestionBtn.addEventListener('click', () => { readQuestionBtn.addEventListener('click', async () => {
if (!currentQuestion) { if (!currentQuestion) {
alert('Load a question first!'); alert('Load a question first!');
return; return;
} }
// Stop any current speech if (!voicesLoaded) {
await loadVoices();
}
if (speechSynthesis.speaking) {
speechSynthesis.cancel(); speechSynthesis.cancel();
await new Promise(resolve => setTimeout(resolve, 100));
}
// Create utterance const textToRead = isShowingBonus ? currentQuestion.bonus_question : currentQuestion.tossup_question;
currentUtterance = new SpeechSynthesisUtterance(currentQuestion.tossup_question); currentUtterance = new SpeechSynthesisUtterance(textToRead);
currentUtterance.rate = 0.9; // Slightly slower for clarity
currentUtterance.pitch = 1; // Select best voice
currentUtterance.volume = 1; const voices = speechSynthesis.getVoices();
const preferredVoice = voices.find(v => v.name.includes('Google') && v.lang.startsWith('en')) ||
voices.find(v => v.lang === 'en-US' && v.name.includes('Natural')) ||
voices.find(v => v.lang === 'en-US') ||
voices[0];
if (preferredVoice) {
currentUtterance.voice = preferredVoice;
}
currentUtterance.rate = 0.9;
currentUtterance.pitch = 1.0;
currentUtterance.volume = 1.0;
console.log('Reading with voice:', preferredVoice?.name);
// Update Firebase that we're reading
database.ref('gameState/isReading').set(true); database.ref('gameState/isReading').set(true);
currentUtterance.onstart = () => {
readQuestionBtn.textContent = '🔊 Reading...';
readQuestionBtn.disabled = true;
};
currentUtterance.onend = () => { currentUtterance.onend = () => {
database.ref('gameState/isReading').set(false); database.ref('gameState/isReading').set(false);
console.log('Finished reading question'); readQuestionBtn.textContent = '🔊 Read Question';
readQuestionBtn.disabled = false;
// Start timer after reading
const timerDuration = isShowingBonus ? 20 : 5;
startTimer(timerDuration);
};
currentUtterance.onerror = (event) => {
console.error('Speech error:', event);
database.ref('gameState/isReading').set(false);
readQuestionBtn.textContent = '🔊 Read Question';
readQuestionBtn.disabled = false;
}; };
speechSynthesis.speak(currentUtterance); speechSynthesis.speak(currentUtterance);
readQuestionBtn.textContent = '🔊 Reading...';
readQuestionBtn.disabled = true;
setTimeout(() => {
readQuestionBtn.textContent = '🔊 Read Question';
readQuestionBtn.disabled = false;
}, 2000);
}); });
// Activate buzzers // Activate buzzers
activateBuzzerBtn.addEventListener('click', () => { activateBuzzerBtn.addEventListener('click', () => {
database.ref('gameState').update({ database.ref('gameState').update({
buzzerActive: true, buzzerActive: true,
buzzer: null, buzzer: null
playerAnswer: null
}); });
activateBuzzerBtn.disabled = true; activateBuzzerBtn.disabled = true;
answerSection.style.display = 'none'; answerSection.style.display = 'none';
@@ -185,32 +357,66 @@ activateBuzzerBtn.addEventListener('click', () => {
markCorrectBtn.addEventListener('click', () => { markCorrectBtn.addEventListener('click', () => {
if (!currentBuzzedPlayer) return; if (!currentBuzzedPlayer) return;
const points = isShowingBonus ? 10 : 4;
database.ref(`gameState/scores/${currentBuzzedPlayer}`).transaction((score) => { database.ref(`gameState/scores/${currentBuzzedPlayer}`).transaction((score) => {
return (score || 0) + 4; return (score || 0) + points;
}); });
// If tossup was correct, show bonus
if (!isShowingBonus && currentQuestion.bonus_question) {
showBonus();
} else {
resetForNextQuestion(); resetForNextQuestion();
}
}); });
// Show bonus question
function showBonus() {
isShowingBonus = true;
questionText.textContent = currentQuestion.bonus_question;
questionCategory.textContent = currentQuestion.category + ' - BONUS';
correctAnswer.textContent = currentQuestion.bonus_answer;
// Reset UI for bonus
buzzedPlayer.textContent = '';
document.querySelectorAll('.light').forEach(l => l.classList.remove('active'));
markCorrectBtn.style.display = 'none';
markIncorrectBtn.style.display = 'none';
showAnswerBtn.style.display = 'none';
answerSection.style.display = 'none';
readQuestionBtn.disabled = false;
alert('Tossup correct! Now reading the BONUS question for the same team.');
}
// Mark incorrect // Mark incorrect
markIncorrectBtn.addEventListener('click', () => { markIncorrectBtn.addEventListener('click', () => {
if (!currentBuzzedPlayer) return; if (!currentBuzzedPlayer) return;
database.ref(`gameState/scores/${currentBuzzedPlayer}`).transaction((score) => { const points = isShowingBonus ? 0 : -4;
return (score || 0) - 4;
});
// Reactivate buzzers for other players if (points !== 0) {
database.ref(`gameState/scores/${currentBuzzedPlayer}`).transaction((score) => {
return (score || 0) + points;
});
}
if (!isShowingBonus) {
// Reactivate buzzers for tossup
database.ref('gameState').update({ database.ref('gameState').update({
buzzerActive: true, buzzerActive: true,
buzzer: null, buzzer: null
playerAnswer: null
}); });
answerSection.style.display = 'none'; answerSection.style.display = 'none';
markCorrectBtn.style.display = 'none'; markCorrectBtn.style.display = 'none';
markIncorrectBtn.style.display = 'none'; markIncorrectBtn.style.display = 'none';
showAnswerBtn.style.display = 'none'; showAnswerBtn.style.display = 'none';
} else {
resetForNextQuestion();
}
}); });
// Show answer // Show answer
@@ -220,9 +426,11 @@ showAnswerBtn.addEventListener('click', () => {
// Reset game // Reset game
resetGameBtn.addEventListener('click', () => { resetGameBtn.addEventListener('click', () => {
if (confirm('Reset all scores and start over?')) { if (confirm('Reset all scores and used questions?')) {
currentQuestionNumber = 1; currentQuestionNumber = 1;
usedQuestionIds.clear();
speechSynthesis.cancel(); speechSynthesis.cancel();
stopTimer();
database.ref('gameState').set({ database.ref('gameState').set({
buzzerActive: false, buzzerActive: false,
currentQuestion: null, currentQuestion: null,
@@ -237,15 +445,20 @@ resetGameBtn.addEventListener('click', () => {
}); });
questionText.textContent = 'Click "New Question" to start'; questionText.textContent = 'Click "New Question" to start';
answerSection.style.display = 'none'; answerSection.style.display = 'none';
readQuestionBtn.disabled = true;
console.log('Game reset! All questions available again.');
} }
}); });
function resetForNextQuestion() { function resetForNextQuestion() {
if (speechSynthesis.speaking) {
speechSynthesis.cancel(); speechSynthesis.cancel();
}
stopTimer();
database.ref('gameState').update({ database.ref('gameState').update({
buzzerActive: false, buzzerActive: false,
buzzer: null, buzzer: null,
playerAnswer: null,
isReading: false isReading: false
}); });
@@ -255,5 +468,8 @@ function resetForNextQuestion() {
markIncorrectBtn.style.display = 'none'; markIncorrectBtn.style.display = 'none';
showAnswerBtn.style.display = 'none'; showAnswerBtn.style.display = 'none';
answerSection.style.display = 'none'; answerSection.style.display = 'none';
readQuestionBtn.textContent = '🔊 Read Question';
readQuestionBtn.disabled = false;
currentBuzzedPlayer = null; currentBuzzedPlayer = null;
isShowingBonus = false;
} }

View File

@@ -26,12 +26,7 @@
</button> </button>
</div> </div>
<div class="answer-container" id="answerContainer" style="display: none;"> <div class="question-display" id="questionDisplay" style="display: none;">
<input type="text" id="answerInput" placeholder="Type your answer...">
<button id="submitAnswer" class="submit-btn">Submit Answer</button>
</div>
<div class="question-display listening" id="questionDisplay" style="display: none;">
🔊 Listen carefully... 🔊 Listen carefully...
</div> </div>
</div> </div>

View File

@@ -4,14 +4,14 @@ const playerId = urlParams.get('id') || '1';
const playerColors = ['#ff4444', '#4444ff', '#44ff44', '#ffff44']; const playerColors = ['#ff4444', '#4444ff', '#44ff44', '#ffff44'];
const playerNames = ['Player 1', 'Player 2', 'Player 3', 'Player 4']; const playerNames = ['Player 1', 'Player 2', 'Player 3', 'Player 4'];
// Buzzer sound frequencies (different for each player)
const buzzerFrequencies = [523.25, 659.25, 783.99, 880.00]; // C5, E5, G5, A5
// DOM elements // DOM elements
const playerName = document.getElementById('playerName'); const playerName = document.getElementById('playerName');
const playerScore = document.getElementById('playerScore'); const playerScore = document.getElementById('playerScore');
const statusMessage = document.getElementById('statusMessage'); const statusMessage = document.getElementById('statusMessage');
const buzzer = document.getElementById('buzzer'); const buzzer = document.getElementById('buzzer');
const answerContainer = document.getElementById('answerContainer');
const answerInput = document.getElementById('answerInput');
const submitAnswer = document.getElementById('submitAnswer');
const questionDisplay = document.getElementById('questionDisplay'); const questionDisplay = document.getElementById('questionDisplay');
// Set player identity // Set player identity
@@ -23,6 +23,26 @@ document.body.style.setProperty('--player-color', playerColors[playerId - 1]);
let canBuzz = false; let canBuzz = false;
let hasBuzzed = false; let hasBuzzed = false;
// Audio context for buzzer sounds
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
function playBuzzerSound(playerNum) {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = buzzerFrequencies[playerNum - 1];
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
}
// Listen to game state // Listen to game state
database.ref('gameState').on('value', (snapshot) => { database.ref('gameState').on('value', (snapshot) => {
const state = snapshot.val(); const state = snapshot.val();
@@ -33,7 +53,7 @@ database.ref('gameState').on('value', (snapshot) => {
playerScore.textContent = state.scores[`player${playerId}`]; playerScore.textContent = state.scores[`player${playerId}`];
} }
// Hide question text - players only hear it // Show question status
if (state.isReading) { if (state.isReading) {
questionDisplay.textContent = '🔊 Listen to the question...'; questionDisplay.textContent = '🔊 Listen to the question...';
questionDisplay.style.display = 'block'; questionDisplay.style.display = 'block';
@@ -51,7 +71,6 @@ database.ref('gameState').on('value', (snapshot) => {
buzzer.disabled = false; buzzer.disabled = false;
buzzer.classList.remove('locked'); buzzer.classList.remove('locked');
statusMessage.textContent = 'Ready to buzz!'; statusMessage.textContent = 'Ready to buzz!';
answerContainer.style.display = 'none';
} else { } else {
canBuzz = false; canBuzz = false;
buzzer.disabled = true; buzzer.disabled = true;
@@ -60,9 +79,8 @@ database.ref('gameState').on('value', (snapshot) => {
// Check if this player buzzed in // Check if this player buzzed in
if (state.buzzer && state.buzzer.playerId === `player${playerId}`) { if (state.buzzer && state.buzzer.playerId === `player${playerId}`) {
statusMessage.textContent = 'You buzzed in! Answer now:'; statusMessage.textContent = '🎯 You buzzed in! Answer verbally to the moderator.';
answerContainer.style.display = 'block'; buzzer.classList.add('locked');
answerInput.focus();
} else if (state.buzzer && state.buzzer.playerId) { } else if (state.buzzer && state.buzzer.playerId) {
const buzzedPlayerNum = state.buzzer.playerId.replace('player', ''); const buzzedPlayerNum = state.buzzer.playerId.replace('player', '');
statusMessage.textContent = `Player ${buzzedPlayerNum} buzzed in`; statusMessage.textContent = `Player ${buzzedPlayerNum} buzzed in`;
@@ -70,6 +88,15 @@ database.ref('gameState').on('value', (snapshot) => {
} }
}); });
// Listen for buzzer events to play sounds
database.ref('gameState/buzzer').on('value', (snapshot) => {
const buzzer = snapshot.val();
if (buzzer && buzzer.playerId) {
const playerNum = parseInt(buzzer.playerId.replace('player', ''));
playBuzzerSound(playerNum);
}
});
// Buzzer click // Buzzer click
buzzer.addEventListener('click', buzzIn); buzzer.addEventListener('click', buzzIn);
@@ -94,24 +121,3 @@ function buzzIn() {
buzzer.classList.add('buzzed'); buzzer.classList.add('buzzed');
setTimeout(() => buzzer.classList.remove('buzzed'), 300); setTimeout(() => buzzer.classList.remove('buzzed'), 300);
} }
// Submit answer
submitAnswer.addEventListener('click', submitPlayerAnswer);
answerInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') submitPlayerAnswer();
});
function submitPlayerAnswer() {
const answer = answerInput.value.trim();
if (!answer) return;
database.ref('gameState/playerAnswer').set({
playerId: `player${playerId}`,
answer: answer,
timestamp: Date.now()
});
answerInput.value = '';
answerContainer.style.display = 'none';
statusMessage.textContent = 'Answer submitted! Waiting for moderator...';
}

View File

@@ -373,3 +373,68 @@ margin-top: 15px;
.instructions li { .instructions li {
margin: 10px 0; margin: 10px 0;
} }
.timer-display {
font-size: 3em;
font-weight: bold;
color: #ffaa00;
text-align: center;
margin: 20px 0;
animation: pulse 1s infinite;
}
.settings-section {
background: rgba(255,255,255,0.1);
padding: 20px;
border-radius: 15px;
margin-bottom: 20px;
}
.setting-group {
margin-bottom: 20px;
}
.setting-group:last-child {
margin-bottom: 0;
}
.setting-group h3 {
margin-bottom: 15px;
color: #ffff44;
}
.source-select {
width: 100%;
padding: 12px;
font-size: 1.1em;
border-radius: 8px;
border: 2px solid rgba(255,255,255,0.3);
background: rgba(255,255,255,0.1);
color: white;
margin-bottom: 10px;
cursor: pointer;
}
.source-select option {
background: #1a1a2e;
color: white;
}
.round-input {
width: 100%;
padding: 12px;
font-size: 1.1em;
border-radius: 8px;
border: 2px solid rgba(255,255,255,0.3);
background: rgba(255,255,255,0.1);
color: white;
}
.round-input::placeholder {
color: rgba(255,255,255,0.5);
}
.category-filter {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
}