ijsbreker/app.js
Frank Meeuwsen da06d6bf00 feat: startscherm met controle over timer toegevoegd
Startscherm met groene "Start IJsbreker" knop geïmplementeerd.
Timer begint nu pas na klik op startknop in plaats van automatisch bij laden.
Facilitator heeft volledige controle over startmoment van de presentatie.

Wijzigingen:
- index.html: Startscherm HTML toegevoegd
- style.css: Styling voor start-screen en start-button
- app.js: Flow aangepast met showStartScreen() en startGame()
- Spatiebalk werkt op startscherm voor snelle start
- Documentatie geüpdatet in CLAUDE.md, gemini.md en agents.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 10:01:22 +01:00

195 lines
5.6 KiB
JavaScript

// Globale state
let config = null;
let currentIndex = 0;
let audioContext = null;
// DOM elementen
const timerBorder = document.querySelector('.timer-border');
const startScreen = document.getElementById('startScreen');
const statementScreen = document.getElementById('statementScreen');
const overlay = document.getElementById('overlay');
const finishScreen = document.getElementById('finishScreen');
const leftStatement = document.getElementById('leftStatement');
const rightStatement = document.getElementById('rightStatement');
const leftText = document.getElementById('leftText');
const rightText = document.getElementById('rightText');
const startButton = document.getElementById('startButton');
const nextButton = document.getElementById('nextButton');
const finishText = document.getElementById('finishText');
// Laad configuratie bij start
async function loadConfig() {
try {
const response = await fetch('config.json');
config = await response.json();
initializeApp();
} catch (error) {
console.error('Fout bij laden config:', error);
alert('Kan config.json niet laden. Zorg dat alle bestanden in dezelfde map staan.');
}
}
// Initialiseer app met config
function initializeApp() {
// Stel CSS variabelen in
document.documentElement.style.setProperty('--timer-duration', `${config.timer}s`);
// Pas font grootte toe
document.querySelectorAll('.statement p').forEach(el => {
el.style.fontSize = config.fontSize;
});
finishText.style.fontSize = config.fontSize;
// Pas kleuren toe
leftStatement.style.backgroundColor = config.colors.left;
rightStatement.style.backgroundColor = config.colors.right;
// Zet knop tekst
nextButton.textContent = config.buttonText;
finishText.textContent = config.finishText;
// Toon startscherm (niet direct beginnen)
showStartScreen();
}
// Toon startscherm
function showStartScreen() {
startScreen.classList.remove('hidden');
statementScreen.classList.add('hidden');
overlay.classList.add('hidden');
finishScreen.classList.add('hidden');
}
// Start het spel
function startGame() {
startScreen.classList.add('hidden');
showStatement(0);
}
// Toon stelling op index
function showStatement(index) {
currentIndex = index;
// Check of we klaar zijn
if (index >= config.stellingen.length) {
showFinish();
return;
}
const stelling = config.stellingen[index];
// Update teksten
leftText.textContent = stelling.links;
rightText.textContent = stelling.rechts;
// Toon stellingen scherm, verberg overlay en finish
statementScreen.classList.remove('hidden');
overlay.classList.add('hidden');
finishScreen.classList.add('hidden');
// Start timer
startTimer();
}
// Start timer animatie
function startTimer() {
// Reset timer
timerBorder.classList.remove('timer-active');
void timerBorder.offsetWidth; // Force reflow
// Start timer
timerBorder.classList.add('timer-active');
// Wacht tot timer klaar is
setTimeout(() => {
playBeep();
// Bij laatste stelling: toon direct finish scherm
if (currentIndex === config.stellingen.length - 1) {
showFinish();
} else {
showOverlay();
}
}, config.timer * 1000);
}
// Toon overlay met knop (stellingen blijven zichtbaar)
function showOverlay() {
overlay.classList.remove('hidden');
timerBorder.classList.remove('timer-active');
}
// Toon eind scherm
function showFinish() {
statementScreen.classList.add('hidden');
overlay.classList.add('hidden');
finishScreen.classList.remove('hidden');
timerBorder.classList.remove('timer-active');
}
// Initialiseer audio context (herbruikbaar)
function initAudioContext() {
if (!audioContext) {
try {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
} catch (error) {
console.error('Fout bij initialiseren audio context:', error);
}
}
}
// Speel beep geluid via Web Audio API
function playBeep() {
try {
// Zorg dat audioContext bestaat
initAudioContext();
if (!audioContext) return;
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
// Configureer oscillator (beep geluid)
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(800, audioContext.currentTime); // 800 Hz
// Configureer volume (fade out)
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
// Verbind nodes
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// Speel beep (300ms)
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.3);
} catch (error) {
console.error('Fout bij afspelen geluid:', error);
}
}
// Event listeners
startButton.addEventListener('click', () => {
startGame();
});
nextButton.addEventListener('click', () => {
showStatement(currentIndex + 1);
});
// Spatiebalk voor volgende stelling EN startscherm
document.addEventListener('keydown', (e) => {
if (e.code === 'Space') {
e.preventDefault();
// Start spel als we op startscherm zijn
if (!startScreen.classList.contains('hidden')) {
startGame();
}
// Volgende stelling als overlay zichtbaar is
else if (!overlay.classList.contains('hidden')) {
showStatement(currentIndex + 1);
}
}
});
// Start de app
loadConfig();