Builder single-file HTML cu editor + preview live jucabil si export de jocuri standalone. Stiluri: clasic (quiz), terminal retro, arcade pixel, story chat, point-and-click. Fara backend, fara build. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
270 lines
12 KiB
HTML
270 lines
12 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; min-height: 100vh; font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
color: #fff; display: flex; align-items: center; justify-content: center; padding: 16px;
|
|
background: linear-gradient(160deg, #14092e 0%, #2a1257 55%, #14092e 100%);
|
|
}
|
|
.card {
|
|
width: 100%; max-width: 560px; background: rgba(255,255,255,.07);
|
|
border: 1px solid rgba(255,255,255,.14); border-radius: 18px; padding: 26px;
|
|
backdrop-filter: blur(6px); box-shadow: 0 18px 50px rgba(0,0,0,.45);
|
|
}
|
|
h1 { margin: 0 0 6px; font-size: 26px; text-align: center; }
|
|
.story { color: rgba(255,255,255,.8); text-align: center; line-height: 1.5; }
|
|
.screen { display: none; }
|
|
.screen.on { display: block; animation: pop .35s ease; }
|
|
@keyframes pop { from { transform: scale(.96); opacity: 0; } to { transform: scale(1); opacity: 1; } }
|
|
.progress { height: 7px; background: rgba(255,255,255,.15); border-radius: 99px; overflow: hidden; margin: 14px 0 4px; }
|
|
.progress i { display: block; height: 100%; background: var(--accent); width: 0; transition: width .4s ease; }
|
|
.meta { display: flex; justify-content: space-between; font-size: 12px; color: rgba(255,255,255,.6); margin-bottom: 14px; }
|
|
.letters { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin: 14px 0; }
|
|
.tile {
|
|
width: 34px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center;
|
|
font-weight: 800; font-size: 18px; background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.18);
|
|
color: rgba(255,255,255,.35);
|
|
}
|
|
.tile.won { background: var(--accent); color: #fff; border-color: transparent; animation: flip .5s ease; }
|
|
@keyframes flip { from { transform: rotateX(90deg); } to { transform: rotateX(0); } }
|
|
.qtitle { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--accent-light); font-weight: 700; }
|
|
.question { font-size: 19px; line-height: 1.45; margin: 8px 0 18px; }
|
|
input[type=text] {
|
|
width: 100%; font: inherit; font-size: 18px; padding: 11px 13px; border-radius: 10px;
|
|
border: 1px solid rgba(255,255,255,.25); background: rgba(0,0,0,.25); color: #fff; text-align: center;
|
|
}
|
|
input:focus { outline: 2px solid var(--accent); border-color: transparent; }
|
|
button {
|
|
font: inherit; cursor: pointer; border: none; border-radius: 10px; padding: 12px 18px;
|
|
font-weight: 700; background: var(--accent); color: #fff; width: 100%; margin-top: 10px;
|
|
}
|
|
button:hover { filter: brightness(1.12); }
|
|
button.opt { background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.2); font-weight: 600; text-align: left; }
|
|
button.opt:hover { background: rgba(255,255,255,.18); }
|
|
button.hint { background: none; border: none; color: rgba(255,255,255,.55); font-weight: 600; font-size: 13px; width: auto; display: block; margin: 12px auto 0; }
|
|
button.hint:hover { color: #fff; }
|
|
.hinttext { background: rgba(255,255,255,.1); border-radius: 9px; padding: 10px 12px; font-size: 14px; margin-top: 10px; white-space: pre-line; display: none; }
|
|
.feedback { min-height: 22px; text-align: center; font-weight: 700; margin-top: 10px; }
|
|
.feedback.bad { color: #fda4af; }
|
|
.feedback.good { color: #86efac; }
|
|
.shake { animation: shake .4s ease; }
|
|
@keyframes shake { 20%,60% { transform: translateX(-8px); } 40%,80% { transform: translateX(8px); } }
|
|
.stars { text-align: center; font-size: 26px; letter-spacing: 4px; color: #fbbf24; margin: 6px 0; }
|
|
.bigword { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin: 18px 0; }
|
|
.bigword 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: flip .6s ease backwards;
|
|
}
|
|
.confetti { position: fixed; top: -12px; width: 9px; height: 14px; z-index: 5; animation: fall linear forwards; }
|
|
@keyframes fall { to { transform: translateY(105vh) rotate(720deg); } }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card">
|
|
<div id="sStart" class="screen on">
|
|
<h1 id="gtitle"></h1>
|
|
<p class="story" id="gstory"></p>
|
|
<button id="btnStart">Incepe aventura</button>
|
|
</div>
|
|
|
|
<div id="sGame" class="screen">
|
|
<div class="progress"><i id="bar"></i></div>
|
|
<div class="meta"><span id="step"></span><span id="score"></span></div>
|
|
<div class="letters" id="lettersBar"></div>
|
|
<div id="qbox">
|
|
<div class="qtitle" id="qtitle"></div>
|
|
<div class="question" id="qtext"></div>
|
|
<div id="answers"></div>
|
|
<div class="feedback" id="feedback"></div>
|
|
<button class="hint" id="btnHint">Vreau un indiciu</button>
|
|
<div class="hinttext" id="hinttext"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="sFinal" class="screen">
|
|
<h1>Evadare reusita!</h1>
|
|
<div class="stars" id="finalStars"></div>
|
|
<div class="bigword" id="bigword"></div>
|
|
<p class="story" id="finalMsg"></p>
|
|
<button id="btnAgain">Joaca din nou</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
var CFG = {"title":"Comoara ascunsa","player":"","color":"#6d28d9","story":"O comoara a fost ascunsa, iar singurul drum spre ea trece prin cateva incercari. Rezolva fiecare puzzle ca sa aduni literele cuvantului magic.","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"},{"title":"Adevarat sau fals","type":"tf","question":"Romania are iesire la Marea Neagra.","answer":"","tfAnswer":"Adevarat","choices":"","hint":"","letter":"A"},{"title":"Alege raspunsul","type":"choice","question":"Care este capitala Frantei?","answer":"","tfAnswer":"Adevarat","choices":"*Paris\nLyon\nMarsilia","hint":"Turnul Eiffel.","letter":"R"}]};
|
|
document.documentElement.style.setProperty('--accent', CFG.color || '#6d28d9');
|
|
document.documentElement.style.setProperty('--accent-light', 'color-mix(in srgb, ' + (CFG.color || '#6d28d9') + ' 40%, white)');
|
|
|
|
var idx = 0, totalStars = 0, attempts = 0, hintUsed = false, won = [];
|
|
|
|
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 show(id) {
|
|
var scr = document.querySelectorAll('.screen');
|
|
for (var i = 0; i < scr.length; i++) scr[i].classList.remove('on');
|
|
el(id).classList.add('on');
|
|
}
|
|
|
|
el('gtitle').textContent = CFG.title;
|
|
var hello = CFG.player ? 'Salut, ' + CFG.player + '! ' : '';
|
|
el('gstory').textContent = hello + CFG.story;
|
|
|
|
el('btnStart').onclick = function () { show('sGame'); renderPuzzle(); };
|
|
el('btnAgain').onclick = function () { location.reload(); };
|
|
|
|
function lettersBar() {
|
|
var bar = el('lettersBar');
|
|
bar.innerHTML = '';
|
|
var any = false;
|
|
for (var i = 0; i < CFG.puzzles.length; i++) {
|
|
var L = (CFG.puzzles[i].letter || '').trim();
|
|
if (!L) continue;
|
|
any = true;
|
|
var d = document.createElement('div');
|
|
d.className = 'tile' + (won[i] ? ' won' : '');
|
|
d.textContent = won[i] ? L.toUpperCase() : '?';
|
|
bar.appendChild(d);
|
|
}
|
|
bar.style.display = any ? '' : 'none';
|
|
}
|
|
|
|
function renderPuzzle() {
|
|
var p = CFG.puzzles[idx];
|
|
attempts = 0; hintUsed = false;
|
|
el('bar').style.width = (idx / CFG.puzzles.length * 100) + '%';
|
|
el('step').textContent = 'Puzzle ' + (idx + 1) + ' din ' + CFG.puzzles.length;
|
|
el('score').textContent = totalStars + ' \u2605';
|
|
el('qtitle').textContent = p.title || 'Puzzle ' + (idx + 1);
|
|
el('qtext').textContent = p.question;
|
|
el('feedback').textContent = ''; el('feedback').className = 'feedback';
|
|
el('hinttext').style.display = 'none';
|
|
el('hinttext').textContent = p.hint || '';
|
|
el('btnHint').style.display = p.hint ? '' : 'none';
|
|
lettersBar();
|
|
|
|
var box = el('answers');
|
|
box.innerHTML = '';
|
|
if (p.type === 'free') {
|
|
var inp = document.createElement('input');
|
|
inp.type = 'text'; inp.autocomplete = 'off'; inp.placeholder = 'Scrie raspunsul...';
|
|
var btn = document.createElement('button');
|
|
btn.textContent = 'Verifica';
|
|
btn.onclick = function () { check(inp.value, p.answer); };
|
|
inp.onkeydown = function (e) { if (e.key === 'Enter') btn.click(); };
|
|
box.appendChild(inp); box.appendChild(btn);
|
|
setTimeout(function () { inp.focus(); }, 50);
|
|
} else if (p.type === 'tf') {
|
|
['Adevarat', 'Fals'].forEach(function (v) {
|
|
var b = document.createElement('button');
|
|
b.className = 'opt'; b.textContent = v;
|
|
b.onclick = function () { check(v, p.tfAnswer); };
|
|
box.appendChild(b);
|
|
});
|
|
} else {
|
|
var correct = '';
|
|
var opts = (p.choices || '').split('\n').map(function (l) { return l.trim(); }).filter(Boolean);
|
|
opts.forEach(function (o) { if (o.charAt(0) === '*') correct = o.slice(1).trim(); });
|
|
opts.map(function (o) { return o.charAt(0) === '*' ? o.slice(1).trim() : o; })
|
|
.forEach(function (o) {
|
|
var b = document.createElement('button');
|
|
b.className = 'opt'; b.textContent = o;
|
|
b.onclick = function () { check(o, correct); };
|
|
box.appendChild(b);
|
|
});
|
|
if (!opts.length) box.textContent = '(puzzle fara variante - completeaza-le in builder)';
|
|
}
|
|
}
|
|
|
|
el('btnHint').onclick = function () {
|
|
hintUsed = true;
|
|
el('hinttext').style.display = 'block';
|
|
};
|
|
|
|
function check(given, expected) {
|
|
if (norm(given) === norm(expected) && norm(given) !== '') {
|
|
var stars = (hintUsed || attempts >= 2) ? 1 : (attempts === 1 ? 2 : 3);
|
|
totalStars += stars;
|
|
won[idx] = true;
|
|
beep(true);
|
|
var f = el('feedback');
|
|
f.textContent = 'Corect! +' + stars + ' \u2605';
|
|
f.className = 'feedback good';
|
|
lettersBar();
|
|
el('bar').style.width = ((idx + 1) / CFG.puzzles.length * 100) + '%';
|
|
setTimeout(next, 900);
|
|
} else {
|
|
attempts++;
|
|
beep(false);
|
|
var fb = el('feedback');
|
|
fb.textContent = 'Nu e bine, mai incearca!';
|
|
fb.className = 'feedback bad';
|
|
var card = document.querySelector('.card');
|
|
card.classList.remove('shake');
|
|
void card.offsetWidth;
|
|
card.classList.add('shake');
|
|
}
|
|
}
|
|
|
|
function next() {
|
|
idx++;
|
|
if (idx < CFG.puzzles.length) { renderPuzzle(); return; }
|
|
show('sFinal');
|
|
var max = CFG.puzzles.length * 3;
|
|
el('finalStars').textContent = totalStars + ' / ' + max + ' \u2605';
|
|
var word = '';
|
|
for (var i = 0; i < CFG.puzzles.length; i++) {
|
|
var L = (CFG.puzzles[i].letter || '').trim();
|
|
if (L) word += L.toUpperCase();
|
|
}
|
|
var bw = el('bigword');
|
|
bw.innerHTML = '';
|
|
for (var j = 0; j < word.length; j++) {
|
|
var s = document.createElement('span');
|
|
s.textContent = word.charAt(j);
|
|
s.style.animationDelay = (j * 0.18) + 's';
|
|
bw.appendChild(s);
|
|
}
|
|
var name = CFG.player ? CFG.player + ', ' : '';
|
|
el('finalMsg').textContent = name ? name + (CFG.finalMessage || '').charAt(0).toLowerCase() + (CFG.finalMessage || '').slice(1) : (CFG.finalMessage || '');
|
|
confetti();
|
|
}
|
|
|
|
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 beep(ok) {
|
|
try {
|
|
var ctx = beep.ctx || (beep.ctx = new (window.AudioContext || window.webkitAudioContext)());
|
|
var t = ctx.currentTime;
|
|
var freqs = ok ? [523, 784] : [196];
|
|
freqs.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) {}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |