mirror of
https://github.com/domfelipe/meu-mundinho.git
synced 2026-08-07 06:16:39 +00:00
App infantil: 35 brincadeiras (three.js + voz PT-BR)
This commit is contained in:
commit
bd6ade82af
1 changed files with 460 additions and 0 deletions
460
index.html
Normal file
460
index.html
Normal file
|
|
@ -0,0 +1,460 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="pt-BR">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>Meu Mundinho — 35 brincadeiras</title>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@400;600;700;800&display=swap" rel="stylesheet">
|
||||||
|
<script src="https://unpkg.com/three@0.160.0/build/three.min.js"></script>
|
||||||
|
<style>
|
||||||
|
*{box-sizing:border-box;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}
|
||||||
|
html,body{margin:0;height:100%;overflow:hidden}
|
||||||
|
body{font-family:'Baloo 2','Arial Rounded MT Bold','Trebuchet MS',sans-serif;color:#2d3a47}
|
||||||
|
#bg{position:fixed;inset:0;z-index:-1;background:linear-gradient(160deg,#8fd3ff 0%,#c9ecff 42%,#ffe9f4 100%)}
|
||||||
|
#bg::after{content:'';position:fixed;inset:0;pointer-events:none;background:radial-gradient(60% 45% at 12% 10%,rgba(255,255,255,.6),transparent 60%),radial-gradient(55% 42% at 88% 88%,rgba(255,214,170,.5),transparent 65%)}
|
||||||
|
#bg.flat{background:linear-gradient(160deg,#8fd3ff,#ffe9f4)}
|
||||||
|
#top{position:fixed;top:0;left:0;right:0;z-index:50;display:flex;gap:10px;padding:10px;pointer-events:none}
|
||||||
|
#top>*{pointer-events:auto;background:#fff;border:3px solid #3d3d3d;border-radius:999px;font-size:22px;padding:7px 16px;cursor:pointer;box-shadow:0 4px 0 rgba(61,61,61,.8);transition:transform .08s}
|
||||||
|
#top>*:active{transform:translateY(3px);box-shadow:0 1px 0 rgba(61,61,61,.8)}
|
||||||
|
#screen{position:fixed;inset:0;overflow:hidden}
|
||||||
|
.big{font-size:clamp(56px,15vw,150px);line-height:1;text-align:center;filter:drop-shadow(0 6px 0 rgba(0,0,0,.12))}
|
||||||
|
.bigBtn{background:linear-gradient(#ffe27a,#ffca28);color:#4a3400;border:4px solid #3d3d3d;border-radius:999px;font-size:clamp(24px,6.5vw,58px);font-weight:800;padding:clamp(14px,2.4vw,24px) clamp(38px,7vw,72px);cursor:pointer;box-shadow:0 8px 0 rgba(61,61,61,.9),0 18px 26px rgba(0,0,0,.14);transition:transform .08s;text-align:center}
|
||||||
|
.bigBtn:active{transform:translateY(6px);box-shadow:0 2px 0 rgba(61,61,61,.9)}
|
||||||
|
.card{display:grid;place-items:center;font-size:clamp(44px,11vw,110px);background:#fff;border:4px solid #3d3d3d;border-radius:26px;aspect-ratio:1;width:clamp(84px,20vw,210px);cursor:pointer;box-shadow:0 6px 0 rgba(61,61,61,.85),0 16px 22px rgba(0,0,0,.1);transition:transform .1s}
|
||||||
|
.card:hover{transform:scale(1.05)}
|
||||||
|
.card:active{transform:translateY(4px);box-shadow:0 2px 0 rgba(61,61,61,.85)}
|
||||||
|
.card .stamp{position:absolute;font-size:clamp(16px,3.5vw,34px);opacity:.32;bottom:7%;right:7%}
|
||||||
|
.card.sel,.sel{outline:8px solid #ffd54a}
|
||||||
|
.row{display:flex;gap:clamp(12px,3vw,28px);justify-content:center;align-items:center;flex-wrap:wrap}
|
||||||
|
.shake{animation:shake .35s}
|
||||||
|
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-12px)}75%{transform:translateX(12px)}}
|
||||||
|
.gate{height:100%;overflow-y:auto;display:grid;place-items:center;align-content:center;gap:clamp(20px,4vh,40px);text-align:center;padding:clamp(56px,10vh,110px) clamp(20px,4vw,40px) clamp(20px,4vh,40px)}
|
||||||
|
.gtitle{font-size:clamp(20px,4.6vw,44px);font-weight:800;color:#2d3a47;line-height:1.25;max-width:94vw}
|
||||||
|
.sub{font-size:clamp(15px,3vw,28px);color:#5b6b7a}
|
||||||
|
.floater{position:absolute;bottom:-16vh;font-size:clamp(48px,12vw,120px);animation:rise linear infinite;cursor:pointer;text-align:center;line-height:1;filter:drop-shadow(0 4px 0 rgba(0,0,0,.1))}
|
||||||
|
@keyframes rise{to{transform:translateY(-140vh) rotate(60deg)}}
|
||||||
|
.floater.pop{animation:none;transform:scale(0) rotate(180deg);transition:transform .18s}
|
||||||
|
.conf{position:fixed;bottom:-10vh;font-size:34px;animation:up linear forwards;pointer-events:none;z-index:99}
|
||||||
|
@keyframes up{to{transform:translateY(-120vh) rotate(360deg)}}
|
||||||
|
@keyframes fall{to{transform:translateY(90vh)}}
|
||||||
|
.item{position:absolute;top:-12vh;font-size:clamp(38px,9vw,88px);animation:fall linear forwards;cursor:pointer}
|
||||||
|
.basket{position:fixed;bottom:10px;left:50%;transform:translateX(-50%);font-size:clamp(48px,10vw,104px);pointer-events:none;z-index:20}
|
||||||
|
.slot{display:grid;place-items:center;border:5px dashed #9fb3c4;border-radius:22px;background:rgba(255,255,255,.6);font-weight:800;color:#2d3a47}
|
||||||
|
.slot.match{background:#d9f7d3;border-style:solid;border-color:#4caf50}
|
||||||
|
#toast{position:fixed;bottom:clamp(90px,16vh,160px);left:50%;transform:translateX(-50%);background:rgba(45,58,71,.85);color:#fff;font-size:clamp(17px,3.6vw,32px);font-weight:700;padding:12px 26px;border-radius:999px;z-index:60;display:none;max-width:92vw;text-align:center;box-shadow:0 10px 22px rgba(0,0,0,.18)}
|
||||||
|
#toast.show{display:block}
|
||||||
|
#cal{height:100%;overflow-y:auto;padding:clamp(58px,11vh,110px) clamp(18px,3vw,40px) clamp(20px,4vh,40px)}
|
||||||
|
#cal h1{font-size:clamp(24px,5vw,48px);text-align:center;margin:0 0 1vh;color:#2d3a47}
|
||||||
|
#cal .week{margin:clamp(14px,2.2vh,26px) 0}
|
||||||
|
#cal .wtitle{font-size:clamp(17px,3.6vw,34px);font-weight:800;color:#5b6b7a;margin-bottom:clamp(8px,1.2vh,14px)}
|
||||||
|
#cal .days{display:grid;grid-template-columns:repeat(5,1fr);gap:clamp(8px,1.8vw,20px)}
|
||||||
|
.day{background:#fff;border:4px solid #3d3d3d;border-radius:20px;text-align:center;padding:10px 2px 8px;cursor:pointer;box-shadow:0 5px 0 rgba(61,61,61,.8),0 12px 18px rgba(0,0,0,.08);transition:transform .1s}
|
||||||
|
.day:hover{transform:scale(1.04)}
|
||||||
|
.day:active{transform:translateY(3px);box-shadow:0 2px 0 rgba(61,61,61,.8)}
|
||||||
|
.day .e{font-size:clamp(30px,6.5vw,64px)}
|
||||||
|
.day .n{font-size:clamp(13px,2.5vw,22px);font-weight:800;color:#2d3a47}
|
||||||
|
.day .t{font-size:clamp(12px,2.2vw,20px);color:#7a8b99}
|
||||||
|
.day .st{font-size:clamp(12px,2.4vw,22px);color:#ffb300;letter-spacing:1px}
|
||||||
|
#cfg{height:100%;overflow-y:auto;padding:clamp(58px,11vh,110px) 5vw 4vh;text-align:center}
|
||||||
|
#cfg label{font-size:clamp(20px,4vw,40px);font-weight:800;color:#2d3a47;display:block;margin-top:3vh}
|
||||||
|
#cfg input,#cfg textarea{font-size:clamp(20px,4vw,40px);padding:clamp(10px,2vw,20px);border:4px solid #3d3d3d;border-radius:18px;width:min(90vw,500px);text-align:center;font-family:inherit;background:#fff;box-shadow:0 4px 0 rgba(61,61,61,.7)}
|
||||||
|
#cfg .fam{font-size:clamp(14px,2.8vw,26px);color:#5b6b7a;margin-top:1vh}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="bg"></div>
|
||||||
|
<div id="top"><button id="btnM" onclick="musicToggle()">🎵</button><button onclick="goHome()">🏠</button><button onclick="goConfig()">⚙️</button><span id="starsBadge">⭐ 0/105</span><span id="who"></span></div>
|
||||||
|
<main id="screen"></main>
|
||||||
|
<div id="toast"></div>
|
||||||
|
<script>
|
||||||
|
// ===================== estado =====================
|
||||||
|
const S=JSON.parse(localStorage.getItem('mm')||'{}');
|
||||||
|
S.name=S.name||'';S.family=S.family||[];S.stars=S.stars||{};
|
||||||
|
const save=()=>localStorage.setItem('mm',JSON.stringify(S));
|
||||||
|
const totalStars=()=>{let t=0;for(let d=1;d<=35;d++)t+=S.stars[d]||0;return t};
|
||||||
|
const updateStars=()=>{const b=$('#starsBadge');if(b)b.textContent='⭐ '+totalStars()+'/105'};
|
||||||
|
function resetAll(){if(!confirm('Apagar TODAS as estrelas, o nome e a família? Isso não pode ser desfeito.'))return;localStorage.removeItem('mm');Object.keys(S).forEach(k=>delete S[k]);S.name='';S.family=[];S.stars={};save();updateStars();toast('Tudo apagado! Configurado de novo:');location.hash='#config'}
|
||||||
|
const $=q=>document.querySelector(q);
|
||||||
|
const rand=a=>a[Math.floor(Math.random()*a.length)];
|
||||||
|
const SZ=(v,cap)=>Math.min(v*innerWidth/100,cap)+'px';
|
||||||
|
const SZH=(v,cap)=>Math.min(v*innerHeight/100,cap)+'px';
|
||||||
|
const shuffle=a=>{a=a.slice();for(let i=a.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[a[i],a[j]]=[a[j],a[i]]}return a};
|
||||||
|
const NUM=['um','dois','três','quatro','cinco','seis','sete','oito','nove','dez'];
|
||||||
|
|
||||||
|
// ===================== áudio =====================
|
||||||
|
let AC;
|
||||||
|
const ac=()=>AC=AC||new(window.AudioContext||window.webkitAudioContext)();
|
||||||
|
function tone(f,d=.15,type='sine',g=.15){const a=ac(),o=a.createOscillator(),v=a.createGain();o.type=type;o.frequency.value=f;v.gain.setValueAtTime(g,a.currentTime);v.gain.exponentialRampToValueAtTime(.001,a.currentTime+d);o.connect(v);v.connect(a.destination);o.start();o.stop(a.currentTime+d)}
|
||||||
|
const POP=f=>tone(f,.12,'square',.06);
|
||||||
|
const buzz=()=>tone(120,.25,'sawtooth',.08);
|
||||||
|
function fanfare(){[523,659,784,1047].forEach((f,i)=>setTimeout(()=>tone(f,.28,'triangle',.18),i*140))}
|
||||||
|
|
||||||
|
// ===================== música chiptune 8-bit =====================
|
||||||
|
let musicT=null,musicOn=true,step=0;
|
||||||
|
const MELO=[523,659,784,659,880,784,659,523,659,784,1047,880,784,0,659,523,587,698,880,698,1047,880,784,659,523,659,784,1047,880,784,659,523];
|
||||||
|
const BASSR=[130,130,98,98,110,110,87,87];
|
||||||
|
function musicStart(){if(musicT)return;try{if(ac().state==='suspended')ac().resume()}catch(e){}musicT=setInterval(()=>{const s=step;step=(step+1)%32;if(!musicOn)return;const f=MELO[s];if(f)tone(f,.18,'square',.045);if(s%4===0)tone(BASSR[(s/4)%8],.3,'triangle',.055)},240)}
|
||||||
|
function musicToggle(){musicOn=!musicOn;const b=$('#btnM');if(b)b.textContent=musicOn?'🎵':'🔇';if(musicOn&&!musicT)musicStart()}
|
||||||
|
|
||||||
|
// ===================== voz =====================
|
||||||
|
let VOICES=[];
|
||||||
|
function loadV(){VOICES=speechSynthesis.getVoices().filter(v=>v.lang&&v.lang.toLowerCase().startsWith('pt'))}
|
||||||
|
if('speechSynthesis' in window){loadV();speechSynthesis.onvoiceschanged=loadV}
|
||||||
|
function say(t){if(!('speechSynthesis' in window))return;try{speechSynthesis.cancel()}catch(e){}const u=new SpeechSynthesisUtterance(t);u.lang='pt-BR';if(VOICES[0])u.voice=VOICES[0];u.rate=.95;u.pitch=1.3;speechSynthesis.speak(u)}
|
||||||
|
const PRAISE=['Muito bem!','Show de bola!','Você é incrível!','Parabéns!','Uau, que legal!','Mandou super bem!','Bravo!','Isso aí!'];
|
||||||
|
const praise=()=>{say(rand(PRAISE));fanfare()};
|
||||||
|
|
||||||
|
// ===================== celebração / ui =====================
|
||||||
|
function celebrate(){for(let i=0;i<20;i++){const c=document.createElement('div');c.className='conf';c.textContent=rand(['⭐','🎈','🌟','✨','🎉','💛','🦖','🏎️']);c.style.left=Math.random()*100+'vw';c.style.animationDuration=(1.6+Math.random()*1.6)+'s';c.style.animationDelay=(Math.random()*.7)+'s';c.style.fontSize=(24+Math.random()*30)+'px';document.body.appendChild(c);setTimeout(()=>c.remove(),3600)}praise()}
|
||||||
|
let toastT;
|
||||||
|
function toast(t){const e=$('#toast');e.textContent=t;e.classList.add('show');clearTimeout(toastT);toastT=setTimeout(()=>e.classList.remove('show'),2400)}
|
||||||
|
const stage=()=>$('#screen');
|
||||||
|
const shake=el=>{el.classList.remove('shake');void el.offsetWidth;el.classList.add('shake')};
|
||||||
|
function stars(day,n){S.stars[day]=Math.max(S.stars[day]||0,n);save();updateStars()}
|
||||||
|
const starStr=n=>'★'.repeat(n||0)+'☆'.repeat(3-(n||0));
|
||||||
|
function bigBtn(txt,cb){const b=document.createElement('div');b.className='bigBtn';b.innerHTML=txt;b.onclick=()=>{ac();tone(600,.08,'square',.05);cb&&cb(b)};return b}
|
||||||
|
function card(e,cb,extra){const c=document.createElement('div');c.className='card';c.innerHTML=e+(extra||'');c.onclick=()=>{ac();tone(650,.08,'square',.05);cb&&cb(c)};return c}
|
||||||
|
function gate(emoji,title,fn){const st=stage();st.innerHTML=`<div class="gate"><div class="big">${emoji}</div><div class="gtitle">${title}</div><div class="sub">Clique no botão para começar</div></div>`;st.querySelector('.gate').appendChild(bigBtn('▶ Vamos!',fn))}
|
||||||
|
function shakeWrong(el){buzz();shake(el)}
|
||||||
|
|
||||||
|
// ===================== motor de balões =====================
|
||||||
|
function floater(items,onPop,host){const st=host||stage();st.innerHTML='';const out=shuffle(items).slice(0,9).map((it,i)=>{const b=document.createElement('div');b.className='floater';b.innerHTML=it.e;b.style.left=(4+Math.random()*84)+'vw';b.style.animationDuration=(4.5+Math.random()*4)+'s';b.style.animationDelay=(-Math.random()*3)+'s';b.onclick=()=>{POP(400+it.k*40);b.classList.add('pop');setTimeout(()=>b.remove(),200);onPop(it,b)};st.appendChild(b);return{it,b}});return out}
|
||||||
|
const it=(e,k)=>({e,k});
|
||||||
|
const ballon=L=>`<span style="display:inline-flex;flex-direction:column;align-items:center;line-height:.85">${L}<span style="font-size:.8em">🎈</span></span>`;
|
||||||
|
|
||||||
|
// ===================== jogo de arrastar por toque =====================
|
||||||
|
// ponytail: clique-clique em vez de arrastar — mais fácil para 3 anos
|
||||||
|
function tapMatch(pieces,slots,onDone){const st=stage();const pcs=shuffle(pieces);let sel=null;
|
||||||
|
const sw=Math.min(24,82/slots.length);
|
||||||
|
const ps=document.createElement('div');ps.style.cssText=`position:absolute;left:0;right:0;bottom:${SZH(28,300)};display:flex;flex-wrap:wrap;justify-content:center;gap:${SZ(2,20)};padding:0 ${SZ(4,40)}`;
|
||||||
|
pcs.forEach(p=>{const d=document.createElement('div');d.style.cssText=`display:grid;place-items:center;font-size:${SZ(7,64)};width:${SZ(12,120)};height:${SZ(12,120)};background:#fff;border:4px solid #3d3d3d;border-radius:20px;box-shadow:0 5px 0 rgba(61,61,61,.8);cursor:pointer;position:relative`;d.textContent=p.e;d.dataset.k=p.k;d.onclick=()=>{sel&&sel.classList.remove('sel');sel=d;d.classList.add('sel');tone(500,.07,'square',.05)};ps.appendChild(d)});
|
||||||
|
st.appendChild(ps);
|
||||||
|
const rows=document.createElement('div');rows.className='row';rows.style.cssText=`position:absolute;bottom:${SZH(5,60)};left:0;right:0;gap:${SZ(1.5,14)}`;
|
||||||
|
slots.forEach(s=>{const d=document.createElement('div');d.className='slot';d.style.width=SZ(sw,230);d.style.height=SZ(sw,230);d.style.fontSize=SZ(Math.min(10,sw*.65),120);d.dataset.k=s.k;d.innerHTML=s.e;d.onclick=()=>{if(!sel)return;if(sel.dataset.k===d.dataset.k){d.classList.add('match');d.textContent=sel.textContent;sel.remove();sel=null;tone(700,.12,'triangle',.12);if(st.querySelectorAll('.slot.match').length===slots.length)onDone()}else shakeWrong(d)};rows.appendChild(d)});
|
||||||
|
st.appendChild(rows)}
|
||||||
|
|
||||||
|
// ===================== temas =====================
|
||||||
|
const THEMES=[
|
||||||
|
{name:'Mundo dos Carrinhos',emoji:'🏎️',pool:['🏎️','🚗','🚕','🚙','🚓','🚑','🚒','🚜','🚌','🏁']},
|
||||||
|
{name:'Terra dos Dinossauros',emoji:'🦖',pool:['🦕','🦖','🦖','🥚','🦴','🌋','🌿','🦕','🌴','🦖']},
|
||||||
|
{name:'Esquadrilha de Aviões',emoji:'✈️',pool:['✈️','🛩️','🚁','🛫','🛬','☁️','🪂','🚀','✈️','🛸']}];
|
||||||
|
const themeOf=d=>THEMES[Math.floor((d-1)/5)%3];
|
||||||
|
|
||||||
|
// ===================== jogos =====================
|
||||||
|
const MECH={
|
||||||
|
// 1 — letras do nome: teclado gigante
|
||||||
|
trace(d){const target=(S.name||'PEDRO').replace(/\s/g,'').toUpperCase().split('');let i=0;
|
||||||
|
const st=stage();const T=themeOf(d);
|
||||||
|
st.innerHTML=`<div style="height:100%;overflow-y:auto;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:clamp(14px,3vh,30px);padding:clamp(60px,10vh,110px) 3vw clamp(20px,4vh,40px)">
|
||||||
|
<div class="gtitle">${T.emoji} Escreva seu nome: <span style="color:#e53935">${(S.name||'PEDRO')}</span></div>
|
||||||
|
<div class="row" id="slots" style="gap:clamp(8px,1.5vw,16px);width:100%"></div>
|
||||||
|
<div id="kb"></div></div>`;
|
||||||
|
const row=st.querySelector('#slots');
|
||||||
|
const w=Math.min(11,64/target.length);
|
||||||
|
const slots=target.map(l=>{const s=document.createElement('div');s.className='slot';s.style.cssText=`width:${SZ(w,130)};height:${SZ(w*1.3,170)};font-size:${SZ(Math.min(7,w*.55),64)};line-height:1;padding:0`;s.textContent='?';row.appendChild(s);return s});
|
||||||
|
const kb=st.querySelector('#kb');kb.style.cssText='width:min(96vw,1100px);display:grid;grid-template-columns:repeat(13,1fr);gap:clamp(6px,1vw,10px)';
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').forEach(L=>{const b=document.createElement('div');b.style.cssText=`height:${SZ(9,80)};display:grid;place-items:center;font-size:${SZ(4.6,42)};background:#fff;border:3px solid #3d3d3d;border-radius:12px;cursor:pointer;box-shadow:0 4px 0 rgba(61,61,61,.8);line-height:1;padding:0`;b.textContent=L;b.onclick=()=>p(L,b);kb.appendChild(b)});
|
||||||
|
addEventListener('keydown',e=>p(String(e.key).toUpperCase()));
|
||||||
|
function p(L,el){if(!/^[A-Z]$/.test(L)||i>=target.length)return;ac();if(L===target[i]){slots[i].textContent=L;slots[i].classList.add('match');tone(600+i*60,.15,'triangle',.12);i++;if(i===target.length){stars(d,3);setTimeout(()=>{st.innerHTML='';celebrate()},500)}}else shakeWrong(el||kb)}
|
||||||
|
},
|
||||||
|
// 2 — balões com letras do nome
|
||||||
|
balLetra(d){const refs=shuffle([...new Set([...(S.name||'PEDRO').replace(/\s/g,'').toUpperCase().split(''),...S.family.filter(f=>f.trim()).map(f=>f.trim()[0].toUpperCase())])]).slice(0,7);let r=0;
|
||||||
|
const st=stage();st.innerHTML=`<div style="position:absolute;top:clamp(56px,8vh,100px);left:50%;transform:translateX(-50%);text-align:center"><div id="ref" style="font-size:clamp(56px,13vw,130px);font-weight:800;color:#e53935;line-height:1;text-shadow:0 4px 0 rgba(0,0,0,.08)">?</div><div class="sub">Estoure as letras!</div></div><div id="balloons"></div>`;
|
||||||
|
const ref=$('#ref'),sub=ref.nextElementSibling;
|
||||||
|
function round(){if(!st.isConnected)return;if(r>=refs.length){stars(d,3);celebrate();return}const L=refs[r];ref.textContent=L;sub.textContent=`Estoure as letras ${L}!`;say(`Estoure as letras ${L}`);
|
||||||
|
const noise='ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').filter(x=>x!==L);
|
||||||
|
const items=shuffle([...Array(2).fill().map(()=>it(ballon(L),1)),...Array(6).fill().map(()=>it(ballon(rand(noise)),0))]);
|
||||||
|
let hits=0,done=false;
|
||||||
|
floater(items,(x,b)=>{if(done)return;if(x.k){hits++;tone(700+hits*60,.2,'triangle',.15);if(hits>=2){done=true;r++;setTimeout(round,700)}}else shakeWrong(b)},$('#balloons'))}
|
||||||
|
round()},
|
||||||
|
// 3 — ache a letra
|
||||||
|
achaLetra(d){const rounds=[...(S.name||'PEDRO').replace(/\s/g,'').toUpperCase().split('')].concat(S.family.filter(f=>f.trim()).map(f=>f.trim()[0].toUpperCase()));let i=0;
|
||||||
|
function rnd(){if(i>=rounds.length){stars(d,3);celebrate();return}const L=rounds[i];say(`Ache a letra ${L}`);toast(`Ache a letra: ${L}`);
|
||||||
|
const st=stage();st.innerHTML='';const others=shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').filter(x=>x!==L)).slice(0,2);
|
||||||
|
const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
shuffle([L,...others]).forEach(x=>row.appendChild(card(`<span style="font-size:${SZ(11,110)}">${x}</span>`,c=>{if(x===L){POP(700);stars(d,1);i++;setTimeout(rnd,700)}else shakeWrong(c)})))}
|
||||||
|
rnd()},
|
||||||
|
// 4 — números nos balões
|
||||||
|
balNum(d){let i=1;gate('🔢','Estoure os números em ordem!',()=>{floater(shuffle([1,2,3,4,5,6,7,8,9].map(n=>it(String(n),n))),(x,b)=>{if(x.k===i){tone(600+i*60,.2,'triangle',.15);i++;if(i>9){stars(d,3);setTimeout(celebrate,400)}}else shakeWrong(b)})})},
|
||||||
|
// 5 — cores
|
||||||
|
cor(d){const T=themeOf(d);const COL=[[['🔴','vermelho'],['🟠','laranja'],['🟡','amarelo'],['🟢','verde'],['🔵','azul'],['🟣','roxo']],[['🟤','marrom'],['🟥','vermelho'],['🟩','verde'],['🟦','azul'],['🟨','amarelo'],['🟪','roxo']],[['🟠','laranja'],['🟥','vermelho'],['🟨','amarelo'],['🟩','verde'],['🟪','roxo'],['🟦','azul']]];const col=COL[Math.floor((d-1)/5)%3];let i=0;
|
||||||
|
function rnd(){if(i>=col.length){stars(d,3);celebrate();return}const [e,c]=col[i];say(`Clique no ${c}`);toast(`Clique no ${c}`);
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
shuffle(col).forEach(([e2,c2])=>row.appendChild(card(`<span style="font-size:${SZ(10,100)}">${e2}</span><span class="stamp">${T.emoji}</span>`,el=>{if(c2===c){POP(700);i++;setTimeout(rnd,800)}else shakeWrong(el)})))}
|
||||||
|
rnd()},
|
||||||
|
// 6 — formas
|
||||||
|
forma(d){const SH=[['⭕','círculo'],['🔺','triângulo'],['🟦','quadrado'],['⭐','estrela']];let i=0;
|
||||||
|
function rnd(){if(i>=SH.length){stars(d,3);celebrate();return}const[e,c]=SH[i];say(`Ache o ${c}`);toast(`Ache o ${c}`);
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
shuffle(SH).forEach(([e2,c2])=>row.appendChild(card(`<span style="font-size:${SZ(10,100)}">${e2}</span>`,el=>{if(c2===c){POP(700);i++;setTimeout(rnd,800)}else shakeWrong(el)})))}
|
||||||
|
rnd()},
|
||||||
|
// 7 — bichos
|
||||||
|
animal(d){const AN=[['🐶','cachorro','Au au!'],['🐱','gato','Miau!'],['🐮','vaca','Muuu!'],['🐔','galinha','Có có!'],['🐷','porquinho','Oinc!'],['🐸','sapo','Croac!']];let i=0;
|
||||||
|
function rnd(){if(i>=AN.length){stars(d,3);celebrate();return}const[e,c,s]=AN[i];say(`Onde está o ${c}?`);
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
shuffle(AN).forEach(([e2,c2])=>row.appendChild(card(`<span style="font-size:${SZ(10,100)}">${e2}</span>`,el=>{if(c2===c){say(s);POP(700);i++;setTimeout(rnd,1200)}else shakeWrong(el)})))}
|
||||||
|
rnd()},
|
||||||
|
// 8 — memória
|
||||||
|
memoria(d){const T=themeOf(d);const pairs=shuffle([...new Set(T.pool)]).slice(0,3);const deck=shuffle([...pairs,...pairs].map(e=>({e,flip:false})));let open=[],found=0;
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center;gap:3vw';st.appendChild(row);
|
||||||
|
deck.forEach(p=>{const c=document.createElement('div');c.className='card';c.style.width=SZ(24,240);c.textContent='❓';c.onclick=()=>{if(c.textContent!=='❓'||open.length===2)return;ac();c.textContent=p.e;open.push([p,c]);
|
||||||
|
if(open.length===2){const[a,b]=open;open=[];if(a[0].e===b[0].e){a[1].style.background='#c8f7c5';b[1].style.background='#c8f7c5';tone(700,.2,'triangle',.12);found++;if(found===3){stars(d,3);setTimeout(celebrate,500)}}else setTimeout(()=>{a[1].textContent='❓';b[1].textContent='❓'},900)}};row.appendChild(c)})},
|
||||||
|
// 9 — desenhar
|
||||||
|
desenho(d){const st=stage();st.innerHTML='<div class="gtitle" style="text-align:center;padding-top:9vh">✏️ Desenhe com o mouse!</div>';
|
||||||
|
const c=document.createElement('canvas');c.style.cssText='position:absolute;inset:8vh 0 0 0;width:100%;height:92vh;cursor:crosshair';st.appendChild(c);c.width=innerWidth;c.height=innerHeight*0.92;c.style.touchAction='none';
|
||||||
|
const g=c.getContext('2d');let brush=null;const COL=['#e53935','#1e88e5','#43a047','#fdd835','#8e24aa'];const STAMP=['⭐','❤️','🌸','🎈'];
|
||||||
|
const bar=document.createElement('div');bar.className='row';bar.style.cssText='position:fixed;bottom:1vh;left:50%;transform:translateX(-50%);z-index:30';
|
||||||
|
COL.forEach(col=>bar.appendChild(card(`<span style="font-size:${SZ(5,50)}">●</span>`,b=>{brush={col};b.style.background=col;b.style.outline='8px solid #ffd54a'},)));
|
||||||
|
bar.querySelectorAll('.card').forEach((b,i)=>{if(i<COL.length){b.style.background=COL[i]}});
|
||||||
|
STAMP.forEach(s=>bar.appendChild(card(`<span style="font-size:${SZ(5,50)}">${s}</span>`,b=>{brush={stamp:s}})));
|
||||||
|
bar.appendChild(bigBtn('🧹',()=>g.clearRect(0,0,c.width,c.height)));
|
||||||
|
st.appendChild(bar);
|
||||||
|
let drawing=false;
|
||||||
|
c.addEventListener('pointerdown',e=>{drawing=true;ac();paint(e)});
|
||||||
|
c.addEventListener('pointermove',e=>drawing&&paint(e));
|
||||||
|
c.addEventListener('pointerup',()=>drawing=false);
|
||||||
|
function paint(e){const x=e.clientX,y=e.clientY-8;if(brush?.stamp){g.font='40px sans-serif';g.fillText(brush.stamp,x,y);return}g.fillStyle=brush?brush.col:COL[0];g.beginPath();g.arc(x,y,26,0,7);g.fill()}},
|
||||||
|
// 10 — contar bolhas
|
||||||
|
conta(d){const n=2+Math.floor(Math.random()*4);let count=0;gate('🫧',`Estoure ${NUM[n-1]} bolhas!`,()=>{floater([...Array(9)].map(()=>it('🫧',5)),x=>{count++;tone(500+count*80,.15,'triangle',.12);if(count===n){stars(d,3);setTimeout(celebrate,300)}})})},
|
||||||
|
// 11 — quebra-cabeça
|
||||||
|
puzzle(d){const T=themeOf(d);const parts=shuffle([...new Set(T.pool)]).slice(0,4);gate('🧩','Monte o quebra-cabeça!',()=>tapMatch(parts.map(p=>({e:p,k:p})),parts.map(p=>({e:'❓',k:p})),()=>{stars(d,3);setTimeout(celebrate,400)}))},
|
||||||
|
// 12 — cesta
|
||||||
|
cesta(d){const T=themeOf(d);let got=0;gate('🧺','Pegue os bichinhos que caem!',()=>{
|
||||||
|
const st=stage();st.innerHTML='';
|
||||||
|
const bas=document.createElement('div');bas.className='basket';bas.textContent='🧺';st.appendChild(bas);
|
||||||
|
const move=e=>{bas.style.left=Math.min(90,Math.max(5,e.clientX/innerWidth*100))+'vw'};
|
||||||
|
addEventListener('pointermove',move);addEventListener('touchmove',e=>move(e.touches[0]),{passive:true});
|
||||||
|
const iv=setInterval(()=>{if(!st.isConnected){clearInterval(iv);return}if(got>=5){clearInterval(iv);removeEventListener('pointermove',move);stars(d,3);setTimeout(celebrate,300);return}
|
||||||
|
const good=Math.random()<.85;const it2=document.createElement('div');it2.className='item';it2.textContent=good?rand(T.pool):'💣';it2.style.left=(5+Math.random()*85)+'vw';it2.style.animationDuration=(2.4+Math.random()*1.6)+'s';st.appendChild(it2);
|
||||||
|
const ck=setInterval(()=>{const b=bas.getBoundingClientRect(),r=it2.getBoundingClientRect();if(!it2.isConnected){clearInterval(ck);return}
|
||||||
|
if(r.bottom>innerHeight*.88){it2.remove();clearInterval(ck);if(!good){buzz();toast('Ai! Uma bomba!')}}
|
||||||
|
else if(r.left<b.right&&r.right>b.left&&r.bottom>b.top&&r.bottom<b.top+60){it2.remove();clearInterval(ck);if(good){got++;POP(500+got*70);say('Peguei!')}else{buzz();toast('Ai! Uma bomba!')}}},60);
|
||||||
|
setTimeout(()=>it2.remove(),4500)},900)})},
|
||||||
|
// 13 — som da letra
|
||||||
|
somLetra(d){const letras=[...(S.name||'PEDRO').replace(/\s/g,'').toUpperCase().split('')].concat(S.family.filter(f=>f.trim()).map(f=>f.trim()[0].toUpperCase()));let i=0;
|
||||||
|
function rnd(){if(i>=letras.length){stars(d,3);celebrate();return}const L=letras[i];say(L);
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
shuffle(letras).slice(0,3).concat([L]).forEach(x=>row.appendChild(card(`<span style="font-size:${SZ(11,110)}">${x}</span>`,c=>{if(x===L){POP(700);i++;setTimeout(rnd,800)}else shakeWrong(c)})))}
|
||||||
|
setTimeout(rnd,600)},
|
||||||
|
// 14 — piano
|
||||||
|
piano(d){const N=[[261,'Dó','#ef5350'],[293,'Ré','#ff9800'],[329,'Mi','#ffd835'],[349,'Fá','#aed581'],[392,'Sol','#4fc3f7'],[440,'Lá','#9575cd'],[494,'Si','#f06292'],[523,'Dó','#f44336']];
|
||||||
|
const st=stage();st.innerHTML='<div class="gtitle" style="text-align:center;padding-top:8vh">🎹 Toque o piano!</div>';
|
||||||
|
const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center;padding:0 2vw';st.appendChild(row);
|
||||||
|
N.forEach(([f,nm,col])=>{const k=document.createElement('div');k.style.cssText=`width:${SZ(11,110)};height:${SZH(34,320)};background:${col};border:5px solid #333;border-radius:14px;cursor:pointer;box-shadow:0 6px 0 #999;display:grid;place-items:center;font-size:${SZ(4,40)};font-weight:800;color:#333`;
|
||||||
|
k.innerHTML=nm;k.onclick=()=>{ac();tone(f,.6,'triangle',.2);say(nm)};row.appendChild(k)});
|
||||||
|
stars(d,1)},
|
||||||
|
// 15 — pintar
|
||||||
|
pintar(d){const COL=['#e53935','#1e88e5','#43a047','#fdd835','#8e24aa','#ff7043'];let sel=null;
|
||||||
|
const st=stage();st.innerHTML='<div class="gtitle" style="text-align:center;padding-top:8vh">🖌️ Pinte o desenho!</div>';
|
||||||
|
const box=document.createElement('div');box.style.cssText='position:absolute;inset:16vh 3vw 14vh;border:6px solid #333;border-radius:20px;background:#fff;overflow:hidden';
|
||||||
|
const regions=[['sky','#cfe8ff',{left:'0',top:'0',right:'0',height:'45%'}],['sun','#ffe082',{left:'8%',top:'4%',width:'20%',height:'20%',borderRadius:'50%'}],['roof','#d7ccc8',{left:'12%',bottom:'20%',width:'40%',height:'32%',clipPath:'polygon(0 100%,50% 0,100% 100%)'}],['wall','#f5f5f5',{left:'12%',bottom:'0',width:'40%',height:'22%'}],['grass','#e8f5e9',{left:'0',bottom:'0',right:'0',height:'12%'}]];
|
||||||
|
regions.forEach(([name,col,pos])=>{const r=document.createElement('div');r.style.cssText=Object.entries(pos).map(([k,v])=>k+':'+v).join(';');r.style.background=col;r.style.border='2px solid #bbb';r.dataset.c=col;r.onclick=()=>{if(!sel){shakeWrong(r);return}ac();r.style.background=sel;r.dataset.c=sel;tone(600,.1,'triangle',.1)};box.appendChild(r)});st.appendChild(box);
|
||||||
|
const bar=document.createElement('div');bar.className='row';bar.style.cssText='position:fixed;bottom:1vh;left:50%;transform:translateX(-50%);z-index:30';
|
||||||
|
COL.forEach(col=>{const b=card(`<span style="font-size:${SZ(5,50)}">●</span>`,x=>{sel=col;bar.querySelectorAll('.card').forEach(c=>c.style.outline='');x.style.outline='10px solid #333'},);b.style.background=col;bar.appendChild(b)});
|
||||||
|
bar.appendChild(bigBtn('🎉',()=>{stars(d,3);celebrate()}));st.appendChild(bar)},
|
||||||
|
// 16 — tempo
|
||||||
|
tempo(d){const W=[['☀️','Sol','Que sol lindo e quentinho!',800],[['🌧️'],'Chuva','Está chovendo... plim plim!',400],[['❄️'],'Neve','Nevou! Brrr, que frio!',300],[['🌈'],'Arco-íris','Que arco-íris colorido!',600]];
|
||||||
|
const st=stage();st.innerHTML='<div class="gtitle" style="text-align:center;padding-top:8vh">☀️ Qual é o tempo hoje?</div>';
|
||||||
|
const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
W.forEach(([e,nm,fr,sf])=>{const c=card(e.join(''),x=>{say(fr);tone(sf,.4,'sine',.12);x.style.transform='scale(1.2)';setTimeout(()=>x.style.transform='',600)});c.style.fontSize=SZ(10,100);row.appendChild(c)});
|
||||||
|
stars(d,1)},
|
||||||
|
// 17 — maior e menor
|
||||||
|
maior(d){const pairs=[[['🐘','🐭'],['🐻','🐜']],[['🦕','🦗'],['🦖','🐞']],[['✈️','🐝'],['🚀','🪰']]];const P=pairs[Math.floor((d-1)/5)%3];let i=0;
|
||||||
|
function rnd(){if(i>=P.length){stars(d,3);celebrate();return}const[a,b]=P[i];const askBig=i%2===0;say(askBig?'Clique no MAIOR!':'Clique no MENOR!');toast(askBig?'Clique no MAIOR':'Clique no MENOR');
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center;gap:6vw';st.appendChild(row);
|
||||||
|
const mk=(e,big)=>{const c=document.createElement('div');c.className='card';c.style.width=SZ(30,300);c.style.fontSize=big?SZ(16,160):SZ(7,70);c.innerHTML=e;c.onclick=()=>{const correct=askBig?big:!big;if(correct){POP(700);i++;setTimeout(rnd,700)}else shakeWrong(c)};row.appendChild(c);return c};mk(a,true);mk(b,false)}
|
||||||
|
rnd()},
|
||||||
|
// 18 — diferente
|
||||||
|
diferente(d){const T=themeOf(d);let i=0;
|
||||||
|
function rnd(){if(i>=5){stars(d,3);celebrate();return}const common=rand(T.pool);const odd=rand(T.pool);let oddOne=odd;
|
||||||
|
while(oddOne===common)oddOne=rand(T.pool);
|
||||||
|
say('Ache o DIFERENTE!');toast('Ache o diferente');
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center;gap:3vw';st.appendChild(row);
|
||||||
|
shuffle([0,0,0,1]).forEach(isOdd=>{const c=document.createElement('div');c.className='card';c.innerHTML=`<span style="font-size:${SZ(10,100)}">${isOdd?oddOne:common}</span>`;c.onclick=()=>{if(isOdd){POP(800);i++;setTimeout(rnd,700)}else shakeWrong(c)};row.appendChild(c)})}
|
||||||
|
rnd()},
|
||||||
|
// 19 — sequência (simon)
|
||||||
|
sequencia(d){const COL=[['🔴',330],['🟡',262],['🟢',392],['🔵',440]];let seq=[],i=0,player=false;
|
||||||
|
const st=stage();st.innerHTML='<div class="gtitle" style="text-align:center;padding-top:8vh">🎯 Repita a sequência!</div>';
|
||||||
|
const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center;gap:4vw';st.appendChild(row);
|
||||||
|
const pads=COL.map(([e,f])=>{const c=document.createElement('div');c.className='card';c.style.width=SZ(30,300);c.style.filter='brightness(.7)';c.innerHTML=`<span style="font-size:${SZ(12,120)}">${e}</span>`;c.onclick=()=>{if(!player)return;ac();tone(f,.2,'triangle',.15);c.style.filter='brightness(1.4)';setTimeout(()=>c.style.filter='brightness(.7)',150);pick(f)};row.appendChild(c);return c});
|
||||||
|
function show(t){player=false;const n=seq.length;seq.forEach((f,j)=>{setTimeout(()=>{const c=pads[COL.findIndex(x=>x[1]===f)];c.style.filter='brightness(1.4)';tone(f,.25,'triangle',.15);setTimeout(()=>c.style.filter='brightness(.7)',250)},800+j*650)});setTimeout(()=>player=true,800+n*650+200)}
|
||||||
|
function pick(f){if(seq[i]!==f){buzz();toast('Quase! Olhe de novo');show(seq.length===0?[]:seq);i=0;return}i++;if(i===seq.length){i=0;if(seq.length>=4){stars(d,3);setTimeout(celebrate,400);return}seq.push(rand(COL)[1]);setTimeout(()=>show(seq),500)}}
|
||||||
|
setTimeout(()=>{seq=[rand(COL)[1]];show(seq)},900)},
|
||||||
|
// 20 — carinhas
|
||||||
|
caras(d){const R=[['😀','feliz'],['😢','triste'],['😡','bravo'],['😮','surpreso']];let i=0;
|
||||||
|
function rnd(){if(i>=R.length){stars(d,3);celebrate();return}const[e,n]=R[i];say(`Mostre a carinha ${n}!`);
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
shuffle(R).forEach(([e2,n2])=>row.appendChild(card(`<span style="font-size:${SZ(11,110)}">${e2}</span>`,c=>{if(n2===n){POP(700);i++;setTimeout(rnd,700)}else shakeWrong(c)})))}
|
||||||
|
rnd()},
|
||||||
|
// 21 — separar
|
||||||
|
separar(d){const fruts=[['🍎','maçã'],['🍌','banana'],['🍇','uva'],['🍓','morango']];const flores=[['🌷','tulipa'],['🌻','girassol'],['🌸','flor'],['🌼','margarida']];
|
||||||
|
gate('🧺','Guarde as frutas e as flores!',()=>{const st=stage();st.innerHTML='';let done=0;
|
||||||
|
const all=shuffle([...fruts.map(([e,n])=>({e,k:1,n})),...flores.map(([e,n])=>({e,k:0,n}))]);
|
||||||
|
const mid=document.createElement('div');mid.style.cssText='position:absolute;inset:8vh 0 26vh;display:grid;grid-template-columns:repeat(4,1fr);place-items:center;padding:0 4vw';
|
||||||
|
all.forEach(p=>{const c=document.createElement('div');c.className='card';c.style.width=SZ(17,170);c.innerHTML=`<span style="font-size:${SZ(9,90)}">${p.e}</span>`;c.onclick=()=>{c.style.pointerEvents='none';say(p.n);fly(c,p.k)};mid.appendChild(c)});st.appendChild(mid);
|
||||||
|
const bs=[];[['🧺 🌸',0],['🧺 🍎',1]].forEach(([txt,i])=>{const b=card(`<span style="font-size:${SZ(7,70)}">${txt}</span>`,()=>{});b.style.aspectRatio='auto';b.style.position='absolute';b.style.bottom=SZH(4,40);b.style.left=(15+i*55)+'vw';b.style.pointerEvents='none';bs[i]=b;st.appendChild(b)});
|
||||||
|
function fly(c,to){const b=bs[to].getBoundingClientRect(),r=c.getBoundingClientRect();c.style.transition='all .6s';c.style.position='absolute';c.style.left=(b.left+b.width/2-r.width/2)+'px';c.style.top=(b.top+20)+'px';setTimeout(()=>{c.style.opacity=0;done++;POP(600+done*50);if(done>=all.length){stars(d,3);setTimeout(celebrate,400)}},650)}
|
||||||
|
})},
|
||||||
|
// 22 — letra na areia (traçar)
|
||||||
|
areia(d){const letters=(S.name||'PEDRO').replace(/\s/g,'').toUpperCase().split('');let li=0;
|
||||||
|
gate('⛱️','Passe o mouse sobre a letra!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
const c=document.createElement('canvas');c.style.cssText='position:absolute;inset:10vh 0 0 0;width:100%;height:90vh;cursor:crosshair;touch-action:none';st.appendChild(c);c.width=innerWidth;c.height=innerHeight*.9;
|
||||||
|
const g=c.getContext('2d');g.fillStyle='#f5e6c8';g.fillRect(0,0,c.width,c.height);
|
||||||
|
const p=document.createElement('div');p.className='gtitle';p.style.cssText='position:absolute;top:9vh;left:50%;transform:translateX(-50%)';st.appendChild(p);
|
||||||
|
let mask=null;
|
||||||
|
function drawLetter(){g.clearRect(0,0,c.width,c.height);g.fillStyle='#f5e6c8';g.fillRect(0,0,c.width,c.height);
|
||||||
|
const L=letters[li];g.font=`bold ${Math.min(c.width*.5,300)}px 'Baloo 2','Arial Rounded MT Bold',sans-serif`;g.textAlign='center';g.textBaseline='middle';
|
||||||
|
g.fillStyle='rgba(0,0,0,.15)';g.fillText(L,c.width/2,c.height/2+30);
|
||||||
|
const off=document.createElement('canvas');off.width=c.width;off.height=c.height;const og=off.getContext('2d');og.font=g.font;og.textAlign='center';og.textBaseline='middle';og.fillText(L,c.width/2,c.height/2+30);
|
||||||
|
const data=og.getImageData(0,0,c.width,c.height).data;mask=new Uint8Array(c.width*c.height);let total=0;
|
||||||
|
for(let y=0;y<c.height;y++)for(let x=0;x<c.width;x++){if(data[(y*c.width+x)*4+3]>60){mask[y*c.width+x]=1;total++}}
|
||||||
|
p.textContent=`Letra ${L} — pinte a letra inteira!`;
|
||||||
|
g.fillStyle='rgba(0,0,0,.12)';g.fillText(L,c.width/2,c.height/2+30);covered=0;}
|
||||||
|
let covered=0;const painted=new Uint8Array(c.width*c.height);
|
||||||
|
function paint(e){const x=e.clientX,y=e.clientY-10;g.fillStyle='#e57373';g.beginPath();g.arc(x,y,34,0,7);g.fill();
|
||||||
|
for(let yy=Math.max(0,y-34);yy<Math.min(c.height,y+34);yy++)for(let xx=Math.max(0,x-34);xx<Math.min(c.width,x+34);xx++){if(!painted[yy*c.width+xx]&&mask[yy*c.width+xx]){painted[yy*c.width+xx]=1;covered++}}}
|
||||||
|
let drawing2=false;let done2=false;
|
||||||
|
c.addEventListener('pointerdown',e=>{drawing2=true;paint(e)});
|
||||||
|
c.addEventListener('pointermove',e=>{if(drawing2)paint(e);if(!done2&&total>0&&covered/total>.55){done2=true;li++;if(li>=letters.length){stars(d,3);setTimeout(celebrate,400)}else drawLetter()}});
|
||||||
|
c.addEventListener('pointerup',()=>drawing2=false);
|
||||||
|
drawLetter()})},
|
||||||
|
// 23 — bolhas da cor
|
||||||
|
bolha(d){const T=themeOf(d);const COLORS=[['#e53935','vermelha'],['#1e88e5','azul'],['#43a047','verde'],['#fdd835','amarela']];const target=rand(COLORS);let got=0;
|
||||||
|
gate('💧',`Estoure só as bolhas ${target[1]}s!`,()=>{floater([...Array(9)].map((_,k)=>({e:`<span style="display:inline-block;width:${SZ(12,120)};height:${SZ(12,120)};border-radius:50%;background:radial-gradient(circle at 35% 30%,#fff8,${COLORS[k%4][0]} 60%)"></span>`,k:k%4})),(x,b)=>{if(x.k===COLORS.findIndex(c=>c[1]===target[1])){got++;POP(600+got*60);if(got>=3){stars(d,3);setTimeout(celebrate,300)}}else{buzz();shakeWrong(b)}})});
|
||||||
|
setTimeout(()=>say(`Estoure só as bolhas ${target[1]}s!`),500)},
|
||||||
|
// 24 — contar estrelas
|
||||||
|
estrelas(d){let n=0;gate('⭐','Conte as estrelinhas comigo!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
[...Array(6)].forEach((_,i)=>{const s=document.createElement('div');s.className='card';s.style.cssText=`position:absolute;left:${5+i*15}vw;top:${18+i%2*22}vh;width:${SZ(20,200)};font-size:${SZ(9,90)}`;s.innerHTML='<span>⭐</span>';s.onclick=()=>{n++;s.style.background='#d9f7d3';s.style.pointerEvents='none';tone(600+n*60,.2,'triangle',.15);say(NUM[n-1]||'dez!');if(n>=6){stars(d,3);setTimeout(celebrate,600)}};st.appendChild(s)})})},
|
||||||
|
// 25 — casa
|
||||||
|
casa(d){const parts=[['🔺','roof'],['🟨','wall'],['🟫','door'],['🟦','window']];gate('🏠','Monte a casinha!',()=>tapMatch(parts.map(p=>({e:p[0],k:p[1]})),parts.map(p=>({e:'❓',k:p[1]})),()=>{stars(d,3);setTimeout(celebrate,400)}))},
|
||||||
|
// 26 — som do bicho
|
||||||
|
somAnimal(d){const AN=[['🐶','Au au!','cachorro'],['🐱','Miau!','gato'],['🐮','Muuu!','vaca'],['🐔','Có có!','galinha'],['🐷','Oinc oinc!','porquinho'],['🐸','Croc croc!','sapo']];let i=0;
|
||||||
|
function rnd(){if(i>=AN.length){stars(d,3);celebrate();return}const[e,s,c]=AN[i];say(`${s} Que bicho é esse?`);
|
||||||
|
const st=stage();st.innerHTML='';const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center';st.appendChild(row);
|
||||||
|
shuffle(AN).forEach(([e2,,c2])=>row.appendChild(card(`<span style="font-size:${SZ(10,100)}">${e2}</span>`,el=>{if(c2===c){say(`É o ${c}!`);POP(700);i++;setTimeout(rnd,1100)}else shakeWrong(el)})))}
|
||||||
|
setTimeout(rnd,500)},
|
||||||
|
// 27 — corrida
|
||||||
|
corrida(d){const T=themeOf(d);gate(T.emoji,'Corra até a chegada! Clique e segure!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
const flag=document.createElement('div');flag.style.cssText=`position:absolute;right:4vw;top:50%;transform:translateY(-50%);font-size:${SZ(12,120)}`;flag.textContent='🏁';st.appendChild(flag);
|
||||||
|
const car=document.createElement('div');car.style.cssText=`position:absolute;left:3vw;bottom:12vh;font-size:${SZ(13,130)};transition:left .06s`;car.textContent=T.pool[0];st.appendChild(car);
|
||||||
|
let iv=null,win=false;
|
||||||
|
const go=e=>{if(win)return;ac();iv=setInterval(()=>{const l=parseFloat(car.style.left)||3;if(l>=80){win=true;clearInterval(iv);stars(d,3);setTimeout(celebrate,300);return}car.style.left=(l+2.5)+'vw';tone(300+Math.random()*200,.06,'square',.05)},40)};
|
||||||
|
const stop=()=>{clearInterval(iv);iv=null};
|
||||||
|
car.addEventListener('pointerdown',go);car.addEventListener('pointerup',stop);car.addEventListener('pointerleave',stop);addEventListener('pointerup',stop)})},
|
||||||
|
// 28 — esconde-esconde
|
||||||
|
esconde(d){const T=themeOf(d);let found=false;gate('🎁','Ache o bichinho escondido!',()=>{const st=stage();st.innerHTML='';say('Onde ele está?');
|
||||||
|
const where=Math.floor(Math.random()*3);const row=document.createElement('div');row.className='row';row.style.cssText='height:100%;align-content:center;gap:5vw';st.appendChild(row);
|
||||||
|
const peeky=document.createElement('div');peeky.style.cssText=`position:absolute;font-size:${SZ(8,80)};transition:all .2s;opacity:0`;peeky.textContent=T.pool[0];st.appendChild(peeky);
|
||||||
|
const boxes=[0,1,2].map(i=>{const b=document.createElement('div');b.className='card';b.style.width=SZ(26,260);b.innerHTML=`<span style="font-size:${SZ(12,120)}">🎁</span>`;b.onclick=()=>{if(found)return;if(i===where){found=true;b.innerHTML=`<span style="font-size:${SZ(12,120)}">${T.pool[0]}</span>`;b.style.background='#c8f7c5';say('Achei!');stars(d,3);setTimeout(celebrate,500)}else{shakeWrong(b);say('Tenta de novo!')}};row.appendChild(b);return b});
|
||||||
|
let cur=null;const iv=setInterval(()=>{if(!st.isConnected){clearInterval(iv);return}if(found){clearInterval(iv);return}const nx=Math.floor(Math.random()*3);if(nx===cur){return}cur=nx;const r=boxes[nx].getBoundingClientRect();peeky.style.opacity=1;peeky.style.left=r.left+'px';peeky.style.top=(r.top-70)+'px';tone(900,.08,'sine',.08);setTimeout(()=>peeky.style.opacity=0,900)},2200)})},
|
||||||
|
// 29 — arco-íris
|
||||||
|
arcoiris(d){const seq=[['#e53935','vermelha'],['#fdd835','amarela'],['#43a047','verde'],['#1e88e5','azul']];let idx=0;
|
||||||
|
gate('🌈','Monte o arco-íris!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
const strip=document.createElement('div');strip.className='row';strip.style.cssText='position:absolute;top:10vh;left:50%;transform:translateX(-50%);gap:1vw';
|
||||||
|
seq.forEach(()=>{const s=document.createElement('div');s.className='slot';s.style.width=SZ(20,200);s.style.height=SZ(20,200);s.style.borderRadius='50%';strip.appendChild(s)});st.appendChild(strip);
|
||||||
|
const row=document.createElement('div');row.className='row';row.style.cssText=`position:absolute;bottom:${SZH(12,120)};left:0;right:0`;
|
||||||
|
shuffle(seq).forEach(([col,name])=>{const c=card(`<span style="font-size:${SZ(7,70)}">●</span>`,x=>{if(col===seq[idx][0]){const s=strip.children[idx];s.style.background=col;s.classList.add('match');x.remove();tone(600+idx*80,.2,'triangle',.12);idx++;if(idx===seq.length){stars(d,3);setTimeout(celebrate,400)}}else shakeWrong(x)});c.style.background=col;row.appendChild(c)});
|
||||||
|
st.appendChild(row)})},
|
||||||
|
// 30 — vestir
|
||||||
|
vestir(d){const parts=[['👒','hat'],['👟','shoes'],['🎀','bow']];gate('🐻','Vista o ursinho!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
const bear=document.createElement('div');bear.style.cssText=`position:absolute;left:50%;top:10vh;transform:translateX(-50%);font-size:${SZ(24,240)};z-index:5`;bear.textContent='🐻';st.appendChild(bear);
|
||||||
|
tapMatch(parts.map(p=>({e:p[0],k:p[1]})),parts.map(p=>({e:'',k:p[1]})),()=>{stars(d,3);setTimeout(celebrate,400)})})},
|
||||||
|
// 31 — pesca
|
||||||
|
pesca(d){const T=themeOf(d);let n=0;gate('🎣','Pesque 5 bichinhos!',()=>{const st=stage();st.innerHTML='';say('Clique nos bichinhos que aparecem!');
|
||||||
|
const pond=document.createElement('div');pond.style.cssText='position:absolute;inset:12vh 4vw 6vh;border-radius:50%;background:linear-gradient(#4fc3f7,#0277bd)';st.appendChild(pond);
|
||||||
|
const iv=setInterval(()=>{if(!st.isConnected){clearInterval(iv);return}if(n>=5){clearInterval(iv);stars(d,3);setTimeout(celebrate,300);return}
|
||||||
|
const f=document.createElement('div');f.style.cssText=`position:absolute;left:${8+Math.random()*80}%;top:${15+Math.random()*60}%;font-size:${SZ(9,90)};cursor:pointer;transition:transform .2s`;f.textContent=rand(T.pool);f.onclick=()=>{n++;f.style.transition='all .6s';f.style.transform='translateY(-30vh) rotate(40deg)';f.style.opacity=0;setTimeout(()=>f.remove(),600);POP(500+n*70);say(NUM[n-1])};pond.appendChild(f);setTimeout(()=>f.remove(),2800)},900)})},
|
||||||
|
// 32 — trem das letras
|
||||||
|
trem(d){const target=(S.name||'PEDRO').replace(/\s/g,'').toUpperCase().split('');const w=Math.min(11,64/target.length);gate('🚂','Monte seu nome no trem!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
const train=document.createElement('div');train.style.cssText=`position:absolute;top:10vh;left:50%;transform:translateX(-50%);font-size:${SZ(11,110)};white-space:nowrap`;st.appendChild(train);
|
||||||
|
const wagons=target.map((L,i)=>{const s=document.createElement('div');s.className='slot';s.style.cssText=`display:inline-block;width:${SZ(w,130)};height:${SZ(w*1.3,170)};margin-left:${SZ(2,20)};vertical-align:middle;font-size:${SZ(Math.min(7,w*.55),64)}`;s.textContent='?';s.dataset.k=L;train.appendChild(s);return s});
|
||||||
|
setTimeout(()=>tapMatch(target.map(L=>({e:L,k:L})),target.map(L=>({e:'',k:L})),()=>{stars(d,3);say('Chu chu!');setTimeout(celebrate,600)}),100)})},
|
||||||
|
// 33 — pipoca
|
||||||
|
pipoca(d){let got=0;gate('🍿','Pegue 10 pipocas!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
const bas=document.createElement('div');bas.className='basket';bas.textContent='🍿';st.appendChild(bas);
|
||||||
|
const move=e=>{bas.style.left=Math.min(90,Math.max(5,e.clientX/innerWidth*100))+'vw'};
|
||||||
|
addEventListener('pointermove',move);addEventListener('touchmove',e=>move(e.touches[0]),{passive:true});
|
||||||
|
const iv=setInterval(()=>{if(!st.isConnected){clearInterval(iv);return}if(got>=10){clearInterval(iv);removeEventListener('pointermove',move);stars(d,3);setTimeout(celebrate,300);return}
|
||||||
|
const p=document.createElement('div');p.className='item';p.textContent=Math.random()<.8?'🍿':'🦖';p.style.left=(5+Math.random()*85)+'vw';p.style.animationDuration=(2.6+Math.random()*1.4)+'s';st.appendChild(p);
|
||||||
|
const ck=setInterval(()=>{if(!p.isConnected){clearInterval(ck);return}const b=bas.getBoundingClientRect(),r=p.getBoundingClientRect();if(r.bottom>innerHeight*.88)p.remove();
|
||||||
|
else if(r.left<b.right&&r.right>b.left&&r.bottom>b.top&&r.bottom<b.top+60){p.remove();clearInterval(ck);got++;POP(500+got*40)}},60);
|
||||||
|
setTimeout(()=>p.remove(),4500)},500)})},
|
||||||
|
// 34 — jardim
|
||||||
|
jardim(d){const T=themeOf(d);let n=0;gate('🌱','Plante e veja crescer!',()=>{const st=stage();st.innerHTML='';
|
||||||
|
const ground=document.createElement('div');ground.style.cssText='position:absolute;bottom:6vh;left:0;right:0;height:18vh;background:linear-gradient(#8d6e63,#6d4c41);border-radius:40px 40px 0 0';st.appendChild(ground);
|
||||||
|
const holes=[0,1,2,3,4].map(i=>{const h=document.createElement('div');h.className='card';h.style.cssText=`position:absolute;bottom:${SZH(9,90)};left:${5+i*18}vw;width:${SZ(15,150)};font-size:${SZ(6,60)}`;h.innerHTML='<span>🕳️</span>';h.onclick=()=>{if(h.dataset.done)return;h.dataset.done=1;n++;tone(500+n*60,.15,'triangle',.12);
|
||||||
|
const g2=document.createElement('div');g2.style.cssText=`position:absolute;bottom:${SZH(23,230)};left:${5+i*18}vw;font-size:${SZ(8,80)};animation:grow 1.5s forwards;transform-origin:bottom`;g2.textContent=n===5?'🎉':rand(T.pool);st.appendChild(g2);
|
||||||
|
say(n===5?'Parabéns, seu jardim está pronto!':`Planta ${NUM[n-1]}!`);
|
||||||
|
if(n>=5){stars(d,3);setTimeout(celebrate,700)}};st.appendChild(h);return h})})},
|
||||||
|
// 35 — ovo do dinossauro
|
||||||
|
ovo(d){let hatched=0;gate('🥚','Choque os ovos de dinossauro!',()=>{const st=stage();st.innerHTML='';say('Clique nos ovos!');
|
||||||
|
const eggs=[0,1,2].map(i=>{const e=document.createElement('div');e.className='card';e.style.cssText=`position:absolute;left:${14+i*27}vw;top:30vh;width:${SZ(22,220)};animation:wobble .8s infinite alternate`;e.innerHTML=`<span style="font-size:${SZ(12,120)}">🥚</span>`;e.onclick=()=>{if(e.dataset.done)return;e.dataset.done=1;hatched++;const dino=rand(['🦕','🦖']);e.innerHTML=`<span style="font-size:${SZ(12,120)}">${dino}</span>`;e.style.background='#c8f7c5';e.style.animation='';tone(150,.5,'sawtooth',.12);setTimeout(()=>tone(300,.4,'sawtooth',.1),250);say('Raaar!');if(hatched===3){stars(d,3);setTimeout(celebrate,800)}};st.appendChild(e);return e})})},
|
||||||
|
};
|
||||||
|
|
||||||
|
// ===================== registro: 35 dias =====================
|
||||||
|
const G=[
|
||||||
|
[1,'Letras do meu nome','trace','🔤'],[2,'Balões das letras','balLetra','🎈'],[3,'Ache a letra','achaLetra','🅰️'],[4,'Números nos balões','balNum','🔢'],[5,'Cores','cor','🎨'],
|
||||||
|
[6,'Formas','forma','🔺'],[7,'Os bichos','animal','🐾'],[8,'Memória','memoria','🧠'],[9,'Desenhar','desenho','✏️'],[10,'Contar bolhas','conta','🫧'],
|
||||||
|
[11,'Quebra-cabeça','puzzle','🧩'],[12,'Pegue o que cai','cesta','🧺'],[13,'Som da letra','somLetra','🔊'],[14,'Piano','piano','🎹'],[15,'Pintar','pintar','🖌️'],
|
||||||
|
[16,'O tempo','tempo','☀️'],[17,'Maior e menor','maior','🐘'],[18,'O diferente','diferente','🕵️'],[19,'Repita a sequência','sequencia','🎯'],[20,'Carinhas','caras','😀'],
|
||||||
|
[21,'Separar','separar','🍎'],[22,'Letra na areia','areia','⛱️'],[23,'Bolhas da cor','bolha','💧'],[24,'Contar estrelas','estrelas','⭐'],[25,'A casinha','casa','🏠'],
|
||||||
|
[26,'Som do bicho','somAnimal','🐮'],[27,'Corrida','corrida','🏎️'],[28,'Esconde-esconde','esconde','🎁'],[29,'Arco-íris','arcoiris','🌈'],[30,'Vestir','vestir','🐻'],
|
||||||
|
[31,'Pesca','pesca','🎣'],[32,'Trem das letras','trem','🚂'],[33,'Pipoca','pipoca','🍿'],[34,'Jardim','jardim','🌱'],[35,'Ovo do dinossauro','ovo','🥚']];
|
||||||
|
|
||||||
|
// ===================== telas =====================
|
||||||
|
function goHome(){location.hash='#home'}
|
||||||
|
function goConfig(){location.hash='#config'}
|
||||||
|
function showConfig(){const st=stage();st.innerHTML=`<div id="cfg"><h1 style="font-size:clamp(28px,6vw,56px);color:#333">⚙️ Para o papai e a mamãe</h1>
|
||||||
|
<label>Nome do(a) pequeno(a)</label><input id="n" maxlength="12" placeholder="ex: Pedro">
|
||||||
|
<label>Família (um nome por linha — as letras aparecem nos jogos)</label><textarea id="f" rows="4" placeholder="Papai Mamãe Vovó"></textarea>
|
||||||
|
<div class="fam">Salva no próprio navegador, sem internet de envio.</div></div>`;
|
||||||
|
$('#n').value=S.name;$('#f').value=S.family.join('\n');
|
||||||
|
$('#cfg').appendChild(bigBtn('💾 Guardar',()=>{const n=$('#n').value.trim();if(!n){toast('Escreva o nome primeiro!');return}S.name=n;S.family=$('#f').value.split('\n').map(x=>x.trim()).filter(Boolean);save();toast('Guardado!');location.hash='#home'}));
|
||||||
|
const rb=bigBtn('🧹 Apagar tudo e recomeçar',resetAll);rb.style.background='linear-gradient(#ff8a80,#ef5350)';rb.style.color='#fff';$('#cfg').appendChild(rb);
|
||||||
|
say('Olá! Vamos brincar?')}
|
||||||
|
function showCal(){const st=stage();st.innerHTML='<div id="cal"></div>';const cal=$('#cal');
|
||||||
|
cal.innerHTML+=`<h1>${S.name?`Olá, <span style="color:#e53935">${S.name}</span>!`:''} 🎈 35 dias de brincadeiras!</h1>`;
|
||||||
|
for(let w=0;w<7;w++){const T=THEMES[Math.floor(w%3)];const wk=`Semana ${w+1} — ${T.name} ${T.emoji}`;
|
||||||
|
const div=document.createElement('div');div.className='week';div.innerHTML=`<div class="wtitle">${wk}</div><div class="days"></div>`;const days=div.querySelector('.days');
|
||||||
|
for(let i=1;i<=5;i++){const d=w*5+i;const g=G[d-1];
|
||||||
|
const b=document.createElement('div');b.className='day';b.innerHTML=`<div class="e">${g[3]}</div><div class="n">Dia ${d}</div><div class="t">${g[1]}</div><div class="st">${starStr(S.stars[d]||0)}</div>`;
|
||||||
|
b.onclick=()=>location.hash='#d'+d;days.appendChild(b)}cal.appendChild(div)}
|
||||||
|
if(S.stars[35])cal.innerHTML+=`<div class="wtitle" style="text-align:center;color:#e53935">🏆 Você completou todos os 35 dias! Pode jogar tudo de novo!</div>`}
|
||||||
|
function playGame(d){const[dayNo,dt,mech]=G[d-1];const T=themeOf(d);gate(T.emoji,`Dia ${d}: ${dt}`,()=>MECH[mech](d))}
|
||||||
|
|
||||||
|
// ===================== roteamento =====================
|
||||||
|
function route(){const h=location.hash;
|
||||||
|
if(h==='#config')showConfig();
|
||||||
|
else if(h.startsWith('#d')){const d=parseInt(h.slice(2));if(d>=1&&d<=35)playGame(d);else goHome()}
|
||||||
|
else showCal()}
|
||||||
|
window.addEventListener('hashchange',route);
|
||||||
|
|
||||||
|
// ===================== fundo three.js =====================
|
||||||
|
try{if(window.THREE){const sc=new THREE.Scene(),cam=new THREE.PerspectiveCamera(60,innerWidth/innerHeight,.1,100);cam.position.z=9;
|
||||||
|
const re=new THREE.WebGLRenderer({alpha:true,antialias:false});re.setPixelRatio(Math.min(devicePixelRatio,2));re.setSize(innerWidth,innerHeight);$('#bg').appendChild(re.domElement);
|
||||||
|
const N=260,pos=new Float32Array(N*3);for(let i=0;i<N;i++){const r=6+Math.random()*8,th=Math.random()*6.28,ph=Math.acos(2*Math.random()-1);pos[i*3]=r*Math.sin(ph)*Math.cos(th);pos[i*3+1]=r*Math.sin(ph)*Math.sin(th);pos[i*3+2]=r*Math.cos(ph)}
|
||||||
|
const geo=new THREE.BufferGeometry();geo.setAttribute('position',new THREE.BufferAttribute(pos,3));
|
||||||
|
const pts=new THREE.Points(geo,new THREE.PointsMaterial({color:0xffd54a,size:.07,transparent:true,opacity:.8}));
|
||||||
|
const blob=(color,x,y,s)=>new THREE.Mesh(new THREE.IcosahedronGeometry(s,1),new THREE.MeshPhongMaterial({color,flatShading:true,transparent:true,opacity:.3}));
|
||||||
|
const b1=blob(0x87ceeb,-5,3,-3),b2=blob(0xffb6c1,5,-2,-2);
|
||||||
|
sc.add(pts,b1,b2);
|
||||||
|
(function anim(){requestAnimationFrame(anim);pts.rotation.y+=.0006;b1.rotation.x+=.001;b1.rotation.y+=.002;b2.rotation.x-=.0015;b2.rotation.z+=.002;re.render(sc,cam)})();
|
||||||
|
addEventListener('resize',()=>{cam.aspect=innerWidth/innerHeight;cam.updateProjectionMatrix();re.setSize(innerWidth,innerHeight)});}
|
||||||
|
else $('#bg').classList.add('flat')}catch(e){$('#bg').classList.add('flat')}
|
||||||
|
|
||||||
|
// ===================== auto-teste =====================
|
||||||
|
function selftest(){const ok=[];const days=new Set();const mechs={};
|
||||||
|
G.forEach(([d,dt,mech])=>{days.add(d);mechs[mech]=(mechs[mech]||0)+1;ok.push(typeof MECH[mech]==='function'?`${mech}: ok`:`${mech}: FALTA MECH`)});
|
||||||
|
ok.push(`dias únicos: ${days.size===35?'ok':'FALHA ('+days.size+')'}`);
|
||||||
|
ok.push(`mecânicas: ${Object.keys(mechs).length}`);
|
||||||
|
if(Object.values(mechs).some(n=>n>1))ok.push('atenção: mecânica repetida');
|
||||||
|
document.title='selftest';return ok.join(' | ')}
|
||||||
|
if(location.hash==='#selftest'){document.body.innerHTML=`<pre style="font-size:20px">${selftest()}</pre>`;window.addEventListener('hashchange',route)}
|
||||||
|
else{$('#who').textContent=S.name?('👋 '+S.name):'';
|
||||||
|
route();updateStars();addEventListener('pointerdown',musicStart);
|
||||||
|
setTimeout(()=>{if(S.name)say(`Olá, ${S.name}! Vamos brincar?`)},600)}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue