SOURCE / PINNED RELEASE
Made of little things.
Truffle Rush
- Release
- bf9d57a12f82…
- Author-recorded commit
- bf11c370d93c…
- License
- Check the original source
- Author’s source reference
- nostr://npub1dmmh0futyszl4445mv4xrygkgsgj8vpu79yx3qyy9qxmz4pemtzqlqmc87/wss%3A%2F%2Fgit.napplet.soy%2F/n-dad0644224b
The hash-verified playable HTML, which may contain bundled or minified code. This view does not execute it.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Truffle Rush</title>
<script type="module" crossorigin>function be(){const e=new Map;function a(i,c){if(e.has(i))throw new Error(`NAP domain "${i}" is already registered`);e.set(i,c)}function o(i){const c=i.type.indexOf(".");if(c<=0)return!1;const f=i.type.slice(0,c),u=e.get(f);return u?(u(i),!0):!1}function r(){return Array.from(e.keys())}return{registerNap:a,dispatch:o,getRegisteredDomains:r}}var Me=be(),ve=Me.registerNap,O="storage";ve(O,e=>{});function Se(){const e=window;if(!e.napplet)throw new Error("window.napplet is unavailable -- runtime did not inject the napplet namespace");return e.napplet}function S(e){const o=Se()[e];if(!o)throw new Error(`window.napplet.${String(e)} is unavailable -- runtime did not inject this domain`);return o}var N={getItem(e){return S("storage").getItem(e)},setItem(e,a){return S("storage").setItem(e,a)},removeItem(e){return S("storage").removeItem(e)},keys(){return S("storage").keys()},instance:{getItem(e){return S("storage").instance.getItem(e)},setItem(e,a){return S("storage").instance.setItem(e,a)},removeItem(e){return S("storage").instance.removeItem(e)},keys(){return S("storage").instance.keys()}}},F={get(){return S("config").get()},subscribe(e){return S("config").subscribe(e)},openSettings(e){S("config").openSettings(e)},registerSchema(e,a){return S("config").registerSchema(e,a)},onSchemaError(e){return S("config").onSchemaError(e)},get schema(){return S("config").schema}};function xe(e,a){return!!(e!=null&&e[a])}function V(e){return xe(window.napplet,e)}const we="http://json-schema.org/draft-07/schema#",Pe=1,ke="object",Te=!1,Ce={sound:{type:"boolean",title:"Sound effects",description:"Oinks, chimes and caws. The in-game sound button also mutes for this session.",default:!0,"x-napplet-section":"Audio","x-napplet-order":1},screenShake:{type:"boolean",title:"Screen shake",description:"Shake the orchard on a crow hit or a truffle frenzy.",default:!0,"x-napplet-section":"Feedback","x-napplet-order":1}},Ie={$schema:we,$version:Pe,type:ke,additionalProperties:Te,properties:Ce},R={sound:!0,screenShake:!0},$=new Set;function Be(e){return $.add(e),e(R),()=>{$.delete(e)}}function Ee(e){typeof e.sound=="boolean"&&(R.sound=e.sound),typeof e.screenShake=="boolean"&&(R.screenShake=e.screenShake);for(const a of $)a(R)}V("config")&&(async()=>{F.schema||await F.registerSchema(Ie);const e=F.subscribe(Ee);window.addEventListener("pagehide",()=>e.close(),{once:!0})})().catch(()=>{});const _=5,ae="truffle-rush:best",oe="truffle-rush:muted",l={app:m("#app"),canvas:m("#game"),score:m("#score"),best:m("#best"),hearts:m("#hearts"),combo:m("#combo"),toast:m("#toast"),bellyFill:m("#bellyFill"),overlay:m("#overlay"),overlayKicker:m("#overlayKicker"),overlayTitle:m("#overlayTitle"),overlayText:m("#overlayText"),overlayStats:m("#overlayStats"),playButton:m("#playButton"),hint:m("#hint"),soundButton:m("#soundButton"),pauseButton:m("#pauseButton")},y=l.canvas,ie=y.getContext("2d");if(!ie)throw new Error("Canvas 2D context is unavailable");const n=ie,t={phase:"ready",w:0,h:0,groundY:0,unit:1,pigW:64,pigH:46,pigX:0,pigTarget:0,pigVX:0,mouth:0,blink:0,invuln:0,score:0,best:0,bestBefore:0,hearts:3,belly:0,combo:0,maxCombo:0,level:1,foodCaught:0,frenzy:0,elapsed:0,time:0,spawnTimer:.6,shake:0,flash:0,items:[],particles:[],floaters:[],fireflies:[],keys:{left:!1,right:!1},pointerDown:!1};let j={screenShake:!0},P=!1,Y=!0,E=null,W=null,ee=0,H=!1,q=performance.now(),A=null;const I=typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,b={score:-1,best:-1,hearts:-1,mult:-1,frenzy:-1,belly:-1,phase:""};function m(e){const a=document.querySelector(e);if(!a)throw new Error(`Missing required element: ${e}`);return a}function p(e,a,o){return Math.min(o,Math.max(a,e))}function v(e,a){return e+Math.random()*(a-e)}function re(e){let a=e>>>0;return()=>{a=a+1831565813>>>0;let o=a;return o=Math.imul(o^o>>>15,o|1),o^=o+Math.imul(o^o>>>7,o|61),((o^o>>>14)>>>0)/4294967296}}function G(){return Math.min(5,1+Math.floor(t.combo/5))}function se(){return!P&&Y}function k(){if(!se())return!1;try{return E??(E=new AudioContext),E.state==="suspended"&&E.resume(),!0}catch{return!1}}function g(e,a=.1,o="triangle",r=.05,i,c=0){if(!k()||!E)return;const f=E,u=f.currentTime+c,s=f.createOscillator(),h=f.createGain();s.type=o,s.frequency.setValueAtTime(Math.max(30,e),u),i!==void 0&&s.frequency.exponentialRampToValueAtTime(Math.max(30,i),u+a),h.gain.setValueAtTime(1e-4,u),h.gain.exponentialRampToValueAtTime(r,u+.012),h.gain.exponentialRampToValueAtTime(1e-4,u+a),s.connect(h),h.connect(f.destination),s.start(u),s.stop(u+a+.03)}function Ae(e){e==="acorn"?g(520+Math.min(t.combo,14)*22,.08,"triangle",.05,780):e==="truffle"?(g(560,.08,"triangle",.055),g(840,.1,"triangle",.045,1080,.05)):e==="golden"&&(g(660,.1,"sine",.06),g(990,.1,"sine",.05,void 0,.06),g(1320,.16,"sine",.045,void 0,.12))}function Ye(){g(230,.1,"sine",.025,170)}function Le(){g(200,.18,"sawtooth",.05,70),g(120,.22,"triangle",.04,55,.03)}function ze(){g(520,.12,"square",.035),g(660,.12,"square",.035,void 0,.1),g(880,.12,"square",.035,void 0,.2),g(1170,.22,"triangle",.05,void 0,.3)}function Re(){g(440,.16,"triangle",.05,void 0,0),g(330,.18,"triangle",.05,void 0,.16),g(220,.34,"triangle",.05,140,.34)}function We(){g(392,.1,"triangle",.04),g(587,.14,"triangle",.045,void 0,.09)}function le(e,a){if(V(O))try{N.setItem(e,a).catch(()=>{})}catch{}}async function Xe(){if(V(O))try{const[e,a]=await Promise.all([N.getItem(ae),N.getItem(oe)]),o=Number(e);Number.isFinite(o)&&o>0&&(t.best=Math.floor(o)),a==="1"&&(P=!0),X(),B(!0),t.phase==="ready"&&U("start")}catch{}}function fe(){H&&(H=!1,le(ae,String(t.best)))}function ce(){const e=y.getBoundingClientRect(),a=Math.max(1,e.width),o=Math.max(1,e.height),r=Math.min(window.devicePixelRatio||1,2),i=Math.round(a*r),c=Math.round(o*r);if(!(i===y.width&&c===y.height&&W)){t.w=a,t.h=o,y.width=i,y.height=c,n.setTransform(r,0,0,r,0,0),t.groundY=o-p(o*.12,14,58),t.unit=p(Math.min(a/500,o/700),.7,1.7),t.pigW=p(a*.2,44,120),t.pigH=t.pigW*.72,t.pigX===0&&t.pigTarget===0?(t.pigX=a/2,t.pigTarget=a/2):(t.pigX=p(t.pigX,t.pigW/2,a-t.pigW/2),t.pigTarget=p(t.pigTarget,t.pigW/2,a-t.pigW/2));for(const f of t.items)f.x=p(f.x,f.r,a-f.r),f.y=Math.min(f.y,o+f.r);t.fireflies=Array.from({length:9},(f,u)=>{const s=re(9001+u*131);return{baseX:.08+s()*.84,baseY:.2+s()*.58,phase:s()*Math.PI*2,speed:.35+s()*.6,amp:6+s()*14}}),W=Fe(a,o,r)}}function te(e,a,o,r,i,c,f){e.fillStyle=c,e.beginPath(),e.moveTo(0,r);const u=Math.max(8,a/48);for(let s=0;s<=a+u;s+=u){const h=r-Math.sin(s/a*Math.PI*2+f)*i-Math.sin(s/a*Math.PI*4+f*1.7)*i*.32;e.lineTo(s,h)}e.lineTo(a,o),e.lineTo(0,o),e.closePath(),e.fill()}function De(e,a,o,r,i){e.fillStyle=i,e.fillRect(a-r*.06,o-r*.3,r*.12,r*.32);for(let c=0;c<3;c+=1){const f=o-r*(.18+c*.23),u=r*(.34-c*.07);e.beginPath(),e.moveTo(a,f-r*.34),e.lineTo(a+u,f),e.lineTo(a-u,f),e.closePath(),e.fill()}}function Fe(e,a,o){const r=document.createElement("canvas");r.width=Math.round(e*o),r.height=Math.round(a*o);const i=r.getContext("2d");if(!i)return r;i.setTransform(o,0,0,o,0,0);const c=i.createLinearGradient(0,0,0,a);c.addColorStop(0,"#0e0622"),c.addColorStop(.45,"#231138"),c.addColorStop(.78,"#3a1b4c"),c.addColorStop(1,"#472357"),i.fillStyle=c,i.fillRect(0,0,e,a);const f=re(1337+Math.round(e)*7+Math.round(a)*13);i.fillStyle="#ffeccb";for(let M=0;M<64;M+=1){const x=f()*e,w=f()*Math.max(16,t.groundY*.72),ye=.4+f()*1.15;i.globalAlpha=.2+f()*.65,i.beginPath(),i.arc(x,w,ye,0,Math.PI*2),i.fill()}i.globalAlpha=1;const u=e*.77,s=Math.max(26,a*.2),h=Math.max(13,Math.min(e,a)*.085),d=i.createRadialGradient(u,s,h*.35,u,s,h*3.4);d.addColorStop(0,"rgba(255, 226, 176, 0.3)"),d.addColorStop(.5,"rgba(255, 208, 150, 0.1)"),d.addColorStop(1,"rgba(255, 208, 150, 0)"),i.fillStyle=d,i.beginPath(),i.arc(u,s,h*3.4,0,Math.PI*2),i.fill(),i.fillStyle="#ffe9c2",i.beginPath(),i.arc(u,s,h,0,Math.PI*2),i.fill(),i.fillStyle="rgba(207, 168, 116, 0.34)";const me=[[-.35,-.2,.24],[.22,.3,.18],[.34,-.38,.12],[-.1,.5,.1]];for(const[M,x,w]of me)i.beginPath(),i.arc(u+M*h,s+x*h,w*h,0,Math.PI*2),i.fill();te(i,e,a,t.groundY+a*.02,a*.075,"#2b1643",.8),te(i,e,a,t.groundY+a*.05,a*.055,"#241139",2.4);for(let M=0;M<5;M+=1){const x=e*(.08+f()*.84);De(i,x,t.groundY+2,Math.max(12,a*(.035+f()*.035)),"#1b0d2e")}const L=i.createLinearGradient(0,t.groundY,0,a);L.addColorStop(0,"#341b45"),L.addColorStop(.45,"#261234"),L.addColorStop(1,"#1a0c26"),i.fillStyle=L,i.fillRect(0,t.groundY,e,a-t.groundY),i.strokeStyle="#7a4792",i.lineWidth=Math.max(1,a*.005),i.beginPath(),i.moveTo(0,t.groundY+.5),i.lineTo(e,t.groundY+.5),i.stroke();const Q=Math.max(8,Math.floor(e/26));for(let M=0;M<Q;M+=1){const x=(M+.5)*(e/Q)+(f()-.5)*8,w=2+f()*4;i.strokeStyle=M%3===0?"#9a63b5":"#5c3275",i.lineWidth=1.2,i.beginPath(),i.moveTo(x,t.groundY+1),i.lineTo(x+(f()-.5)*3,t.groundY+1-w),i.stroke()}for(let M=0;M<4;M+=1){const x=(.12+f()*.76)*e,w=t.groundY+6+f()*Math.max(4,(a-t.groundY)*.45);i.fillStyle="rgba(255, 207, 107, 0.55)",i.beginPath(),i.arc(x,w,1.4,0,Math.PI*2),i.fill()}const D=i.createRadialGradient(e/2,a*.45,Math.min(e,a)*.18,e/2,a*.45,Math.max(e,a)*.78);return D.addColorStop(0,"rgba(0, 0, 0, 0)"),D.addColorStop(1,"rgba(6, 2, 14, 0.55)"),i.fillStyle=D,i.fillRect(0,0,e,a),r}function Ne(e){I||(e.classList.remove("bump"),e.offsetWidth,e.classList.add("bump"))}function $e(){if(b.hearts===t.hearts)return;b.hearts=t.hearts;const e=[];for(let a=0;a<3;a+=1){const o=document.createElement("span");o.className=a<t.hearts?"life":"life off",o.textContent="♥︎",o.setAttribute("aria-hidden","true"),e.push(o)}l.hearts.replaceChildren(...e),l.hearts.setAttribute("aria-label",`${t.hearts} ${t.hearts===1?"life":"lives"} remaining`)}function B(e=!1){const a=t.score,o=t.best,r=G();(e||a!==b.score)&&(!e&&a>b.score&&b.score>=0&&Ne(l.score),l.score.textContent=String(a),b.score=a),(e||o!==b.best)&&(l.best.textContent=String(o),b.best=o),$e();const i=t.frenzy>0;(e||r!==b.mult||Number(i)!==b.frenzy)&&(l.combo.hidden=r<=1&&!i,l.combo.textContent=i?"Frenzy ×2":`×${r}`,l.combo.dataset.hot=String(i),b.mult=r,b.frenzy=Number(i),l.app.classList.toggle("is-frenzy",i));const c=i?p(t.frenzy/_,0,1):t.belly,f=Math.round(c*100);(e||f!==b.belly)&&(l.bellyFill.style.width=`${f}%`,b.belly=f),(e||b.phase!==t.phase)&&(l.pauseButton.disabled=t.phase!=="playing"&&t.phase!=="paused",l.pauseButton.setAttribute("aria-label",t.phase==="paused"?"Resume":"Pause"),l.pauseButton.querySelector("span").textContent=t.phase==="paused"?"▶︎":"❚❚",b.phase=t.phase,y.style.cursor=t.phase==="playing"?"crosshair":"default")}function X(){const e=se();if(l.soundButton.classList.toggle("muted",!e),l.soundButton.disabled=!Y,!Y){l.soundButton.setAttribute("aria-label","Sound disabled in settings"),l.soundButton.title="Sound disabled in settings";return}l.soundButton.setAttribute("aria-label",e?"Mute sound":"Enable sound"),l.soundButton.title=e?"Sound on (M)":"Sound off (M)"}function z(e,a){const o=document.createElement("div");o.className="mini-stat";const r=document.createElement("span");r.className="mini-label",r.textContent=e;const i=document.createElement("span");return i.className="mini-value",i.textContent=String(a),o.append(r,i),o}function U(e){if(l.overlay.hidden=!1,l.overlay.dataset.mode=e,l.overlayStats.hidden=!0,l.overlayStats.replaceChildren(),e==="start")l.overlayKicker.textContent="Moonlit piggy arcade",l.overlayTitle.textContent="Truffle Rush",l.overlayText.textContent="Catch the falling snacks. Dodge the crows. Fill your belly for a golden frenzy.",l.playButton.textContent="Play",l.hint.hidden=!1,t.best>0&&(l.overlayStats.hidden=!1,l.overlayStats.replaceChildren(z("Best",t.best)));else if(e==="pause")l.overlayKicker.textContent="Take a breath",l.overlayTitle.textContent="Paused",l.overlayText.textContent="The truffles can wait. Your pig is safe here.",l.playButton.textContent="Resume",l.hint.hidden=!0;else{const a=t.score>t.bestBefore;l.overlayKicker.textContent=a?"A new orchard record":"Snout out",l.overlayTitle.textContent=a?"New best!":"Snout out!",l.overlayText.textContent=a?`You snuffled up ${t.score} points. The orchard will remember that snout.`:`The orchard got the better of you at ${t.score} points. One more run?`,l.playButton.textContent="Play again",l.hint.hidden=!0,l.overlayStats.hidden=!1,l.overlayStats.replaceChildren(z("Score",t.score),z("Best",t.best),z("Max combo",t.maxCombo))}}function Z(e){window.clearTimeout(ee),l.toast.textContent=e,l.toast.classList.remove("show"),l.toast.offsetWidth,l.toast.classList.add("show"),ee=window.setTimeout(()=>{l.toast.classList.remove("show")},1400)}function ue(){k(),t.phase="playing",t.score=0,t.bestBefore=t.best,t.hearts=3,t.belly=0,t.combo=0,t.maxCombo=0,t.level=1,t.foodCaught=0,t.frenzy=0,t.elapsed=0,t.spawnTimer=.55,t.invuln=1,t.mouth=0,t.shake=0,t.flash=0,t.items=[],t.particles=[],t.floaters=[],t.keys.left=!1,t.keys.right=!1,t.pigX=t.w/2,t.pigTarget=t.pigX,l.overlay.hidden=!0,l.playButton.blur(),l.toast.classList.remove("show"),B(!0),We()}function He(){t.phase="over",t.frenzy=0,t.shake=I?0:10,l.app.classList.remove("is-frenzy"),t.score>t.best&&(t.best=t.score,H=!0,fe()),B(!0),U("over"),Re()}function T(){t.phase==="playing"?(t.phase="paused",U("pause")):t.phase==="paused"&&(t.phase="playing",l.overlay.hidden=!0,l.playButton.blur(),q=performance.now()),B(!0)}function de(){Y&&(P=!P,le(oe,P?"1":"0"),X(),P||(k(),g(660,.08,"triangle",.04)))}function qe(){const e=Math.random();let a;if(t.frenzy>0)e<.14?a="golden":e<.72?a="truffle":a="acorn";else{const s=Math.min(.29,.07+t.level*.027);e<s?a="crow":e<s+.03?a="golden":e<s+.03+.24?a="truffle":a="acorn"}const o=t.unit,r=a==="acorn"?8*o:a==="truffle"?10*o:a==="golden"?11*o:14*o,i=r+7,c=t.w<=i*2?t.w/2:v(i,t.w-i),f=t.h*(.3+t.level*.012)*(t.frenzy>0?1.18:1),u=a==="crow"?f*v(1.02,1.18):f*v(.84,1.14);t.items.push({kind:a,x:c,y:-r-6,vy:u,drift:a==="crow"?v(-26,26):v(-8,8),phase:v(0,Math.PI*2),spin:v(-1.6,1.6),r})}function Ge(){return t.frenzy>0?v(.24,.36):Math.max(.34,.95-t.level*.05)*v(.74,1.24)}function C(e,a,o,r,i){const c=I?Math.ceil(r/2):r;for(let f=0;f<c;f+=1){const u=v(0,Math.PI*2),s=v(i*.3,i);t.particles.push({x:e,y:a,vx:Math.cos(u)*s,vy:Math.sin(u)*s-i*.25,life:v(.35,.8),maxLife:.8,size:v(1.5,4)*t.unit,color:o[Math.floor(Math.random()*o.length)],gravity:260})}}function K(e,a,o,r){t.floaters.push({x:p(e,28,t.w-28),y:a,text:o,life:.85,maxLife:.85,color:r})}function Ke(){t.frenzy=_,t.belly=0,t.score+=100,t.shake=j.screenShake&&!I?9:0,t.flash=.35,K(t.pigX,t.groundY-t.pigH*1.5,"+100","#ffd97a"),Z("Truffle frenzy!"),ze(),C(t.pigX,t.groundY-t.pigH*.6,["#ffe9a8","#ffcf6b","#fff6d8"],26,260);for(let e=t.items.length-1;e>=0;e-=1){const a=t.items[e];a.kind==="crow"&&(C(a.x,a.y,["#3a2148","#241231","#7a4d8f"],6,140),t.items.splice(e,1))}}function Oe(e){const a=G();t.combo+=1,t.maxCombo=Math.max(t.maxCombo,t.combo),t.foodCaught+=1,t.mouth=.22;const o=G(),r=e.kind==="acorn"?5:e.kind==="truffle"?25:75,i=Math.round(r*o*(t.frenzy>0?2:1));t.score+=i;const c=e.kind==="acorn"?.085:e.kind==="truffle"?.2:.45;t.frenzy<=0&&(t.belly=Math.min(1,t.belly+c));const f=e.kind==="golden"?["#fff3c4","#ffcf6b","#ffb03e"]:e.kind==="truffle"?["#e7b07f","#9a6244","#ffcf6b"]:["#e0a968","#9c6a3d","#ffd98f"];C(e.x,e.y,f,e.kind==="acorn"?7:12,e.kind==="golden"?240:170),K(e.x,e.y-8,`+${i}`,e.kind==="golden"?"#ffe9a8":e.kind==="truffle"?"#ffd98a":"#ffe9cf"),e.kind==="golden"&&t.frenzy>0&&(t.frenzy=Math.min(_+2,t.frenzy+1.2)),Ae(e.kind),o>a&&(K(t.pigX,t.groundY-t.pigH*1.35,`×${o}`,"#ffcf6b"),o>=3&&Z(`×${o} snout streak`)),t.belly>=1&&t.frenzy<=0&&Ke(),t.level=Math.min(9,1+Math.floor(t.foodCaught/12))}function Ve(e){t.hearts-=1,t.combo=0,t.invuln=1.5,t.shake=j.screenShake&&!I?13:0,t.flash=.55,C(e.x,e.y,["#2b1739","#472a5e","#ff7d86"],14,210),Le(),t.hearts<=0&&He()}function _e(e){t.elapsed+=e,t.mouth=Math.max(0,t.mouth-e),t.invuln=Math.max(0,t.invuln-e),t.flash=Math.max(0,t.flash-e),t.shake=Math.max(0,t.shake-e*34),t.frenzy>0&&(t.frenzy=Math.max(0,t.frenzy-e),t.frenzy===0&&Z("Frenzy over"));const a=t.w*1.5+180;t.keys.left&&(t.pigTarget-=a*e),t.keys.right&&(t.pigTarget+=a*e),t.pigTarget=p(t.pigTarget,t.pigW/2,t.w-t.pigW/2);const o=(t.w*1.8+260)*e,r=p(t.pigTarget-t.pigX,-o,o);t.pigX+=r,t.pigVX=t.pigVX*.8+r/Math.max(e,.001)*.2,t.spawnTimer-=e,t.spawnTimer<=0&&t.items.length<46&&(qe(),t.spawnTimer=Ge());const i=t.groundY-t.pigH*.38,c=t.pigW*.56,f=t.pigH*.62;for(let u=t.items.length-1;u>=0;u-=1){const s=t.items[u];if(s.y+=s.vy*e,s.x+=s.drift*e+Math.sin(t.elapsed*2.2+s.phase)*10*e,s.x=p(s.x,s.r,t.w-s.r),s.spin+=(s.kind==="crow"?2.4:1.2)*e,Math.abs(s.x-t.pigX)<c+s.r*.6&&Math.abs(s.y-i)<f+s.r*.6){if(s.kind==="crow"){if(t.invuln<=0&&(t.items.splice(u,1),Ve(s),t.phase!=="playing"))return}else t.items.splice(u,1),Oe(s);continue}s.y>t.groundY+s.r*.4&&(t.items.splice(u,1),s.kind==="crow"?C(s.x,t.groundY,["#33204a","#4c2d63"],5,110):(t.combo=0,C(s.x,t.groundY,["#4a2a5e","#2c153f"],4,90),Ye()))}}function je(e){for(let a=t.particles.length-1;a>=0;a-=1){const o=t.particles[a];if(o.life-=e,o.life<=0){t.particles.splice(a,1);continue}o.vy+=o.gravity*e,o.x+=o.vx*e,o.y+=o.vy*e}for(let a=t.floaters.length-1;a>=0;a-=1){const o=t.floaters[a];if(o.life-=e,o.life<=0){t.floaters.splice(a,1);continue}o.y-=34*e}t.particles.length>240&&t.particles.splice(0,t.particles.length-240)}function Ue(e,a,o,r){n.save(),n.translate(e,a),n.rotate(r*.25),n.fillStyle="#d99a58",n.beginPath(),n.ellipse(0,o*.18,o*.72,o*.82,0,0,Math.PI*2),n.fill(),n.strokeStyle="rgba(55, 26, 30, 0.7)",n.lineWidth=Math.max(1,o*.12),n.stroke(),n.fillStyle="#7a4426",n.beginPath(),n.ellipse(0,-o*.38,o*.82,o*.44,0,Math.PI,Math.PI*2),n.fill(),n.strokeRect(-o*.06,-o*1.12,o*.12,o*.3),n.fillStyle="rgba(255, 240, 210, 0.5)",n.beginPath(),n.arc(-o*.26,o*.05,o*.16,0,Math.PI*2),n.fill(),n.restore()}function ne(e,a,o,r,i){n.fillStyle=r,n.beginPath(),n.arc(e-o*.3,a+o*.1,o*.68,0,Math.PI*2),n.arc(e+o*.34,a+o*.05,o*.6,0,Math.PI*2),n.arc(e,a-o*.32,o*.72,0,Math.PI*2),n.fill(),n.fillStyle=i;const c=[[-.36,.24,.1],[.28,.34,.08],[.05,-.28,.09],[-.08,.42,.07],[.42,-.12,.07]];for(const[f,u,s]of c)n.beginPath(),n.arc(e+f*o,a+u*o,s*o,0,Math.PI*2),n.fill()}function Ze(e,a,o,r){if(n.save(),r?(n.shadowColor="rgba(255, 196, 90, 0.9)",n.shadowBlur=o*1.7,n.fillStyle="rgba(255, 220, 130, 0.22)",n.beginPath(),n.arc(e,a,o*1.5,0,Math.PI*2),n.fill(),n.shadowBlur=0,ne(e,a,o,"#ffce62","#fff1b8"),n.strokeStyle="rgba(255, 248, 214, 0.9)"):(n.shadowColor="rgba(255, 193, 110, 0.35)",n.shadowBlur=o*.9,ne(e,a,o,"#8a573d","#d8a274"),n.strokeStyle="rgba(255, 219, 176, 0.35)"),n.lineWidth=Math.max(1,o*.1),n.beginPath(),n.arc(e-o*.15,a-o*.1,o*.85,0,Math.PI*2),n.stroke(),n.restore(),r){n.save(),n.translate(e,a),n.rotate(t.time*1.4),n.strokeStyle="rgba(255, 249, 214, 0.9)",n.lineWidth=1.4;for(let i=0;i<4;i+=1){const c=i/4*Math.PI*2,f=o*1.15,u=o*1.55;n.beginPath(),n.moveTo(Math.cos(c)*f,Math.sin(c)*f),n.lineTo(Math.cos(c)*u,Math.sin(c)*u),n.stroke()}n.restore()}}function Je(e){const{x:a,y:o,r}=e,i=Math.sin(t.elapsed*15+e.phase);n.save(),n.translate(a,o),n.rotate(p(e.drift*.004,-.18,.18)),n.fillStyle="#1d102c",n.beginPath(),n.ellipse(0,0,r*.72,r*.54,0,0,Math.PI*2),n.fill(),n.beginPath(),n.ellipse(-r*.62,-r*.1+i*r*.34,r*.55,r*.26,-.5,0,Math.PI*2),n.fill(),n.beginPath(),n.ellipse(r*.62,-r*.1-i*r*.34,r*.55,r*.26,.5,0,Math.PI*2),n.fill(),n.beginPath(),n.arc(r*.42,-r*.3,r*.34,0,Math.PI*2),n.fillStyle="#241436",n.fill(),n.fillStyle="#ffb457",n.beginPath(),n.moveTo(r*.72,-r*.3),n.lineTo(r*1.16,-r*.18),n.lineTo(r*.72,-r*.08),n.closePath(),n.fill(),n.fillStyle="#ffe9cf",n.beginPath(),n.arc(r*.5,-r*.38,r*.08,0,Math.PI*2),n.fill(),n.restore()}function Qe(){const e=t.pigW,a=t.pigH,o=t.phase==="playing"&&!I?Math.sin(t.elapsed*9)*1.8:0,r=t.mouth>0,i=t.frenzy>0,c=t.groundY-a*.38+o,f=t.invuln>0&&Math.floor(t.time*16)%2===0;if(i){const d=n.createRadialGradient(t.pigX,c,e*.2,t.pigX,c,e*1.15);d.addColorStop(0,"rgba(255, 219, 130, 0.4)"),d.addColorStop(1,"rgba(255, 190, 80, 0)"),n.fillStyle=d,n.beginPath(),n.arc(t.pigX,c,e*1.15,0,Math.PI*2),n.fill()}n.save(),n.globalAlpha=f?.4:1,n.translate(t.pigX,c);const u=p(t.pigVX*22e-5,-.14,.14);n.rotate(u),n.strokeStyle="#d96385",n.lineWidth=Math.max(1.5,e*.035),n.lineCap="round",n.beginPath(),n.arc(-e*.5,-a*.02,e*.12,.4,Math.PI*1.7),n.stroke(),n.fillStyle="#e8799a";for(const d of[-1,1])n.beginPath(),n.roundRect(d*e*.26-e*.09,a*.28,e*.18,a*.3,e*.06),n.fill();n.fillStyle="#ffb0c4",n.strokeStyle="#7c2c49",n.lineWidth=Math.max(1.4,e*.025);for(const d of[-1,1])n.beginPath(),n.moveTo(d*e*.17,-a*.36),n.lineTo(d*e*.42,-a*.64),n.lineTo(d*e*.46,-a*.24),n.closePath(),n.fill(),n.stroke();const s=n.createLinearGradient(0,-a*.5,0,a*.5);s.addColorStop(0,"#ffc0cf"),s.addColorStop(.55,"#ffabc0"),s.addColorStop(1,"#f28aa7"),n.fillStyle=s,n.strokeStyle="#7c2c49",n.lineWidth=Math.max(1.6,e*.03),n.beginPath(),n.ellipse(0,0,e*.5,a*.48,0,0,Math.PI*2),n.fill(),n.stroke(),n.fillStyle="#ffd4dd",n.beginPath(),n.ellipse(0,a*.12,e*.24,a*.17,0,0,Math.PI*2),n.fill(),n.strokeStyle="rgba(124, 44, 73, 0.55)",n.lineWidth=Math.max(1,e*.018),n.stroke(),n.fillStyle="#a64667";for(const d of[-1,1])n.beginPath(),n.ellipse(d*e*.075,a*.12,e*.028,a*.05,0,0,Math.PI*2),n.fill();n.fillStyle="rgba(233, 105, 140, 0.4)";for(const d of[-1,1])n.beginPath(),n.ellipse(d*e*.32,a*.1,e*.075,a*.05,0,0,Math.PI*2),n.fill();const h=-a*.12;if(n.strokeStyle="#3c1428",n.fillStyle="#3c1428",n.lineWidth=Math.max(1.4,e*.022),i)for(const d of[-1,1])n.beginPath(),n.arc(d*e*.19,h,e*.06,Math.PI*.15,Math.PI*.85),n.stroke();else for(const d of[-1,1])n.beginPath(),n.ellipse(d*e*.19,h,e*.045,a*.055,0,0,Math.PI*2),n.fill(),n.fillStyle="rgba(255, 255, 255, 0.9)",n.beginPath(),n.arc(d*e*.19+e*.016,h-a*.018,e*.014,0,Math.PI*2),n.fill(),n.fillStyle="#3c1428";r||i?(n.fillStyle="#7a2544",n.beginPath(),n.ellipse(0,a*.3,e*.1,a*.075,0,0,Math.PI*2),n.fill(),n.fillStyle="#ff9fb6",n.beginPath(),n.ellipse(0,a*.325,e*.05,a*.035,0,0,Math.PI*2),n.fill()):(n.strokeStyle="rgba(124, 44, 73, 0.7)",n.beginPath(),n.arc(0,a*.2,e*.13,Math.PI*.18,Math.PI*.82),n.stroke()),n.restore()}function et(){for(const e of t.items){if(n.save(),e.kind==="crow"){const a=p(e.y/Math.max(1,t.groundY),0,1);n.globalAlpha=.12+a*.26,n.fillStyle="#05020c",n.beginPath(),n.ellipse(e.x,t.groundY+3,e.r*1.5*a,e.r*.35*a,0,0,Math.PI*2),n.fill(),n.globalAlpha=1,Je(e)}else e.kind==="acorn"?Ue(e.x,e.y,e.r,e.spin):Ze(e.x,e.y,e.r,e.kind==="golden");n.restore()}}function tt(e){n.save();for(const a of t.fireflies){const o=a.baseX*t.w+Math.sin(e*a.speed+a.phase)*a.amp,r=a.baseY*t.h+Math.cos(e*a.speed*.8+a.phase*1.3)*a.amp*.6,i=.55+.45*Math.sin(e*2.2+a.phase);n.globalAlpha=.35+i*.5,n.fillStyle="#ffe3a0",n.shadowColor="rgba(255, 214, 120, 0.9)",n.shadowBlur=8,n.beginPath(),n.arc(o,r,1.5+i,0,Math.PI*2),n.fill()}n.restore()}function nt(){for(const e of t.particles){const a=p(e.life/e.maxLife,0,1);n.globalAlpha=a,n.fillStyle=e.color,n.beginPath(),n.arc(e.x,e.y,e.size*(.4+a*.6),0,Math.PI*2),n.fill()}n.globalAlpha=1}function at(){n.save(),n.textAlign="center",n.textBaseline="middle",n.font=`900 ${Math.max(11,14*t.unit)}px "Trebuchet MS", "Avenir Next", sans-serif`;for(const e of t.floaters){const a=p(e.life/e.maxLife,0,1);n.globalAlpha=a,n.fillStyle=e.color,n.shadowColor="rgba(10, 4, 18, 0.85)",n.shadowBlur=4,n.fillText(e.text,e.x,e.y)}n.restore()}function ot(e){const{w:a,h:o}=t;if(!(a<=0||o<=0)){if(n.clearRect(0,0,a,o),n.save(),t.shake>.2){const r=t.shake;n.translate(v(-r,r)*.5,v(-r,r)*.5)}W&&n.drawImage(W,0,0,a,o),tt(e),et(),Qe(),nt(),at(),n.restore(),t.flash>0&&(n.fillStyle=`rgba(255, 120, 120, ${p(t.flash*.35,0,.3)})`,n.fillRect(0,0,a,o))}}function he(e){const a=p((e-q)/1e3,0,.05);q=e,t.time+=a,t.phase==="playing"&&_e(a),je(a),B(),ot(t.time),window.requestAnimationFrame(he)}function pe(e){const a=y.getBoundingClientRect();t.pigTarget=p(e-a.left,t.pigW/2,t.w-t.pigW/2)}function ge(e){return e==="ArrowLeft"||e==="a"||e==="A"?"left":e==="ArrowRight"||e==="d"||e==="D"?"right":null}window.addEventListener("keydown",e=>{if(e.metaKey||e.ctrlKey||e.altKey)return;const a=ge(e.key);if(a){t.keys[a]=!0,k(),e.preventDefault();return}if(e.key==="m"||e.key==="M"){e.preventDefault(),de();return}if(e.key===" "||e.key==="Enter"){e.preventDefault(),k(),t.phase==="ready"||t.phase==="over"?ue():T();return}(e.key==="p"||e.key==="P"||e.key==="Escape")&&(e.preventDefault(),(t.phase==="playing"||t.phase==="paused")&&T())});window.addEventListener("keyup",e=>{const a=ge(e.key);a&&(t.keys[a]=!1)});window.addEventListener("blur",()=>{t.keys.left=!1,t.keys.right=!1,t.pointerDown=!1,t.phase==="playing"&&T()});y.addEventListener("pointerdown",e=>{if(k(),t.pointerDown=!0,pe(e.clientX),y.setPointerCapture)try{y.setPointerCapture(e.pointerId)}catch{}e.preventDefault()});y.addEventListener("pointermove",e=>{(e.pointerType==="mouse"||t.pointerDown)&&pe(e.clientX)});function J(){t.pointerDown=!1}y.addEventListener("pointerup",J);y.addEventListener("pointercancel",J);y.addEventListener("pointerleave",e=>{e.pointerType==="mouse"&&J()});y.addEventListener("contextmenu",e=>e.preventDefault());l.playButton.addEventListener("click",()=>{t.phase==="paused"?T():ue()});l.pauseButton.addEventListener("click",()=>{(t.phase==="playing"||t.phase==="paused")&&T()});l.soundButton.addEventListener("click",()=>{de()});document.addEventListener("visibilitychange",()=>{document.hidden&&t.phase==="playing"&&T()});window.addEventListener("pagehide",()=>{fe(),A==null||A.disconnect()});Be(e=>{j={...e},Y=e.sound,X()});l.hearts.setAttribute("aria-label","3 lives remaining");X();B(!0);A=new ResizeObserver(()=>ce());A.observe(y);ce();Xe();window.requestAnimationFrame(he);
</script>
<style>:root{--night-0: #0d0620;--night-1: #1a0c2e;--plum: #2c1546;--cream: #ffe9cf;--cream-soft: rgba(255, 233, 207, .78);--cream-faint: rgba(255, 233, 207, .5);--pink: #ffb0c4;--pink-deep: #e8698c;--gold: #ffcf6b;--gold-deep: #f0a93c;--danger: #ff7d86;--panel: rgba(26, 12, 46, .74);--line: rgba(255, 225, 196, .18);--radius: 12px;--hud-pad: 10px;color-scheme:dark;font:13px/1.4 Trebuchet MS,Avenir Next,Segoe UI,system-ui,sans-serif}*{box-sizing:border-box}html,body,#app{height:100%;margin:0}body{background:var(--night-0);color:var(--cream);overflow:hidden;-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent}button{font:inherit;color:inherit}[hidden]{display:none!important}.app{position:relative;container-type:inline-size;width:100%;height:100%;overflow:hidden;background:var(--night-0);user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;touch-action:manipulation}#game{position:absolute;top:0;right:0;bottom:0;left:0;display:block;width:100%;height:100%;touch-action:none;cursor:crosshair}.app.is-frenzy:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:none;box-shadow:inset 0 0 70px #ffc15238}.hud{position:absolute;z-index:3;top:max(var(--hud-pad),env(safe-area-inset-top));left:max(var(--hud-pad),env(safe-area-inset-left));right:max(var(--hud-pad),env(safe-area-inset-right));display:flex;align-items:flex-start;justify-content:space-between;gap:6px;pointer-events:none}.hud-left,.hud-right{display:flex;align-items:flex-start;gap:6px;min-width:0}.hud-right{justify-content:flex-end}.stat,.hearts{display:flex;align-items:center;gap:6px;min-height:32px;padding:3px 10px;border:1px solid var(--line);border-radius:var(--radius);background:var(--panel);box-shadow:0 2px 10px #05020c59;white-space:nowrap}.stat{display:grid;grid-template-columns:auto auto;grid-auto-flow:column;align-items:baseline;gap:6px}.stat-label{font-size:9px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--cream-faint)}.stat-value{font-size:17px;font-weight:900;font-variant-numeric:tabular-nums;letter-spacing:.01em;color:var(--cream);line-height:1}.stat-value.bump{animation:bump .18s ease-out}.hearts{padding:3px 8px;font-size:15px;line-height:1;letter-spacing:1px;color:var(--pink)}.life{display:inline-block;transition:transform .15s ease,opacity .15s ease}.life.off{color:#ffb0c438;transform:scale(.86)}.icon-button{position:relative;display:grid;place-items:center;width:34px;height:34px;padding:0;border:1px solid var(--line);border-radius:999px;background:var(--panel);color:var(--cream-soft);font-size:13px;cursor:pointer;pointer-events:auto;box-shadow:0 2px 10px #05020c59;transition:color .15s ease,border-color .15s ease,transform .1s ease}.icon-button:after{content:"";position:absolute;top:-5px;right:-5px;bottom:-5px;left:-5px;border-radius:999px}.icon-button:hover:not(:disabled){color:var(--gold);border-color:#ffcf6b8c}.icon-button:active:not(:disabled){transform:scale(.94)}.icon-button:disabled{opacity:.38;cursor:default}.icon-button.muted{color:var(--cream-faint)}.icon-button.muted:before{content:"";position:absolute;width:17px;height:2px;border-radius:2px;background:var(--danger);transform:rotate(-45deg)}.icon-button:focus-visible,.play-button:focus-visible{outline:2px solid var(--gold);outline-offset:2px}.combo{position:absolute;z-index:3;top:calc(max(var(--hud-pad),env(safe-area-inset-top)) + 40px);left:50%;transform:translate(-50%) rotate(-3deg);padding:3px 11px;border-radius:999px;background:linear-gradient(180deg,#ffd97f,#f2b243);color:#35162c;font-size:12px;font-weight:900;letter-spacing:.06em;box-shadow:0 3px #7a411ae6,0 0 18px #ffc15273;animation:comboIn .18s ease-out;pointer-events:none}.combo[data-hot=true]{background:linear-gradient(180deg,#fff3c8,#ffbe55);animation:comboPulse .9s ease-in-out infinite}.toast{position:absolute;z-index:4;top:30%;left:50%;transform:translate(-50%,-50%);padding:0 10px;font-size:clamp(16px,7cqi,34px);font-weight:900;letter-spacing:.08em;text-transform:uppercase;text-align:center;color:var(--gold);text-shadow:0 0 18px rgba(255,190,80,.65),0 3px 0 rgba(70,30,20,.7);opacity:0;pointer-events:none;white-space:nowrap}.toast.show{animation:toastPop 1.35s ease-out forwards}.belly{position:absolute;z-index:3;left:max(12px,env(safe-area-inset-left));right:max(12px,env(safe-area-inset-right));bottom:max(6px,env(safe-area-inset-bottom));display:flex;align-items:center;gap:8px;pointer-events:none}.belly-label{font-size:8px;font-weight:800;letter-spacing:.18em;text-transform:uppercase;color:#ffe9cf99;text-shadow:0 1px 2px rgba(5,2,12,.8)}.belly-track{position:relative;flex:1;height:7px;overflow:hidden;border:1px solid rgba(255,225,196,.22);border-radius:999px;background:#0a0416ad;box-shadow:0 2px 8px #05020c80}.belly-fill{height:100%;width:0%;border-radius:inherit;background:linear-gradient(90deg,var(--pink-deep),var(--pink) 45%,var(--gold));transition:width .14s ease-out}.app.is-frenzy .belly-fill{background:linear-gradient(90deg,#ffe9a8,#fff6d8,#ffc24f);box-shadow:0 0 14px #ffd678e6;transition:width .08s linear}.overlay{position:absolute;top:0;right:0;bottom:0;left:0;z-index:5;display:grid;place-items:center;padding:12px;background:radial-gradient(circle at 50% 38%,#3c185466,#080412cc 75%);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}.card{width:min(336px,100%);padding:18px 18px 16px;border:1px solid rgba(255,214,160,.26);border-radius:20px;background:linear-gradient(180deg,#3a1c54f7,#1e0d31fa);box-shadow:0 18px 44px #04020a9e,inset 0 1px #ffffff14;text-align:center;container-type:inline-size}.kicker{margin:0 0 5px;font-size:9px;font-weight:800;letter-spacing:.2em;text-transform:uppercase;color:var(--pink)}.title{margin:0 0 8px;font-size:clamp(23px,10cqi,34px);font-weight:900;line-height:.95;letter-spacing:.01em;color:var(--gold);text-shadow:0 0 22px rgba(255,190,80,.35),0 3px 0 rgba(80,34,22,.75)}.blurb{max-width:32ch;margin:0 auto 13px;font-size:12px;line-height:1.45;color:var(--cream-soft)}.overlay-stats{display:flex;justify-content:center;gap:7px;width:100%;margin:0 0 12px}.mini-stat{display:grid;flex:1;gap:1px;min-width:0;max-width:100px;padding:5px 8px;border:1px solid var(--line);border-radius:10px;background:#0c051880}.mini-label{font-size:7.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--cream-faint)}.mini-value{font-size:14px;font-weight:900;font-variant-numeric:tabular-nums;color:var(--gold)}.play-button{width:min(220px,100%);min-height:44px;padding:0 22px;border:0;border-radius:999px;background:linear-gradient(180deg,#ffdd8b,#f2b23f);color:#35162c;font-size:15px;font-weight:900;letter-spacing:.05em;text-transform:uppercase;cursor:pointer;box-shadow:0 5px #a4662a,0 10px 20px #04020a73;transition:transform .08s ease,box-shadow .08s ease;touch-action:manipulation}.play-button:hover{background:linear-gradient(180deg,#ffe6a6,#f7bc4c)}.play-button:active{transform:translateY(3px);box-shadow:0 2px #a4662a,0 5px 12px #04020a73}.hint{margin:10px 0 0;font-size:10px;letter-spacing:.03em;color:#ffe9cf7a}@container (max-width: 360px){.hud{--hud-pad: 7px;gap:4px}.hud-left,.hud-right{gap:4px}.stat,.hearts{min-height:28px;padding:2px 7px;border-radius:10px}.stat-label{display:none}.stat-value{font-size:15px}.stat-best{display:none}.hearts{font-size:13px;letter-spacing:0}.icon-button{width:30px;height:30px;font-size:12px}.combo{top:calc(max(7px,env(safe-area-inset-top)) + 35px);font-size:11px;padding:2px 9px}.card{padding:14px 12px 12px;border-radius:16px}.blurb{font-size:11px;margin-bottom:10px}.play-button{min-height:40px;font-size:13.5px}.hint{font-size:9px}}@container (max-width: 300px){.kicker{display:none}.title{font-size:21px;margin-bottom:5px}.blurb{font-size:10.5px;line-height:1.35}.belly-label{display:none}.card{width:min(250px,100%)}.overlay-stats{gap:4px}.mini-stat{min-width:56px;padding:4px 6px}}@container (max-width: 250px){.stat-value{font-size:14px}.hearts{gap:2px;padding:2px 6px;font-size:12px}.icon-button{width:28px;height:28px;font-size:11px}}@media(max-height:230px){.hud{--hud-pad: 6px}.kicker,.hint{display:none}.title{font-size:22px;margin-bottom:5px}.blurb{margin-bottom:9px;font-size:10.5px}.card{padding:12px 12px 10px}.play-button{min-height:38px;font-size:13px}.mini-stat{padding:3px 7px}.overlay-stats{margin-bottom:9px}}@media(max-height:175px){.blurb{display:none}.card{padding:10px 12px}.title{margin-bottom:7px}.overlay-stats{margin-bottom:8px}}@keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.22);color:var(--gold)}to{transform:scale(1)}}@keyframes comboIn{0%{transform:translate(-50%) rotate(-3deg) scale(.6);opacity:0}to{transform:translate(-50%) rotate(-3deg) scale(1);opacity:1}}@keyframes comboPulse{0%,to{transform:translate(-50%) rotate(-3deg) scale(1)}50%{transform:translate(-50%) rotate(-2deg) scale(1.06)}}@keyframes toastPop{0%{opacity:0;transform:translate(-50%,-50%) scale(.7)}14%{opacity:1;transform:translate(-50%,-50%) scale(1.08)}24%{transform:translate(-50%,-50%) scale(1)}72%{opacity:1}to{opacity:0;transform:translate(-50%,-62%) scale(1)}}@media(prefers-reduced-motion:reduce){.combo[data-hot=true],.stat-value.bump{animation:none}.toast.show{animation:toastFade 1.2s ease-out forwards}@keyframes toastFade{0%,75%{opacity:1}to{opacity:0}}}
</style>
<meta name="napplet-type" content="my-napplet">
<meta name="napplet-config-schema" content="{"$schema":"http://json-schema.org/draft-07/schema#","$version":1,"type":"object","additionalProperties":false,"properties":{"sound":{"type":"boolean","title":"Sound effects","description":"Oinks, chimes and caws. The in-game sound button also mutes for this session.","default":true,"x-napplet-section":"Audio","x-napplet-order":1},"screenShake":{"type":"boolean","title":"Screen shake","description":"Shake the orchard on a crow hit or a truffle frenzy.","default":true,"x-napplet-section":"Feedback","x-napplet-order":1}}}">
</head>
<body>
<main id="app" class="app">
<canvas id="game" aria-label="Truffle Rush play field. Move the pig with the pointer, touch, or arrow keys."></canvas>
<header class="hud">
<div class="hud-left">
<div class="stat stat-score">
<span class="stat-label">Score</span>
<span id="score" class="stat-value">0</span>
</div>
<div class="stat stat-best">
<span class="stat-label">Best</span>
<span id="best" class="stat-value">0</span>
</div>
</div>
<div class="hud-right">
<div id="hearts" class="hearts" role="img" aria-label="3 lives"></div>
<button id="soundButton" class="icon-button" type="button" aria-label="Mute sound" title="Sound (M)">
<span aria-hidden="true">♪</span>
</button>
<button id="pauseButton" class="icon-button" type="button" aria-label="Pause" title="Pause (Space)">
<span aria-hidden="true">❚❚</span>
</button>
</div>
</header>
<div id="combo" class="combo" hidden>×2</div>
<div id="toast" class="toast" aria-live="polite"></div>
<div class="belly" aria-hidden="true">
<span class="belly-label">Belly</span>
<div class="belly-track"><div id="bellyFill" class="belly-fill"></div></div>
</div>
<div id="overlay" class="overlay">
<section class="card" aria-labelledby="overlayTitle">
<p id="overlayKicker" class="kicker">Moonlit piggy arcade</p>
<p id="overlayTitle" class="title">Truffle Rush</p>
<p id="overlayText" class="blurb">
Catch the falling snacks. Dodge the crows. Fill your belly for a golden frenzy.
</p>
<div id="overlayStats" class="overlay-stats" hidden></div>
<button id="playButton" class="play-button" type="button">Play</button>
<p id="hint" class="hint">Drag · Arrow keys · Space to pause</p>
</section>
</div>
</main>
</body>
</html>
