Music Numbers π΅
*{box-sizing:border-box}
body{margin:0;font-family:system-ui,-apple-system,sans-serif;background:linear-gradient(135deg,#fff7d6,#e7f8ff);min-height:100vh;display:flex;justify-content:center;align-items:center;padding:20px;color:#24324a}
.game{width:min(760px,100%);text-align:center}
.top{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}
.label{font-size:12px;font-weight:800;color:#77839a;text-align:left}
.title{font-size:24px;font-weight:900}
.score{text-align:right;font-weight:800}
.stars{font-size:20px;letter-spacing:3px}
.note-box{background:white;border:3px solid #dce7f2;border-radius:30px;padding:20px;box-shadow:0 8px 24px rgba(40,70,100,.10)}
.picture{font-size:72px;line-height:1;margin-bottom:8px;animation:bounce .7s ease}
.question{font-size:21px;font-weight:900;margin-bottom:8px}
.notes{min-height:105px;display:flex;flex-wrap:wrap;justify-content:center;align-items:center}
.note{font-size:46px;display:inline-block;margin:3px;line-height:1;animation:pop .3s ease}
button{font-family:inherit}
.hear{margin-top:10px;padding:12px 22px;border-radius:999px;border:2px solid #dce7f2;background:#f7fbff;font-size:16px;font-weight:800;cursor:pointer}
.choices{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;margin-top:16px}
.choice{min-height:70px;font-size:21px;font-weight:900;border-radius:20px;border:3px solid transparent;cursor:pointer;box-shadow:0 5px 0 rgba(0,0,0,.10);transition:.15s}
.choice:hover{transform:translateY(-3px)}
.choice:active{transform:translateY(2px);box-shadow:0 2px 0 rgba(0,0,0,.08)}
.c1{background:#FFE08A}.c2{background:#AEE8FF}.c3{background:#C9F7B5}.c4{background:#F6C4F5}
.choice:disabled{cursor:default}
.feedback{min-height:40px;margin-top:10px;font-size:19px;font-weight:900}
@keyframes pop{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes bounce{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
@media(max-width:480px){
.title{font-size:20px}.picture{font-size:60px}.note{font-size:38px}.choice{font-size:18px}
}
π΅ MUSIC NUMBERS
Count & Learn English!
π°
How many notes?
π Hear it
(() => {
const notes = document.getElementById('notes');
const choices = document.getElementById('choices');
const message = document.getElementById('message');
const scoreEl = document.getElementById('score');
const stars = document.getElementById('stars');
const picture = document.getElementById('picture');
const speak = document.getElementById('speak');
const words = ['zero','one','two','three','four','five','six','seven','eight','nine','ten'];
const pictures = ['π°','πΌ','π±','πΆ','π¦','πΈ','π₯','π¦','π»','π¨'];
let answer = 0;
let score = 0;
let locked = false;
let timer = null;
function say(text) {
try {
speechSynthesis.cancel();
const u = new SpeechSynthesisUtterance(text);
u.lang = 'en-US';
u.rate = 0.78;
u.pitch = 1.08;
speechSynthesis.speak(u);
} catch(e) {}
}
function beep(ok) {
try {
const Audio = window.AudioContext || window.webkitAudioContext;
if (!Audio) return;
const ctx = new Audio();
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = 'sine';
osc.frequency.value = ok ? 680 : 230;
gain.gain.value = .08;
osc.connect(gain);
gain.connect(ctx.destination);
osc.start();
osc.frequency.exponentialRampToValueAtTime(ok ? 920 : 160, ctx.currentTime + .16);
gain.gain.exponentialRampToValueAtTime(.001, ctx.currentTime + .22);
osc.stop(ctx.currentTime + .23);
} catch(e) {}
}
function newQuestion() {
clearTimeout(timer);
locked = false;
message.textContent = '';
choices.innerHTML = '';
answer = Math.floor(Math.random() * 10) + 1;
picture.textContent = pictures[answer - 1] || 'π΅';
notes.innerHTML = '';
for (let i = 0; i < answer; i++) {
const n = document.createElement('span');
n.className = 'note';
n.textContent = i % 2 ? 'βͺ' : 'β«';
n.style.animationDelay = (i * .035) + 's';
notes.appendChild(n);
}
const set = new Set([answer]);
while (set.size Math.random() - .5).forEach((v, i) => {
const b = document.createElement('button');
b.type = 'button';
b.className = 'choice c' + (i + 1);
b.textContent = words[v].toUpperCase();
b.addEventListener('click', () => choose(v, b));
choices.appendChild(b);
});
timer = setTimeout(() => say('How many notes?'), 350);
}
function choose(v, button) {
if (locked) return;
locked = true;
choices.querySelectorAll('button').forEach(b => b.disabled = true);
if (v === answer) {
score++;
scoreEl.textContent = 'Score: ' + score;
message.textContent = 'π Excellent! ' + words[answer] + '!';
button.textContent = 'β ' + words[answer].toUpperCase();
beep(true);
say(words[answer]);
stars.textContent =
score % 3 === 0 ? 'β
β
β
' :
score % 3 === 1 ? 'β
β β' : 'β
β
β';
} else {
message.textContent = 'π Almost! The answer is ' + words[answer] + '.';
button.textContent = 'β ' + words[v].toUpperCase();
beep(false);
say(words[answer]);
}
timer = setTimeout(newQuestion, 1250);
}
speak.addEventListener('click', () => say('How many notes?'));
newQuestion();
})();