Hello, world!

Inscription #0 DOT DODGE โ€ข Seed Code + Verifier

๐ŸŸฆ DOT DODGE โ€ข Seed Code + Verifier

Sterowanie: โ†โ†‘โ†’โ†“ / WASD โ€ข Pauza: P โ€ข Tap na canvasie = pauza
Score: 0
Best: 0
Speed: 1x
Kopiuje czysty token (base64url.base64url)

Hello, world!

Inscription #0 DOT DODGE โ€ข Seed Code + Verifier

๐ŸŸฆ DOT DODGE โ€ข Seed Code + Verifier

Sterowanie: โ†โ†‘โ†’โ†“ / WASD โ€ข Pauza: P โ€ข Tap na canvasie = pauza
Score: 0
Best: 0
Speed: 1x
Kopiuje czysty token (base64url.base64url)
b// I18N const I={en:{legend:"Controls: โ†โ†‘โ†’โ†“ / WASD. Pause P. Tap canvas to pause on mobile.", start:"Ready?",startBtn:"Start",pause:"Paused",resume:"Resume",restart:"Restart",over:"Game Over!",enterSig:"Enter your nickname/signature, then press โ€œGenerate Codeโ€.",genBtn:"๐ŸŽ‰ Generate Code",codeTitle:"Your Secret Snake Code:",copied:"Copied!",vLabel:"Paste your Code or Token",vOK:"OK โ€” integrity: {sig}, score: {score} (matches), duration: {dur}ms.",vBAD:"INVALID โ€” hash:{sig} score:{score} duration:{dur}."}, pl:{legend:"Sterowanie: โ†โ†‘โ†’โ†“ / WASD. Pauza P. Na mobile stuknij w canvas, by zapauzowaฤ‡.",start:"Gotowy?",startBtn:"Start",pause:"Pauza",resume:"Wznรณw",restart:"Restart",over:"Koniec gry!",enterSig:"Wpisz swรณj podpis/nick i kliknij โ€žGeneruj kodโ€.",genBtn:"๐ŸŽ‰ Generuj kod",codeTitle:"Twรณj Sekretny Kod Wฤ™ลผa:",copied:"Skopiowano!",vLabel:"Wklej Kod lub Token",vOK:"OK โ€” integralnoล›ฤ‡: {sig}, wynik: {score} (zgodny), czas: {dur} ms.",vBAD:"NIEZGODNY โ€” hash:{sig} wynik:{score} czas:{dur}."}, ko:{legend:"์กฐ์ž‘: โ†โ†‘โ†’โ†“ / WASD. ์ผ์‹œ์ •์ง€ P. ๋ชจ๋ฐ”์ผ์—์„œ๋Š” ์บ”๋ฒ„์Šค๋ฅผ ํƒญํ•˜์„ธ์š”.",start:"์ค€๋น„?",startBtn:"์‹œ์ž‘",pause:"์ผ์‹œ์ •์ง€",resume:"์žฌ๊ฐœ",restart:"์žฌ์‹œ์ž‘",over:"๊ฒŒ์ž„ ์˜ค๋ฒ„!",enterSig:"๋‹‰๋„ค์ž„/์„œ๋ช…์„ ์ž…๋ ฅํ•˜๊ณ  โ€˜์ฝ”๋“œ ์ƒ์„ฑโ€™์„ ๋ˆ„๋ฅด์„ธ์š”.",genBtn:"๐ŸŽ‰ ์ฝ”๋“œ ์ƒ์„ฑ",codeTitle:"๋‹น์‹ ์˜ ๋น„๋ฐ€ ์Šค๋„ค์ดํฌ ์ฝ”๋“œ:",copied:"๋ณต์‚ฌ๋จ!",vLabel:"์ฝ”๋“œ ๋˜๋Š” ํ† ํฐ์„ ๋ถ™์—ฌ๋„ฃ๊ธฐ",vOK:"OK โ€” ๋ฌด๊ฒฐ์„ฑ: {sig}, ์ ์ˆ˜: {score} (์ผ์น˜), ์‹œ๊ฐ„: {dur}ms.",vBAD:"์œ ํšจํ•˜์ง€ ์•Š์Œ โ€” ํ•ด์‹œ:{sig} ์ ์ˆ˜:{score} ์‹œ๊ฐ„:{dur}."}}; const $=(s,r=document)=>r.querySelector(s), $$=(s,r=document)=>[...r.querySelectorAll(s)]; const langSel=$("#lang"); function T(k){return I[langSel.value][k]} function sync(){ $("#legend").textContent=T('legend'); $("#sigLabel").textContent=T('enterSig'); $("#genSeed").textContent=T('genBtn'); $("#vLabel").textContent=T('vLabel'); } langSel.addEventListener('change',sync); sync(); // Tabs $$('.tab').forEach(b=>b.addEventListener('click',()=>{ $$('.tab').forEach(x=>x.classList.remove('active')); b.classList.add('active'); $('#gameTab').style.display=b.dataset.tab==='game'?'grid':'none'; $('#verifyTab').style.display=b.dataset.tab==='verify'?'grid':'none'; })); // Crypto helpers const enc=new TextEncoder(), dec=new TextDecoder(); const b64url={ enc:(u8)=>btoa(String.fromCharCode(...u8)).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,''), dec:(s)=>{ s=s.replace(/[^A-Za-z0-9\-_\.]/g,''); const [p,h]=s.split('.'); if(!p||!h) throw Error('Bad token'); const b=x=>{ let z=x.replace(/-/g,'+').replace(/_/g,'/'); const pad=z.length%4?4-(z.length%4):0; return new Uint8Array([...atob(z+'='.repeat(pad))].map(c=>c.charCodeAt(0))); }; return {payload:b(p),sig:b(h)}; } }; async function sha256(u8){ const buf=await crypto.subtle.digest('SHA-256',u8); return new Uint8Array(buf) } function hex(u8){ return [...u8].map(b=>b.toString(16).padStart(2,'0')).join('') } function u8eq(a,b){ if(a.length!==b.length) return false; let x=0; for(let i=0;i>>0; return ()=>{ s^=s<<13; s>>>=0; s^=s>>>17; s>>>=0; s^=s<<5; s>>>=0; return s>>>0; } } function randi(rng,n){ return (rng()/2**32*n)|0 } // Game const GRID=28, CELL=20, BASE_STEP=120; const cv=$("#cv"), ctx=cv.getContext('2d'); cv.width=GRID*CELL; cv.height=GRID*CELL; const ov=$("#ov"); const scoreEl=$("#score"), bestEl=$("#best"), spdEl=$("#spd"); let snake,dir,alive=false,paused=false,step=BASE_STEP,acc=0,last=0; let score=0,best=Number(localStorage.getItem('snake-best')||0); bestEl.textContent=best; let inputs=[],queued=[],lastDir2=0,ticksSinceTurn=0; let rngSeed=0,rng=null; let apple=null; const D=[{x:1,y:0},{x:0,y:-1},{x:-1,y:0},{x:0,y:1}]; // R,U,L,D function showOverlay(html){ ov.innerHTML=`
${html}
`; ov.classList.remove('hidden') } function hideOverlay(){ ov.classList.add('hidden') } function startScreen(){ showOverlay(`

