Upload 4 files
Browse files- assets/index-ChKWcDIf.js +1 -0
- assets/index-wdrp1RHT.css +1 -0
- assets/worker-Dvof_Pv2.js +0 -0
- index.html +6 -4
assets/index-ChKWcDIf.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
var he=Object.defineProperty;var fe=(e,t,o)=>t in e?he(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o;var p=(e,t,o)=>fe(e,typeof t!="symbol"?t+"":t,o);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))n(a);new MutationObserver(a=>{for(const r of a)if(r.type==="childList")for(const s of r.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&n(s)}).observe(document,{childList:!0,subtree:!0});function o(a){const r={};return a.integrity&&(r.integrity=a.integrity),a.referrerPolicy&&(r.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?r.credentials="include":a.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function n(a){if(a.ep)return;a.ep=!0;const r=o(a);fetch(a.href,r)}})();const ge=["aircraft carrier","airplane","alarm clock","ambulance","angel","animal migration","ant","anvil","apple","arm","asparagus","axe","backpack","banana","bandage","barn","baseball","baseball bat","basket","basketball","bat","bathtub","beach","bear","beard","bed","bee","belt","bench","bicycle","binoculars","bird","birthday cake","blackberry","blueberry","book","boomerang","bottlecap","bowtie","bracelet","brain","bread","bridge","broccoli","broom","bucket","bulldozer","bus","bush","butterfly","cactus","cake","calculator","calendar","camel","camera","camouflage","campfire","candle","cannon","canoe","car","carrot","castle","cat","ceiling fan","cello","cell phone","chair","chandelier","church","circle","clarinet","clock","cloud","coffee cup","compass","computer","cookie","cooler","couch","cow","crab","crayon","crocodile","crown","cruise ship","cup","diamond","dishwasher","diving board","dog","dolphin","donut","door","dragon","dresser","drill","drums","duck","dumbbell","ear","elbow","elephant","envelope","eraser","eye","eyeglasses","face","fan","feather","fence","finger","fire hydrant","fireplace","firetruck","fish","flamingo","flashlight","flip flops","floor lamp","flower","flying saucer","foot","fork","frog","frying pan","garden","garden hose","giraffe","goatee","golf club","grapes","grass","guitar","hamburger","hammer","hand","harp","hat","headphones","hedgehog","helicopter","helmet","hexagon","hockey puck","hockey stick","horse","hospital","hot air balloon","hot dog","hot tub","hourglass","house","house plant","hurricane","ice cream","jacket","jail","kangaroo","key","keyboard","knee","knife","ladder","lantern","laptop","leaf","leg","light bulb","lighter","lighthouse","lightning","line","lion","lipstick","lobster","lollipop","mailbox","map","marker","matches","megaphone","mermaid","microphone","microwave","monkey","moon","mosquito","motorbike","mountain","mouse","moustache","mouth","mug","mushroom","nail","necklace","nose","ocean","octagon","octopus","onion","oven","owl","paintbrush","paint can","palm tree","panda","pants","paper clip","parachute","parrot","passport","peanut","pear","peas","pencil","penguin","piano","pickup truck","picture frame","pig","pillow","pineapple","pizza","pliers","police car","pond","pool","popsicle","postcard","potato","power outlet","purse","rabbit","raccoon","radio","rain","rainbow","rake","remote control","rhinoceros","rifle","river","roller coaster","rollerskates","sailboat","sandwich","saw","saxophone","school bus","scissors","scorpion","screwdriver","sea turtle","see saw","shark","sheep","shoe","shorts","shovel","sink","skateboard","skull","skyscraper","sleeping bag","smiley face","snail","snake","snorkel","snowflake","snowman","soccer ball","sock","speedboat","spider","spoon","spreadsheet","square","squiggle","squirrel","stairs","star","steak","stereo","stethoscope","stitches","stop sign","stove","strawberry","streetlight","string bean","submarine","suitcase","sun","swan","sweater","swing set","sword","syringe","table","teapot","teddy-bear","telephone","television","tennis racquet","tent","The Eiffel Tower","The Great Wall of China","The Mona Lisa","tiger","toaster","toe","toilet","tooth","toothbrush","toothpaste","tornado","tractor","traffic light","train","tree","triangle","trombone","truck","trumpet","t-shirt","umbrella","underwear","van","vase","violin","washing machine","watermelon","waterslide","whale","wheel","windmill","wine bottle","wine glass","wristwatch","yoga","zebra","zigzag"];var J="https://huggingface.co";async function R(e,t){var a;const o=new me(e.url,e.status,e.headers.get("X-Request-Id")??(t==null?void 0:t.requestId));o.message=`Api error with status ${o.statusCode}`;const n=[`URL: ${o.url}`,o.requestId?`Request ID: ${o.requestId}`:void 0].filter(Boolean).join(". ");if((a=e.headers.get("Content-Type"))!=null&&a.startsWith("application/json")){const r=await e.json();o.message=r.error||r.message||o.message,r.error_description&&(o.message=o.message?o.message+`: ${r.error_description}`:r.error_description),o.data=r}else o.data={message:await e.text()};throw o.message+=`. ${n}`,o}var me=class extends Error{constructor(t,o,n,a){super(a);p(this,"statusCode");p(this,"url");p(this,"requestId");p(this,"data");this.statusCode=o,this.requestId=n,this.url=t}};new Promise(e=>{});function we(e){if(globalThis.Buffer)return globalThis.Buffer.from(e).toString("base64");{const t=[];return e.forEach(o=>{t.push(String.fromCharCode(o))}),globalThis.btoa(t.join(""))}}var A=65536;pe();function pe(){try{return new Uint32Array(A)}catch{const t=new Array(A);for(let o=0;o<A;o++)t[o]=0;return t}}async function W(e){if(typeof window>"u")throw new Error("oauthHandleRedirect is only available in the browser, unless you provide redirectedUrl");if(typeof localStorage>"u")throw new Error("oauthHandleRedirect requires localStorage to be available, unless you provide nonce and codeVerifier");const t=window.location.href,o=(()=>{try{return new URL(t).searchParams}catch{throw new Error("Failed to parse redirected URL: "+t)}})(),[n,a]=[o.get("error"),o.get("error_description")];if(n)throw new Error(`${n}: ${a}`);const r=o.get("code"),s=localStorage.getItem("huggingface.co:oauth:nonce");if(!r)throw new Error("Missing oauth code from query parameters in redirected URL: "+t);if(!s)throw new Error("Missing oauth nonce from localStorage");const c=localStorage.getItem("huggingface.co:oauth:code_verifier");if(!c)throw new Error("Missing oauth code_verifier from localStorage");const w=o.get("state");if(!w)throw new Error("Missing oauth state from query parameters in redirected URL");let d;try{d=JSON.parse(w)}catch{throw new Error("Invalid oauth state in redirected URL, unable to parse JSON: "+w)}if(d.nonce!==s)throw new Error("Invalid oauth state in redirected URL");const k=J,T=`${new URL(k).origin}/.well-known/openid-configuration`,f=await fetch(T,{headers:{Accept:"application/json"}});if(!f.ok)throw await R(f);const z=await f.json(),B=await fetch(z.token_endpoint,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:r,redirect_uri:d.redirectUri,code_verifier:c}).toString()});if(localStorage.removeItem("huggingface.co:oauth:code_verifier"),localStorage.removeItem("huggingface.co:oauth:nonce"),!B.ok)throw await R(B);const I=await B.json(),de=new Date(Date.now()+I.expires_in*1e3),D=await fetch(z.userinfo_endpoint,{headers:{Authorization:`Bearer ${I.access_token}`}});if(!D.ok)throw await R(D);const ue=await D.json();return{accessToken:I.access_token,accessTokenExpiresAt:de,userInfo:ue,state:d.state,scope:I.scope}}async function be(e){if(typeof window>"u")throw new Error("oauthHandleRedirect is only available in the browser, unless you provide redirectedUrl");if(typeof localStorage>"u")throw new Error("oauthHandleRedirect requires localStorage to be available, unless you provide nonce and codeVerifier");const t=new URLSearchParams(window.location.search);return t.has("error")?W():t.has("code")?localStorage.getItem("huggingface.co:oauth:nonce")?W():(console.warn("Missing oauth nonce from localStorage. This can happen when the user refreshes the page after logging in, without changing the URL."),!1):!1}async function ye(e){var f;if(typeof window>"u"&&(!(e!=null&&e.redirectUrl)||!(e!=null&&e.clientId)))throw new Error("oauthLogin is only available in the browser, unless you provide clientId and redirectUrl");if(typeof localStorage>"u"&&!(e!=null&&e.localStorage))throw new Error("oauthLogin requires localStorage to be available in the context, unless you provide a localStorage empty object as argument");const t=(e==null?void 0:e.hubUrl)||J,o=`${new URL(t).origin}/.well-known/openid-configuration`,n=await fetch(o,{headers:{Accept:"application/json"}});if(!n.ok)throw await R(n);const a=await n.json(),r=globalThis.crypto.randomUUID(),s=globalThis.crypto.randomUUID()+globalThis.crypto.randomUUID();if(e!=null&&e.localStorage){if(e.localStorage.codeVerifier!==void 0&&e.localStorage.codeVerifier!==null)throw new Error("localStorage.codeVerifier must be initially set to null or undefined, and will be filled by oauthLoginUrl");if(e.localStorage.nonce!==void 0&&e.localStorage.nonce!==null)throw new Error("localStorage.nonce must be initially set to null or undefined, and will be filled by oauthLoginUrl");e.localStorage.codeVerifier=s,e.localStorage.nonce=r}else localStorage.setItem("huggingface.co:oauth:nonce",r),localStorage.setItem("huggingface.co:oauth:code_verifier",s);const c=(e==null?void 0:e.redirectUrl)||(typeof window<"u"?window.location.href:void 0);if(!c)throw new Error("Missing redirectUrl");const w=JSON.stringify({nonce:r,redirectUri:c,state:e==null?void 0:e.state}),d=typeof window<"u"?((f=window.huggingface)==null?void 0:f.variables)??null:null,k=(e==null?void 0:e.clientId)||(d==null?void 0:d.OAUTH_CLIENT_ID);if(!k)throw d?new Error("Missing clientId, please add hf_oauth: true to the README.md's metadata in your static Space"):new Error("Missing clientId");const T=we(new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256",new TextEncoder().encode(s)))).replace(/[+]/g,"-").replace(/[/]/g,"_").replace(/=/g,"");return`${a.authorization_endpoint}?${new URLSearchParams({client_id:k,scope:e==null?void 0:e.scopes,response_type:"code",redirect_uri:c,state:w,code_challenge:T,code_challenge_method:"S256"}).toString()}`}const ve={},Ee=ge,F=document.getElementById("screen-start"),X=document.getElementById("screen-draw"),Y=document.getElementById("screen-results"),ke=document.getElementById("progress-bar"),Ie=document.getElementById("model-status-text"),Se=document.getElementById("model-status"),K=document.getElementById("btn-start"),N=document.getElementById("btn-signin"),Q=document.getElementById("btn-signout"),Le=document.getElementById("round-label"),b=document.getElementById("timer"),Re=document.getElementById("prompt-word"),i=document.getElementById("draw-canvas"),Ue=document.getElementById("btn-clear"),xe=document.getElementById("btn-done"),$=document.getElementById("result-overlay"),_e=document.getElementById("result-icon"),Ce=document.getElementById("result-label"),Te=document.getElementById("final-score"),V=document.getElementById("results-grid"),Be=document.getElementById("btn-again"),Z=document.getElementById("next-round-overlay"),De=document.getElementById("next-round-number"),Ae=document.getElementById("next-round-word"),Pe=document.getElementById("btn-next-round"),ee=document.getElementById("ai-guess"),te=document.getElementById("ai-guess-label"),l=i.getContext("2d");let x=!1;function q(){l.fillStyle="#fff",l.fillRect(0,0,i.width,i.height)}function C(e){const t=i.getBoundingClientRect(),o=i.width/t.width,n=i.height/t.height;return{x:(e.clientX-t.left)*o,y:(e.clientY-t.top)*n}}function oe(e,t){h&&(x=!0,l.beginPath(),l.moveTo(e,t))}function ne(e,t){!x||!h||(l.lineTo(e,t),l.stroke())}function O(){x&&$e(),x=!1}i.addEventListener("mousedown",e=>{const{x:t,y:o}=C(e);oe(t,o)});i.addEventListener("mousemove",e=>{const{x:t,y:o}=C(e);ne(t,o)});i.addEventListener("mouseup",O);i.addEventListener("mouseleave",O);i.addEventListener("touchstart",e=>{e.preventDefault();const t=e.touches[0],o=C(t);oe(o.x,o.y)},{passive:!1});i.addEventListener("touchmove",e=>{e.preventDefault();const t=e.touches[0],o=C(t);ne(o.x,o.y)},{passive:!1});i.addEventListener("touchend",e=>{e.preventDefault(),O()},{passive:!1});function re(){l.lineWidth=4,l.lineCap="round",l.lineJoin="round",l.strokeStyle="#000"}const j=new Worker(new URL("/assets/worker-Dvof_Pv2.js",import.meta.url),{type:"module"});let y=null,v=null,S=!1,g=null,ae=!1;j.onmessage=e=>{const t=e.data;switch(t.type){case"ready":ae=!0,Ie.textContent="Ready!",ke.style.width="100%",K.disabled=!1;break;case"result":y&&(y(t.predictions),y=null,v=null);break;case"error":v?(v(t.message),y=null,v=null):console.error("Worker error:",t.message);break}};function ie(e){return S&&g||(S=!0,g=new Promise((t,o)=>{y=n=>{S=!1,g=null,t(n)},v=n=>{S=!1,g=null,o(n)},j.postMessage({type:"classify",dataUrl:e})})),g}let P=!1,L=null;async function $e(){var e;if(h&&(L=i.toDataURL(),!P)){P=!0;try{for(;L!==null&&h;){const t=L;L=null;const o=await ie(t);if(console.log("live classify:",o.map(n=>`${n.label} (${(n.score*100).toFixed(1)}%)`).join(", ")),!h)break;if(te.textContent=((e=o[0])==null?void 0:e.label)??"",ee.classList.remove("hidden"),o.some(n=>se(n.label,E[u]))){H(o);break}}}catch{}P=!1}}let E=[],u=0,_=[],h=!1,m=20,U=null;function Ne(){return[...Ee].sort(()=>Math.random()-.5).slice(0,6)}function M(e){for(const t of[F,X,Y])t.classList.remove("active");e.classList.add("active")}function qe(){m=20,b.textContent=String(m),b.classList.remove("urgent"),U=setInterval(()=>{m--,b.textContent=String(m),m<=5&&b.classList.add("urgent"),m<=0&&H()},1e3)}function Oe(){U!==null&&(clearInterval(U),U=null)}function se(e,t){const o=e.toLowerCase().trim(),n=t.toLowerCase().trim();return o===n||o===n+"s"||o+"s"===n}function ce(){const e=E[u];h=!0,$.classList.add("hidden"),ee.classList.add("hidden"),te.textContent="",Le.textContent=`Round ${u+1} / 6`,Re.textContent=e,b.classList.remove("urgent"),q(),qe()}async function H(e){var s;if(!h)return;h=!1,Oe();const t=E[u],o=i.toDataURL();let n=[];if(e)n=e;else try{n=await ie(o)}catch(c){console.error("Classification failed:",c)}const a=((s=n[0])==null?void 0:s.label)??"unknown",r=n.some(c=>se(c.label,t));_.push({word:t,correct:r,guess:a,thumbnail:o}),_e.textContent=r?"✓":"✗",Ce.textContent=r?`Yes! It's a ${a}`:`Nope — AI guessed: ${a}`,$.classList.remove("hidden"),setTimeout(()=>{$.classList.add("hidden"),u++,u<6?je():Me()},2e3)}function je(){const e=E[u];De.textContent=`Round ${u+1} / 6`,Ae.textContent=e,Z.classList.remove("hidden")}function Me(){M(Y);const e=_.filter(t=>t.correct).length;Te.textContent=`${e} / 6`,V.innerHTML="";for(const t of _){const o=document.createElement("div");o.className=`result-card ${t.correct?"correct":"wrong"}`;const n=document.createElement("img");n.src=t.thumbnail,n.alt=t.word;const a=document.createElement("div");a.className="card-word",a.textContent=t.word;const r=document.createElement("div");r.className="card-guess",r.textContent=t.guess,o.append(n,a,r),V.appendChild(o)}}function le(){E=Ne(),u=0,_=[],M(X),re(),ce()}K.addEventListener("click",()=>{ae&&le()});Ue.addEventListener("click",q);xe.addEventListener("click",()=>H());Be.addEventListener("click",le);Pe.addEventListener("click",()=>{Z.classList.add("hidden"),ce()});async function He(){try{const t=localStorage.getItem("hf_oauth");if(t){const o=JSON.parse(t);if(new Date(o.accessTokenExpiresAt)>new Date){G(o.accessToken);return}localStorage.removeItem("hf_oauth")}}catch{localStorage.removeItem("hf_oauth")}const e=await be();if(e!=null&&e.accessToken){localStorage.setItem("hf_oauth",JSON.stringify(e)),G(e.accessToken);return}N.classList.remove("hidden")}function G(e){Se.classList.remove("hidden"),N.classList.add("hidden"),Q.classList.remove("hidden"),j.postMessage({type:"init",token:e})}N.addEventListener("click",async()=>{const t=ve.VITE_OAUTH_CLIENT_ID,o=await ye({...t&&{clientId:t},scopes:"inference-api",redirectUrl:window.location.origin+window.location.pathname});window.location.href=o});Q.addEventListener("click",()=>{localStorage.removeItem("hf_oauth"),window.location.reload()});re();q();M(F);He();
|
assets/index-wdrp1RHT.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}body{font-family:system-ui,sans-serif;background:#f5f5f5;min-height:100vh;display:flex;align-items:center;justify-content:center}.screen{display:none;flex-direction:column;align-items:center;gap:16px;padding:32px 24px;max-width:480px;width:100%;text-align:center}.screen.active{display:flex}.hidden{display:none}h1{font-size:2.5rem;font-weight:800;letter-spacing:-1px}#model-status{width:100%}#model-status-text{font-size:.85rem;color:#666;margin-bottom:6px}#progress-bar-wrap{width:100%;height:6px;background:#ddd;border-radius:3px;overflow:hidden}#progress-bar{height:100%;width:0%;background:#333;border-radius:3px;transition:width .2s ease}button{padding:10px 28px;font-size:1rem;font-weight:600;border:2px solid #333;background:#333;color:#fff;border-radius:8px;cursor:pointer;transition:background .15s,color .15s}button:hover:not(:disabled){background:#fff;color:#333}button:disabled{opacity:.4;cursor:not-allowed}button.secondary{background:transparent;border-color:#aaa;color:#666;font-size:.8rem;padding:6px 16px}button.secondary:hover:not(:disabled){background:#eee;color:#333}#draw-header{width:100%;display:flex;justify-content:space-between;align-items:center;font-weight:600;font-size:.95rem}#timer{font-size:1.6rem;font-weight:800;width:2.5ch;text-align:right}#timer.urgent{color:#c00}#prompt-text{font-size:1.15rem}#prompt-text strong{font-size:1.5rem}#draw-canvas{border:2px solid #333;border-radius:8px;background:#fff;touch-action:none;cursor:crosshair;max-width:100%}#draw-controls{display:flex;gap:12px}#ai-guess{font-size:.85rem;color:#666;min-height:1.2em}#ai-guess.hidden{visibility:hidden;display:block}#result-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;color:#fff;font-size:1.2rem;font-weight:600}#result-overlay.hidden{display:none}#result-icon{font-size:4rem}#next-round-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#000000bf;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;color:#fff;font-size:1.1rem;font-weight:600}#next-round-overlay.hidden{display:none}#next-round-number{font-size:.95rem;opacity:.7;font-weight:400}#next-round-word{font-size:2.5rem;font-weight:800}h2{font-size:2rem;font-weight:800}#final-score{font-size:1.3rem;font-weight:700}#results-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;width:100%}.result-card{display:flex;flex-direction:column;align-items:center;gap:4px;background:#fff;border:2px solid #ddd;border-radius:8px;padding:8px;font-size:.75rem}.result-card img{width:100%;aspect-ratio:1;border-radius:4px}.result-card .card-word{font-weight:700;text-transform:capitalize}.result-card .card-guess{color:#666}.result-card.correct{border-color:#2a2}.result-card.wrong{border-color:#c00}
|
assets/worker-Dvof_Pv2.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
index.html
CHANGED
|
@@ -4,19 +4,21 @@
|
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
<title>Quick Draw</title>
|
| 7 |
-
<script type="module" crossorigin src="/assets/index-
|
| 8 |
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
| 9 |
</head>
|
| 10 |
<body>
|
| 11 |
<!-- Start screen -->
|
| 12 |
<div id="screen-start" class="screen active">
|
| 13 |
<h1>Quick Draw</h1>
|
| 14 |
<p>Draw 6 objects in 20 seconds each.<br />Can the AI guess what you drew?</p>
|
| 15 |
-
<
|
| 16 |
-
|
|
|
|
| 17 |
<div id="progress-bar-wrap"><div id="progress-bar"></div></div>
|
| 18 |
</div>
|
| 19 |
<button id="btn-start" disabled>Start Game</button>
|
|
|
|
| 20 |
</div>
|
| 21 |
|
| 22 |
<!-- Drawing screen -->
|
|
|
|
| 4 |
<meta charset="UTF-8" />
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
<title>Quick Draw</title>
|
| 7 |
+
<script type="module" crossorigin src="/assets/index-ChKWcDIf.js"></script>
|
| 8 |
+
<link rel="stylesheet" crossorigin href="/assets/index-wdrp1RHT.css">
|
| 9 |
</head>
|
| 10 |
<body>
|
| 11 |
<!-- Start screen -->
|
| 12 |
<div id="screen-start" class="screen active">
|
| 13 |
<h1>Quick Draw</h1>
|
| 14 |
<p>Draw 6 objects in 20 seconds each.<br />Can the AI guess what you drew?</p>
|
| 15 |
+
<button id="btn-signin" class="hidden">Sign in with Hugging Face</button>
|
| 16 |
+
<div id="model-status" class="hidden">
|
| 17 |
+
<p id="model-status-text">Connecting…</p>
|
| 18 |
<div id="progress-bar-wrap"><div id="progress-bar"></div></div>
|
| 19 |
</div>
|
| 20 |
<button id="btn-start" disabled>Start Game</button>
|
| 21 |
+
<button id="btn-signout" class="hidden secondary">Sign out</button>
|
| 22 |
</div>
|
| 23 |
|
| 24 |
<!-- Drawing screen -->
|