Classic: fundal radial spotlight, card cu glow accent, tile-uri 44px bouncy, progres bar 10px cu neon glow. Terminal: FIX WCAG critic .line.dim (#1f9c4a→ #2ecc71, 3.1:1→6.1:1) + bordura CRT + flicker cu motion guard + #cmd 44px. Arcade: canvas border neon violet, dpad butoane fizice 56x52px, titlu neon, fundal radial. Chat: header frosted-glass (backdrop-filter), bule NPC distincte (#1e2d45) cu shadow, tile reward bouncy. Point: fundal distinct fata de arcade, fix contrast .note (#a89fd4), usa cu glow pulsant. prefers-reduced-motion peste tot. Toate 5 demo-urile regenerate. Smoke 21/21 + capturi vizuale pe fiecare stil. S3 COMPLET (Bomberman + Overworld + restyle). Board: TODOS.md S3 [x]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
190 lines
14 KiB
HTML
190 lines
14 KiB
HTML
<!doctype html>
|
|
<html lang="ro">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Comoara ascunsa</title>
|
|
<style>
|
|
* { box-sizing: border-box; }
|
|
body { margin: 0; background: #060d1a; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; color: #e2e8f0; display: flex; justify-content: center; min-height: 100vh; }
|
|
#app { width: 100%; max-width: 480px; height: 100vh; height: 100dvh; display: flex; flex-direction: column; background: #0d1626; }
|
|
header { display: flex; gap: 10px; align-items: center; padding: 10px 14px; background: rgba(23,32,53,.85); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid rgba(255,255,255,.08); box-shadow: 0 1px 0 rgba(255,255,255,.05); }
|
|
.avatar { width: 38px; height: 38px; border-radius: 50%; background: var(--accent); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 18px; color: #fff; box-shadow: 0 0 0 2px rgba(255,255,255,.15); }
|
|
.cname { font-weight: 700; }
|
|
.cstatus { font-size: 12px; color: #34d399; }
|
|
#msgs { flex: 1; overflow-y: auto; padding: 14px 12px; display: flex; flex-direction: column; gap: 8px; }
|
|
.row { display: flex; }
|
|
.row.me { justify-content: flex-end; }
|
|
.bub { max-width: 78%; padding: 9px 13px; border-radius: 16px; line-height: 1.4; font-size: 15px; white-space: pre-line; animation: bin .25s cubic-bezier(.22,1,.36,1); }
|
|
@keyframes bin { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }
|
|
.row.him .bub { background: #1e2d45; border: 1px solid rgba(255,255,255,.08); box-shadow: 0 2px 8px rgba(0,0,0,.25); color: #e2e8f0; border-bottom-left-radius: 5px; }
|
|
.row.me .bub { background: var(--accent); color: #fff; box-shadow: 0 2px 12px rgba(109,40,217,.4); border-bottom-right-radius: 5px; }
|
|
.bub.tile { font-size: 28px; font-weight: 900; letter-spacing: 3px; padding: 14px 20px; background: linear-gradient(135deg, #14532d, #166534); border: 1px solid #22c55e; box-shadow: 0 0 16px rgba(34,197,94,.3); animation: tile-pop .4s cubic-bezier(.34,1.56,.64,1); }
|
|
@keyframes tile-pop { from { transform: scale(.6) rotate(-5deg); opacity: 0; } to { transform: none; opacity: 1; } }
|
|
.bub.typing i { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #64748b; margin: 0 2px; animation: tp 1s infinite; }
|
|
.bub.typing i:nth-child(2) { animation-delay: .15s; } .bub.typing i:nth-child(3) { animation-delay: .3s; }
|
|
@keyframes tp { 30% { transform: translateY(-6px); background: #34d399; } }
|
|
#composer { padding: 10px 12px; background: rgba(23,32,53,.9); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border-top: 1px solid rgba(255,255,255,.08); display: flex; flex-wrap: wrap; gap: 8px; min-height: 58px; }
|
|
#composer input { flex: 1; min-width: 120px; min-height: 44px; font: inherit; font-size: 15px; padding: 9px 13px; border-radius: 99px; border: 1px solid #334155; background: rgba(13,22,38,.8); color: #fff; }
|
|
#composer input:focus { outline: 2px solid var(--accent); outline-offset: 2px; border-color: transparent; }
|
|
#composer button { font: inherit; cursor: pointer; border: none; border-radius: 99px; padding: 9px 16px; min-height: 44px; min-width: 44px; font-weight: 600; background: var(--accent); color: #fff; }
|
|
#composer button.chip { background: #0d1626; border: 1px solid #334155; color: #cbd5e1; min-height: 44px; }
|
|
#composer button.chip:hover { border-color: var(--accent); color: #fff; }
|
|
@media (prefers-reduced-motion: reduce) { .bub, .bub.tile, .bub.typing i { animation: none; } }
|
|
|
|
.confetti { position: fixed; top: -12px; width: 9px; height: 14px; z-index: 99; animation: fall linear forwards; }
|
|
@keyframes fall { to { transform: translateY(105vh) rotate(720deg); } }
|
|
.shake { animation: shake .4s ease; }
|
|
@keyframes shake { 20%,60% { transform: translateX(-8px); } 40%,80% { transform: translateX(8px); } }
|
|
#fOverlay { display: none; position: fixed; inset: 0; background: rgba(8,4,20,.88); z-index: 30; align-items: center; justify-content: center; padding: 16px; }
|
|
#fOverlay .fcard { width: 100%; max-width: 480px; text-align: center; background: #221440; border: 1px solid rgba(255,255,255,.18); border-radius: 18px; padding: 28px; color: #fff; font-family: system-ui, sans-serif; }
|
|
#fOverlay h1 { margin: 0 0 8px; font-size: 26px; }
|
|
#fOverlay .fstars { font-size: 26px; letter-spacing: 4px; color: #fbbf24; margin: 6px 0; }
|
|
#fOverlay .fword { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin: 16px 0; }
|
|
#fOverlay .fword span { width: 44px; height: 52px; border-radius: 10px; background: var(--accent); display: flex; align-items: center; justify-content: center; font-size: 26px; font-weight: 800; animation: flipin .6s ease backwards; }
|
|
@keyframes flipin { from { transform: rotateX(90deg); } to { transform: rotateX(0); } }
|
|
#fOverlay p { color: rgba(255,255,255,.8); line-height: 1.5; }
|
|
#fOverlay button { font: inherit; cursor: pointer; border: none; border-radius: 10px; padding: 12px 18px; font-weight: 700; background: var(--accent); color: #fff; width: 100%; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<header><div class="avatar" id="av"></div><div><div class="cname" id="cn"></div><div class="cstatus" id="cs">online</div></div></header>
|
|
<div id="msgs"></div>
|
|
<div id="composer"></div>
|
|
</div>
|
|
<div id="fOverlay"><div class="fcard">
|
|
<h1>Evadare reusita!</h1>
|
|
<div class="fstars" id="fStars"></div>
|
|
<div class="fword" id="fWord"></div>
|
|
<p id="fMsg"></p>
|
|
<button id="fAgain">Joaca din nou</button>
|
|
</div></div>
|
|
<script>
|
|
var CFG = {"title":"Comoara ascunsa","player":"","color":"#6d28d9","charName":"Alex","story":"O comoara a fost ascunsa, iar singurul drum spre ea trece prin cateva incercari.","finalMessage":"Felicitari! Ai gasit comoara!","puzzles":[{"title":"Incalzirea","type":"free","question":"Cat fac 7 x 8?","answer":"56","tfAnswer":"Adevarat","choices":"","hint":"Tabla inmultirii cu 7.","letter":"D","style":""},{"title":"Adevarat sau fals","type":"tf","question":"Romania are iesire la Marea Neagra.","answer":"","tfAnswer":"Adevarat","choices":"","hint":"","letter":"A","style":""},{"title":"Alege raspunsul","type":"choice","question":"Care este capitala Frantei?","answer":"","tfAnswer":"Adevarat","choices":"*Paris\nLyon\nMarsilia","hint":"Turnul Eiffel.","letter":"R","style":""}],"style":"chat"};
|
|
document.documentElement.style.setProperty('--accent', CFG.color || '#6d28d9');
|
|
var totalStars = 0;
|
|
function el(id){ return document.getElementById(id); }
|
|
function norm(s){ return String(s).trim().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/\s+/g, ' ').replace(/,/g, '.'); }
|
|
function starsFor(att, hint){ return (hint || att >= 2) ? 1 : (att === 1 ? 2 : 3); }
|
|
function finalWord(){ var w = ''; for (var i = 0; i < CFG.puzzles.length; i++){ var L = (CFG.puzzles[i].letter || '').trim(); if (L) w += L.toUpperCase(); } return w; }
|
|
function choiceOpts(p){ return (p.choices || '').split('\n').map(function(l){ return l.trim(); }).filter(Boolean).map(function(o){ return o.charAt(0) === '*' ? o.slice(1).trim() : o; }); }
|
|
function choiceCorrect(p){ var ls = (p.choices || '').split('\n'); for (var i = 0; i < ls.length; i++){ var l = ls[i].trim(); if (l.charAt(0) === '*') return l.slice(1).trim(); } return ''; }
|
|
function checkAnswer(p, given){ var exp = p.type === 'tf' ? p.tfAnswer : (p.type === 'choice' ? choiceCorrect(p) : p.answer); return norm(given) !== '' && norm(given) === norm(exp); }
|
|
function beep(ok){ if(CFG._campaign){ try{ parent.beep(ok); }catch(e){} return; } try { var ctx = beep.ctx || (beep.ctx = new (window.AudioContext || window.webkitAudioContext)()); var t = ctx.currentTime; var fs = ok ? [523, 784] : [196]; fs.forEach(function(f, k){ var o = ctx.createOscillator(), g = ctx.createGain(); o.frequency.value = f; o.type = 'triangle'; g.gain.setValueAtTime(0.12, t + k * 0.09); g.gain.exponentialRampToValueAtTime(0.001, t + k * 0.09 + 0.25); o.connect(g); g.connect(ctx.destination); o.start(t + k * 0.09); o.stop(t + k * 0.09 + 0.3); }); } catch (e) {} }
|
|
function confetti(){ var colors = [CFG.color || '#6d28d9', '#fbbf24', '#34d399', '#60a5fa', '#f472b6']; for (var i = 0; i < 90; i++){ var c = document.createElement('div'); c.className = 'confetti'; c.style.left = (i * 137 % 100) + 'vw'; c.style.background = colors[i % colors.length]; c.style.animationDuration = (2.2 + (i * 53 % 18) / 10) + 's'; c.style.animationDelay = ((i * 31 % 14) / 10) + 's'; document.body.appendChild(c); } }
|
|
function roomReady(){ if(CFG._campaign){ try{ parent.roomReady(CFG._campaign.idx); }catch(e){} } }
|
|
window.onerror = function(msg){ if(CFG._campaign){ try{ parent.roomError(CFG._campaign.idx, String(msg)); }catch(e){} } };
|
|
if(CFG._campaign){
|
|
/* Mod cameră (§Design pct.12): ascunde h1, progres propriu, restart propriu */
|
|
var _cs = document.createElement('style');
|
|
_cs.textContent = 'h1{display:none!important}.progress{display:none!important}.meta{display:none!important}';
|
|
(document.head || document.documentElement).appendChild(_cs);
|
|
}
|
|
var who = (CFG.charName || 'Alex').trim() || 'Alex';
|
|
el('cn').textContent = who; el('av').textContent = who.charAt(0).toUpperCase();
|
|
var msgs = el('msgs'), composer = el('composer');
|
|
var idx = -1, attempts = 0, hintUsed = false;
|
|
var wrongs = ['Nu... nu a mers. Mai incearca!', 'Hmm, nu e asta. Gandeste-te bine!', 'Tot incuiat. Alta idee?'];
|
|
|
|
function scrollEnd(){ msgs.scrollTop = msgs.scrollHeight; }
|
|
function bubble(side, text, cls){
|
|
var r = document.createElement('div'); r.className = 'row ' + side;
|
|
var b = document.createElement('div'); b.className = 'bub' + (cls ? ' ' + cls : '');
|
|
b.textContent = text;
|
|
r.appendChild(b); msgs.appendChild(r); scrollEnd();
|
|
return b;
|
|
}
|
|
function charMsg(text, cb){
|
|
el('cs').textContent = 'scrie...';
|
|
var b = bubble('him', '', 'typing');
|
|
b.innerHTML = '<i></i><i></i><i></i>';
|
|
var d = Math.min(450 + text.length * 14, 1800);
|
|
setTimeout(function(){
|
|
b.className = 'bub'; b.textContent = text;
|
|
el('cs').textContent = 'online'; scrollEnd();
|
|
if (cb) setTimeout(cb, 280);
|
|
}, d);
|
|
}
|
|
function seq(texts, cb){ var i = 0; (function n(){ if (i >= texts.length) { if (cb) cb(); return; } charMsg(texts[i++], n); })(); }
|
|
|
|
function storyChunks(){
|
|
var parts = (CFG.story || '').match(/[^.!?]+[.!?]*\s*/g) || [];
|
|
var out = [], cur = '';
|
|
for (var i = 0; i < parts.length; i++) {
|
|
if (cur && (cur + parts[i]).length > 110) { out.push(cur.trim()); cur = ''; }
|
|
cur += parts[i];
|
|
}
|
|
if (cur.trim()) out.push(cur.trim());
|
|
return out.length ? out : [CFG.story || ''];
|
|
}
|
|
|
|
function setComposer(p){
|
|
composer.innerHTML = '';
|
|
function chip(label, fn, cls){ var b = document.createElement('button'); if (cls) b.className = cls; b.textContent = label; b.onclick = fn; composer.appendChild(b); return b; }
|
|
if (p.type === 'free') {
|
|
var inp = document.createElement('input'); inp.placeholder = 'Scrie raspunsul...'; inp.autocomplete = 'off';
|
|
composer.appendChild(inp);
|
|
var send = chip('Trimite', function(){ if (inp.value.trim()) { var v = inp.value.trim(); inp.value = ''; answer(v); } });
|
|
inp.onkeydown = function(e){ if (e.key === 'Enter') send.click(); };
|
|
setTimeout(function(){ inp.focus(); }, 100);
|
|
} else if (p.type === 'tf') {
|
|
chip('Adevarat', function(){ answer('Adevarat'); }, 'chip');
|
|
chip('Fals', function(){ answer('Fals'); }, 'chip');
|
|
} else {
|
|
choiceOpts(p).forEach(function(o){ chip(o, function(){ answer(o); }, 'chip'); });
|
|
}
|
|
if (p.hint) chip('Cere un indiciu', function(){ hintUsed = true; bubble('me', 'Ai vreun indiciu?'); composer.innerHTML = ''; charMsg(p.hint, function(){ setComposer(p); }); }, 'chip');
|
|
}
|
|
|
|
function answer(given){
|
|
var p = CFG.puzzles[idx];
|
|
bubble('me', given);
|
|
composer.innerHTML = '';
|
|
if (checkAnswer(p, given)) {
|
|
var s = starsFor(attempts, hintUsed);
|
|
totalStars += s; beep(true);
|
|
var L = (p.letter || '').trim();
|
|
charMsg('Da! Asta era! (+' + s + ' \u2605, total ' + totalStars + ')', function(){
|
|
if (L) { bubble('him', L.toUpperCase(), 'tile'); charMsg('Am gasit o litera!', next); }
|
|
else next();
|
|
});
|
|
} else {
|
|
attempts++; beep(false);
|
|
charMsg(wrongs[(attempts - 1) % wrongs.length], function(){ setComposer(p); });
|
|
}
|
|
}
|
|
|
|
function next(){
|
|
idx++; attempts = 0; hintUsed = false;
|
|
if (idx >= CFG.puzzles.length) {
|
|
seq(['AM IESIT! Multumesc' + (CFG.player ? ', ' + CFG.player : '') + '!', CFG.finalMessage || ''], function(){ showFinal(); });
|
|
return;
|
|
}
|
|
var p = CFG.puzzles[idx];
|
|
seq([(p.title ? p.title + '. ' : '') + p.question], function(){ setComposer(p); });
|
|
}
|
|
|
|
var chatIntro = CFG._campaign
|
|
? ['Camera ' + (CFG._campaign.idx + 1) + ' din ' + CFG._campaign.total + '. Sa incepem!']
|
|
: ['Salut' + (CFG.player ? ', ' + CFG.player : '') + '!'].concat(storyChunks()).concat(['Ma ajuti sa ies de aici?']);
|
|
seq(chatIntro, next);
|
|
function showFinal(){
|
|
if(CFG._campaign){
|
|
var L = finalWord().charAt(0);
|
|
try{ parent.nextRoom({idx:CFG._campaign.idx, stars:totalStars, letter:L}); }catch(e){}
|
|
return;
|
|
}
|
|
el('fStars').textContent = totalStars + ' / ' + (CFG.puzzles.length * 3) + ' \u2605';
|
|
var w = finalWord(); var bw = el('fWord'); bw.innerHTML = '';
|
|
for (var j = 0; j < w.length; j++){ var s = document.createElement('span'); s.textContent = w.charAt(j); s.style.animationDelay = (j * 0.18) + 's'; bw.appendChild(s); }
|
|
var msg = CFG.finalMessage || '';
|
|
el('fMsg').textContent = CFG.player ? CFG.player + ', ' + msg.charAt(0).toLowerCase() + msg.slice(1) : msg;
|
|
el('fOverlay').style.display = 'flex';
|
|
beep(true); confetti();
|
|
}
|
|
el('fAgain').onclick = function(){ location.reload(); };
|
|
roomReady();
|
|
</script>
|
|
</body>
|
|
</html> |