${T('start')}

`); draw() } function init(){ rngSeed=((crypto.getRandomValues(new Uint32Array(1))[0]||Date.now())>>>0); rng=XorShift32(rngSeed); function spawn(){ let pos; const occ=new Set(snake?.map(p=>p.x+','+p.y)||[]); do{ pos={x:randi(rng,GRID),y:randi(rng,GRID)} }while(occ.has(pos.x+','+pos.y)); return pos } snake=[{x:(GRID/2)|0,y:(GRID/2)|0}]; dir=D[0]; lastDir2=0; ticksSinceTurn=0; queued.length=0; inputs.length=0; apple=spawn(); score=0; scoreEl.textContent=0; step=BASE_STEP; spdEl.textContent='1x'; alive=true; paused=false; acc=0; last=performance.now(); hideOverlay(); function loop(t){ if(!alive){ draw(); return } const dt=Math.min(50,t-last); last=t; if(!paused){ acc+=dt; while(acc>=step){ applyTurn(); stepOnce(spawn); acc-=step; ticksSinceTurn++; } } draw(); requestAnimationFrame(loop) } requestAnimationFrame(loop); } function enqueue(n2){ const lastQ=queued.length?queued[queued.length-1]:lastDir2; if((n2^2)===lastQ) return; queued.push(n2) } function dir2(){ if(dir.x===1&&dir.y===0) return 0; if(dir.x===0&&dir.y===-1) return 1; if(dir.x===-1&&dir.y===0) return 2; return 3 } function applyTurn(){ if(!queued.length) return; const n2=queued.shift(); if((n2^2)!==dir2()){ inputs.push([ticksSinceTurn,n2]); ticksSinceTurn=0; dir=D[n2]; lastDir2=n2 } } function stepOnce(spawn){ const head={x:snake[0].x+dir.x,y:snake[0].y+dir.y}; if(head.x<0||head.y<0||head.x>=GRID||head.y>=GRID) return over(); for(const s of snake){ if(s.x===head.x&&s.y===head.y) return over() } snake.unshift(head); if(head.x===apple.x&&head.y===apple.y){ score++; scoreEl.textContent=score; if(score%5===0){ step=Math.max(60,step-8); spdEl.textContent=step<=90?'3x':'2x' } apple=spawn() } else snake.pop(); } function over(){ alive=false; best=Math.max(best,score); localStorage.setItem('snake-best',best); bestEl.textContent=best; showOverlay(`

${T('over')}

${T('enterSig')}

`); } function pauseToggle(){ if(!alive) return; paused=!paused; paused?showOverlay(`

${T('pause')}

