@liveloop · 5/18/2026, 12:14:22 PM
Initial version — all lines are new.
+<style>+ html,body{height:100%;margin:0;background:#03040c;overflow:hidden;}+ *{box-sizing:border-box;}+ #wrap{position:relative;height:100%;width:100%;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;}+ canvas{display:block;width:100%;height:100%;touch-action:none;}+ #hud{position:absolute;top:0;left:0;right:0;display:flex;justify-content:space-between;align-items:flex-start;padding:.7rem .95rem;color:#cffafe;font-size:.86rem;font-weight:800;letter-spacing:.04em;pointer-events:none;text-shadow:0 0 10px rgba(0,0,0,.95);}+ #hud .lab{font-size:.56rem;opacity:.6;letter-spacing:.14em;margin-bottom:.05rem;}+ #hud .r{text-align:right;}+ #time.low{color:#fb7185;}+ #ov{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;text-align:center;padding:1.6rem;background:rgba(3,4,12,.86);color:#e0f2fe;cursor:pointer;-webkit-tap-highlight-color:transparent;touch-action:none;user-select:none;-webkit-user-select:none;}+ #ov h1{margin:0;font-size:2.05rem;font-weight:900;letter-spacing:.02em;background:linear-gradient(90deg,#22d3ee,#38bdf8,#a3e635);-webkit-background-clip:text;background-clip:text;color:transparent;}+ #ov .sub{margin:.1rem 0 0;font-size:.9rem;color:#7dd3fc;max-width:26ch;}+ #ov .big{margin:.1rem 0 0;font-size:1.05rem;font-weight:800;color:#e0f2fe;}+ #ov .pulse{margin-top:.5rem;font-size:.84rem;color:#67e8f9;animation:dcpulse 1.3s ease-in-out infinite;}+ @keyframes dcpulse{0%,100%{opacity:.35}50%{opacity:1}}+</style>+<div id="wrap">+ <canvas id="cv"></canvas>+ <div id="hud">+ <div><div class="lab">TIME</div><div id="time">60</div></div>+ <div class="r"><div class="lab">SCORE</div><div id="score">0</div></div>+ <div class="r"><div class="lab">BEST</div><div id="best">0</div></div>+ </div>+ <div id="ov">+ <h1>DEEP CATCH</h1>+ <p class="sub" id="ovsub">Drag the lure to hook a fish, then drag it up to the boat. Dodge the jellyfish.</p>+ <p class="big" id="ovbig"></p>+ <p class="pulse">Tap to dive</p>+ </div>+</div>+<script>+(function(){+ var LL=window.liveloop||null;+ var cv=document.getElementById('cv'), ctx=cv.getContext('2d');+ var ov=document.getElementById('ov'), ovsub=document.getElementById('ovsub'),+ ovbig=document.getElementById('ovbig'), ovtitle=ov.querySelector('h1');+ var scoreEl=document.getElementById('score'), bestEl=document.getElementById('best'),+ timeEl=document.getElementById('time');+ var W=0,H=0,dpr=1;+ var state='start', score=0, best=0, timeLeft=60, jellyTimer=0;+ var hook=null, fish=[], jellies=[], parts=[], floaters=[];+ var dragging=false, ptrX=0, ptrY=0;+ var lastT=0, raf=0, running=false;++ var TYPES=[+ {key:'common',color:'#67e8f9',points:10,r:0.026,spd:0.010,wt:50,band:[0.22,0.46]},+ {key:'silver',color:'#a5b4fc',points:25,r:0.034,spd:0.0072,wt:30,band:[0.44,0.66]},+ {key:'deep', color:'#34d399',points:50,r:0.044,spd:0.0052,wt:15,band:[0.66,0.9]},+ {key:'gold', color:'#fbbf24',points:100,r:0.03,spd:0.014,wt:5, band:[0.3,0.84]}+ ];++ function setCanvas(){+ var r=cv.getBoundingClientRect();+ W=Math.max(160,r.width); H=Math.max(220,r.height);+ dpr=Math.min(window.devicePixelRatio||1,2.5);+ cv.width=Math.round(W*dpr); cv.height=Math.round(H*dpr);+ ctx.setTransform(dpr,0,0,dpr,0,0);+ }+ function anchorX(){ return W/2; }+ function anchorY(){ return H*0.07; }+ function bankY(){ return H*0.15; }+ function rint(a,b){ return a+Math.floor(Math.random()*(b-a+1)); }+ function pickType(){+ var total=0,i; for(i=0;i<TYPES.length;i++) total+=TYPES[i].wt;+ var n=Math.random()*total;+ for(i=0;i<TYPES.length;i++){ n-=TYPES[i].wt; if(n<=0) return TYPES[i]; }+ return TYPES[0];+ }+ function spawnFish(){+ var t=pickType();+ var dir=Math.random()<0.5?-1:1;+ var y=H*(t.band[0]+Math.random()*(t.band[1]-t.band[0]));+ fish.push({+ t:t, x:dir<0?W+W*0.1:-W*0.1, y:y, vx:dir*t.spd*H,+ w:W*t.r, h:W*t.r*0.62, color:t.color, points:t.points, caught:false,+ phase:Math.random()*6.28+ });+ }+ function spawnJelly(){+ jellies.push({+ x:Math.random()*W, y:H*(0.32+Math.random()*0.5),+ vx:(Math.random()<0.5?-1:1)*H*0.0016, baseY:0, phase:Math.random()*6.28,+ r:W*0.05+ });+ }+ function newGame(){+ score=0; timeLeft=60; jellyTimer=0;+ fish=[]; jellies=[]; parts=[]; floaters=[];+ hook={x:W/2,y:H*0.3,r:W*0.026,carry:null,stunUntil:0};+ var i;+ for(i=0;i<8;i++) spawnFish();+ for(i=0;i<fish.length;i++) fish[i].x=Math.random()*W;+ for(i=0;i<4;i++) spawnJelly();+ state='playing'; syncHud();+ }+ function syncHud(){+ scoreEl.textContent=score;+ bestEl.textContent=best;+ var s=Math.max(0,Math.ceil(timeLeft));+ timeEl.textContent=s;+ if(s<=10) timeEl.classList.add('low'); else timeEl.classList.remove('low');+ }+ function floater(x,y,text,color){+ floaters.push({x:x,y:y,text:text,color:color,life:46});+ }+ function burst(x,y,color,n){+ for(var i=0;i<n;i++){+ var a=Math.random()*6.2832;+ parts.push({x:x,y:y,vx:Math.cos(a)*(1+Math.random()*3),+ vy:Math.sin(a)*(1+Math.random()*3),life:16+Math.random()*14,color:color});+ }+ }+ function gameOver(){+ state='over';+ if(score>best){ best=score; saveBest(); }+ syncHud();+ ovtitle.textContent='TIME UP';+ ovsub.textContent='Lures in for the day.';+ ovbig.textContent='Score '+score+' · Best '+best;+ ov.style.display='flex';+ }+ function step(dt){+ timeLeft-=dt/60;+ if(timeLeft<=0){ timeLeft=0; gameOver(); return; }+ jellyTimer+=dt/60;+ if(jellyTimer>=20 && jellies.length<6){ spawnJelly(); jellyTimer=0; }++ // hook: follow the finger, or drift gently up when released+ if(dragging){+ hook.x+=(ptrX-hook.x)*Math.min(1,0.34*dt);+ hook.y+=(ptrY-hook.y)*Math.min(1,0.34*dt);+ } else {+ hook.y-=H*0.0011*dt;+ }+ if(hook.x<W*0.03)hook.x=W*0.03; if(hook.x>W*0.97)hook.x=W*0.97;+ if(hook.y<anchorY())hook.y=anchorY(); if(hook.y>H*0.97)hook.y=H*0.97;++ var i,j;+ // fish+ for(i=0;i<fish.length;i++){+ var f=fish[i];+ if(f.caught) continue;+ f.x+=f.vx*dt;+ f.phase+=0.08*dt;+ if(f.vx>0 && f.x>W+W*0.12) f.x=-W*0.12;+ if(f.vx<0 && f.x<-W*0.12) f.x=W+W*0.12;+ }+ // jellies+ for(i=0;i<jellies.length;i++){+ var jl=jellies[i];+ jl.x+=jl.vx*dt; jl.phase+=0.05*dt;+ if(jl.x<-W*0.1) jl.x=W+W*0.1;+ if(jl.x>W+W*0.1) jl.x=-W*0.1;+ }+ var stunned=performance.now()<hook.stunUntil;+ // catch+ if(!hook.carry && !stunned){+ for(i=0;i<fish.length;i++){+ var ff=fish[i]; if(ff.caught) continue;+ var dx=ff.x-hook.x, dy=ff.y-hook.y;+ if(dx*dx+dy*dy < (hook.r+ff.w*0.75)*(hook.r+ff.w*0.75)){+ ff.caught=true; hook.carry=ff;+ burst(hook.x,hook.y,ff.color,8);+ break;+ }+ }+ }+ // jelly collision+ for(i=0;i<jellies.length;i++){+ var jj=jellies[i];+ var jdx=jj.x-hook.x, jdy=jj.y-hook.y;+ if(jdx*jdx+jdy*jdy < (hook.r+jj.r*0.8)*(hook.r+jj.r*0.8)){+ if(hook.carry){+ var lost=hook.carry; hook.carry=null;+ lost.caught=false; lost.x=jj.x; lost.y=jj.y+jj.r;+ floater(hook.x,hook.y,'Lost!','#fb7185');+ } else if(!stunned){+ hook.stunUntil=performance.now()+650;+ burst(hook.x,hook.y,'#fb7185',6);+ }+ break;+ }+ }+ // carried fish rides the hook; bank it at the surface+ if(hook.carry){+ hook.carry.x=hook.x; hook.carry.y=hook.y+hook.r+hook.carry.h;+ if(hook.y<=bankY()){+ var c=hook.carry;+ score+=c.points;+ floater(anchorX(),bankY(),'+'+c.points,c.color);+ burst(anchorX(),bankY(),c.color,14);+ var idx=fish.indexOf(c); if(idx>=0) fish.splice(idx,1);+ hook.carry=null;+ spawnFish();+ syncHud();+ }+ }+ // particles + floaters+ for(i=parts.length-1;i>=0;i--){+ var p=parts[i];+ p.x+=p.vx*dt; p.y+=p.vy*dt; p.vy+=0.05*dt; p.life-=dt;+ if(p.life<=0) parts.splice(i,1);+ }+ for(i=floaters.length-1;i>=0;i--){+ var fl=floaters[i];+ fl.y-=0.6*dt; fl.life-=dt;+ if(fl.life<=0) floaters.splice(i,1);+ }+ }+ function drawFish(f){+ var dir=f.vx<0?-1:1, wob=Math.sin(f.phase)*f.h*0.3;+ ctx.save();+ ctx.translate(f.x,f.y);+ ctx.scale(dir,1);+ ctx.shadowColor=f.color; ctx.shadowBlur=12;+ ctx.fillStyle=f.color;+ ctx.beginPath(); ctx.ellipse(0,0,f.w,f.h,0,0,6.2832); ctx.fill();+ ctx.beginPath();+ ctx.moveTo(-f.w*0.75,0);+ ctx.lineTo(-f.w*1.5,-f.h*0.95+wob);+ ctx.lineTo(-f.w*1.5,f.h*0.95+wob);+ ctx.closePath(); ctx.fill();+ ctx.shadowBlur=0;+ ctx.fillStyle='#03040c';+ ctx.beginPath(); ctx.arc(f.w*0.5,-f.h*0.22,Math.max(1.2,f.h*0.2),0,6.2832); ctx.fill();+ ctx.restore();+ }+ function drawJelly(jl){+ ctx.save();+ ctx.translate(jl.x,jl.y);+ ctx.shadowColor='#fb7185'; ctx.shadowBlur=14;+ ctx.fillStyle='rgba(251,113,133,0.82)';+ ctx.beginPath(); ctx.arc(0,0,jl.r,Math.PI,Math.PI*2); ctx.closePath(); ctx.fill();+ ctx.strokeStyle='rgba(251,113,133,0.6)'; ctx.lineWidth=2;+ for(var k=0;k<4;k++){+ var tx=-jl.r*0.62+k*(jl.r*0.41);+ ctx.beginPath();+ ctx.moveTo(tx,0);+ ctx.quadraticCurveTo(tx+Math.sin(jl.phase+k)*5,jl.r*0.95,tx,jl.r*1.7);+ ctx.stroke();+ }+ ctx.shadowBlur=0;+ ctx.restore();+ }+ function render(){+ var bg=ctx.createLinearGradient(0,0,0,H);+ bg.addColorStop(0,'#0c3a52'); bg.addColorStop(0.45,'#082235'); bg.addColorStop(1,'#03040c');+ ctx.fillStyle=bg; ctx.fillRect(0,0,W,H);+ // light shafts+ ctx.fillStyle='rgba(186,230,253,0.045)';+ var s;+ for(s=0;s<3;s++){+ var lx=W*(0.2+s*0.32);+ ctx.beginPath();+ ctx.moveTo(lx-W*0.04,0); ctx.lineTo(lx+W*0.04,0);+ ctx.lineTo(lx+W*0.16,H); ctx.lineTo(lx-W*0.16,H);+ ctx.closePath(); ctx.fill();+ }+ // bank line+ ctx.strokeStyle='rgba(103,232,249,0.25)'; ctx.lineWidth=1.5;+ ctx.beginPath(); ctx.moveTo(0,bankY()); ctx.lineTo(W,bankY()); ctx.stroke();+ var i;+ for(i=0;i<fish.length;i++) if(!fish[i].caught) drawFish(fish[i]);+ for(i=0;i<jellies.length;i++) drawJelly(jellies[i]);+ if(hook){+ // line+ ctx.strokeStyle='rgba(226,232,240,0.5)'; ctx.lineWidth=1.5;+ ctx.beginPath(); ctx.moveTo(anchorX(),anchorY()); ctx.lineTo(hook.x,hook.y); ctx.stroke();+ // boat hull+ ctx.fillStyle='#e2e8f0';+ var bw=W*0.1, by=anchorY();+ ctx.beginPath();+ ctx.moveTo(anchorX()-bw,by-H*0.022);+ ctx.lineTo(anchorX()+bw,by-H*0.022);+ ctx.lineTo(anchorX()+bw*0.6,by);+ ctx.lineTo(anchorX()-bw*0.6,by);+ ctx.closePath(); ctx.fill();+ // carried fish+ if(hook.carry) drawFish(hook.carry);+ // lure+ var stunned=performance.now()<hook.stunUntil;+ ctx.shadowColor=stunned?'#fb7185':'#fde68a'; ctx.shadowBlur=16;+ ctx.fillStyle=stunned?'#fb7185':'#fde68a';+ ctx.beginPath(); ctx.arc(hook.x,hook.y,hook.r,0,6.2832); ctx.fill();+ ctx.shadowBlur=0;+ ctx.strokeStyle='#cbd5e1'; ctx.lineWidth=2;+ ctx.beginPath(); ctx.arc(hook.x,hook.y+hook.r*1.4,hook.r*0.62,0.1*Math.PI,0.9*Math.PI); ctx.stroke();+ }+ for(i=0;i<parts.length;i++){+ var p=parts[i];+ ctx.globalAlpha=Math.max(0,Math.min(1,p.life/18));+ ctx.fillStyle=p.color;+ ctx.fillRect(p.x-2,p.y-2,4,4);+ }+ ctx.globalAlpha=1;+ for(i=0;i<floaters.length;i++){+ var fl=floaters[i];+ ctx.globalAlpha=Math.max(0,Math.min(1,fl.life/30));+ ctx.fillStyle=fl.color;+ ctx.font='900 '+Math.round(H*0.035)+'px system-ui';+ ctx.textAlign='center'; ctx.textBaseline='middle';+ ctx.fillText(fl.text,fl.x,fl.y);+ }+ ctx.globalAlpha=1;+ }+ function frame(now){+ if(!running) return;+ var dt=(now-lastT)/16.667; lastT=now;+ if(dt<0.2)dt=0.2; if(dt>2.6)dt=2.6;+ if(state==='playing') step(dt);+ render();+ raf=requestAnimationFrame(frame);+ }+ function startLoop(){+ if(running) return;+ running=true; lastT=performance.now(); raf=requestAnimationFrame(frame);+ }+ function stopLoop(){ running=false; if(raf)cancelAnimationFrame(raf); raf=0; }+ function saveBest(){+ if(LL&&LL.storage&&LL.storage.set){ try{ LL.storage.set({best:best}); }catch(e){} }+ }+ function loadBest(){+ if(LL&&LL.storage&&LL.storage.get){+ LL.storage.get().then(function(s){+ if(s&&typeof s.best==='number'&&s.best>best){ best=s.best; syncHud(); }+ },function(){});+ }+ }+ function ptr(e){+ var r=cv.getBoundingClientRect();+ ptrX=e.clientX-r.left; ptrY=e.clientY-r.top;+ }+ cv.addEventListener('pointerdown',function(e){ dragging=true; ptr(e); });+ cv.addEventListener('pointermove',function(e){ if(dragging) ptr(e); });+ cv.addEventListener('pointerup',function(){ dragging=false; });+ cv.addEventListener('pointercancel',function(){ dragging=false; });+ cv.addEventListener('pointerleave',function(){ dragging=false; });+ ov.addEventListener('pointerdown',function(e){+ e.preventDefault();+ ov.style.display='none';+ newGame();+ });+ function onResize(){+ var oW=W,oH=H;+ setCanvas();+ if(oW>0&&oH>0&&(oW!==W||oH!==H)){+ var sx=W/oW, sy=H/oH, i;+ if(hook){ hook.x*=sx; hook.y*=sy; hook.r*=sx; }+ for(i=0;i<fish.length;i++){+ var f=fish[i]; f.x*=sx; f.y*=sy; f.w*=sx; f.h*=sx; f.vx*=sx;+ }+ for(i=0;i<jellies.length;i++){+ var jl=jellies[i]; jl.x*=sx; jl.y*=sy; jl.r*=sx; jl.vx*=sx;+ }+ for(i=0;i<parts.length;i++){ parts[i].x*=sx; parts[i].y*=sy; }+ for(i=0;i<floaters.length;i++){ floaters[i].x*=sx; floaters[i].y*=sy; }+ }+ }+ window.addEventListener('resize',onResize);+ if(LL && LL.onResize) LL.onResize(onResize);+ if(LL && LL.onVisibility) LL.onVisibility(function(v){ if(v) startLoop(); else stopLoop(); });+ document.addEventListener('visibilitychange',function(){+ if(document.hidden) stopLoop(); else startLoop();+ });++ setCanvas(); syncHud(); loadBest(); startLoop();+})();+</script>