@onceworlds/cli 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/emulator.js CHANGED
@@ -1,4 +1,6 @@
1
- "use strict";(()=>{var Te=["#f6dcc5","#ebc29f","#d4a07a","#b07a55","#875839","#5e3d29","#93c9bb","#a8c595","#94bcd3","#ab9bd9","#dca3ad","#b3bccb"],ce=["#c95f56","#dc8a4f","#e2bd52","#9cc27a","#5a8a5e","#4f9a8e","#6fb7c8","#5b87c5","#465089","#8b68a8","#dc8fae","#f2eee6","#a9a8ad","#5d5c63","#2b2a30","#80604d"],De=["Happy","Grin","Shades","Wink","Surprised","Determined","Joyful","Shy"],Oe=["None","Sprout","Cap","Beanie","Crown","Headphones","Horns","Antenna","Bow","Halo","Party hat","Cat ears","Short hair","Tuft","Bob","Spikes","Bun","Curls","Long","Mop"];var _e=["Plain","Band","Spots","Stripes","Star"];var wo={skin:Te.length,shirt:ce.length,pants:ce.length,face:De.length,hat:Oe.length,top:_e.length},jt=[[5,6],[3,4],[6,7],[9,8],[10,0],[12,13]];function je(t){let e=2166136261;for(let h of t)e=Math.imul(e^h.charCodeAt(0),16777619)>>>0;let o=h=>(e=Math.imul(e^e>>>13,2654435761)>>>0,e%h),r=o(Te.length),n=r>=6?jt[r-6][o(2)]:o(ce.length),a=o(2)===0?n:[8,13,14,15][o(4)],i=o(5)===0?1:12+o(Oe.length-12),s=o(2)===0?0:o(_e.length);return{skin:r,shirt:n,pants:a,face:o(De.length),hat:i,top:s}}var S={roomMaxPlayersDefault:16,roomMaxPlayersCap:30,teamsMax:8,messageBytes:16*1024,presenceBytes:1024,stateKeyLength:64,stateValueBytes:16*1024,stateKeys:256,privateKeys:16,privateValueBytes:4*1024,privateBytesPerPlayer:8*1024,messagesPerSecond:60,messagesPerSecondMin:10,roomBytesPerSecond:128*1024,roomBytesPerSecondMin:16*1024,presenceHz:20,presenceHzMin:5,roomMessagesPerSecond:900,roomBytesPerSecondTotal:2*1024*1024,matchCountdownMs:3e3,matchCountdownMaxMs:1e4,matchIdleMs:45e3,matchAbandonMs:12e4,idleAfterMs:3e4,idleAbandonMs:5*6e4,rankedPairMatchesPerDay:5,chatLength:200,chatIntervalMs:750,chatHistory:50,chatChannelsPerPlayer:10,saveValueBytes:64*1024,saveKeysPerGame:100,saveBytesPerGame:1024*1024,guestSaveBytesPerGame:128*1024,serverDataKeys:128,serverDataBytes:512*1024,serverDataServersPerGame:5e3,serverDataBytesPerGame:64*1024*1024,serverDataIdleDays:120,gameDataKeys:32,gameDataListMax:100,gameDataItemBytes:1024,gameDataValueBytes:8*1024,gameDataMapFields:1e3,gameDataMapPerPlayer:100,gameDataNumberMax:1e15,gameDataWritesPerMinute:30,deployFiles:2e3,deployFileBytes:25*1024*1024,deployHtmlBytes:10*1024*1024,deployPathLength:200,deployTotalBytes:100*1024*1024,envVars:50,envValueBytes:4*1024,envTotalBytes:16*1024,proxyRequestBytes:1024*1024,proxyTextRequestBytes:256*1024,proxySpeechRequestBytes:16*1024,proxyResponseBytes:10*1024*1024,proxyMaxOutputTokens:4096,proxyCallsPerDay:2e3,proxyCallsPerDayMax:1e5,proxyCallsPerPlayerPerDay:100,proxyCallsPerNetworkPerDay:1e3,proxyMediaCallsPerDay:100,proxyMediaCallsPerDayMax:1e4,proxyMediaCallsPerPlayerPerDay:20,proxyMediaCallsPerNetworkPerDay:25,proxyUnitsPerDay:2e6,proxyUnitsPerDayMax:1e8,proxyUnitsPerPlayerPerDay:25e4,proxyUnitsPerGuestPerDay:1e5,proxyUnitsPerNetworkPerDay:5e5,errorReportsPerPage:10,consoleLineLength:2e3,consoleLinesPerSecond:50,gameNameLength:60,gameDescriptionLength:1e3,galleryItems:5,mediaImageBytes:5*1024*1024,mediaVideoBytes:30*1024*1024,mediaGifBytes:1024*1024,mediaGifSide:512,mediaUploadsPerDay:200,mediaBytesPerDay:500*1024*1024,badgesPerGame:50,controlHints:12,controlHintKeys:4,controlKeyLength:12,controlActionLength:40,helpLength:400,badgeNameLength:50,badgeDescriptionLength:200,leaderboardsPerGame:25,leaderboardTop:100,gamesPerOwner:50,gamesCreatedPerCreatorPerDay:3,uploadAccountAgeMs:10080*6e4,deploysPerOwnerPerDay:100,draftsPerOwnerPerDay:1e3,draftsKeptPerGame:3,cliTokensPerAccount:10,cliDeviceCodeSeconds:600,deploymentsKeptPerGame:10,deployBytesPerOwnerPerDay:2*1024*1024*1024,deployEntriesPerOwnerPerDay:1e5,bioLength:500,exportRows:2e3,exportSaveChars:4*1024*1024,exportEveryMs:60*6e4,friendsMax:200,friendRequestsMax:100,friendRequestsIncomingMax:50,friendRequestsPerDay:20,friendRequestsPerNetworkPerDay:120,friendRequestPushesPerDay:5,passwordMinLength:8,passwordMaxLength:72,signupsPerNetworkPerDay:100,signupsPerWidePerDay:300,guestsPerNetworkPerDay:300,guestsPerWidePerDay:1500,visitsPerNetworkPerDay:10,visitSeconds:10,errorsPerDeployment:100,controlButtons:4,controlLabelLength:12,partySize:6,partyChatHistory:50,messageLength:500,messagesPerPage:50,groupChatMembers:20,groupChatNameLength:40,conversationsListed:50,notificationsListed:50,invitesPerRequest:10,inviteLiveMs:30*6e4,partyInviteMs:60*6e4};var Be=/^[a-z0-9]{12}$/,V=2;function ge(t){return`${t.mode}.${t.max}.${t.teams}.${t.ranked?1:0}${t.min!==V?`.${t.min}`:""}`}var It=/^pub:([a-z0-9-]+)\.(\d+)\.(\d)\.([01])(?:\.(\d+))?:(\d+)$/;function Ne(t){let e=It.exec(t);if(!e)return null;let o={mode:e[1],max:Number(e[2]),teams:Number(e[3]),ranked:e[4]==="1",min:e[5]===void 0?V:Number(e[5])};return{...o,name:ge(o),n:Number(e[6])}}function Ge(t,e,o){let r=typeof t=="string"?Number(t):t;return typeof r!="number"||!Number.isInteger(r)?Math.min(o,e):Math.min(e,Math.max(1,r))}var Ie=t=>t.replace(/[\u0000-\u001f\u007f]/g," ").replace(/\s+/g," ").trim();var Bt=/^[a-z0-9][a-z0-9-]{0,19}$/;function Ue(t){if(!t||typeof t!="object")return null;let e=t,o=[];for(let n of Array.isArray(e.buttons)?e.buttons:[]){if(o.length>=S.controlButtons)break;let{id:a,label:i}=n??{};if(typeof a!="string"||!Bt.test(a)||o.some(h=>h.id===a))continue;let s=typeof i=="string"?i.replace(/[\u0000-\u001f\u007f]/g,"").replace(/\s+/g," ").trim().slice(0,S.controlLabelLength).trim():"";o.push({id:a,label:s||a})}let r=e.stick===!0;return r||o.length>0?{stick:r,zone:e.zone==="corner"?"corner":"wide",buttons:o}:null}var U="host:ow.settings",Nt=/^[a-z][a-zA-Z0-9]{0,15}$/;function He(t){if(!Array.isArray(t))return[];let e=[];for(let o of t){if(e.length>=6)break;let{id:r,label:n,options:a,default:i}=o??{};if(typeof r!="string"||!Nt.test(r)||e.some(g=>g.id===r)||!Array.isArray(a))continue;let s=[];for(let g of a){let l=typeof g=="object"&&g!==null?g.value:g;if(typeof l!="string"&&typeof l!="number"||typeof l=="number"&&!Number.isFinite(l)||s.length>=8||s.some(m=>m.value===l))continue;let y=typeof g=="object"&&g!==null&&typeof g.label=="string"?g.label:String(l);s.push({value:l,label:Ie(y).slice(0,20)||String(l)})}if(s.length<2)continue;let h=typeof n=="string"?Ie(n).slice(0,24):"";e.push({id:r,label:h||r,options:s,default:s.some(g=>g.value===i)?i:s[0].value})}return e}function Fe(t,e){let o=e!==null&&typeof e=="object"?e[t.id]:void 0;return t.options.some(r=>r.value===o)?o:t.default}var he='{"t":"ping"}';var qe=4001,Ke=4003,Ve=4008,We=4006;var Ye="onceworlds:hello",Je="onceworlds:connect",Gt=/^[a-z0-9]{1,32}~(?:(?:0|[1-9]\d{0,3})\.(?:0|[1-9]\d{0,4})\.(?:0|[1-9]\d{0,5}))?~[0-9a-z]{1,11}~[lp]~[A-Za-z0-9_-]{43}$/;function Xe(t){let e=t!==null&&typeof t=="object"?t.build:void 0;return typeof e=="string"&&Gt.test(e)?e:null}var Ze="onceworlds-console";var Qe="allow-scripts allow-pointer-lock allow-forms allow-orientation-lock",et=["autoplay","gamepad","screen-wake-lock","accelerometer","gyroscope"].map(t=>`${t} *`).join("; ");var tt=new Set(["server","join","deploy","watch","player","embed","k","console","tester","live","demo",Ze]);function ot(t){return t?.ownCountdown!==!0}var Ut=/^#(?:[0-9a-f]{3}){1,2}$/i,$={panel:"#111216",text:"#f7f7f8",accent:"#d33e00"},ue=4.5,me=3,W=["#4ade80","#15803d"];function nt(t){let e=[];if(t==null)return{look:null,notes:e};if(typeof t!="object")return{look:null,notes:["a look is { accent, panel, text } or null"]};let o=t,r=l=>{let y=o[l];return y==null?null:typeof y=="string"&&Ut.test(y)?at(y):(e.push(`${l} is not #rgb or #rrggbb`),null)},n=r("panel"),a=r("text"),i=r("accent");if(n||a){let l=E(a??$.text,n??$.panel);l<ue&&(e.push(`text on panel is ${l.toFixed(1)}:1, under ${ue}:1: the platform's are used`),n=a=null)}let s=n??$.panel,h=a??$.text;if(i){let l=E(i,s);l<me&&(e.push(`accent on panel is ${l.toFixed(1)}:1, under ${me}:1: the platform's is used`),i=null)}if(!i&&n&&E($.accent,n)<me&&(i=h),!n&&!a&&!i)return{look:null,notes:e};let g=i?Ht(i):null;return{look:{panel:n,text:a,muted:n||a?Ft(h,s):null,accent:i,accentHover:i?it(i,g==="#ffffff"?"#000000":"#ffffff",.14):null,onAccent:g,ok:n?E(W[0],n)>=E(W[1],n)?W[0]:W[1]:null},notes:e}}function at(t){let e=t.slice(1).toLowerCase();return`#${e.length===3?[...e].map(o=>o+o).join(""):e}`}function H(t){let e=at(t);return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function rt(t){let[e,o,r]=H(t).map(n=>{let a=n/255;return a<=.04045?a/12.92:((a+.055)/1.055)**2.4});return .2126*e+.7152*o+.0722*r}function E(t,e){let[o,r]=[rt(t),rt(e)].sort((n,a)=>a-n);return(o+.05)/(r+.05)}function Ht(t){return E(t,"#000000")>E(t,"#ffffff")?"#000000":"#ffffff"}function it(t,e,o){let[r,n]=[H(t),H(e)];return`#${r.map((a,i)=>Math.round(a+(n[i]-a)*o).toString(16).padStart(2,"0")).join("")}`}function Ft(t,e){for(let o=.3;o>.001;o-=.05){let r=it(t,e,o);if(E(r,e)>=ue)return r}return t}var Y=class{port=null;handlers;events;onConnect;solo;demo;onActivity;constructor(e,o,r,n,a={}){this.handlers=o,this.events=r,this.onConnect=n,this.solo=a.solo===!0,this.demo=a.demo===!0,this.onActivity=a.onActivity??null,window.addEventListener("message",i=>{i.source!==e.contentWindow||i.origin!=="null"||i.data?.type===Ye&&this.connect(i.source,Xe(i.data))})}activity(e,o){try{this.onActivity?.(e,o)}catch{}}emit(e,o){this.port?.postMessage({kind:"event",name:e,data:o})}connect(e,o){this.port?.close();let r=new MessageChannel,n=r.port1;this.port=n,n.onmessage=i=>this.receive(n,i.data);let a={type:Je,...this.solo?{solo:!0}:{},...this.demo?{demo:!0}:{}};e.postMessage(a,"*",[r.port2]),this.onConnect(o)}async receive(e,o){if(!(e!==this.port||!o||typeof o!="object")){if(o.kind==="event"){Object.hasOwn(this.events,o.name)&&(this.events[o.name](o.data),this.activity(String(o.name),null));return}if(o.kind==="req")try{if(!Object.hasOwn(this.handlers,o.method))throw new Error(`Unknown method: ${String(o.method)}`);let r=this.handlers[o.method],n=await r(o.params);e.postMessage({kind:"res",id:o.id,ok:!0,result:n??null}),this.activity(String(o.method),null)}catch(r){let n=r instanceof Error?r.message:String(r);e.postMessage({kind:"res",id:o.id,ok:!1,error:n}),this.activity(String(o.method),n)}}}};var J=class{pressed=new Set;press(e){this.pressed.add(e)}take(e){let o=new Set(e),r=!1;for(let n of this.pressed)o.has(n)||(o.add(n),r=!0);return this.pressed.clear(),{buttons:[...o],owed:r}}};var st=["--ow-panel","--ow-face-edge","--ow-hover","--ow-on-accent","--text","--muted","--line","--line-strong","--fill","--fill-strong","--ok","--accent-fill","--accent-fill-hover","--accent-hover"],lt=["--ow-ctl-edge","--ow-ctl-fill","--ow-ctl-stick","--ow-ctl-knob","--ow-ctl-label","--ow-ctl-shadow","--ow-ctl-held","--ow-ctl-main","--ow-ctl-main-edge","--ow-ctl-main-label","--ow-ctl-main-shadow","--ow-ctl-main-held"];function x(t,e){return`rgba(${H(t).join(", ")}, ${e})`}function pt(t){let e={};if(!t)return e;if(t.panel&&(e["--ow-panel"]=t.panel,e["--ow-face-edge"]=t.panel),t.ok&&(e["--ok"]=t.ok),t.panel||t.text){let o=t.text??$.text;t.text&&(e["--text"]=t.text),t.muted&&(e["--muted"]=t.muted),e["--line"]=x(o,.09),e["--line-strong"]=x(o,.16),e["--fill"]=x(o,.06),e["--fill-strong"]=x(o,.1),e["--ow-hover"]=x(o,.16)}return t.accent&&t.accentHover&&t.onAccent&&(e["--accent-fill"]=t.accent,e["--accent-fill-hover"]=t.accentHover,e["--accent-hover"]=t.accent,e["--ow-on-accent"]=t.onAccent),e}function dt(t){let e={};return t&&(t.text&&(e["--ow-ctl-edge"]=x(t.text,.4),e["--ow-ctl-knob"]=x(t.text,.9),e["--ow-ctl-label"]=t.text,e["--ow-ctl-held"]=x(t.text,.35)),t.panel&&(e["--ow-ctl-fill"]=x(t.panel,.4),e["--ow-ctl-stick"]=x(t.panel,.3),e["--ow-ctl-shadow"]=x(t.panel,.5)),t.accent&&t.accentHover&&t.onAccent&&(e["--ow-ctl-main"]=x(t.accent,.85),e["--ow-ctl-main-edge"]=t.accent,e["--ow-ctl-main-label"]=t.onAccent,e["--ow-ctl-main-shadow"]="none",e["--ow-ctl-main-held"]=t.accentHover)),e}function X(t,e,o){for(let r of e)Object.hasOwn(o,r)?t.style.setProperty(r,o[r]):t.style.removeProperty(r);t.toggleAttribute("data-look",e.some(r=>Object.hasOwn(o,r)))}var M=52,xe=.12,fe=96,qt=400,Kt=2e4,Z=class{parent;root;zone;base;knob;buttonBox;send;onLayout;layout=null;touch;blocked=!1;keyboard=!1;stickPointer=null;center={x:0,y:0};x=0;y=0;buttons=new Map;held=new Map;fingers=new Map;report=new J;queued=0;sent="";placed={stick:null,buttons:null};constructor(e,o,r=()=>{}){this.send=o,this.onLayout=r,this.parent=e,this.touch=matchMedia("(pointer: coarse)").matches,this.root=L("div","ow-controls"),this.root.hidden=!0,this.zone=L("div","ow-stick-zone"),this.base=L("div","ow-stick"),this.knob=L("div","ow-stick-knob"),this.base.append(this.knob),this.zone.append(this.base),this.buttonBox=L("div","ow-control-buttons"),this.root.append(this.zone,this.buttonBox),e.append(this.root),this.zone.addEventListener("pointerdown",n=>this.stickDown(n)),this.zone.addEventListener("pointermove",n=>this.stickMove(n));for(let n of["pointerup","pointercancel","lostpointercapture"])this.zone.addEventListener(n,a=>this.stickUp(a));this.root.addEventListener("contextmenu",n=>n.preventDefault())}setLayout(e){this.layout=Ue(e);let o=this.buttons;this.buttons=new Map,(this.layout?.buttons??[]).forEach((r,n)=>{let a=o.get(r.id)??this.button(r.id);o.delete(r.id),a.className=`ow-control-btn ow-control-btn-${n}`,a.classList.toggle("ow-held",[...this.held.values()].includes(r.id)),a.textContent=r.label,a.isConnected||this.buttonBox.append(a),this.buttons.set(r.id,a)});for(let[r,n]of o){for(let[a,i]of this.held)i===r&&this.letGo(a);n.remove()}this.zone.hidden=!this.layout?.stick,this.zone.classList.toggle("ow-stick-corner",this.layout?.zone==="corner"),this.zone.hidden&&this.stickPointer!==null&&this.letGo(this.stickPointer),this.render(),this.onLayout()}setLook(e){X(this.root,lt,e)}reservedBoxes(){if(this.root.hidden)return this.blocked&&this.layout&&this.touch&&!this.keyboard?this.placed:{stick:null,buttons:null};let e=this.zone.hidden?null:gt(this.base),o=null;for(let r of this.buttons.values()){let n=gt(r);!n.width||!n.height||(o=o?Wt(o,n):n)}return this.placed={stick:e,buttons:o},this.placed}setTouch(e){this.touch=e,this.render()}setKeyboard(e){this.keyboard=e,this.render()}setBlocked(e){this.blocked=e,this.render()}render(){let e=!!this.layout&&this.touch&&!this.blocked&&!this.keyboard;this.root.hidden!==!e&&(e||this.reset(),this.root.hidden=!e,this.onLayout())}reset(){for(let e of[...this.held.keys()])this.letGo(e);this.stickPointer!==null&&this.letGo(this.stickPointer),this.endStick()}letGo(e){e===this.stickPointer&&this.endStick();let o=this.held.get(e);this.held.delete(e),o!==void 0&&![...this.held.values()].includes(o)&&this.buttons.get(o)?.classList.remove("ow-held");let r=this.fingers.get(e);this.fingers.delete(e),r&&Vt(this.parent,e,r),this.changed()}button(e){let o=L("button","ow-control-btn");o.type="button",o.tabIndex=-1,o.addEventListener("pointerdown",n=>{n.preventDefault(),ct(o,n.pointerId),o.classList.add("ow-held"),this.held.set(n.pointerId,e),this.report.press(e),this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY}),this.changed()}),o.addEventListener("pointermove",n=>{this.held.get(n.pointerId)===e&&this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY})});let r=n=>{this.held.get(n.pointerId)===e&&(this.held.delete(n.pointerId),this.fingers.delete(n.pointerId),[...this.held.values()].includes(e)||o.classList.remove("ow-held"),this.changed())};for(let n of["pointerup","pointercancel","lostpointercapture"])o.addEventListener(n,a=>r(a));return o}stickDown(e){if(this.stickPointer!==null)return;e.preventDefault(),ct(this.zone,e.pointerId),this.stickPointer=e.pointerId,this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=this.zone.getBoundingClientRect(),r=this.base.getBoundingClientRect(),n=M+8;this.center={x:Math.min(Math.max(e.clientX,o.left+n),o.right-n),y:Math.min(Math.max(e.clientY,o.top+n),o.bottom-n)},this.base.style.transform=`translate(${this.center.x-(r.left+r.width/2)}px, ${this.center.y-(r.top+r.height/2)}px)`,this.base.classList.add("ow-active"),this.stickMove(e)}stickMove(e){if(e.pointerId!==this.stickPointer)return;this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=e.clientX-this.center.x,r=e.clientY-this.center.y,n=Math.hypot(o,r);n>M&&(o=o/n*M,r=r/n*M),this.knob.style.transform=`translate(${o}px, ${r}px)`;let a=Math.min(n,M)/M,i=a<xe?0:(a-xe)/(1-xe)/(a||1);this.x=ht(o/M*i),this.y=ht(r/M*i),this.changed()}stickUp(e){e.pointerId===this.stickPointer&&(this.fingers.delete(e.pointerId),this.endStick())}endStick(){this.stickPointer=null,this.x=0,this.y=0,this.base.classList.remove("ow-active"),this.base.style.transform="",this.knob.style.transform="",this.changed()}changed(){this.queued||(this.queued=requestAnimationFrame(()=>{this.queued=0;let{buttons:e,owed:o}=this.report.take(this.held.values()),r={x:this.x,y:this.y,buttons:e};o&&this.changed();let n=JSON.stringify(r);n!==this.sent&&(this.sent=n,this.send(r))}))}};function Vt(t,e,o){let r=L("div","ow-tap-shield");r.style.left=`${o.x-fe/2}px`,r.style.top=`${o.y-fe/2}px`,r.style.width=r.style.height=`${fe}px`,t.append(r);let n=setTimeout(()=>r.remove(),Kt),a=()=>{clearTimeout(n),n=setTimeout(()=>r.remove(),qt)};for(let i of["pointerup","pointercancel","lostpointercapture"])r.addEventListener(i,s=>s.pointerId===e&&a());r.addEventListener("contextmenu",i=>i.preventDefault());try{r.setPointerCapture(e)}catch{a()}}function ct(t,e){try{t.setPointerCapture(e)}catch{}}function gt(t){let e=t.getBoundingClientRect(),o=getComputedStyle(t).transform;if(!o||o==="none")return e;let r=new DOMMatrixReadOnly(o);if(r.b||r.c||!r.a||!r.d)return e;let n=e.width/Math.abs(r.a),a=e.height/Math.abs(r.d),i=e.left+e.width/2-r.e,s=e.top+e.height/2-r.f;return{left:i-n/2,top:s-a/2,width:n,height:a}}function Wt(t,e){let o=Math.min(t.left,e.left),r=Math.min(t.top,e.top);return{left:o,top:r,width:Math.max(t.left+t.width,e.left+e.width)-o,height:Math.max(t.top+t.height,e.top+e.height)-r}}function ht(t){return Math.round(t*1e3)/1e3}function L(t,e,o){let r=document.createElement(t);return r.className=e,o!==void 0&&(r.textContent=o),r}function Yt(t,e){return t!=="lobby"?{surface:t,hidden:!1}:{surface:e?"none":"lobby",hidden:e}}var be=t=>Math.max(0,Math.ceil(t/1e3)),we=t=>{let e=t.slice(0,2).map(o=>o.name);return t.length>2?`${e.join(", ")} +${t.length-2}`:e.join(", ")};function Jt(t){let{you:e,host:o,kind:r,match:n,now:a}=t,i=[...t.players].sort((p,k)=>p.id===e?-1:k.id===e?1:p.id===o?-1:k.id===o?1:p.name.localeCompare(k.name)).map(p=>({id:p.id,name:p.name,ready:!!p.ready,host:p.id===o,you:p.id===e,away:p.connected===!1,idle:p.connected!==!1&&!!p.idle})),s=t.players.filter(p=>p.connected!==!1),h=t.players.find(p=>p.id===e),g=o===e&&n.phase==="lobby",l=t.schema.map(p=>({id:p.id,label:p.label,value:Fe(p,t.written),options:p.options,editable:g})),y={n:s.filter(p=>p.ready||r!=="public"&&p.id===o).length,of:s.length},m={surface:"none",rows:i,count:`${t.players.length} / ${t.max}`,ready:y,status:"",action:{kind:"none",label:"",disabled:!0},settings:l,seconds:null},Ce=n.participants?.includes(e)??!1,Ae=o===e&&r!=="public";if(n.phase==="starting"){if(!Ce)return{...m,surface:"watching",status:"Watching"};let p=Ae?{kind:"stop",label:"Stop",disabled:!1}:{kind:"unready",label:"Not ready",disabled:!1};return t.ownCountdown?{...m,surface:"countdown",action:p,seconds:null,status:"Get ready"}:{...m,surface:"countdown",action:p,seconds:Math.max(1,be((n.startsAt??a)-a)),status:"Get ready"}}if(n.phase==="playing"){if(n.paused){let p=s.filter(k=>n.participants?.includes(k.id)).length;return n.paused.reason==="host"?{...m,surface:"paused",status:"Paused"}:{...m,surface:"paused",seconds:be(n.paused.since+S.matchAbandonMs-a),status:`Waiting for players \xB7 ${p} / ${n.min}`}}return Ce?m:{...m,surface:"watching",status:"Watching"}}let P=s.filter(p=>!p.ready&&(r==="public"||p.id!==o));if(m.surface="lobby",Ae){let p=s.length<n.min;return m.action={kind:"start",label:"Start",disabled:p||P.length>0},m.status=p?`Need ${n.min} players`:P.length?`Waiting for ${we(P)}`:"",m}if(m.action={kind:h?.ready?"unready":"ready",label:h?.ready?"Not ready":"Ready",disabled:!1},r==="public")s.length<n.min?m.status=`Need ${n.min} players`:n.waitUntil!==void 0&&P.length?(m.seconds=be(n.waitUntil-a),m.status=`${we(P)} \xB7 ${m.seconds}s`):m.status=`${s.length-P.length} / ${s.length} ready`;else{let p=P.filter(k=>k.id!==e);m.status=h?.ready?p.length?`Waiting for ${we(p)}`:`Waiting for ${t.players.find(k=>k.id===o)?.name??"the host"}`:""}return m}function c(t,e="",o){let r=document.createElement(t);return e&&(r.className=e),o!==void 0&&(r.textContent=o),r}var Q=class{mode=null;ownCountdown=!1;hiddenByGame=!1;state=null;schema=[];timer=0;opts;root;card;title;count;list;settingsBox;status;action;invite;bar;barFaces;barStatus;barAction;countdown;numeral;cancel;pause;pauseStatus;pauseTimer;chip;last=null;lastNumeral=-1;listSignature="";settingsSignature="";faceSignature="";constructor(e,o){this.opts=o,this.root=c("div","ow-lobby"),this.root.hidden=!0,this.card=c("section","ow-lobby-card"),this.card.setAttribute("aria-label","Lobby");let r=c("header","ow-lobby-head");this.title=c("h2","","Lobby"),this.count=c("span","ow-lobby-count"),r.append(this.title,this.count),this.list=c("ul","ow-lobby-players"),this.settingsBox=c("div","ow-lobby-settings"),this.status=c("p","ow-lobby-status"),this.status.setAttribute("role","status"),this.action=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.invite=this.button("ow-btn ow-lobby-invite",()=>this.opts.onInvite()),this.invite.textContent="Invite";let n=c("div","ow-lobby-actions");n.append(this.action,this.invite),this.card.append(r,this.list,this.settingsBox,this.status,n),this.bar=c("div","ow-lobby-bar"),this.barFaces=c("span","ow-lobby-faces"),this.barStatus=c("span","ow-lobby-bar-status"),this.barStatus.setAttribute("role","status"),this.barAction=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.bar.append(this.barFaces,this.barStatus,this.barAction),this.countdown=c("div","ow-lobby-countdown"),this.numeral=c("b"),this.numeral.setAttribute("aria-hidden","true");let a=c("span","","Get ready");a.setAttribute("aria-hidden","true"),this.cancel=this.button("ow-btn ow-lobby-cancel",()=>this.press()),this.countdown.append(this.numeral,a,this.cancel),this.pause=c("div","ow-lobby-pause");let i=c("div","ow-lobby-pause-box");this.pauseStatus=c("p","ow-lobby-pause-status"),this.pauseStatus.setAttribute("role","status"),this.pauseTimer=c("p","ow-lobby-pause-timer"),i.append(this.pauseStatus,this.pauseTimer),this.pause.append(i),this.chip=c("div","ow-lobby-chip"),this.chip.setAttribute("role","status"),this.root.append(this.card,this.bar,this.countdown,this.pause,this.chip),e.append(this.root)}setSchema(e){this.schema=e,this.render()}enable(e,o={}){this.mode=e,this.ownCountdown=o.ownCountdown===!0,this.root.dataset.mode=e??"",e||this.reset(),this.render()}setLook(e){X(this.root,st,e)}reservedBox(){if(this.root.hidden)return null;let e=!this.countdown.hidden&&this.countdown.classList.contains("ow-lobby-countdown-bare"),o=this.bar.hidden?e&&!this.cancel.hidden?this.cancel:null:this.bar;return o?o.getBoundingClientRect():null}setHidden(e){this.hiddenByGame=e,this.render()}setRoom(e,o=0){if(!e)return this.reset();this.state={you:e.you,host:e.host,kind:e.room.startsWith("private:")?"private":e.room.startsWith("room:")?"named":"public",max:Math.max(o,e.players.length),players:e.players.map(r=>({...r})),match:e.match??{phase:"lobby",n:0,min:1},written:e.state?.[U]},this.render()}handle(e){let o=this.state;if(o){switch(e.t){case"join":o.players=[...o.players.filter(r=>r.id!==e.player.id),{...e.player}];break;case"leave":o.players=o.players.filter(r=>r.id!==e.id);break;case"away":o.players=o.players.map(r=>r.id===e.id?{...r,connected:!1}:r);break;case"back":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{connected:n,...a}=r;return a});break;case"ready":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{ready:n,...a}=r;return e.ready?{...a,ready:!0}:a});break;case"unready":o.players=o.players.map(({ready:r,...n})=>n);break;case"host":o.host=e.id;break;case"idle":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{idle:n,...a}=r;return e.idle?{...a,idle:!0}:a});break;case"name":o.players=o.players.map(r=>r.id===e.id?{...r,name:e.name}:r);break;case"match":o.match=e.match;break;case"state":if(e.k!==U)return;o.written=e.v;break;default:return}this.render()}}chooseSetting(e,o){let r=this.state,n=this.schema.find(i=>i.id===e);if(!r||!n||!n.options.some(i=>i.value===o))return null;let a={...r.written!==null&&typeof r.written=="object"?r.written:{},[e]:o};return r.written=a,this.render(),a}setReadyLocal(e){let o=this.state?.players.find(r=>r.id===this.state?.you);o&&(e?o.ready=!0:delete o.ready,this.render())}button(e,o){let r=c("button",e);return r.type="button",r.addEventListener("pointerdown",n=>n.preventDefault()),r.addEventListener("click",o),r}press(){let e=this.last?.action.kind;e==="start"?this.opts.onStart():e==="stop"?this.opts.onStop():e==="ready"?(this.setReadyLocal(!0),this.opts.onReady(!0)):e==="unready"&&(this.setReadyLocal(!1),this.opts.onReady(!1))}reset(){this.state=null,this.last=null,this.hiddenByGame=!1,window.clearInterval(this.timer),this.timer=0,this.root.hidden=!0,this.opts.onLayout?.()}render(){this.draw(),this.opts.onLayout?.()}draw(){if(!this.mode||!this.state){this.root.hidden=!0;return}let e=Jt({...this.state,schema:this.schema,now:this.opts.now(),ownCountdown:this.ownCountdown});this.last=e;let o=Yt(e.surface,this.hiddenByGame);this.hiddenByGame=o.hidden;let r=o.surface==="lobby";if(this.root.hidden=o.surface==="none",this.card.hidden=!(r&&this.mode==="card"),this.bar.hidden=!(r&&this.mode==="bar"),this.countdown.hidden=e.surface!=="countdown",this.countdown.classList.toggle("ow-lobby-countdown-bare",e.surface==="countdown"&&e.seconds===null),this.pause.hidden=e.surface!=="paused",this.chip.hidden=e.surface!=="watching",this.root.classList.toggle("ow-lobby-dim",r&&this.mode==="card"),r&&this.mode==="card"&&this.renderCard(e),r&&this.mode==="bar"&&this.renderBar(e),e.surface==="countdown"&&e.seconds!==null&&e.seconds!==this.lastNumeral&&(this.lastNumeral=e.seconds,this.numeral.textContent=String(e.seconds),this.numeral.style.animation="none",this.numeral.offsetWidth,this.numeral.style.animation=""),e.surface==="countdown"&&(this.cancel.textContent=e.action.label),e.surface!=="countdown"&&(this.lastNumeral=-1),e.surface==="paused"&&(this.pauseStatus.textContent=e.status,this.pauseTimer.textContent=e.seconds!==null?`Ends in ${Xt(e.seconds)}`:""),e.surface==="watching"){let[a,...i]=e.status.split(" \xB7 "),s=c("span","ow-lobby-chip-more",i.length?` \xB7 ${i.join(" \xB7 ")}`:"");this.chip.replaceChildren(a,s)}let n=e.seconds!==null;n&&!this.timer?this.timer=window.setInterval(()=>this.render(),250):!n&&this.timer&&(window.clearInterval(this.timer),this.timer=0)}renderCard(e){this.count.textContent=e.count,this.settingsBox.hidden=e.settings.length===0,this.status.textContent=e.status,this.status.hidden=e.status==="",this.setAction(this.action,e);let o=JSON.stringify(e.settings);o!==this.settingsSignature&&(this.settingsSignature=o,this.settingsBox.replaceChildren(...e.settings.map(n=>this.settingRow(n))));let r=JSON.stringify(e.rows);r!==this.listSignature&&(this.listSignature=r,this.list.replaceChildren(...e.rows.map(n=>{let a=c("li",n.away||n.idle?"ow-lobby-away":n.ready?"ow-lobby-ready":""),i=c("img","ow-headshot");i.src=`/avatar/${encodeURIComponent(n.id)}/head.svg`,i.alt="";let s=c("span","ow-lobby-name",n.name),h=[n.away?"Reconnecting":n.idle?"Idle":"",n.you?"You":"",n.host?"Host":""].filter(Boolean).join(" \xB7 ");return a.append(i,s),h&&a.append(c("span","ow-player-notes",h)),a.append(c("span",`ow-lobby-check${n.ready?" ow-lobby-check-on":""}`,n.ready?"Ready":"")),a})))}settingRow(e){let o=c("div","ow-lobby-setting");if(o.append(c("span","ow-lobby-setting-label",e.label)),!e.editable)return o.append(c("span","ow-lobby-setting-value",e.options.find(n=>n.value===e.value)?.label??String(e.value))),o;let r=c("div","ow-segments");r.setAttribute("role","radiogroup"),r.setAttribute("aria-label",e.label);for(let n of e.options){let a=this.button(`ow-segment${n.value===e.value?" ow-segment-on":""}`,()=>this.opts.onSetting(e.id,n.value));a.textContent=n.label,a.setAttribute("role","radio"),a.setAttribute("aria-checked",String(n.value===e.value)),r.append(a)}return o.append(r),o}renderBar(e){this.barStatus.textContent=e.status||`${e.ready.n} / ${e.ready.of} ready`,this.setAction(this.barAction,e);let o=JSON.stringify(e.rows.slice(0,5).map(r=>[r.id,r.ready]));o!==this.faceSignature&&(this.faceSignature=o,this.barFaces.replaceChildren(...e.rows.slice(0,5).map(r=>{let n=c("img",`ow-headshot${r.ready?" ow-lobby-face-ready":""}`);return n.src=`/avatar/${encodeURIComponent(r.id)}/head.svg`,n.alt="",n})))}setAction(e,o){e.hidden=o.action.kind==="none",e.textContent=o.action.label,e.disabled=o.action.disabled,e.classList.toggle("ow-btn-primary",o.action.kind!=="unready")}};function Xt(t){return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}function mt(t,e){let o=[];for(let{kind:r,box:n}of e){if(!n||!(n.width>0)||!(n.height>0))continue;let a=Math.max(0,n.left-t.left),i=Math.max(0,n.top-t.top),s=Math.min(t.width,n.left+n.width-t.left),h=Math.min(t.height,n.top+n.height-t.top);if(!(s-a>.01&&h-i>.01))continue;let g=Math.floor(a+.01),l=Math.floor(i+.01);o.push({kind:r,x:g,y:l,w:Math.ceil(s-.01)-g,h:Math.ceil(h-.01)-l})}return o}var ee=class{measure;send;nextFrame;queued=!1;sent=null;constructor(e,o,r=n=>requestAnimationFrame(n)){this.measure=e,this.send=o,this.nextFrame=r}changed(){this.queued||(this.queued=!0,this.nextFrame(()=>{this.queued=!1;let e=this.measure();if(!e)return;let o=JSON.stringify(e);o!==this.sent&&(this.sent=o,this.send(e))}))}resend(){this.sent=null,this.changed()}};var ve=t=>`ow:resume:${t}`;function T(t,e){try{e?sessionStorage.setItem(ve(t),JSON.stringify({...e,at:Date.now()})):sessionStorage.removeItem(ve(t))}catch{}}function ut(t){try{let e=sessionStorage.getItem(ve(t));if(!e)return null;let o=performance.getEntriesByType("navigation")[0];if(o&&o.type!=="reload"&&o.type!=="back_forward")return te(t);let r=JSON.parse(e);return typeof r.key!="string"||typeof r.rejoin!="string"||typeof r.at!="number"||Date.now()-r.at>18e4||Number(r.rejoin.split(".")[0])*1e3<Date.now()?te(t):{key:r.key,rejoin:r.rejoin}}catch{return null}}var Zt=t=>`ow:own-server:${t}`;function xt(t,e){try{sessionStorage.setItem(Zt(t),e)}catch{}}function te(t){return T(t,null),null}var oe=class extends Error{constructor(o,r=0,n=0,a=""){super(o);this.status=r;this.retryAfterMs=n;this.code=a;this.name="RequestError"}status;retryAfterMs;code;get retryable(){return this.status===0||this.status===408||this.status===429||this.status>=500}};var re=class{constructor(e=48*1024){this.max=e}max;used=0;async run(e,o){let r=new TextEncoder().encode(e).byteLength;if(this.used+r>this.max)throw new oe("Progress is waiting to sync when you return to the game.");this.used+=r;try{return await o()}finally{this.used-=r}}};var ye=/^[2-9]$/.test(new URLSearchParams(location.search).get("player")??"")?new URLSearchParams(location.search).get("player"):null;var Qt=null;function ft(){return Qt?.n??null}var Zo=new re;var bt=[300,700,1500,3e3,5e3,8e3],eo=9e4,to=1e4,vt=()=>Array.from(crypto.getRandomValues(new Uint8Array(10)),t=>"abcdefghijklmnopqrstuvwxyz0123456789"[t%36]).join(""),yt=vt();function kt(){yt=vt()}var wt=null;var St=!1;function zt(t){St=t}var oo=5e4,ro=4e3,ne=class{ws=null;key=null;rejoin=null;you="";closed=!1;attempt=0;droppedAt=0;sleeping=!1;lastHeard=0;heardCount=0;pingAt=0;hintedHidden=!1;pingTimer=0;watchTimer=0;retryTimer=0;page=yt;slug;options;callbacks;onVisible=()=>{this.hint(),document.visibilityState==="visible"&&this.wake()};onOnline=()=>this.wake();onShow=e=>e.persisted&&this.wake();onHide=()=>this.hint();constructor(e,o,r){this.slug=e,this.options=o,this.callbacks=r,this.key=o.key??null,this.rejoin=o.rejoin??null,document.addEventListener("visibilitychange",this.onVisible),addEventListener("online",this.onOnline),addEventListener("pageshow",this.onShow),addEventListener("pagehide",this.onHide)}join(){return new Promise((e,o)=>this.open(e,o))}send(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e))}hint(){let e=document.visibilityState==="hidden";e===this.hintedHidden||this.ws?.readyState!==WebSocket.OPEN||(this.hintedHidden=e,this.send({t:"vis",hidden:e}))}ping(){let e=this.ws;e?.readyState===WebSocket.OPEN&&(this.pingAt&&Date.now()-this.pingAt<5e3||(this.pingAt=Date.now(),e.send(he)))}close(){this.closed=!0,T(this.slug,null),this.dispose(),this.ws?.close(1e3)}reload(){return this.closed=!0,this.dispose(),this.ws?.close(We,"Updating"),this.key?.startsWith("pub:")&&this.rejoin?{key:this.key,rejoin:this.rejoin}:null}open(e,o){this.retryTimer=0;let r=new URL(`/api/games/${this.slug}/rooms/connect`,location.href);r.protocol=location.protocol==="https:"?"wss:":"ws:",this.key?(r.searchParams.set("key",this.key),this.rejoin&&r.searchParams.set("rejoin",this.rejoin)):this.options.server?(r.searchParams.set("server",this.options.server),this.options.private&&r.searchParams.set("own","1")):this.options.name?r.searchParams.set("name",this.options.name):(this.options.mode&&r.searchParams.set("mode",this.options.mode),this.options.follow&&r.searchParams.set("follow",this.options.follow)),this.options.maxPlayers&&r.searchParams.set("max",String(this.options.maxPlayers)),this.options.minPlayers&&r.searchParams.set("min",String(this.options.minPlayers)),this.options.countdown!==void 0&&r.searchParams.set("countdown",String(this.options.countdown)),this.options.teams&&r.searchParams.set("teams",String(this.options.teams)),this.options.ranked&&r.searchParams.set("ranked","1"),ye&&r.searchParams.set("devplayer",ye);let n=ft();n&&r.searchParams.set("tester",n),r.searchParams.set("page",this.page),this.options.build&&r.searchParams.set("build",this.options.build),wt&&r.searchParams.set("pass",wt),St&&r.searchParams.set("demo","1");let a=new WebSocket(r);this.ws=a,this.lastHeard=Date.now();let i=!1;a.onopen=()=>{this.lastHeard=Date.now(),window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),this.pingTimer=window.setInterval(()=>a.readyState===WebSocket.OPEN&&this.ping(),to),this.watchTimer=window.setInterval(()=>{a===this.ws&&a.readyState===WebSocket.OPEN&&Date.now()-this.lastHeard>oo&&this.lost(a)},5e3)},a.onmessage=g=>{this.lastHeard=Date.now(),this.heardCount++;let l;try{l=JSON.parse(g.data)}catch{return}if(l.t==="pong"){this.pingAt&&this.callbacks.onRtt?.(Date.now()-this.pingAt),this.pingAt=0;return}if(l.t==="welcome"&&(l.rejoin&&(this.rejoin=l.rejoin),delete l.rejoin,l.room.startsWith("pub:")&&this.rejoin&&T(this.slug,{key:l.room,rejoin:this.rejoin})),l.t==="leave"&&l.kicked&&l.id===this.you){this.close(),this.finish("kicked");return}if(l.t==="welcome"&&(this.hintedHidden=!1,this.hint()),l.t==="welcome"&&!i&&(i=!0,this.key=l.room,this.you=l.you,this.attempt=0,this.droppedAt&&(this.droppedAt=0,this.callbacks.onConnection?.(!0)),e)){let{t:y,...m}=l;e(m),e=void 0;return}this.callbacks.onMessage(l)};let s=!1,h=g=>{if(!s&&(s=!0,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),!(this.closed||a!==this.ws))){if(g.code===qe)return this.finish("replaced");if(g.code===Ve&&i&&document.visibilityState==="hidden"){this.sleeping=!0,this.droppedAt||(this.droppedAt=Date.now(),this.callbacks.onConnection?.(!1));return}if(g.code===Ke){if(i||!o)return this.finish("kicked");this.closed=!0,this.dispose(),T(this.slug,null),o(Object.assign(new Error("You were removed from this server."),{kicked:!0}));return}if(!i&&o){this.closed=!0,this.dispose(),o(new Error(this.options.name||this.options.server?"Could not join that server. It may be full.":"Could not join a server. Try again soon."));return}this.retry()}};a.onclose=h,a.onerror=()=>{window.setTimeout(()=>{a.readyState===WebSocket.CLOSED&&h({code:1006})},1e3)}}retry(){if(this.closed)return;let e=Date.now();if(this.droppedAt||(this.droppedAt=e,this.callbacks.onConnection?.(!1)),e-this.droppedAt>eo)return this.finish("disconnected");if(this.retryTimer)return;let o=bt[Math.min(this.attempt++,bt.length-1)]*(.5+Math.random());this.retryTimer=window.setTimeout(()=>{this.retryTimer=0,this.closed||this.open()},o)}lost(e){if(!(e!==this.ws||this.closed)){e.onopen=e.onmessage=e.onclose=e.onerror=null,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer);try{e.close()}catch{}this.retry()}}wake(){if(this.closed)return;if(this.sleeping){this.sleeping=!1,this.droppedAt=Date.now(),this.attempt=0,this.open();return}let e=this.ws;if(!e||e.readyState===WebSocket.CLOSING||e.readyState===WebSocket.CLOSED){this.retryTimer&&(window.clearTimeout(this.retryTimer),this.retryTimer=0,this.open());return}if(e.readyState!==WebSocket.OPEN)return;let o=this.heardCount;try{e.send(he)}catch{return this.lost(e)}window.setTimeout(()=>e===this.ws&&!this.closed&&this.heardCount===o&&this.lost(e),ro)}dispose(){window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),window.clearTimeout(this.retryTimer),this.retryTimer=0,document.removeEventListener("visibilitychange",this.onVisible),removeEventListener("online",this.onOnline),removeEventListener("pageshow",this.onShow),removeEventListener("pagehide",this.onHide)}finish(e){this.closed=!0,this.dispose(),T(this.slug,null),this.callbacks.onClose(e)}};var Rt=`:root {
1
+ "use strict";(()=>{var He=["#f6dcc5","#ebc29f","#d4a07a","#b07a55","#875839","#5e3d29","#93c9bb","#a8c595","#94bcd3","#ab9bd9","#dca3ad","#b3bccb"],ve=["#c95f56","#dc8a4f","#e2bd52","#9cc27a","#5a8a5e","#4f9a8e","#6fb7c8","#5b87c5","#465089","#8b68a8","#dc8fae","#f2eee6","#a9a8ad","#5d5c63","#2b2a30","#80604d"],Fe=["Happy","Grin","Shades","Wink","Surprised","Determined","Joyful","Shy"],Ke=["None","Sprout","Cap","Beanie","Crown","Headphones","Horns","Antenna","Bow","Halo","Party hat","Cat ears","Short hair","Tuft","Bob","Spikes","Bun","Curls","Long","Mop"];var qe=["Plain","Band","Spots","Stripes","Star"];var Ho={skin:He.length,shirt:ve.length,pants:ve.length,face:Fe.length,hat:Ke.length,top:qe.length},ro=[[5,6],[3,4],[6,7],[9,8],[10,0],[12,13]];function Ve(t){let e=2166136261;for(let d of t)e=Math.imul(e^d.charCodeAt(0),16777619)>>>0;let o=d=>(e=Math.imul(e^e>>>13,2654435761)>>>0,e%d),r=o(He.length),n=r>=6?ro[r-6][o(2)]:o(ve.length),a=o(2)===0?n:[8,13,14,15][o(4)],i=o(5)===0?1:12+o(Ke.length-12),s=o(2)===0?0:o(qe.length);return{skin:r,shirt:n,pants:a,face:o(Fe.length),hat:i,top:s}}var P={roomMaxPlayersDefault:16,roomMaxPlayersCap:30,teamsMax:8,messageBytes:16*1024,presenceBytes:1024,stateKeyLength:64,stateValueBytes:16*1024,stateKeys:256,privateKeys:16,privateValueBytes:4*1024,privateBytesPerPlayer:8*1024,messagesPerSecond:60,messagesPerSecondMin:10,roomBytesPerSecond:128*1024,roomBytesPerSecondMin:16*1024,presenceHz:20,presenceHzMin:5,roomMessagesPerSecond:900,roomBytesPerSecondTotal:2*1024*1024,matchCountdownMs:3e3,matchCountdownMaxMs:1e4,matchIdleMs:45e3,matchAbandonMs:12e4,idleAfterMs:3e4,idleAbandonMs:5*6e4,rankedPairMatchesPerDay:5,chatLength:200,chatIntervalMs:750,chatHistory:50,chatChannelsPerPlayer:10,saveValueBytes:64*1024,saveKeysPerGame:100,saveBytesPerGame:1024*1024,guestSaveBytesPerGame:128*1024,serverDataKeys:128,serverDataBytes:512*1024,serverDataServersPerGame:5e3,serverDataBytesPerGame:64*1024*1024,serverDataIdleDays:120,gameDataKeys:32,gameDataListMax:100,gameDataItemBytes:1024,gameDataValueBytes:8*1024,gameDataMapFields:1e3,gameDataMapPerPlayer:100,gameDataNumberMax:1e15,gameDataWritesPerMinute:30,deployFiles:2e3,deployFileBytes:25*1024*1024,deployHtmlBytes:10*1024*1024,deployPathLength:200,deployTotalBytes:100*1024*1024,envVars:50,envValueBytes:4*1024,envTotalBytes:16*1024,proxyRequestBytes:1024*1024,proxyTextRequestBytes:256*1024,proxySpeechRequestBytes:16*1024,proxyResponseBytes:10*1024*1024,proxyMaxOutputTokens:4096,proxyCallsPerDay:2e3,proxyCallsPerDayMax:1e5,proxyCallsPerPlayerPerDay:100,proxyCallsPerNetworkPerDay:1e3,proxyMediaCallsPerDay:100,proxyMediaCallsPerDayMax:1e4,proxyMediaCallsPerPlayerPerDay:20,proxyMediaCallsPerNetworkPerDay:25,proxyUnitsPerDay:2e6,proxyUnitsPerDayMax:1e8,proxyUnitsPerPlayerPerDay:25e4,proxyUnitsPerGuestPerDay:1e5,proxyUnitsPerNetworkPerDay:5e5,errorReportsPerPage:10,consoleLineLength:2e3,consoleLinesPerSecond:50,gameNameLength:60,gameDescriptionLength:1e3,galleryItems:5,mediaImageBytes:5*1024*1024,mediaVideoBytes:30*1024*1024,mediaGifBytes:1024*1024,mediaGifSide:512,mediaUploadsPerDay:200,mediaBytesPerDay:500*1024*1024,badgesPerGame:50,controlHints:12,controlHintKeys:4,controlKeyLength:12,controlActionLength:40,helpLength:400,badgeNameLength:50,badgeDescriptionLength:200,leaderboardsPerGame:25,leaderboardTop:100,gamesPerOwner:50,gamesCreatedPerCreatorPerDay:3,uploadAccountAgeMs:10080*6e4,deploysPerOwnerPerDay:100,draftsPerOwnerPerDay:1e3,draftsKeptPerGame:3,cliTokensPerAccount:10,cliDeviceCodeSeconds:600,deploymentsKeptPerGame:10,deployBytesPerOwnerPerDay:2*1024*1024*1024,deployEntriesPerOwnerPerDay:1e5,bioLength:500,exportRows:2e3,exportSaveChars:4*1024*1024,exportEveryMs:60*6e4,friendsMax:200,friendRequestsMax:100,friendRequestsIncomingMax:50,friendRequestsPerDay:20,friendRequestsPerNetworkPerDay:120,friendRequestPushesPerDay:5,passwordMinLength:8,passwordMaxLength:72,signupsPerNetworkPerDay:100,signupsPerWidePerDay:300,guestsPerNetworkPerDay:300,guestsPerWidePerDay:1500,visitsPerNetworkPerDay:10,visitSeconds:10,errorsPerDeployment:100,controlButtons:4,controlLabelLength:12,partySize:6,partyChatHistory:50,messageLength:500,messagesPerPage:50,groupChatMembers:20,groupChatNameLength:40,conversationsListed:50,notificationsListed:50,invitesPerRequest:10,inviteLiveMs:30*6e4,partyInviteMs:60*6e4};var Ye=/^[a-z0-9]{12}$/,ee=2;function ke(t){return`${t.mode}.${t.max}.${t.teams}.${t.ranked?1:0}${t.min!==ee?`.${t.min}`:""}`}var no=/^pub:([a-z0-9-]+)\.(\d+)\.(\d)\.([01])(?:\.(\d+))?:(\d+)$/;function Je(t){let e=no.exec(t);if(!e)return null;let o={mode:e[1],max:Number(e[2]),teams:Number(e[3]),ranked:e[4]==="1",min:e[5]===void 0?ee:Number(e[5])};return{...o,name:ke(o),n:Number(e[6])}}function Xe(t,e,o){let r=typeof t=="string"?Number(t):t;return typeof r!="number"||!Number.isInteger(r)?Math.min(o,e):Math.min(e,Math.max(1,r))}var We=t=>t.replace(/[\u0000-\u001f\u007f]/g," ").replace(/\s+/g," ").trim();var ao=/^[a-z0-9][a-z0-9-]{0,19}$/;function Ze(t){if(!t||typeof t!="object")return null;let e=t,o=[];for(let n of Array.isArray(e.buttons)?e.buttons:[]){if(o.length>=P.controlButtons)break;let{id:a,label:i}=n??{};if(typeof a!="string"||!ao.test(a)||o.some(d=>d.id===a))continue;let s=typeof i=="string"?i.replace(/[\u0000-\u001f\u007f]/g,"").replace(/\s+/g," ").trim().slice(0,P.controlLabelLength).trim():"";o.push({id:a,label:s||a})}let r=e.stick===!0;return r||o.length>0?{stick:r,zone:e.zone==="corner"?"corner":"wide",buttons:o}:null}var V="host:ow.settings",io=/^[a-z][a-zA-Z0-9]{0,15}$/;function Qe(t){if(!Array.isArray(t))return[];let e=[];for(let o of t){if(e.length>=6)break;let{id:r,label:n,options:a,default:i}=o??{};if(typeof r!="string"||!io.test(r)||e.some(c=>c.id===r)||!Array.isArray(a))continue;let s=[];for(let c of a){let p=typeof c=="object"&&c!==null?c.value:c;if(typeof p!="string"&&typeof p!="number"||typeof p=="number"&&!Number.isFinite(p)||s.length>=8||s.some(u=>u.value===p))continue;let x=typeof c=="object"&&c!==null&&typeof c.label=="string"?c.label:String(p);s.push({value:p,label:We(x).slice(0,20)||String(p)})}if(s.length<2)continue;let d=typeof n=="string"?We(n).slice(0,24):"";e.push({id:r,label:d||r,options:s,default:s.some(c=>c.value===i)?i:s[0].value})}return e}function et(t,e){let o=e!==null&&typeof e=="object"?e[t.id]:void 0;return t.options.some(r=>r.value===o)?o:t.default}var Se='{"t":"ping"}';var tt=4001,ot=4003,rt=4008,nt=4006;var at="onceworlds:hello",it="onceworlds:connect",so=/^[a-z0-9]{1,32}~(?:(?:0|[1-9]\d{0,3})\.(?:0|[1-9]\d{0,4})\.(?:0|[1-9]\d{0,5}))?~[0-9a-z]{1,11}~[lp]~[A-Za-z0-9_-]{43}$/;function st(t){let e=t!==null&&typeof t=="object"?t.build:void 0;return typeof e=="string"&&so.test(e)?e:null}var lt="onceworlds-console";var pt="allow-scripts allow-pointer-lock allow-forms allow-orientation-lock",dt=["autoplay","gamepad","screen-wake-lock","accelerometer","gyroscope"].map(t=>`${t} *`).join("; "),ct=100*1024*1024;var gt=new Set(["server","join","deploy","watch","player","embed","k","console","tester","live","demo",lt]);var ze="onceworlds:page",lo=["ran","blocked","failed","threw","loaded"];function ht(t){if(t===null||typeof t!="object")return null;let{what:e,detail:o}=t;return typeof e!="string"||!lo.includes(e)?null:{what:e,detail:typeof o=="string"?o.slice(0,200):""}}var po=`(function(){var n=0,s=function(w,d){if(n++<12)try{parent.postMessage({type:${JSON.stringify(ze)},what:w,detail:String(d).slice(0,200)},"*")}catch(e){}};s("ran",document.readyState);addEventListener("securitypolicyviolation",function(e){s("blocked",e.effectiveDirective+" "+e.blockedURI)});addEventListener("error",function(e){var t=e.target;t&&t.tagName?s("failed",t.tagName+" "+(t.src||t.href)):s("threw",e.message+" "+e.filename+":"+e.lineno)},true);addEventListener("load",function(){s("loaded",typeof onceworlds)})})();`,Yo=`<script>${po}<\/script>`;function ut(t){return t?.ownCountdown!==!0}function mt(t){let e=t?.lobby;return e==="card"||e==="bar"?e:e==="game"?null:typeof t?.minPlayers=="number"||typeof t?.minPlayersPrivate=="number"||typeof t?.countdown=="number"||Array.isArray(t?.settings)&&t.settings.length>0?"bar":null}function xt(t){return t.key==="Enter"&&!t.isComposing&&!t.ctrlKey&&!t.metaKey&&!t.altKey&&!t.shiftKey}var ft=400;var co=/^#(?:[0-9a-f]{3}){1,2}$/i,T={panel:"#111216",text:"#f7f7f8",accent:"#d33e00"},Ee=4.5,Re=3,te=["#4ade80","#15803d"];function wt(t){let e=[];if(t==null)return{look:null,notes:e};if(typeof t!="object")return{look:null,notes:["a look is { accent, panel, text } or null"]};let o=t,r=p=>{let x=o[p];return x==null?null:typeof x=="string"&&co.test(x)?yt(x):(e.push(`${p} is not #rgb or #rrggbb`),null)},n=r("panel"),a=r("text"),i=r("accent");if(n||a){let p=A(a??T.text,n??T.panel);p<Ee&&(e.push(`text on panel is ${p.toFixed(1)}:1, under ${Ee}:1: the platform's are used`),n=a=null)}let s=n??T.panel,d=a??T.text;if(i){let p=A(i,s);p<Re&&(e.push(`accent on panel is ${p.toFixed(1)}:1, under ${Re}:1: the platform's is used`),i=null)}if(!i&&n&&A(T.accent,n)<Re&&(i=d),!n&&!a&&!i)return{look:null,notes:e};let c=i?go(i):null;return{look:{panel:n,text:a,muted:n||a?ho(d,s):null,accent:i,accentHover:i?vt(i,c==="#ffffff"?"#000000":"#ffffff",.14):null,onAccent:c,ok:n?A(te[0],n)>=A(te[1],n)?te[0]:te[1]:null},notes:e}}function yt(t){let e=t.slice(1).toLowerCase();return`#${e.length===3?[...e].map(o=>o+o).join(""):e}`}function W(t){let e=yt(t);return[parseInt(e.slice(1,3),16),parseInt(e.slice(3,5),16),parseInt(e.slice(5,7),16)]}function bt(t){let[e,o,r]=W(t).map(n=>{let a=n/255;return a<=.04045?a/12.92:((a+.055)/1.055)**2.4});return .2126*e+.7152*o+.0722*r}function A(t,e){let[o,r]=[bt(t),bt(e)].sort((n,a)=>a-n);return(o+.05)/(r+.05)}function go(t){return A(t,"#000000")>A(t,"#ffffff")?"#000000":"#ffffff"}function vt(t,e,o){let[r,n]=[W(t),W(e)];return`#${r.map((a,i)=>Math.round(a+(n[i]-a)*o).toString(16).padStart(2,"0")).join("")}`}function ho(t,e){for(let o=.3;o>.001;o-=.05){let r=vt(t,e,o);if(A(r,e)>=Ee)return r}return t}var oe=class{port=null;handlers;events;onConnect;solo;demo;onActivity;onPage;constructor(e,o,r,n,a={}){this.handlers=o,this.events=r,this.onConnect=n,this.solo=a.solo===!0,this.demo=a.demo===!0,this.onActivity=a.onActivity??null,this.onPage=a.onPage??null,window.addEventListener("message",i=>{if(!(i.source!==e.contentWindow||i.origin!=="null")&&(i.data?.type===at&&this.connect(i.source,st(i.data)),i.data?.type===ze)){let s=ht(i.data);s&&this.onPage?.(s)}})}activity(e,o){try{this.onActivity?.(e,o)}catch{}}emit(e,o){this.port?.postMessage({kind:"event",name:e,data:o})}connect(e,o){this.port?.close();let r=new MessageChannel,n=r.port1;this.port=n,n.onmessage=i=>this.receive(n,i.data);let a={type:it,...this.solo?{solo:!0}:{},...this.demo?{demo:!0}:{}};e.postMessage(a,"*",[r.port2]),this.onConnect(o)}async receive(e,o){if(!(e!==this.port||!o||typeof o!="object")){if(o.kind==="event"){Object.hasOwn(this.events,o.name)&&(this.events[o.name](o.data),this.activity(String(o.name),null));return}if(o.kind==="req")try{if(!Object.hasOwn(this.handlers,o.method))throw new Error(`Unknown method: ${String(o.method)}`);let r=this.handlers[o.method],n=await r(o.params);e.postMessage({kind:"res",id:o.id,ok:!0,result:n??null}),this.activity(String(o.method),null)}catch(r){let n=r instanceof Error?r.message:String(r);e.postMessage({kind:"res",id:o.id,ok:!1,error:n}),this.activity(String(o.method),n)}}}};var uo="ow-game-storage",mo=256,kt="guest";function Pe(t){let e=0,o=new Set,r=[t];for(;r.length;){let n=r.pop();if(typeof n=="string")e+=n.length*2;else if(typeof n!="object"||n===null)e+=8;else{if(o.has(n))continue;if(o.add(n),n instanceof ArrayBuffer)e+=n.byteLength;else if(ArrayBuffer.isView(n))e+=n.buffer.byteLength;else if(typeof Blob=="function"&&n instanceof Blob)e+=n.size;else if(n instanceof Map)for(let[a,i]of n)r.push(a,i);else if(n instanceof Set)for(let a of n)r.push(a);else if(Array.isArray(n))r.push(...n.slice(0,1e5),...n.length>1e5?[n.slice(1e5)]:[]);else for(let[a,i]of Object.entries(n))r.push(a,i)}}return e}function L(t){if(typeof t!="string"||t.length>mo)throw new Error("Bad name");return t}function St(t){if(t===null)return null;if(typeof t=="string")return L(t);if(Array.isArray(t)&&t.length<=32)return t.map(L);throw new Error("Bad key path")}function xo(t){if(typeof t!="object"||t===null)throw new Error("Bad stores");let e=Object.keys(t);if(e.length>1e3)throw new Error("Too many stores");let o={};for(let r of e){let n=t[L(r)];if(typeof n!="object"||n===null||!Array.isArray(n.indexes)||n.indexes.length>1e3)throw new Error("Bad store");let a=Number(n.nextKey),i=n.indexes.map(s=>{let d=St(s?.keyPath);if(d===null)throw new Error("Bad index");return{name:L(s.name),keyPath:d,unique:s.unique===!0,multiEntry:s.multiEntry===!0}});o[r]={keyPath:St(n.keyPath),autoIncrement:n.autoIncrement===!0,nextKey:Number.isFinite(a)?a:1,indexes:i}}return o}function k(t){return new Promise((e,o)=>{t.onsuccess=()=>e(t.result),t.onerror=()=>o(t.error??new Error("Storage failed"))})}function Me(t){return new Promise((e,o)=>{t.oncomplete=()=>e(),t.onabort=t.onerror=()=>o(t.error??new Error("Storage failed"))})}var re=class{database=null;named=null;owner;factory;limit;constructor(e,o={}){this.owner=e,this.factory=o.factory??(()=>indexedDB),this.limit=o.limit??ct}open(){return this.database??=new Promise((e,o)=>{let r=this.factory().open(uo,1);r.onupgradeneeded=()=>{r.result.createObjectStore("dbs",{keyPath:["owner","db"]}),r.result.createObjectStore("records")},r.onsuccess=()=>e(r.result),r.onerror=()=>o(r.error??new Error("No storage in this browser"))}),this.database}who(){return this.named??=this.owner().then(async({game:e,player:o})=>{let r=`${e}
2
+ ${o??kt}`;return o!==null&&await this.adopt(`${e}
3
+ ${kt}`,r),r}),this.named}async adopt(e,o){let n=(await this.open()).transaction(["dbs","records"],"readwrite"),a=Me(n),i=n.objectStore("dbs"),s=n.objectStore("records"),d=await k(i.getAll(this.ownerRange(e)));for(let c of d){let p=this.dbRange(e,c.db);if(!await k(i.getKey([o,c.db]))){let x=await k(s.getAllKeys(p));for(let u of x){let E=await k(s.get(u));s.put(E,[o,...u.slice(1)])}i.put({...c,owner:o})}s.delete(p),i.delete([e,c.db])}await a}ownerRange(e){return IDBKeyRange.bound([e],[`${e}\0`],!1,!0)}dbRange(e,o){return IDBKeyRange.bound([e,o],[e,`${o}\0`],!1,!0)}storeRange(e,o,r){return IDBKeyRange.bound([e,o,r],[e,o,`${r}\0`],!1,!0)}async read({db:e}){L(e);let o=await this.who(),n=(await this.open()).transaction(["dbs","records"]),a=await k(n.objectStore("dbs").get([o,e]));if(!a)return null;let i=n.objectStore("records"),s=this.dbRange(o,e),[d,c]=await Promise.all([k(i.getAllKeys(s)),k(i.getAll(s))]);return{version:a.version,stores:a.stores,records:d.map((p,x)=>({store:p[2],key:p[3],value:c[x].value}))}}async commit(e){let o=L(e?.db),r=Number(e.version);if(!Number.isFinite(r)||r<0)throw new Error("Bad version");let n=e.ops;if(!Array.isArray(n))throw new Error("Bad changes");let a=e.stores===void 0?void 0:xo(e.stores),i=await this.who(),d=(await this.open()).transaction(["dbs","records"],"readwrite"),c=Me(d),p=d.objectStore("dbs"),x=d.objectStore("records");try{let u=await k(p.getAll(this.ownerRange(i))),E=u.find(l=>l.db===o)??{owner:i,db:o,version:r,stores:{},bytes:0},q=u.reduce((l,f)=>l+(f===E?0:f.bytes),0),b=E.bytes;for(let l of n){let f=L(l?.store);if("clear"in l){b-=await this.sum(x,this.storeRange(i,o,f)),x.delete(this.storeRange(i,o,f));continue}let ye=[i,o,f,"put"in l?l.put:l.remove],Ge=await k(x.get(ye));if(Ge&&(b-=Ge.bytes),"put"in l){let Ue=Pe(l.value)+Pe(l.put)+64;b+=Ue,x.put({value:l.value,bytes:Ue},ye)}else x.delete(ye)}if(a)for(let l of Object.keys(E.stores))Object.hasOwn(a,l)||(b-=await this.sum(x,this.storeRange(i,o,l)),x.delete(this.storeRange(i,o,l)));if(q+=Pe(a??E.stores),q+b>this.limit)throw new Error("QuotaExceededError");p.put({owner:i,db:o,version:r,stores:a??E.stores,bytes:Math.max(0,b)})}catch(u){try{d.abort()}catch{}throw c.catch(()=>{}),u}return await c,null}async sum(e,o){return(await k(e.getAll(o))).reduce((n,a)=>n+a.bytes,0)}async remove({db:e}){L(e);let o=await this.who(),n=(await this.open()).transaction(["dbs","records"],"readwrite"),a=Me(n);return n.objectStore("records").delete(this.dbRange(o,e)),n.objectStore("dbs").delete([o,e]),await a,null}async list(){let e=await this.who(),o=await this.open();return(await k(o.transaction("dbs").objectStore("dbs").getAll(this.ownerRange(e)))).map(n=>({name:n.db,version:n.version}))}};var ne=class{pressed=new Set;press(e){this.pressed.add(e)}take(e){let o=new Set(e),r=!1;for(let n of this.pressed)o.has(n)||(o.add(n),r=!0);return this.pressed.clear(),{buttons:[...o],owed:r}}};var zt=["--ow-panel","--ow-face-edge","--ow-hover","--ow-on-accent","--text","--muted","--line","--line-strong","--fill","--fill-strong","--ok","--accent-fill","--accent-fill-hover","--accent-hover"],Rt=["--ow-ctl-edge","--ow-ctl-fill","--ow-ctl-stick","--ow-ctl-knob","--ow-ctl-label","--ow-ctl-shadow","--ow-ctl-held","--ow-ctl-main","--ow-ctl-main-edge","--ow-ctl-main-label","--ow-ctl-main-shadow","--ow-ctl-main-held"];function y(t,e){return`rgba(${W(t).join(", ")}, ${e})`}function Et(t){let e={};if(!t)return e;if(t.panel&&(e["--ow-panel"]=t.panel,e["--ow-face-edge"]=t.panel),t.ok&&(e["--ok"]=t.ok),t.panel||t.text){let o=t.text??T.text;t.text&&(e["--text"]=t.text),t.muted&&(e["--muted"]=t.muted),e["--line"]=y(o,.09),e["--line-strong"]=y(o,.16),e["--fill"]=y(o,.06),e["--fill-strong"]=y(o,.1),e["--ow-hover"]=y(o,.16)}return t.accent&&t.accentHover&&t.onAccent&&(e["--accent-fill"]=t.accent,e["--accent-fill-hover"]=t.accentHover,e["--accent-hover"]=t.accent,e["--ow-on-accent"]=t.onAccent),e}function Pt(t){let e={};return t&&(t.text&&(e["--ow-ctl-edge"]=y(t.text,.4),e["--ow-ctl-knob"]=y(t.text,.9),e["--ow-ctl-label"]=t.text,e["--ow-ctl-held"]=y(t.text,.35)),t.panel&&(e["--ow-ctl-fill"]=y(t.panel,.4),e["--ow-ctl-stick"]=y(t.panel,.3),e["--ow-ctl-shadow"]=y(t.panel,.5)),t.accent&&t.accentHover&&t.onAccent&&(e["--ow-ctl-main"]=y(t.accent,.85),e["--ow-ctl-main-edge"]=t.accent,e["--ow-ctl-main-label"]=t.onAccent,e["--ow-ctl-main-shadow"]="none",e["--ow-ctl-main-held"]=t.accentHover)),e}function ae(t,e,o){for(let r of e)Object.hasOwn(o,r)?t.style.setProperty(r,o[r]):t.style.removeProperty(r);t.toggleAttribute("data-look",e.some(r=>Object.hasOwn(o,r)))}var $=52,Ae=.12,Le=96,fo=400,bo=2e4,ie=class{parent;root;zone;base;knob;buttonBox;send;onLayout;layout=null;touch;blocked=!1;keyboard=!1;stickPointer=null;center={x:0,y:0};x=0;y=0;buttons=new Map;held=new Map;fingers=new Map;report=new ne;queued=0;sent="";placed={stick:null,buttons:null};constructor(e,o,r=()=>{}){this.send=o,this.onLayout=r,this.parent=e,this.touch=matchMedia("(pointer: coarse)").matches,this.root=D("div","ow-controls"),this.root.hidden=!0,this.zone=D("div","ow-stick-zone"),this.base=D("div","ow-stick"),this.knob=D("div","ow-stick-knob"),this.base.append(this.knob),this.zone.append(this.base),this.buttonBox=D("div","ow-control-buttons"),this.root.append(this.zone,this.buttonBox),e.append(this.root),this.zone.addEventListener("pointerdown",n=>this.stickDown(n)),this.zone.addEventListener("pointermove",n=>this.stickMove(n));for(let n of["pointerup","pointercancel","lostpointercapture"])this.zone.addEventListener(n,a=>this.stickUp(a));this.root.addEventListener("contextmenu",n=>n.preventDefault())}setLayout(e){this.layout=Ze(e);let o=this.buttons;this.buttons=new Map,(this.layout?.buttons??[]).forEach((r,n)=>{let a=o.get(r.id)??this.button(r.id);o.delete(r.id),a.className=`ow-control-btn ow-control-btn-${n}`,a.classList.toggle("ow-held",[...this.held.values()].includes(r.id)),a.textContent=r.label,a.isConnected||this.buttonBox.append(a),this.buttons.set(r.id,a)});for(let[r,n]of o){for(let[a,i]of this.held)i===r&&this.letGo(a);n.remove()}this.zone.hidden=!this.layout?.stick,this.zone.classList.toggle("ow-stick-corner",this.layout?.zone==="corner"),this.zone.hidden&&this.stickPointer!==null&&this.letGo(this.stickPointer),this.render(),this.onLayout()}setLook(e){ae(this.root,Rt,e)}reservedBoxes(){if(this.root.hidden)return this.blocked&&this.layout&&this.touch&&!this.keyboard?this.placed:{stick:null,buttons:null};let e=this.zone.hidden?null:At(this.base),o=null;for(let r of this.buttons.values()){let n=At(r);!n.width||!n.height||(o=o?yo(o,n):n)}return this.placed={stick:e,buttons:o},this.placed}setTouch(e){this.touch=e,this.render()}setKeyboard(e){this.keyboard=e,this.render()}setBlocked(e){this.blocked=e,this.render()}render(){let e=!!this.layout&&this.touch&&!this.blocked&&!this.keyboard;this.root.hidden!==!e&&(e||this.reset(),this.root.hidden=!e,this.onLayout())}reset(){for(let e of[...this.held.keys()])this.letGo(e);this.stickPointer!==null&&this.letGo(this.stickPointer),this.endStick()}letGo(e){e===this.stickPointer&&this.endStick();let o=this.held.get(e);this.held.delete(e),o!==void 0&&![...this.held.values()].includes(o)&&this.buttons.get(o)?.classList.remove("ow-held");let r=this.fingers.get(e);this.fingers.delete(e),r&&wo(this.parent,e,r),this.changed()}button(e){let o=D("button","ow-control-btn");o.type="button",o.tabIndex=-1,o.addEventListener("pointerdown",n=>{n.preventDefault(),Mt(o,n.pointerId),o.classList.add("ow-held"),this.held.set(n.pointerId,e),this.report.press(e),this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY}),this.changed()}),o.addEventListener("pointermove",n=>{this.held.get(n.pointerId)===e&&this.fingers.set(n.pointerId,{x:n.clientX,y:n.clientY})});let r=n=>{this.held.get(n.pointerId)===e&&(this.held.delete(n.pointerId),this.fingers.delete(n.pointerId),[...this.held.values()].includes(e)||o.classList.remove("ow-held"),this.changed())};for(let n of["pointerup","pointercancel","lostpointercapture"])o.addEventListener(n,a=>r(a));return o}stickDown(e){if(this.stickPointer!==null)return;e.preventDefault(),Mt(this.zone,e.pointerId),this.stickPointer=e.pointerId,this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=this.zone.getBoundingClientRect(),r=this.base.getBoundingClientRect(),n=$+8;this.center={x:Math.min(Math.max(e.clientX,o.left+n),o.right-n),y:Math.min(Math.max(e.clientY,o.top+n),o.bottom-n)},this.base.style.transform=`translate(${this.center.x-(r.left+r.width/2)}px, ${this.center.y-(r.top+r.height/2)}px)`,this.base.classList.add("ow-active"),this.stickMove(e)}stickMove(e){if(e.pointerId!==this.stickPointer)return;this.fingers.set(e.pointerId,{x:e.clientX,y:e.clientY});let o=e.clientX-this.center.x,r=e.clientY-this.center.y,n=Math.hypot(o,r);n>$&&(o=o/n*$,r=r/n*$),this.knob.style.transform=`translate(${o}px, ${r}px)`;let a=Math.min(n,$)/$,i=a<Ae?0:(a-Ae)/(1-Ae)/(a||1);this.x=Lt(o/$*i),this.y=Lt(r/$*i),this.changed()}stickUp(e){e.pointerId===this.stickPointer&&(this.fingers.delete(e.pointerId),this.endStick())}endStick(){this.stickPointer=null,this.x=0,this.y=0,this.base.classList.remove("ow-active"),this.base.style.transform="",this.knob.style.transform="",this.changed()}changed(){this.queued||(this.queued=requestAnimationFrame(()=>{this.queued=0;let{buttons:e,owed:o}=this.report.take(this.held.values()),r={x:this.x,y:this.y,buttons:e};o&&this.changed();let n=JSON.stringify(r);n!==this.sent&&(this.sent=n,this.send(r))}))}};function wo(t,e,o){let r=D("div","ow-tap-shield");r.style.left=`${o.x-Le/2}px`,r.style.top=`${o.y-Le/2}px`,r.style.width=r.style.height=`${Le}px`,t.append(r);let n=setTimeout(()=>r.remove(),bo),a=()=>{clearTimeout(n),n=setTimeout(()=>r.remove(),fo)};for(let i of["pointerup","pointercancel","lostpointercapture"])r.addEventListener(i,s=>s.pointerId===e&&a());r.addEventListener("contextmenu",i=>i.preventDefault());try{r.setPointerCapture(e)}catch{a()}}function Mt(t,e){try{t.setPointerCapture(e)}catch{}}function At(t){let e=t.getBoundingClientRect(),o=getComputedStyle(t).transform;if(!o||o==="none")return e;let r=new DOMMatrixReadOnly(o);if(r.b||r.c||!r.a||!r.d)return e;let n=e.width/Math.abs(r.a),a=e.height/Math.abs(r.d),i=e.left+e.width/2-r.e,s=e.top+e.height/2-r.f;return{left:i-n/2,top:s-a/2,width:n,height:a}}function yo(t,e){let o=Math.min(t.left,e.left),r=Math.min(t.top,e.top);return{left:o,top:r,width:Math.max(t.left+t.width,e.left+e.width)-o,height:Math.max(t.top+t.height,e.top+e.height)-r}}function Lt(t){return Math.round(t*1e3)/1e3}function D(t,e,o){let r=document.createElement(t);return r.className=e,o!==void 0&&(r.textContent=o),r}function Y(t,e){let o=[];for(let{kind:r,box:n}of e){if(!n||!(n.width>0)||!(n.height>0))continue;let a=Math.max(0,n.left-t.left),i=Math.max(0,n.top-t.top),s=Math.min(t.width,n.left+n.width-t.left),d=Math.min(t.height,n.top+n.height-t.top);if(!(s-a>.01&&d-i>.01))continue;let c=Math.floor(a+.01),p=Math.floor(i+.01);o.push({kind:r,x:c,y:p,w:Math.ceil(s-.01)-c,h:Math.ceil(d-.01)-p})}return o}var se=class{measure;send;nextFrame;queued=!1;sent=null;constructor(e,o,r=n=>requestAnimationFrame(n)){this.measure=e,this.send=o,this.nextFrame=r}changed(){this.queued||(this.queued=!0,this.nextFrame(()=>{this.queued=!1;let e=this.measure();if(!e)return;let o=JSON.stringify(e);o!==this.sent&&(this.sent=o,this.send(e))}))}resend(){this.sent=null,this.changed()}};var $t=t=>Math.max(0,Math.ceil(t/1e3)),$e=t=>{let e=t.slice(0,2).map(o=>o.name);return t.length>2?`${e.join(", ")} +${t.length-2}`:e.join(", ")};function vo(t){let{you:e,host:o,kind:r,match:n,now:a}=t,i=[...t.players].sort((l,f)=>l.id===e?-1:f.id===e?1:l.id===o?-1:f.id===o?1:l.name.localeCompare(f.name)).map(l=>({id:l.id,name:l.name,ready:!!l.ready,host:l.id===o,you:l.id===e,away:l.connected===!1,idle:l.connected!==!1&&!!l.idle})),s=t.players.filter(l=>l.connected!==!1),d=t.players.find(l=>l.id===e),c=o===e&&n.phase==="lobby",p=t.schema.map(l=>({id:l.id,label:l.label,value:et(l,t.written),options:l.options,editable:c})),x={n:s.filter(l=>l.ready||r!=="public"&&l.id===o).length,of:s.length},u={surface:"none",rows:i,count:`${t.players.length} / ${t.max}`,ready:x,status:"",action:{kind:"none",label:"",disabled:!0},settings:p,seconds:null},E=n.participants?.includes(e)??!1,q=o===e&&r!=="public";if(n.phase==="starting"){if(!E)return{...u,surface:"watching",status:"Watching"};let l=q?{kind:"stop",label:"Stop",disabled:!1}:{kind:"unready",label:"Not ready",disabled:!1};return t.ownCountdown?{...u,surface:"countdown",action:l,seconds:null,status:"Get ready"}:{...u,surface:"countdown",action:l,seconds:Math.max(1,$t((n.startsAt??a)-a)),status:"Get ready"}}if(n.phase==="playing"){if(n.paused){let l=s.filter(f=>n.participants?.includes(f.id)).length;return n.paused.reason==="host"?{...u,surface:"paused",status:"Paused"}:{...u,surface:"paused",seconds:$t(n.paused.since+P.matchAbandonMs-a),status:`Waiting for players \xB7 ${l} / ${n.min}`}}return E?u:{...u,surface:"watching",status:"Watching"}}let b=s.filter(l=>!l.ready&&(r==="public"||l.id!==o));if(u.surface="lobby",q){let l=s.length<n.min;return u.action={kind:"start",label:"Start",disabled:l||b.length>0},u.status=l?`Need ${n.min} players`:b.length?`Waiting for ${$e(b)}`:"",u}if(u.action={kind:d?.ready?"unready":"ready",label:d?.ready?"Not ready":"Ready",disabled:!1},r==="public")s.length<n.min?u.status=`Need ${n.min} players`:n.waitUntil!==void 0&&b.length?u.status=b.some(l=>l.id===e)?"Waiting for you":`Waiting for ${$e(b)}`:u.status=`${s.length-b.length} / ${s.length} ready`;else{let l=b.filter(f=>f.id!==e);u.status=d?.ready?l.length?`Waiting for ${$e(l)}`:`Waiting for ${t.players.find(f=>f.id===o)?.name??"the host"}`:""}return u}function h(t,e="",o){let r=document.createElement(t);return e&&(r.className=e),o!==void 0&&(r.textContent=o),r}var le=class{mode=null;ownCountdown=!1;targetOk=!1;targetTimer=0;lastKey=-1/0;state=null;schema=[];timer=0;opts;root;card;title;count;list;settingsBox;status;action;invite;bar;barFaces;barStatus;barAction;countdown;numeral;cancel;pause;pauseStatus;pauseTimer;chip;last=null;lastNumeral=-1;listSignature="";settingsSignature="";faceSignature="";constructor(e,o){this.opts=o,this.root=h("div","ow-lobby"),this.root.hidden=!0;for(let s of["pointerdown","mousedown"])this.root.addEventListener(s,d=>d.preventDefault());this.card=h("section","ow-lobby-card"),this.card.setAttribute("aria-label","Lobby");let r=h("header","ow-lobby-head");this.title=h("h2","","Lobby"),this.count=h("span","ow-lobby-count"),r.append(this.title,this.count),this.list=h("ul","ow-lobby-players"),this.settingsBox=h("div","ow-lobby-settings"),this.status=h("p","ow-lobby-status"),this.status.setAttribute("role","status"),this.action=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.invite=this.button("ow-btn ow-lobby-invite",()=>this.opts.onInvite()),this.invite.textContent="Invite";let n=h("div","ow-lobby-actions");n.append(this.action,this.invite),this.card.append(r,this.list,this.settingsBox,this.status,n),this.bar=h("div","ow-lobby-bar"),this.barFaces=h("span","ow-lobby-faces"),this.barStatus=h("span","ow-lobby-bar-status"),this.barStatus.setAttribute("role","status"),this.barAction=this.button("ow-btn ow-btn-primary ow-lobby-action",()=>this.press()),this.bar.append(this.barFaces,this.barStatus,this.barAction),this.countdown=h("div","ow-lobby-countdown"),this.numeral=h("b"),this.numeral.setAttribute("aria-hidden","true");let a=h("span","","Get ready");a.setAttribute("aria-hidden","true"),this.cancel=this.button("ow-btn ow-lobby-cancel",()=>this.press()),this.countdown.append(this.numeral,a,this.cancel),this.pause=h("div","ow-lobby-pause");let i=h("div","ow-lobby-pause-box");this.pauseStatus=h("p","ow-lobby-pause-status"),this.pauseStatus.setAttribute("role","status"),this.pauseTimer=h("p","ow-lobby-pause-timer"),i.append(this.pauseStatus,this.pauseTimer),this.pause.append(i),this.chip=h("div","ow-lobby-chip"),this.chip.setAttribute("role","status"),this.root.append(this.card,this.bar,this.countdown,this.pause,this.chip),e.append(this.root)}setSchema(e){this.schema=e,this.render()}enable(e,o={}){this.mode=e,this.ownCountdown=o.ownCountdown===!0,this.root.dataset.mode=e??"",e||this.reset(),this.render()}setLook(e){ae(this.root,zt,e)}reservedBox(){if(this.root.hidden)return null;let e=!this.countdown.hidden&&this.countdown.classList.contains("ow-lobby-countdown-bare"),o=this.bar.hidden?e&&!this.cancel.hidden?this.cancel:null:this.bar;return o?o.getBoundingClientRect():null}link(e){let o=!this.root.hidden&&(this.last?.surface==="lobby"||this.last?.surface==="countdown"),r=this.pressable()?.getBoundingClientRect()??null;if(!(r!==null&&r.left>=e.left&&r.top>=e.top&&r.left+r.width<=e.left+e.width&&r.top+r.height<=e.top+e.height))return{keys:o,button:null,cover:null};let[a]=Y(e,[{kind:"lobby",box:r}]),[i]=this.mode==="bar"?Y(e,[{kind:"lobby",box:this.bar.getBoundingClientRect()}]):[{x:0,y:0,w:e.width,h:e.height}];return!a||!i?{keys:o,button:null,cover:null}:{keys:o,button:{x:a.x,y:a.y,w:a.w,h:a.h},cover:{x:i.x,y:i.y,w:i.w,h:i.h}}}setTarget(e,o){window.clearTimeout(this.targetTimer),e&&(this.targetTimer=window.setTimeout(()=>this.setTarget(!1,!1),1600)),this.targetOk!==e&&(this.targetOk=e,this.applyTarget()),this.pressable()?.classList.toggle("ow-lobby-hover",e&&o)}pressKey(e=performance.now()){this.pressable()===null||e-this.lastKey<ft||(this.lastKey=e,this.press())}pressTarget(){this.pressable()&&this.press()}setKeyMark(e){this.root.classList.toggle("ow-lobby-keys",e)}pressable(){let e=this.last;return this.root.hidden||!e||e.surface!=="lobby"||e.action.kind==="none"||e.action.disabled?null:this.mode==="card"?this.action:this.barAction}applyTarget(){let e=this.targetOk&&this.pressable()!==null;if(this.root.classList.toggle("ow-lobby-through",e),!e)for(let o of[this.action,this.barAction])o.classList.remove("ow-lobby-hover")}setRoom(e,o=0){if(!e)return this.reset();this.state={you:e.you,host:e.host,kind:e.room.startsWith("private:")?"private":e.room.startsWith("room:")?"named":"public",max:Math.max(o,e.players.length),players:e.players.map(r=>({...r})),match:e.match??{phase:"lobby",n:0,min:1},written:e.state?.[V]},this.render()}handle(e){let o=this.state;if(o){switch(e.t){case"join":o.players=[...o.players.filter(r=>r.id!==e.player.id),{...e.player}];break;case"leave":o.players=o.players.filter(r=>r.id!==e.id);break;case"away":o.players=o.players.map(r=>r.id===e.id?{...r,connected:!1}:r);break;case"back":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{connected:n,...a}=r;return a});break;case"ready":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{ready:n,...a}=r;return e.ready?{...a,ready:!0}:a});break;case"unready":o.players=o.players.map(({ready:r,...n})=>n);break;case"host":o.host=e.id;break;case"idle":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{idle:n,...a}=r;return e.idle?{...a,idle:!0}:a});break;case"name":o.players=o.players.map(r=>r.id===e.id?{...r,name:e.name}:r);break;case"match":o.match=e.match;break;case"state":if(e.k!==V)return;o.written=e.v;break;default:return}this.render()}}chooseSetting(e,o){let r=this.state,n=this.schema.find(i=>i.id===e);if(!r||!n||!n.options.some(i=>i.value===o))return null;let a={...r.written!==null&&typeof r.written=="object"?r.written:{},[e]:o};return r.written=a,this.render(),a}setReadyLocal(e){let o=this.state?.players.find(r=>r.id===this.state?.you);o&&(e?o.ready=!0:delete o.ready,this.render())}button(e,o){let r=h("button",e);return r.type="button",r.addEventListener("pointerdown",n=>n.preventDefault()),r.addEventListener("click",o),r}press(){let e=this.last?.action.kind;e==="start"?this.opts.onStart():e==="stop"?this.opts.onStop():e==="ready"?(this.setReadyLocal(!0),this.opts.onReady(!0)):e==="unready"&&(this.setReadyLocal(!1),this.opts.onReady(!1)),this.opts.onPressed?.()}reset(){this.state=null,this.last=null,this.setTarget(!1,!1),window.clearInterval(this.timer),this.timer=0,this.root.hidden=!0,this.opts.onLayout?.()}render(){this.draw(),this.opts.onLayout?.()}draw(){if(!this.mode||!this.state){this.root.hidden=!0;return}let e=vo({...this.state,schema:this.schema,now:this.opts.now(),ownCountdown:this.ownCountdown});this.last=e;let o=e.surface==="lobby";if(this.root.hidden=e.surface==="none",this.card.hidden=!(o&&this.mode==="card"),this.bar.hidden=!(o&&this.mode==="bar"),this.countdown.hidden=e.surface!=="countdown",this.countdown.classList.toggle("ow-lobby-countdown-bare",e.surface==="countdown"&&e.seconds===null),this.pause.hidden=e.surface!=="paused",this.chip.hidden=e.surface!=="watching",this.root.classList.toggle("ow-lobby-dim",o&&this.mode==="card"),o&&this.mode==="card"&&this.renderCard(e),o&&this.mode==="bar"&&this.renderBar(e),this.applyTarget(),e.surface==="countdown"&&e.seconds!==null&&e.seconds!==this.lastNumeral&&(this.lastNumeral=e.seconds,this.numeral.textContent=String(e.seconds),this.numeral.style.animation="none",this.numeral.offsetWidth,this.numeral.style.animation=""),e.surface==="countdown"&&(this.cancel.textContent=e.action.label),e.surface!=="countdown"&&(this.lastNumeral=-1),e.surface==="paused"&&(this.pauseStatus.textContent=e.status,this.pauseTimer.textContent=e.seconds!==null?`Ends in ${ko(e.seconds)}`:""),e.surface==="watching"){let[n,...a]=e.status.split(" \xB7 "),i=h("span","ow-lobby-chip-more",a.length?` \xB7 ${a.join(" \xB7 ")}`:"");this.chip.replaceChildren(n,i)}let r=e.seconds!==null;r&&!this.timer?this.timer=window.setInterval(()=>this.render(),250):!r&&this.timer&&(window.clearInterval(this.timer),this.timer=0)}renderCard(e){this.count.textContent=e.count,this.settingsBox.hidden=e.settings.length===0,this.status.textContent=e.status,this.status.hidden=e.status==="",this.setAction(this.action,e);let o=JSON.stringify(e.settings);o!==this.settingsSignature&&(this.settingsSignature=o,this.settingsBox.replaceChildren(...e.settings.map(n=>this.settingRow(n))));let r=JSON.stringify(e.rows);r!==this.listSignature&&(this.listSignature=r,this.list.replaceChildren(...e.rows.map(n=>{let a=h("li",n.away||n.idle?"ow-lobby-away":n.ready?"ow-lobby-ready":""),i=h("img","ow-headshot");i.src=`/avatar/${encodeURIComponent(n.id)}/head.svg`,i.alt="";let s=h("span","ow-lobby-name",n.name),d=[n.away?"Reconnecting":n.idle?"Idle":"",n.you?"You":"",n.host?"Host":""].filter(Boolean).join(" \xB7 ");return a.append(i,s),d&&a.append(h("span","ow-player-notes",d)),a.append(h("span",`ow-lobby-check${n.ready?" ow-lobby-check-on":""}`,n.ready?"Ready":"")),a})))}settingRow(e){let o=h("div","ow-lobby-setting");if(o.append(h("span","ow-lobby-setting-label",e.label)),!e.editable)return o.append(h("span","ow-lobby-setting-value",e.options.find(n=>n.value===e.value)?.label??String(e.value))),o;let r=h("div","ow-segments");r.setAttribute("role","radiogroup"),r.setAttribute("aria-label",e.label);for(let n of e.options){let a=this.button(`ow-segment${n.value===e.value?" ow-segment-on":""}`,()=>this.opts.onSetting(e.id,n.value));a.textContent=n.label,a.setAttribute("role","radio"),a.setAttribute("aria-checked",String(n.value===e.value)),r.append(a)}return o.append(r),o}renderBar(e){this.barStatus.textContent=e.status||`${e.ready.n} / ${e.ready.of} ready`,this.setAction(this.barAction,e);let o=JSON.stringify(e.rows.slice(0,5).map(r=>[r.id,r.ready]));o!==this.faceSignature&&(this.faceSignature=o,this.barFaces.replaceChildren(...e.rows.slice(0,5).map(r=>{let n=h("img",`ow-headshot${r.ready?" ow-lobby-face-ready":""}`);return n.src=`/avatar/${encodeURIComponent(r.id)}/head.svg`,n.alt="",n})))}setAction(e,o){e.hidden=o.action.kind==="none",e.textContent=o.action.label,e.disabled=o.action.disabled,e.setAttribute("aria-keyshortcuts","Enter"),e.classList.toggle("ow-btn-primary",o.action.kind!=="unready")}};function ko(t){return`${Math.floor(t/60)}:${String(t%60).padStart(2,"0")}`}var Ce=t=>`ow:resume:${t}`;function I(t,e){try{e?sessionStorage.setItem(Ce(t),JSON.stringify({...e,at:Date.now()})):sessionStorage.removeItem(Ce(t))}catch{}}function Ct(t){try{let e=sessionStorage.getItem(Ce(t));if(!e)return null;let o=performance.getEntriesByType("navigation")[0];if(o&&o.type!=="reload"&&o.type!=="back_forward")return pe(t);let r=JSON.parse(e);return typeof r.key!="string"||typeof r.rejoin!="string"||typeof r.at!="number"||Date.now()-r.at>18e4||Number(r.rejoin.split(".")[0])*1e3<Date.now()?pe(t):{key:r.key,rejoin:r.rejoin}}catch{return null}}var So=t=>`ow:own-server:${t}`;function Tt(t,e){try{sessionStorage.setItem(So(t),e)}catch{}}function pe(t){return I(t,null),null}var de=class extends Error{constructor(o,r=0,n=0,a=""){super(o);this.status=r;this.retryAfterMs=n;this.code=a;this.name="RequestError"}status;retryAfterMs;code;get retryable(){return this.status===0||this.status===408||this.status===429||this.status>=500}};var ce=class{constructor(e=48*1024){this.max=e}max;used=0;async run(e,o){let r=new TextEncoder().encode(e).byteLength;if(this.used+r>this.max)throw new de("Progress is waiting to sync when you return to the game.");this.used+=r;try{return await o()}finally{this.used-=r}}};var Te=/^[2-9]$/.test(new URLSearchParams(location.search).get("player")??"")?new URLSearchParams(location.search).get("player"):null;var zo=null;function Dt(){return zo?.n??null}var Mr=new ce;var Ot=[300,700,1500,3e3,5e3,8e3],Ro=9e4,Eo=1e4,It=()=>Array.from(crypto.getRandomValues(new Uint8Array(10)),t=>"abcdefghijklmnopqrstuvwxyz0123456789"[t%36]).join(""),Bt=It();function jt(){Bt=It()}var _t=null;var Nt=!1;function Gt(t){Nt=t}var Po=5e4,Mo=4e3,ge=class{ws=null;key=null;rejoin=null;you="";closed=!1;attempt=0;droppedAt=0;sleeping=!1;lastHeard=0;heardCount=0;pingAt=0;hintedHidden=!1;pingTimer=0;watchTimer=0;retryTimer=0;page=Bt;slug;options;callbacks;onVisible=()=>{this.hint(),document.visibilityState==="visible"&&this.wake()};onOnline=()=>this.wake();onShow=e=>e.persisted&&this.wake();onHide=()=>this.hint();constructor(e,o,r){this.slug=e,this.options=o,this.callbacks=r,this.key=o.key??null,this.rejoin=o.rejoin??null,document.addEventListener("visibilitychange",this.onVisible),addEventListener("online",this.onOnline),addEventListener("pageshow",this.onShow),addEventListener("pagehide",this.onHide)}join(){return new Promise((e,o)=>this.open(e,o))}send(e){this.ws?.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify(e))}hint(){let e=document.visibilityState==="hidden";e===this.hintedHidden||this.ws?.readyState!==WebSocket.OPEN||(this.hintedHidden=e,this.send({t:"vis",hidden:e}))}ping(){let e=this.ws;e?.readyState===WebSocket.OPEN&&(this.pingAt&&Date.now()-this.pingAt<5e3||(this.pingAt=Date.now(),e.send(Se)))}close(){this.closed=!0,I(this.slug,null),this.dispose(),this.ws?.close(1e3)}reload(){return this.closed=!0,this.dispose(),this.ws?.close(nt,"Updating"),this.key?.startsWith("pub:")&&this.rejoin?{key:this.key,rejoin:this.rejoin}:null}open(e,o){this.retryTimer=0;let r=new URL(`/api/games/${this.slug}/rooms/connect`,location.href);r.protocol=location.protocol==="https:"?"wss:":"ws:",this.key?(r.searchParams.set("key",this.key),this.rejoin&&r.searchParams.set("rejoin",this.rejoin)):this.options.server?(r.searchParams.set("server",this.options.server),this.options.private&&r.searchParams.set("own","1")):this.options.name?r.searchParams.set("name",this.options.name):(this.options.mode&&r.searchParams.set("mode",this.options.mode),this.options.follow&&r.searchParams.set("follow",this.options.follow)),this.options.maxPlayers&&r.searchParams.set("max",String(this.options.maxPlayers)),this.options.minPlayers&&r.searchParams.set("min",String(this.options.minPlayers)),this.options.countdown!==void 0&&r.searchParams.set("countdown",String(this.options.countdown)),this.options.teams&&r.searchParams.set("teams",String(this.options.teams)),this.options.ranked&&r.searchParams.set("ranked","1"),Te&&r.searchParams.set("devplayer",Te);let n=Dt();n&&r.searchParams.set("tester",n),r.searchParams.set("page",this.page),this.options.build&&r.searchParams.set("build",this.options.build),_t&&r.searchParams.set("pass",_t),Nt&&r.searchParams.set("demo","1");let a=new WebSocket(r);this.ws=a,this.lastHeard=Date.now();let i=!1;a.onopen=()=>{this.lastHeard=Date.now(),window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),this.pingTimer=window.setInterval(()=>a.readyState===WebSocket.OPEN&&this.ping(),Eo),this.watchTimer=window.setInterval(()=>{a===this.ws&&a.readyState===WebSocket.OPEN&&Date.now()-this.lastHeard>Po&&this.lost(a)},5e3)},a.onmessage=c=>{this.lastHeard=Date.now(),this.heardCount++;let p;try{p=JSON.parse(c.data)}catch{return}if(p.t==="pong"){this.pingAt&&this.callbacks.onRtt?.(Date.now()-this.pingAt),this.pingAt=0;return}if(p.t==="welcome"&&(p.rejoin&&(this.rejoin=p.rejoin),delete p.rejoin,p.room.startsWith("pub:")&&this.rejoin&&I(this.slug,{key:p.room,rejoin:this.rejoin})),p.t==="leave"&&p.kicked&&p.id===this.you){this.close(),this.finish("kicked");return}if(p.t==="welcome"&&(this.hintedHidden=!1,this.hint()),p.t==="welcome"&&!i&&(i=!0,this.key=p.room,this.you=p.you,this.attempt=0,this.droppedAt&&(this.droppedAt=0,this.callbacks.onConnection?.(!0)),e)){let{t:x,...u}=p;e(u),e=void 0;return}this.callbacks.onMessage(p)};let s=!1,d=c=>{if(!s&&(s=!0,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),!(this.closed||a!==this.ws))){if(c.code===tt)return this.finish("replaced");if(c.code===rt&&i&&document.visibilityState==="hidden"){this.sleeping=!0,this.droppedAt||(this.droppedAt=Date.now(),this.callbacks.onConnection?.(!1));return}if(c.code===ot){if(i||!o)return this.finish("kicked");this.closed=!0,this.dispose(),I(this.slug,null),o(Object.assign(new Error("You were removed from this server."),{kicked:!0}));return}if(!i&&o){this.closed=!0,this.dispose(),o(new Error(this.options.name||this.options.server?"Could not join that server. It may be full.":"Could not join a server. Try again soon."));return}this.retry()}};a.onclose=d,a.onerror=()=>{window.setTimeout(()=>{a.readyState===WebSocket.CLOSED&&d({code:1006})},1e3)}}retry(){if(this.closed)return;let e=Date.now();if(this.droppedAt||(this.droppedAt=e,this.callbacks.onConnection?.(!1)),e-this.droppedAt>Ro)return this.finish("disconnected");if(this.retryTimer)return;let o=Ot[Math.min(this.attempt++,Ot.length-1)]*(.5+Math.random());this.retryTimer=window.setTimeout(()=>{this.retryTimer=0,this.closed||this.open()},o)}lost(e){if(!(e!==this.ws||this.closed)){e.onopen=e.onmessage=e.onclose=e.onerror=null,window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer);try{e.close()}catch{}this.retry()}}wake(){if(this.closed)return;if(this.sleeping){this.sleeping=!1,this.droppedAt=Date.now(),this.attempt=0,this.open();return}let e=this.ws;if(!e||e.readyState===WebSocket.CLOSING||e.readyState===WebSocket.CLOSED){this.retryTimer&&(window.clearTimeout(this.retryTimer),this.retryTimer=0,this.open());return}if(e.readyState!==WebSocket.OPEN)return;let o=this.heardCount;try{e.send(Se)}catch{return this.lost(e)}window.setTimeout(()=>e===this.ws&&!this.closed&&this.heardCount===o&&this.lost(e),Mo)}dispose(){window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),window.clearTimeout(this.retryTimer),this.retryTimer=0,document.removeEventListener("visibilitychange",this.onVisible),removeEventListener("online",this.onOnline),removeEventListener("pageshow",this.onShow),removeEventListener("pagehide",this.onHide)}finish(e){this.closed=!0,this.dispose(),I(this.slug,null),this.callbacks.onClose(e)}};var Ut=`:root {
2
4
  color-scheme: light;
3
5
  /* Site pages: as wide as this at most, with gutters that grow with the window. */
4
6
  --page: 1440px;
@@ -57,9 +59,8 @@
57
59
  --play-fill-hover: #ff8366;
58
60
  --play-ink: #121418;
59
61
  --play-text: var(--ok);
60
- /* Live: players in a game right now. The store's signal colour: a dot, a count, a Join. */
62
+ /* Live: players in a game right now. The store's signal colour: a dot, a count. */
61
63
  --live: #3ddc84;
62
- --live-ink: #0b2a17;
63
64
  --live-text: #12813f;
64
65
  /* The phone tab bar (and popups opened from it). */
65
66
  --dock-bg: var(--bar);
@@ -383,12 +384,33 @@ h3 {
383
384
  color: var(--danger);
384
385
  }
385
386
 
386
- .btn-small {
387
+ /* (A row's buttons are always this size: a list reads the same whatever its row can do.) */
388
+ .btn-small,
389
+ .row-actions .btn {
387
390
  min-height: 32px;
388
391
  padding: 0 12px;
389
392
  font-size: 13px;
390
393
  }
391
394
 
395
+ /* Fingers: small buttons and links stay easy to hit (padding on the links, which doesn't move anything around them). */
396
+ @media (pointer: coarse) {
397
+ .btn-small,
398
+ .row-actions .btn {
399
+ min-height: 40px;
400
+ }
401
+
402
+ .see-all,
403
+ .clear-search {
404
+ margin: -10px 0;
405
+ padding: 10px 0;
406
+ }
407
+
408
+ .label-row a,
409
+ .auth-switch a {
410
+ padding: 10px 4px;
411
+ }
412
+ }
413
+
392
414
  /* A plain file picker (a form that posts its file, like Upload files' Cover): its button is a small .btn. */
393
415
  input[type='file'] {
394
416
  max-width: 100%;
@@ -438,10 +460,14 @@ input[type='file']::file-selector-button:hover {
438
460
 
439
461
  .link-btn {
440
462
  padding: 6px 10px;
463
+ border: 0;
464
+ background: none;
441
465
  color: var(--text);
466
+ font-family: inherit;
442
467
  font-weight: 600;
443
468
  font-size: 14px;
444
469
  text-decoration: none;
470
+ cursor: pointer;
445
471
  }
446
472
 
447
473
  .link-btn:hover {
@@ -461,6 +487,7 @@ input[type='text'],
461
487
  input[type='email'],
462
488
  input[type='password'],
463
489
  input[type='search'],
490
+ input[type='number'],
464
491
  input:not([type]),
465
492
  select,
466
493
  textarea {
@@ -1268,6 +1295,15 @@ button.icon-btn:hover {
1268
1295
  background: var(--accent);
1269
1296
  }
1270
1297
 
1298
+ /* The chat is open over the page: one tab is lit, Chat. */
1299
+ .tabbar:has(> button[aria-expanded='true']) > a[aria-current='page'] {
1300
+ color: var(--dock-muted);
1301
+ }
1302
+
1303
+ .tabbar:has(> button[aria-expanded='true']) > a[aria-current='page']::before {
1304
+ content: none;
1305
+ }
1306
+
1271
1307
  .tabbar > a:focus-visible,
1272
1308
  .tabbar > button:focus-visible {
1273
1309
  outline: 2px solid var(--accent);
@@ -1528,7 +1564,6 @@ body:has(.tabbar) .footer-inner {
1528
1564
  color: var(--muted);
1529
1565
  font-size: 14px;
1530
1566
  font-weight: 600;
1531
- font-variant-numeric: tabular-nums;
1532
1567
  }
1533
1568
 
1534
1569
  .see-all {
@@ -1771,6 +1806,21 @@ body:has(.tabbar) .footer-inner {
1771
1806
  left: 0;
1772
1807
  }
1773
1808
 
1809
+ @media (max-width: 560px) {
1810
+ .storenav {
1811
+ flex-wrap: wrap;
1812
+ height: auto;
1813
+ }
1814
+ .storenav-links {
1815
+ flex: 1 1 100%;
1816
+ height: 46px;
1817
+ }
1818
+ .storenav-filters,
1819
+ .storenav-random {
1820
+ height: 40px;
1821
+ }
1822
+ }
1823
+
1774
1824
  .storenav-filters {
1775
1825
  display: flex;
1776
1826
  }
@@ -2423,17 +2473,6 @@ body:has(.tabbar) .footer-inner {
2423
2473
  background: var(--live);
2424
2474
  }
2425
2475
 
2426
- .btn.btn-live {
2427
- border-color: transparent;
2428
- background: var(--live);
2429
- color: var(--live-ink);
2430
- font-weight: 700;
2431
- }
2432
-
2433
- .btn.btn-live:hover {
2434
- background: color-mix(in srgb, var(--live) 85%, #fff);
2435
- }
2436
-
2437
2476
  /* Every game: its title (with See all on home, Clear on a search), the filters that are on, and the grid. */
2438
2477
  .browse-head {
2439
2478
  display: flex;
@@ -2898,6 +2937,14 @@ body:has(.tabbar) .footer-inner {
2898
2937
  padding: 96px 16px;
2899
2938
  }
2900
2939
 
2940
+ .lib-empty-actions {
2941
+ display: flex;
2942
+ flex-wrap: wrap;
2943
+ justify-content: center;
2944
+ gap: 10px;
2945
+ margin-top: 20px;
2946
+ }
2947
+
2901
2948
  /* A repo whose first deploy failed, in the side: its square says so. */
2902
2949
  .lib-icon.mine-failed {
2903
2950
  color: var(--danger);
@@ -2950,11 +2997,15 @@ body:has(.tabbar) .footer-inner {
2950
2997
  height: clamp(22px, 10.4cqi, 36px);
2951
2998
  border-radius: 5px;
2952
2999
  object-fit: cover;
2953
- background: var(--fill);
2954
3000
  font-size: 12px;
2955
3001
  font-weight: 800;
2956
3002
  }
2957
3003
 
3004
+ /* (A letter's square keeps its game's colour.) */
3005
+ .lib-icon:not(.gcard-letter) {
3006
+ background: var(--fill);
3007
+ }
3008
+
2958
3009
  @container side (min-width: 320px) {
2959
3010
  .lib-list a {
2960
3011
  min-height: 42px;
@@ -3683,6 +3734,11 @@ body:has(.tabbar) .footer-inner {
3683
3734
  align-items: start;
3684
3735
  }
3685
3736
 
3737
+ /* A page with nothing else: More like this keeps the gap it has under the game's body. */
3738
+ .game-top + .section {
3739
+ margin-top: 44px;
3740
+ }
3741
+
3686
3742
  /* One column: Play comes first in the panel, right under the gallery. */
3687
3743
  @media (max-width: 1000px) {
3688
3744
  .game-top {
@@ -3979,6 +4035,12 @@ body:has(.tabbar) .footer-inner {
3979
4035
  list-style: none;
3980
4036
  }
3981
4037
 
4038
+ .play-pay > summary,
4039
+ a.play-pay {
4040
+ padding: 6px 0;
4041
+ text-decoration: underline;
4042
+ }
4043
+
3982
4044
  .play-pay[open] > summary {
3983
4045
  margin-bottom: 8px;
3984
4046
  }
@@ -4365,9 +4427,11 @@ body:has(.tabbar) .footer-inner {
4365
4427
  }
4366
4428
 
4367
4429
  .fold-count {
4430
+ margin-left: 4px;
4368
4431
  color: var(--muted);
4369
4432
  font-size: 14px;
4370
4433
  font-variant-numeric: tabular-nums;
4434
+ white-space: nowrap;
4371
4435
  }
4372
4436
 
4373
4437
  .fold-caret {
@@ -4547,6 +4611,11 @@ body:has(.tabbar) .footer-inner {
4547
4611
  margin: 0 0 18px;
4548
4612
  }
4549
4613
 
4614
+ /* An order: its Play or Open, then what was bought. */
4615
+ .market-order .form-row:has(+ .kv) {
4616
+ margin-bottom: 18px;
4617
+ }
4618
+
4550
4619
  .kv dt {
4551
4620
  color: var(--muted);
4552
4621
  font-size: 12px;
@@ -7211,8 +7280,7 @@ body.play {
7211
7280
  body.play .ow-menu,
7212
7281
  body.play .ow-social-body,
7213
7282
  body.play .ow-chat-log,
7214
- body.play .ow-players,
7215
- body.play .ow-badges {
7283
+ body.play .ow-players {
7216
7284
  touch-action: pan-y;
7217
7285
  }
7218
7286
 
@@ -7742,9 +7810,11 @@ body.play input {
7742
7810
  padding-bottom: 16px;
7743
7811
  }
7744
7812
 
7813
+ /* Its first line level with the head's buttons. */
7745
7814
  .ow-menu-title {
7746
7815
  flex: 1;
7747
7816
  min-width: 0;
7817
+ padding-top: 4px;
7748
7818
  }
7749
7819
 
7750
7820
  .ow-menu-head h2 {
@@ -7797,8 +7867,7 @@ body.play input {
7797
7867
  }
7798
7868
 
7799
7869
  .ow-section[hidden],
7800
- .ow-setting[hidden],
7801
- .ow-guest[hidden] {
7870
+ .ow-setting[hidden] {
7802
7871
  display: none;
7803
7872
  }
7804
7873
 
@@ -7861,11 +7930,14 @@ body.play input {
7861
7930
  overflow-y: auto;
7862
7931
  }
7863
7932
 
7933
+ /* A row with more buttons than room takes a second line for them: the name stays readable. */
7864
7934
  .ow-players li {
7865
7935
  display: flex;
7936
+ flex-wrap: wrap;
7866
7937
  align-items: center;
7867
- gap: 10px;
7938
+ gap: 2px 10px;
7868
7939
  min-height: 40px;
7940
+ padding: 2px 0;
7869
7941
  font-size: 14px;
7870
7942
  }
7871
7943
 
@@ -7901,8 +7973,10 @@ a.ow-player-name:focus-visible {
7901
7973
  }
7902
7974
 
7903
7975
  .ow-player-actions {
7904
- flex: none;
7976
+ flex: 0 1 auto;
7905
7977
  display: flex;
7978
+ flex-wrap: wrap;
7979
+ justify-content: flex-end;
7906
7980
  gap: 6px;
7907
7981
  margin-left: auto;
7908
7982
  }
@@ -8044,17 +8118,6 @@ a.ow-player-name:focus-visible {
8044
8118
  white-space: nowrap;
8045
8119
  }
8046
8120
 
8047
- .ow-server {
8048
- display: flex;
8049
- flex-wrap: wrap;
8050
- align-items: center;
8051
- justify-content: space-between;
8052
- gap: 4px 12px;
8053
- margin-top: 6px;
8054
- color: var(--muted);
8055
- font-size: 13px;
8056
- }
8057
-
8058
8121
  .ow-text-btn {
8059
8122
  padding: 0;
8060
8123
  border: 0;
@@ -8118,24 +8181,6 @@ button.ow-setting-icon:hover {
8118
8181
  outline-offset: 2px;
8119
8182
  }
8120
8183
 
8121
- .ow-guest {
8122
- margin: 0;
8123
- padding: 12px 0;
8124
- border-top: 1px solid var(--line);
8125
- color: var(--muted);
8126
- font-size: 13px;
8127
- }
8128
-
8129
- .ow-guest a {
8130
- color: var(--accent-text);
8131
- font-weight: 600;
8132
- text-decoration: none;
8133
- }
8134
-
8135
- .ow-guest a:hover {
8136
- text-decoration: underline;
8137
- }
8138
-
8139
8184
  .ow-menu-foot {
8140
8185
  display: flex;
8141
8186
  gap: 8px;
@@ -8305,80 +8350,14 @@ button.ow-setting-icon:hover {
8305
8350
  letter-spacing: 0.06em;
8306
8351
  }
8307
8352
 
8308
- .ow-badges {
8309
- list-style: none;
8310
- margin: 0;
8311
- padding: 0;
8312
- display: flex;
8313
- flex-wrap: wrap;
8314
- gap: 8px;
8315
- }
8316
-
8317
- .ow-badge-item {
8318
- display: block;
8319
- padding: 0;
8320
- border: 0;
8321
- border-radius: 50%;
8322
- background: none;
8323
- cursor: pointer;
8324
- opacity: 0.35;
8325
- filter: grayscale(1);
8326
- transition: opacity 0.15s ease;
8327
- }
8328
-
8329
- .ow-badge-item:hover {
8330
- opacity: 0.55;
8331
- }
8332
-
8333
- .ow-badge-item.ow-earned {
8334
- opacity: 1;
8335
- filter: none;
8336
- }
8337
-
8338
- .ow-badge-item:focus-visible {
8339
- outline: 2px solid var(--accent-hover);
8340
- outline-offset: 2px;
8341
- }
8342
-
8343
- .ow-badge-icon {
8344
- display: block;
8345
- width: 40px;
8346
- height: 40px;
8347
- border-radius: 50%;
8348
- object-fit: cover;
8349
- }
8350
-
8351
- .ow-badge-blank {
8353
+ .ow-toast .ow-badge-blank {
8352
8354
  display: grid;
8353
8355
  place-items: center;
8354
- background: var(--fill-strong);
8355
- color: var(--text);
8356
- font-size: 18px;
8357
- }
8358
-
8359
- .ow-earned .ow-badge-blank,
8360
- .ow-toast .ow-badge-blank {
8361
8356
  background: var(--accent-soft);
8362
8357
  color: var(--accent-hover);
8363
- }
8364
-
8365
- .ow-toast .ow-badge-blank {
8366
8358
  font-size: 20px;
8367
8359
  }
8368
8360
 
8369
- .ow-badge-caption {
8370
- margin: 10px 0 0;
8371
- color: var(--muted);
8372
- font-size: 13px;
8373
- line-height: 1.45;
8374
- }
8375
-
8376
- .ow-badge-caption b {
8377
- margin-right: 2px;
8378
- color: var(--text);
8379
- font-weight: 600;
8380
- }
8381
-
8382
8361
  /* loading card shown until the game's page has loaded */
8383
8362
  .ow-loading {
8384
8363
  position: fixed;
@@ -8402,6 +8381,39 @@ button.ow-setting-icon:hover {
8402
8381
  transition: opacity 0.35s ease, visibility 0s linear 0.35s;
8403
8382
  }
8404
8383
 
8384
+ /* A page that never ran: what's in the frame (a device's filter page, an error) stays in view and can be tapped, the card below it. */
8385
+ .ow-loading.ow-loading-clear {
8386
+ align-items: end;
8387
+ background: none;
8388
+ pointer-events: none;
8389
+ }
8390
+
8391
+ .ow-loading-clear .ow-loading-cover,
8392
+ .ow-loading-clear .ow-loading-icon {
8393
+ display: none;
8394
+ }
8395
+
8396
+ .ow-loading-clear .ow-loading-inner {
8397
+ gap: 10px;
8398
+ margin-bottom: calc(16px + env(safe-area-inset-bottom));
8399
+ padding: 16px 20px;
8400
+ border-radius: 16px;
8401
+ background: #0e0f12;
8402
+ pointer-events: auto;
8403
+ }
8404
+
8405
+ .ow-loading-clear .ow-loading-name {
8406
+ font-size: 16px;
8407
+ }
8408
+
8409
+ /* On the right: the play page's own buttons show on the left now that the card doesn't cover them. */
8410
+ .ow-loading.ow-loading-clear .ow-loading-close {
8411
+ right: calc(20px + env(safe-area-inset-right));
8412
+ left: auto;
8413
+ background: #0e0f12;
8414
+ pointer-events: auto;
8415
+ }
8416
+
8405
8417
  /* The game's cover, full-bleed, blurred and darkened (a blur hides the small size it is fetched at). */
8406
8418
  .ow-loading-cover {
8407
8419
  position: absolute;
@@ -8576,6 +8588,26 @@ button.ow-setting-icon:hover {
8576
8588
  .ow-menu {
8577
8589
  padding: 16px;
8578
8590
  }
8591
+ .ow-menu-title {
8592
+ padding-top: 8px;
8593
+ }
8594
+ }
8595
+
8596
+ /* The narrowest phones: rows wrap instead of pushing the menu sideways. */
8597
+ @media (max-width: 360px) {
8598
+ .ow-menu {
8599
+ padding: 12px;
8600
+ overflow-x: hidden;
8601
+ }
8602
+ .ow-menu-foot {
8603
+ flex-wrap: wrap;
8604
+ }
8605
+ .ow-menu-foot .ow-btn {
8606
+ flex: 1 1 100%;
8607
+ }
8608
+ .ow-section-head {
8609
+ flex-wrap: wrap;
8610
+ }
8579
8611
  }
8580
8612
 
8581
8613
  @media (prefers-reduced-motion: reduce) {
@@ -10402,6 +10434,38 @@ body.play .ow-card {
10402
10434
  border-radius: 999px;
10403
10435
  }
10404
10436
 
10437
+ /* Enter presses the button: one small mark, for keyboards. */
10438
+ .ow-lobby-keys .ow-lobby-action:not(:disabled)::after {
10439
+ content: '\\21B5' / '';
10440
+ margin-left: 8px;
10441
+ font-size: 0.85em;
10442
+ font-weight: 400;
10443
+ opacity: 0.65;
10444
+ }
10445
+
10446
+ /* A press goes through to the target under the button, inside the game's frame (shell/lobby.ts, link): it is then the player's gesture
10447
+ there. The strip goes through whole, and the card's own parts stay on this page. */
10448
+ .ow-lobby.ow-lobby-through,
10449
+ .ow-lobby-through > .ow-lobby-card,
10450
+ .ow-lobby-through > .ow-lobby-bar,
10451
+ .ow-lobby-through .ow-lobby-actions,
10452
+ .ow-lobby-through .ow-lobby-action {
10453
+ pointer-events: none;
10454
+ }
10455
+
10456
+ .ow-lobby-through > .ow-lobby-card > :not(.ow-lobby-actions),
10457
+ .ow-lobby-through .ow-lobby-invite {
10458
+ pointer-events: auto;
10459
+ }
10460
+
10461
+ .ow-lobby-hover.ow-btn {
10462
+ background: rgba(255, 255, 255, 0.16);
10463
+ }
10464
+
10465
+ .ow-lobby-hover.ow-btn-primary {
10466
+ background: var(--accent-fill-hover);
10467
+ }
10468
+
10405
10469
  /* 3, 2, 1. */
10406
10470
  .ow-lobby-countdown {
10407
10471
  position: fixed;
@@ -10811,6 +10875,32 @@ body.ow-calm .ow-fold-caret {
10811
10875
  overflow-wrap: anywhere;
10812
10876
  }
10813
10877
 
10878
+ .upload-kinds dl {
10879
+ margin: 0;
10880
+ font-size: 14px;
10881
+ }
10882
+
10883
+ .upload-kinds dl > div {
10884
+ display: grid;
10885
+ grid-template-columns: 7.5em minmax(0, 1fr);
10886
+ gap: 12px;
10887
+ padding: 7px 0;
10888
+ border-top: 1px solid var(--line);
10889
+ }
10890
+
10891
+ .upload-kinds dt {
10892
+ font-weight: 600;
10893
+ }
10894
+
10895
+ .upload-kinds dd {
10896
+ margin: 0;
10897
+ color: var(--muted);
10898
+ }
10899
+
10900
+ .upload-kinds .fine {
10901
+ margin: 7px 0 12px;
10902
+ }
10903
+
10814
10904
  .upload-form .flash {
10815
10905
  margin: 0;
10816
10906
  }
@@ -13537,35 +13627,6 @@ body.share-frame {
13537
13627
  }
13538
13628
  }
13539
13629
 
13540
- /* The play page's menu: Share (the server's invite link, on X or a phone's share sheet), and for guests one quiet line. */
13541
- .ow-share {
13542
- display: flex;
13543
- gap: 8px;
13544
- padding: 12px 0;
13545
- border-top: 1px solid var(--line);
13546
- }
13547
-
13548
- .ow-share .ow-pill {
13549
- text-decoration: none;
13550
- }
13551
-
13552
- .ow-made {
13553
- margin: 0;
13554
- padding: 0 0 12px;
13555
- color: var(--muted);
13556
- font-size: 12px;
13557
- }
13558
-
13559
- .ow-made a {
13560
- color: inherit;
13561
- font-weight: 600;
13562
- text-decoration: none;
13563
- }
13564
-
13565
- .ow-made a:hover {
13566
- color: var(--text);
13567
- }
13568
-
13569
13630
  /* A clip frame records the game alone: the platform's corner buttons and chat stay out of the creator's view. */
13570
13631
  .ow-clip-frame .ow-hud,
13571
13632
  .ow-clip-frame .ow-stats {
@@ -13742,7 +13803,7 @@ body.share-frame {
13742
13803
  gap: 16px;
13743
13804
  margin-top: 12px;
13744
13805
  }
13745
- `;var q=JSON.parse(document.getElementById("ow-data").textContent),pe=q.game.slug,O=new URL(location.href).searchParams,ze=/^[2-9]$/.test(O.get("player")??"")?O.get("player"):null,ke=O.get("demo"),D=ke===null||ke==="0"?null:{paid:ke!=="free"};zt(D!==null);var $t=document.createElement("style");$t.textContent=`${Rt}
13806
+ `;var X=JSON.parse(document.getElementById("ow-data").textContent),Z=X.game.slug,N=new URL(location.href).searchParams,_e=/^[2-9]$/.test(N.get("player")??"")?N.get("player"):null,De=N.get("demo"),B=De===null||De==="0"?null:{paid:De!=="free"};Gt(B!==null);var Vt=document.createElement("style");Vt.textContent=`${Ut}
13746
13807
  .ow-local-panel { position: fixed; z-index: 30; top: 64px; left: 10px; max-width: min(340px, calc(100vw - 20px)); padding: 12px 14px; border-radius: 12px; background: var(--glass); border: 1px solid var(--line); color: var(--text); font: 14px/1.45 var(--font); backdrop-filter: blur(12px); }
13747
13808
  .ow-local-panel[hidden] { display: none; }
13748
13809
  .ow-local-panel b { font-weight: 650; }
@@ -13750,4 +13811,4 @@ body.share-frame {
13750
13811
  .ow-local-panel p { margin: 0 0 6px; }
13751
13812
  .ow-local-toast { position: fixed; z-index: 40; left: 50%; bottom: 24px; transform: translateX(-50%); max-width: calc(100vw - 32px); padding: 10px 14px; border-radius: 10px; background: var(--glass); color: var(--text); font: 14px/1.4 var(--font); border: 1px solid var(--line); }
13752
13813
  .ow-local-toast[hidden] { display: none; }
13753
- `;document.head.append($t);document.body.classList.add("play");var R=document.getElementById("ow-game");R.setAttribute("sandbox",Qe);R.setAttribute("allow",et);var G=document.getElementById("ow-root");function ao(){let t=new URLSearchParams;for(let[o,r]of O)tt.has(o)||t.append(o,r);let e=t.toString();return e&&e.length<=400?`?${e}`:""}var _=w("div","ow-hud ow-pos-top-left"),Ee=w("div","ow-bar"),io='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>',so='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.4c-.5.4-1.3 0-1.3-.6V16A2.5 2.5 0 0 1 4 13.5z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg>',lo='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="10" cy="8" r="3.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M3.5 19.5c.8-3.4 3.3-5.5 6.5-5.5s5.7 2.1 6.5 5.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><path d="M19 7.5v6M16 10.5h6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',Lt=Me("Local platform",io),Ct=Me("Chat (not on this computer)",so),At=Me("Another player",lo);Ee.append(Lt,Ct,At);_.append(Ee);var C=w("div","ow-local-panel");C.hidden=!0;G.append(_,C);var F=w("div","ow-local-toast");F.hidden=!0;G.append(F);var Et=0;function j(t){F.textContent=t,F.hidden=!1,window.clearTimeout(Et),Et=window.setTimeout(()=>F.hidden=!0,4e3)}Lt.addEventListener("click",()=>{C.hidden=!C.hidden,C.hidden||po()});Ct.addEventListener("click",()=>j("Chat is the platform\u2019s: it isn\u2019t on this computer."));At.addEventListener("click",()=>{window.open(K(),"_blank")});function K(){let t=new URL(location.href),e=Math.min(9,Number(ze??1)+1);return t.searchParams.set("player",String(e)),z&&t.searchParams.set("server",z),t.href}function po(){C.replaceChildren();let t=e=>{let o=document.createElement("p");o.innerHTML=e,C.append(o)};t(`<b>${ae(q.game.name)}</b> on this computer`),t(`You are <b>${ae(Tt?.name??"\u2026")}</b>${I?` in <code>${ae(I)}</code>`:""}`),t(`<a href="${ae(K())}" target="_blank">Open another player</a> (up to 9: <code>?player=2</code>\u2026)`),t("Saves, badges and scores are kept by <code>onceworlds serve</code> while it runs.")}function w(t,e=""){let o=document.createElement(t);return e&&(o.className=e),o}function Me(t,e){let o=w("button","ow-icon-btn");return o.type="button",o.title=t,o.setAttribute("aria-label",t),o.innerHTML=e,o}function ae(t){return t.replace(/[&<>"']/g,e=>`&#${e.charCodeAt(0)};`)}async function b(t,e={}){let o=new URL(`/__emulator/api/${t}`,location.href);ze&&o.searchParams.set("player",ze);let r=await fetch(o,{...e,headers:e.body?{"Content-Type":"application/json"}:void 0}),n=await r.json().catch(()=>null);if(!r.ok)throw new Error(n?.message??`The local platform answered ${r.status}`);return n}var co=Date.now(),le=b("me").then(({player:t,now:e})=>({player:t,timeOffset:Math.round(e-(co+Date.now())/2)})),Tt=null;le.then(t=>Tt=t.player).catch(()=>{});var d=null,I=null,B=null,de="",Pe=null,$e=!1,Re=0,Dt=0;le.then(t=>Dt=t.timeOffset).catch(()=>{});var z=Be.test(O.get("server")??"")?O.get("server"):null,ie={value:ut(pe)},v={hellos:0,joins:0,errors:[],lastAlive:0,closed:null},u=new Q(G,{now:()=>Date.now()+Dt,onSetting:(t,e)=>{let o=u.chooseSetting(t,e);o&&(d?.send({t:"state",k:U,v:o}),d?.send({t:"unready"}),u.handle({t:"unready"}),f.emit("room",{t:"unready"}))},onReady:t=>Ot(t),onStart:()=>d?.send({t:"start"}),onStop:()=>d?.send({t:"end"}),onInvite:()=>window.open(K(),"_blank"),onLayout:()=>N.changed()}),A=new Z(G,t=>f.emit("controls",t),()=>N.changed());function Ot(t){d?.send({t:"ready",ready:t}),u.setReadyLocal(t),f.emit("room",{t:"ready",id:de,ready:t})}function Le(t,e=!1){A.touch!==t&&(A.setTouch(t),e||f.emit("input",{touch:t}))}addEventListener("pointerdown",t=>t.isTrusted&&Le(t.pointerType!=="mouse"),!0);addEventListener("keydown",t=>t.isTrusted&&Le(!1),!0);var N=new ee(_t,t=>f.emit("reserved",t)),f=new Y(R,{async"session.get"(){let{player:t,timeOffset:e}=await le;return{player:t,game:{slug:pe,name:q.game.name,owner:"local"},audio:{volume:1,muted:!1},settings:{quality:"auto",reducedMotion:!1,showStats:!1},timeOffset:e,platformOrigin:location.origin}},"save.get":({key:t})=>b(`save?key=${encodeURIComponent(String(t))}`),"save.set":({key:t,value:e})=>b(`save?key=${encodeURIComponent(String(t))}`,{method:"PUT",body:JSON.stringify({value:e??null})}).then(()=>null),"save.delete":({key:t})=>b(`save?key=${encodeURIComponent(String(t))}`,{method:"DELETE"}).then(()=>null),"save.list":()=>b("saves"),async"room.join"(t){await le;let e=t??{};if(Pe=e.lobby==="card"||e.lobby==="bar"?e.lobby:null,$e=!ot(e),u.setSchema(He(e.settings)),e.party&&d)throw new Error("Parties go into matchmaking on onceworlds.com: the local platform keeps everyone where they are.");se();let o=!e.name&&!z&&!e.private&&ie.value&&mo(ie.value.key,e)?ie.value:null;if(ie.value=null,o){let r=await Pt({key:o.key,rejoin:o.rejoin,maxPlayers:e.maxPlayers,minPlayers:e.minPlayers,countdown:e.countdown,teams:e.teams,ranked:e.ranked}).catch(()=>null);if(r)return r;se()}return Pt(xo(e))},"room.leave"(){return se(),null},"net.fetch":()=>{throw new Error("onceworlds.fetch fills in secrets on onceworlds.com: it does nothing on this computer. Push a draft (onceworlds deploy) to try it.")},"badges.list":()=>b("badges"),"badges.award":({key:t})=>D?.paid?{awarded:!1}:b("badges",{method:"POST",body:JSON.stringify({key:String(t)})}).then(e=>(e.awarded&&j(`Badge earned: ${e.badge?.name??t}`),{awarded:e.awarded})),"leaderboards.submit":({board:t,score:e,lowerIsBetter:o})=>D?.paid?null:b("leaderboards",{method:"POST",body:JSON.stringify({board:String(t),score:Number(e),lowerIsBetter:o===!0})}),"leaderboards.top":({board:t,limit:e,lowerIsBetter:o})=>b(`leaderboards?board=${encodeURIComponent(String(t))}&limit=${Number(e)||10}&lower=${o===!0?1:0}`),"ratings.get":()=>null,"ratings.top":()=>[],"ui.invite"(){return window.open(K(),"_blank"),null},"ui.fullscreen"(){return document.documentElement.requestFullscreen?.().catch(()=>{}),null},"ui.tapped":()=>null,"ui.controls"(t){return A.setLayout(t),null},"ui.orientation":()=>null,"ui.menuPosition"(t){let e=t?.position;return(e==="top-left"||e==="top-right"||e==="bottom-left"||e==="bottom-right")&&(_.className=`ow-hud ow-pos-${e}`,N.changed()),null},"ui.look"(t){return Mt(t),null},"player.rename":()=>null,"demo.end":()=>D?go(D.paid):!1,"data.game.get":({key:t})=>b(`gamedata?key=${encodeURIComponent(String(t))}`),"data.game.op":t=>b("gamedata",{method:"POST",body:JSON.stringify(t)}),"player.avatar":t=>{let e=t?.id;return typeof e=="string"&&/^[A-Za-z0-9-]{1,64}$/.test(e)?je(e):null}},{"room.send":({d:t,to:e})=>d?.send({t:"msg",d:t,to:e}),"room.presence":({d:t})=>d?.send({t:"presence",d:t}),"room.hideLobby":({hidden:t})=>u.setHidden(t===!0),"room.state":({k:t,v:e,w:o})=>d?.send({t:"state",k:t,v:e,...typeof o=="number"&&Number.isSafeInteger(o)&&o>0&&o<=2147483647?{w:o}:{}}),"room.team":({id:t,team:e})=>d?.send({t:"team",id:String(t),team:Number(e)}),"room.open":({open:t})=>d?.send({t:"open",open:t===!0}),"room.result":({result:t})=>d?.send({t:"result",result:t}),"room.kick":({id:t})=>d?.send({t:"kick",id:String(t)}),"room.votekick":({id:t})=>d?.send({t:"votekick",id:String(t)}),"room.ready":({ready:t})=>{d?.send({t:"ready",ready:t===!0}),u.setReadyLocal(t===!0)},"room.unready":()=>{d?.send({t:"unready"}),u.handle({t:"unready"})},"room.transfer":({id:t})=>d?.send({t:"transfer",id:String(t)}),"room.start":({countdown:t,open:e})=>d?.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{},...e===!0?{open:!0}:{}}),"room.end":()=>d?.send({t:"end"}),"room.pause":({paused:t})=>d?.send({t:"pause",paused:t===!0}),"room.idle":({idle:t})=>d?.send({t:"idle",idle:t===!0}),"room.private":({k:t,v:e,id:o})=>typeof t=="string"&&d?.send({t:"private",k:t,v:e,...typeof o=="string"?{id:o}:{}}),"room.datareset":()=>d?.send({t:"datareset"}),"room.admit":({ids:t})=>d?.send({t:"admit",ids:Array.isArray(t)?t.filter(e=>typeof e=="string").slice(0,50):[]}),alive:()=>{v.lastAlive=Date.now()},stats:()=>{},hotkey:()=>{},vibrate:()=>{},input:t=>Le(t?.touch===!0,!0),error:t=>{v.errors.length<20&&v.errors.push(String(t?.message??t).slice(0,300))},"input.first":()=>{},console:()=>{},debug:()=>{}},()=>{v.hellos++,kt(),se(),_.className="ow-hud ow-pos-top-left",A.setLayout(null),Mt(null),f.emit("input",{touch:A.touch}),N.resend()},{demo:D!==null}),Se=null;function go(t){return Se??=new Promise(e=>{f.emit("pause",null);let o=w("div","ow-name ow-demo-end"),r=w("div","ow-name-form ow-demo-box"),n=w("h2");n.textContent="End of demo";let a=w("p","ow-demo-name");a.textContent=q.game.name;let i=w("button","ow-btn ow-btn-primary");i.type="button",i.textContent=t?"Buy":"Favorite",i.addEventListener("click",()=>j(t?"On onceworlds.com, Buy opens the game\u2019s store page.":"On onceworlds.com, Favorite follows the game."));let s=w("button","ow-text-btn ow-name-login");s.type="button",s.textContent="Back to game",s.addEventListener("click",()=>{o.remove(),Se=null,f.emit("resume",null),R.focus(),e(!0)}),r.append(n,a,i,s),o.append(r),G.append(o),i.focus()}),Se}function Mt(t){let{look:e}=nt(t);u.setLook(pt(e)),A.setLook(dt(e))}function _t(){let t=R.getBoundingClientRect();if(!t.width||!t.height)return null;let{stick:e,buttons:o}=A.reservedBoxes(),r=Ee.getBoundingClientRect(),n=parseFloat(getComputedStyle(_).paddingTop)||0,a=r.width&&r.height?{left:r.left-n,top:r.top-n,width:r.width+2*n,height:r.height+2*n}:null;return mt(t,[{kind:"menu",box:_.hidden?null:a},{kind:"lobby",box:u.reservedBox()},{kind:"stick",box:e},{kind:"buttons",box:o}])}for(let t of["resize","orientationchange"])addEventListener(t,()=>N.changed());typeof ResizeObserver=="function"&&new ResizeObserver(()=>N.changed()).observe(R);function ho(t){return t.slice(0,t.lastIndexOf(":"))}function mo(t,e){let o=(e.teams??0)>=2?e.teams:0,r=Math.min(S.roomMaxPlayersCap,Math.max(2,e.maxPlayers??16)),n=Ge(e.minPlayers,r,V);return ho(t)===`pub:${ge({mode:e.mode||"default",max:r,teams:o,ranked:e.ranked===!0,min:n})}`}function uo(){let t="abcdefghijklmnopqrstuvwxyz0123456789";return Array.from(crypto.getRandomValues(new Uint8Array(12)),e=>t[e%t.length]).join("")}function xo(t){let{name:e,maxPlayers:o,minPlayers:r,countdown:n,mode:a,teams:i,ranked:s}=t,h=t.minPlayersPrivate??r;if(e)return{name:e,maxPlayers:o,minPlayers:h,countdown:n,teams:i};if(t.private&&!z){z=uo(),xt(pe,z);let g=new URL(location.href);g.searchParams.set("server",z),history.replaceState(null,"",g.href)}return z?{server:z,maxPlayers:o,minPlayers:h,countdown:n,teams:i,private:t.private}:{mode:a,maxPlayers:o,minPlayers:r,countdown:n,teams:i,ranked:s}}async function Pt(t){let e=new ne(pe,t,{onMessage:n=>e===d&&fo(n),onClose:n=>e===d&&bo(n),onConnection:n=>{e===d&&(n||f.emit("room.connection",{connected:!1}))}});d=e;let o=await e.join();if(e!==d)throw new Error("Left the server while joining");let r=o.room.startsWith("private:")?{...o,invite:K()}:o;return de=o.you,B=o.match??null,I=o.room,v.joins++,Re=Ne(o.room)?.max??Math.min(t.maxPlayers??S.roomMaxPlayersDefault,S.roomMaxPlayersCap),u.enable(Pe,{ownCountdown:$e}),u.setRoom(r,Re),r}function fo(t){if(t.t==="update"||t.t==="move")return;if(t.t==="datareset"){j("This server\u2019s world was started over."),R.src=R.src;return}t.t==="chat"&&(t.entry.to||t.entry.channel)||t.t==="channel"||f.emit("room",t),t.t!=="welcome"&&u.handle(t),t.t==="welcome"?(u.setRoom(t,Re),B=t.match??null):t.t==="match"?B=t.match:t.t==="error"&&t.code==="cooldown"&&(j(t.message),u.setReadyLocal(!1),f.emit("room",{t:"ready",id:de,ready:!1}))}function bo(t){d=null,I=null,B=null,v.closed=t,u.setRoom(null),j(t==="replaced"?"You opened this game in another tab, so multiplayer moved there.":t==="kicked"?"You were removed from the server.":"Disconnected from the server."),f.emit("room.closed",{reason:t})}function se(){d&&(d.close(),d=null,I=null,B=null,u.setRoom(null))}window.__owLocal={get you(){return de},get room(){return I},get match(){return B},get lobby(){return Pe},get ownCountdown(){return $e},get hellos(){return v.hellos},get joins(){return v.joins},get errors(){return v.errors},get lastAlive(){return v.lastAlive},get closed(){return v.closed},get reserved(){return _t()},ready(t){return d?(Ot(t),!0):!1},start(t){return d?(d.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{}}),!0):!1},chrome(t){G.style.visibility=t?"":"hidden"}};R.src=`${q.gameOrigin}/${ao()}`;})();
13814
+ `;document.head.append(Vt);document.body.classList.add("play");var v=document.getElementById("ow-game");v.setAttribute("sandbox",pt);v.setAttribute("allow",dt);var K=document.getElementById("ow-root");function Lo(){let t=new URLSearchParams;for(let[o,r]of N)gt.has(o)||t.append(o,r);let e=t.toString();return e&&e.length<=400?`?${e}`:""}var G=z("div","ow-hud ow-pos-top-left"),Be=z("div","ow-bar"),$o='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>',Co='<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H10l-4.2 3.4c-.5.4-1.3 0-1.3-.6V16A2.5 2.5 0 0 1 4 13.5z" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg>',To='<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="10" cy="8" r="3.5" fill="none" stroke="currentColor" stroke-width="1.8"/><path d="M3.5 19.5c.8-3.4 3.3-5.5 6.5-5.5s5.7 2.1 6.5 5.5" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/><path d="M19 7.5v6M16 10.5h6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',Wt=je("Local platform",$o),Yt=je("Chat (not on this computer)",Co),Jt=je("Another player",To);Be.append(Wt,Yt,Jt);G.append(Be);var O=z("div","ow-local-panel");O.hidden=!0;K.append(G,O);var J=z("div","ow-local-toast");J.hidden=!0;K.append(J);var Ht=0;function U(t){J.textContent=t,J.hidden=!1,window.clearTimeout(Ht),Ht=window.setTimeout(()=>J.hidden=!0,4e3)}Wt.addEventListener("click",()=>{O.hidden=!O.hidden,O.hidden||Do()});Yt.addEventListener("click",()=>U("Chat is the platform\u2019s: it isn\u2019t on this computer."));Jt.addEventListener("click",()=>{window.open(Q(),"_blank")});function Q(){let t=new URL(location.href),e=Math.min(9,Number(_e??1)+1);return t.searchParams.set("player",String(e)),M&&t.searchParams.set("server",M),t.href}function Do(){O.replaceChildren();let t=e=>{let o=document.createElement("p");o.innerHTML=e,O.append(o)};t(`<b>${he(X.game.name)}</b> on this computer`),t(`You are <b>${he(Xt?.name??"\u2026")}</b>${H?` in <code>${he(H)}</code>`:""}`),t(`<a href="${he(Q())}" target="_blank">Open another player</a> (up to 9: <code>?player=2</code>\u2026)`),t("Saves, badges and scores are kept by <code>onceworlds serve</code> while it runs.")}function z(t,e=""){let o=document.createElement(t);return e&&(o.className=e),o}function je(t,e){let o=z("button","ow-icon-btn");return o.type="button",o.title=t,o.setAttribute("aria-label",t),o.innerHTML=e,o}function he(t){return t.replace(/[&<>"']/g,e=>`&#${e.charCodeAt(0)};`)}async function S(t,e={}){let o=new URL(`/__emulator/api/${t}`,location.href);_e&&o.searchParams.set("player",_e);let r=await fetch(o,{...e,headers:e.body?{"Content-Type":"application/json"}:void 0}),n=await r.json().catch(()=>null);if(!r.ok)throw new Error(n?.message??`The local platform answered ${r.status}`);return n}var Oo=Date.now(),fe=S("me").then(({player:t,now:e})=>({player:t,timeOffset:Math.round(e-(Oo+Date.now())/2)})),Xt=null;fe.then(t=>Xt=t.player).catch(()=>{});var g=null,H=null,_=null,be="",j=null,we=!1,Zt=!1,Ie=0,Qt=0;fe.then(t=>Qt=t.timeOffset).catch(()=>{});var M=Ye.test(N.get("server")??"")?N.get("server"):null,ue={value:Ct(Z)},R={hellos:0,joins:0,errors:[],lastAlive:0,closed:null},m=new le(K,{now:()=>Date.now()+Qt,onSetting:(t,e)=>{let o=m.chooseSetting(t,e);o&&(g?.send({t:"state",k:V,v:o}),g?.send({t:"unready"}),m.handle({t:"unready"}),w.emit("room",{t:"unready"}))},onReady:t=>eo(t),onStart:()=>g?.send({t:"start"}),onStop:()=>g?.send({t:"end"}),onInvite:()=>window.open(Q(),"_blank"),onLayout:()=>F.changed(),onPressed:to}),C=new ie(K,t=>w.emit("controls",t),()=>F.changed());m.setKeyMark(!C.touch);function eo(t){g?.send({t:"ready",ready:t}),m.setReadyLocal(t),w.emit("room",{t:"ready",id:be,ready:t})}function Ne(t,e=!1){C.touch!==t&&(C.setTouch(t),m.setKeyMark(!t),e||w.emit("input",{touch:t}))}addEventListener("pointerdown",t=>t.isTrusted&&Ne(t.pointerType!=="mouse"),!0);addEventListener("keydown",t=>t.isTrusted&&Ne(!1),!0);addEventListener("keydown",t=>{let e=document.activeElement;t.isTrusted&&!t.repeat&&xt(t)&&(!e||e===document.body)&&m.pressKey()});function to(){v.focus(),v.contentWindow?.focus()}function Ft(){j||Zt||(j="bar",m.enable(j,{ownCountdown:we}))}var F=new se(()=>{let t=oo();return t&&{areas:t,link:m.link(v.getBoundingClientRect())}},({areas:t,link:e})=>{w.emit("reserved",t),w.emit("lobby",e)}),me=new re(async()=>({game:Z,player:null})),w=new oe(v,{async"session.get"(){let{player:t,timeOffset:e}=await fe;return{player:t,game:{slug:Z,name:X.game.name,owner:"local"},audio:{volume:1,muted:!1},settings:{quality:"auto",reducedMotion:!1,showStats:!1},timeOffset:e,platformOrigin:location.origin}},"save.get":({key:t})=>S(`save?key=${encodeURIComponent(String(t))}`),"save.set":({key:t,value:e})=>S(`save?key=${encodeURIComponent(String(t))}`,{method:"PUT",body:JSON.stringify({value:e??null})}).then(()=>null),"save.delete":({key:t})=>S(`save?key=${encodeURIComponent(String(t))}`,{method:"DELETE"}).then(()=>null),"save.list":()=>S("saves"),"storage.open":t=>me.read(t),"storage.commit":t=>me.commit(t),"storage.delete":t=>me.remove(t),"storage.list":()=>me.list(),async"room.join"(t){await fe;let e=t??{};if(j=mt(e),Zt=e.lobby==="game",we=!ut(e),m.setSchema(Qe(e.settings)),e.party&&g)throw new Error("Parties go into matchmaking on onceworlds.com: the local platform keeps everyone where they are.");xe();let o=!e.name&&!M&&!e.private&&ue.value&&Bo(ue.value.key,e)?ue.value:null;if(ue.value=null,o){let r=await qt({key:o.key,rejoin:o.rejoin,maxPlayers:e.maxPlayers,minPlayers:e.minPlayers,countdown:e.countdown,teams:e.teams,ranked:e.ranked}).catch(()=>null);if(r)return r;xe()}return qt(No(e))},"room.leave"(){return xe(),null},"net.fetch":()=>{throw new Error("onceworlds.fetch fills in secrets on onceworlds.com: it does nothing on this computer. Push a draft (onceworlds deploy) to try it.")},"badges.list":()=>S("badges"),"badges.award":({key:t})=>B?.paid?{awarded:!1}:S("badges",{method:"POST",body:JSON.stringify({key:String(t)})}).then(e=>(e.awarded&&U(`Badge earned: ${e.badge?.name??t}`),{awarded:e.awarded})),"leaderboards.submit":({board:t,score:e,lowerIsBetter:o})=>B?.paid?null:S("leaderboards",{method:"POST",body:JSON.stringify({board:String(t),score:Number(e),lowerIsBetter:o===!0})}),"leaderboards.top":({board:t,limit:e,lowerIsBetter:o})=>S(`leaderboards?board=${encodeURIComponent(String(t))}&limit=${Number(e)||10}&lower=${o===!0?1:0}`),"ratings.get":()=>null,"ratings.top":()=>[],"ui.invite"(){return window.open(Q(),"_blank"),null},"ui.fullscreen"(){return document.documentElement.requestFullscreen?.().catch(()=>{}),null},"ui.tapped":()=>null,"ui.controls"(t){return C.setLayout(t),null},"ui.orientation":()=>null,"ui.menuPosition"(t){let e=t?.position;return(e==="top-left"||e==="top-right"||e==="bottom-left"||e==="bottom-right")&&(G.className=`ow-hud ow-pos-${e}`,F.changed()),null},"ui.look"(t){return Kt(t),null},"player.rename":()=>null,"demo.end":()=>B?_o(B.paid):!1,"data.game.get":({key:t})=>S(`gamedata?key=${encodeURIComponent(String(t))}`),"data.game.op":t=>S("gamedata",{method:"POST",body:JSON.stringify(t)}),"player.avatar":t=>{let e=t?.id;return typeof e=="string"&&/^[A-Za-z0-9-]{1,64}$/.test(e)?Ve(e):null}},{"room.send":({d:t,to:e})=>g?.send({t:"msg",d:t,to:e}),"room.presence":({d:t})=>g?.send({t:"presence",d:t}),"room.hideLobby":()=>{},"lobby.press":()=>m.pressTarget(),"lobby.target":t=>m.setTarget(t?.ok===!0,t?.hover===!0),"room.state":({k:t,v:e,w:o})=>g?.send({t:"state",k:t,v:e,...typeof o=="number"&&Number.isSafeInteger(o)&&o>0&&o<=2147483647?{w:o}:{}}),"room.team":({id:t,team:e})=>g?.send({t:"team",id:String(t),team:Number(e)}),"room.open":({open:t})=>g?.send({t:"open",open:t===!0}),"room.result":({result:t})=>g?.send({t:"result",result:t}),"room.kick":({id:t})=>g?.send({t:"kick",id:String(t)}),"room.votekick":({id:t})=>g?.send({t:"votekick",id:String(t)}),"room.ready":({ready:t})=>{Ft(),g?.send({t:"ready",ready:t===!0}),m.setReadyLocal(t===!0)},"room.unready":()=>{g?.send({t:"unready"}),m.handle({t:"unready"})},"room.transfer":({id:t})=>g?.send({t:"transfer",id:String(t)}),"room.start":({countdown:t,open:e})=>{Ft(),g?.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{},...e===!0?{open:!0}:{}})},"room.end":()=>g?.send({t:"end"}),"room.pause":({paused:t})=>g?.send({t:"pause",paused:t===!0}),"room.idle":({idle:t})=>g?.send({t:"idle",idle:t===!0}),"room.private":({k:t,v:e,id:o})=>typeof t=="string"&&g?.send({t:"private",k:t,v:e,...typeof o=="string"?{id:o}:{}}),"room.datareset":()=>g?.send({t:"datareset"}),"room.admit":({ids:t})=>g?.send({t:"admit",ids:Array.isArray(t)?t.filter(e=>typeof e=="string").slice(0,50):[]}),alive:()=>{R.lastAlive=Date.now()},stats:()=>{},hotkey:({key:t})=>{t==="Enter"&&m.pressKey()},vibrate:()=>{},input:t=>Ne(t?.touch===!0,!0),error:t=>{R.errors.length<20&&R.errors.push(String(t?.message??t).slice(0,300))},"input.first":()=>{},console:()=>{},debug:()=>{}},()=>{R.hellos++,jt(),xe(),G.className="ow-hud ow-pos-top-left",C.setLayout(null),Kt(null),w.emit("input",{touch:C.touch}),F.resend()},{demo:B!==null}),Oe=null;function _o(t){return Oe??=new Promise(e=>{w.emit("pause",null);let o=z("div","ow-name ow-demo-end"),r=z("div","ow-name-form ow-demo-box"),n=z("h2");n.textContent="End of demo";let a=z("p","ow-demo-name");a.textContent=X.game.name;let i=z("button","ow-btn ow-btn-primary");i.type="button",i.textContent=t?"Buy":"Favorite",i.addEventListener("click",()=>U(t?"On onceworlds.com, Buy opens the game\u2019s store page.":"On onceworlds.com, Favorite follows the game."));let s=z("button","ow-text-btn ow-name-login");s.type="button",s.textContent="Back to game",s.addEventListener("click",()=>{o.remove(),Oe=null,w.emit("resume",null),v.focus(),e(!0)}),r.append(n,a,i,s),o.append(r),K.append(o),i.focus()}),Oe}function Kt(t){let{look:e}=wt(t);m.setLook(Et(e)),C.setLook(Pt(e))}function oo(){let t=v.getBoundingClientRect();if(!t.width||!t.height)return null;let{stick:e,buttons:o}=C.reservedBoxes(),r=Be.getBoundingClientRect(),n=parseFloat(getComputedStyle(G).paddingTop)||0,a=r.width&&r.height?{left:r.left-n,top:r.top-n,width:r.width+2*n,height:r.height+2*n}:null;return Y(t,[{kind:"menu",box:G.hidden?null:a},{kind:"lobby",box:m.reservedBox()},{kind:"stick",box:e},{kind:"buttons",box:o}])}for(let t of["resize","orientationchange"])addEventListener(t,()=>F.changed());typeof ResizeObserver=="function"&&new ResizeObserver(()=>F.changed()).observe(v);function Io(t){return t.slice(0,t.lastIndexOf(":"))}function Bo(t,e){let o=(e.teams??0)>=2?e.teams:0,r=Math.min(P.roomMaxPlayersCap,Math.max(2,e.maxPlayers??16)),n=Xe(e.minPlayers,r,ee);return Io(t)===`pub:${ke({mode:e.mode||"default",max:r,teams:o,ranked:e.ranked===!0,min:n})}`}function jo(){let t="abcdefghijklmnopqrstuvwxyz0123456789";return Array.from(crypto.getRandomValues(new Uint8Array(12)),e=>t[e%t.length]).join("")}function No(t){let{name:e,maxPlayers:o,minPlayers:r,countdown:n,mode:a,teams:i,ranked:s}=t,d=t.minPlayersPrivate??r;if(e)return{name:e,maxPlayers:o,minPlayers:d,countdown:n,teams:i};if(t.private&&!M){M=jo(),Tt(Z,M);let c=new URL(location.href);c.searchParams.set("server",M),history.replaceState(null,"",c.href)}return M?{server:M,maxPlayers:o,minPlayers:d,countdown:n,teams:i,private:t.private}:{mode:a,maxPlayers:o,minPlayers:r,countdown:n,teams:i,ranked:s}}async function qt(t){let e=new ge(Z,t,{onMessage:n=>e===g&&Go(n),onClose:n=>e===g&&Uo(n),onConnection:n=>{e===g&&(n||w.emit("room.connection",{connected:!1}))}});g=e;let o=await e.join();if(e!==g)throw new Error("Left the server while joining");let r=o.room.startsWith("private:")?{...o,invite:Q()}:o;return be=o.you,_=o.match??null,H=o.room,R.joins++,Ie=Je(o.room)?.max??Math.min(t.maxPlayers??P.roomMaxPlayersDefault,P.roomMaxPlayersCap),m.enable(j,{ownCountdown:we}),m.setRoom(r,Ie),r}function Go(t){if(t.t==="update"||t.t==="move")return;if(t.t==="datareset"){U("This server\u2019s world was started over."),v.src=v.src;return}t.t==="chat"&&(t.entry.to||t.entry.channel)||t.t==="channel"||w.emit("room",t),t.t!=="welcome"&&m.handle(t),t.t==="welcome"?(m.setRoom(t,Ie),_=t.match??null):t.t==="match"?(t.match.phase!=="lobby"&&t.match.phase!==_?.phase&&to(),_=t.match):t.t==="error"&&t.code==="cooldown"&&(U(t.message),m.setReadyLocal(!1),w.emit("room",{t:"ready",id:be,ready:!1}))}function Uo(t){g=null,H=null,_=null,R.closed=t,m.setRoom(null),U(t==="replaced"?"You opened this game in another tab, so multiplayer moved there.":t==="kicked"?"You were removed from the server.":"Disconnected from the server."),w.emit("room.closed",{reason:t})}function xe(){g&&(g.close(),g=null,H=null,_=null,m.setRoom(null))}window.__owLocal={get you(){return be},get room(){return H},get match(){return _},get lobby(){return j},get ownCountdown(){return we},get hellos(){return R.hellos},get joins(){return R.joins},get errors(){return R.errors},get lastAlive(){return R.lastAlive},get closed(){return R.closed},get reserved(){return oo()},ready(t){return g?(eo(t),!0):!1},start(t){return g?(g.send({t:"start",...Number.isFinite(t)?{countdown:Number(t)}:{}}),!0):!1},chrome(t){K.style.visibility=t?"":"hidden"}};v.src=`${X.gameOrigin}/${Lo()}`;})();