`):hideOverlay() } function draw(){ ctx.clearRect(0,0,cv.width,cv.height); ctx.fillStyle='#0b122a'; ctx.fillRect(0,0,cv.width,cv.height); ctx.strokeStyle='rgba(255,255,255,.05)'; ctx.beginPath(); for(let i=1;i{ const b=e.target.closest('button'); if(!b) return; if(b.dataset.start) init(); if(b.dataset.resume){ paused=false; hideOverlay() } if(b.dataset.restart) init(); }); $("#pause").addEventListener('pointerdown',e=>{e.preventDefault(); pauseToggle()}); addEventListener('keydown',e=>{ if(e.code==='ArrowUp'||e.key==='w'||e.key==='W') enqueue(1); if(e.code==='ArrowDown'||e.key==='s'||e.key==='S') enqueue(3); if(e.code==='ArrowLeft'||e.key==='a'||e.key==='A') enqueue(2); if(e.code==='ArrowRight'||e.key==='d'||e.key==='D') enqueue(0); if(e.key==='p'||e.key==='P') pauseToggle(); if(!alive&&(e.code==='Space'||e.code==='Enter')) init(); },{passive:false}); let tStart=null; cv.addEventListener('touchstart',e=>{ if(e.touches.length===1) tStart={x:e.touches[0].clientX,y:e.touches[0].clientY} },{passive:true}); cv.addEventListener('touchend',e=>{ if(!tStart) return; const p=e.changedTouches[0]; const dx=p.clientX-tStart.x, dy=p.clientY-tStart.y; if(Math.max(Math.abs(dx),Math.abs(dy))>20){ if(Math.abs(dx)>Math.abs(dy)) enqueue(dx>0?0:2); else enqueue(dy>0?3:1) } else pauseToggle(); tStart=null },{passive:true}); $$('.pad[data-d]').forEach(b=>b.addEventListener('pointerdown',()=>{ const d=b.dataset.d; enqueue(d==='L'?2:d==='R'?0:d==='U'?1:3) })); // Seed / token function cleanSig(s){ return (s||'').trim().slice(0,40) } async function buildRecord(){ const rec={v:1,variant:'snake',grid:GRID,step:BASE_STEP,prng:rngSeed,inputs:inputs.slice(),score,duration:inputs.reduce((a,b)=>a+b[0],0)*BASE_STEP,signature:cleanSig($("#sig").value||'Anonymous')}; const payload=enc.encode(JSON.stringify(rec)); const sig=await sha256(payload); rec.hash=hex(sig); return {rec,payload,sig} } function makePretty(token){ const chunks=token.match(/.{1,5}/g)||[token]; return `๐Ÿ ${chunks.join('-')} โœจ` } let lastToken=''; $("#genSeed").addEventListener('click',async()=>{ const {payload,sig}=await buildRecord(); lastToken=b64url.enc(payload)+'.'+b64url.enc(sig); $("#seedPretty").innerHTML=`
${T('codeTitle')}
${makePretty(lastToken)}
`; }); $("#copyToken").addEventListener('click',async()=>{ if(!lastToken) return; await navigator.clipboard.writeText(lastToken); $("#copyHint").textContent=T('copied'); setTimeout(()=>$("#copyHint").textContent='Copies a clean token (no emojis/spaces)',1500) }); $("#sig").addEventListener('keydown',e=>{ if(e.key==='Enter'){ e.preventDefault(); $("#genSeed").click() }}); // Verifier $("#verifyBtn").addEventListener('click',async()=>{ const out=$("#verifyOut"); out.textContent='...'; try{ const raw=$("#seedIn").value.replace(/[^A-Za-z0-9\-_\.]/g,''); const {payload,sig}=b64url.dec(raw); const calc=await sha256(payload); const ok=u8eq(sig,calc); const rec=JSON.parse(dec.decode(payload)); function replay(r){ const rng=XorShift32(r.prng); function spawn(s){ let pos; const occ=new Set(s.map(p=>p.x+','+p.y)); do{ pos={x:randi(rng,r.grid),y:randi(rng,r.grid)} }while(occ.has(pos.x+','+pos.y)); return pos } let snake=[{x:(r.grid/2)|0,y:(r.grid/2)|0}], dir=D[0], apple=spawn(snake), t=0, score=0, i=0, dt=r.inputs.length?r.inputs[0][0]:Infinity; while(i=r.grid||head.y>=r.grid) break; let hit=false; for(const s of snake){ if(s.x===head.x&&s.y===head.y){ hit=true; break } } if(hit) break; snake.unshift(head); if(head.x===apple.x&&head.y===apple.y){ score++; apple=spawn(snake) } else snake.pop(); t+=r.step; } return {score,duration:t}; } const rep=replay(rec); const okS=rep.score===rec.score, okD=rep.duration===rec.duration; out.innerHTML=(ok&&okS&&okD)?`
${T('vOK').replace('{sig}',ok).replace('{score}',rep.score).replace('{dur}',rep.duration)}
${JSON.stringify(rec,null,2)}
`:`
${T('vBAD').replace('{sig}',ok).replace('{score}',okS).replace('{dur}',okD)}
`; }catch(err){ $("#verifyOut").innerHTML=`
Error: ${err.message}
` } });b