@onceworlds/cli 0.13.0 → 0.14.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.
Files changed (3) hide show
  1. package/dist/cli.js +228 -83
  2. package/dist/emulator.js +1066 -151
  3. package/package.json +1 -1
package/dist/emulator.js CHANGED
@@ -1,6 +1,6 @@
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}
1
+ "use strict";(()=>{var He=["#f6dcc5","#ebc29f","#d4a07a","#b07a55","#875839","#5e3d29","#93c9bb","#a8c595","#94bcd3","#ab9bd9","#dca3ad","#b3bccb"],ye=["#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"],qe=["None","Sprout","Cap","Beanie","Crown","Headphones","Horns","Antenna","Bow","Halo","Party hat","Cat ears","Short hair","Tuft","Bob","Spikes","Bun","Curls","Long","Mop"];var Ke=["Plain","Band","Spots","Stripes","Star"];var Ho={skin:He.length,shirt:ye.length,pants:ye.length,face:Fe.length,hat:qe.length,top:Ke.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),a=r>=6?ro[r-6][o(2)]:o(ye.length),n=o(2)===0?a:[8,13,14,15][o(4)],i=o(5)===0?1:12+o(qe.length-12),s=o(2)===0?0:o(Ke.length);return{skin:r,shirt:a,pants:n,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 ao=/^pub:([a-z0-9-]+)\.(\d+)\.(\d)\.([01])(?:\.(\d+))?:(\d+)$/;function Je(t){let e=ao.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 no=/^[a-z0-9][a-z0-9-]{0,19}$/;function Ze(t){if(!t||typeof t!="object")return null;let e=t,o=[];for(let a of Array.isArray(e.buttons)?e.buttons:[]){if(o.length>=P.controlButtons)break;let{id:n,label:i}=a??{};if(typeof n!="string"||!no.test(n)||o.some(d=>d.id===n))continue;let s=typeof i=="string"?i.replace(/[\u0000-\u001f\u007f]/g,"").replace(/\s+/g," ").trim().slice(0,P.controlLabelLength).trim():"";o.push({id:n,label:s||n})}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:a,options:n,default:i}=o??{};if(typeof r!="string"||!io.test(r)||e.some(c=>c.id===r)||!Array.isArray(n))continue;let s=[];for(let c of n){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(m=>m.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 a=="string"?We(a).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,at=4006;var nt="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 mt(t){return t?.ownCountdown!==!0}function ut(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)?vt(x):(e.push(`${p} is not #rgb or #rrggbb`),null)},a=r("panel"),n=r("text"),i=r("accent");if(a||n){let p=A(n??T.text,a??T.panel);p<Ee&&(e.push(`text on panel is ${p.toFixed(1)}:1, under ${Ee}:1: the platform's are used`),a=n=null)}let s=a??T.panel,d=n??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&&a&&A(T.accent,a)<Re&&(i=d),!a&&!n&&!i)return{look:null,notes:e};let c=i?go(i):null;return{look:{panel:a,text:n,muted:a||n?ho(d,s):null,accent:i,accentHover:i?yt(i,c==="#ffffff"?"#000000":"#ffffff",.14):null,onAccent:c,ok:a?A(te[0],a)>=A(te[1],a)?te[0]:te[1]:null},notes:e}}function vt(t){let e=t.slice(1).toLowerCase();return`#${e.length===3?[...e].map(o=>o+o).join(""):e}`}function W(t){let e=vt(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(a=>{let n=a/255;return n<=.04045?n/12.92:((n+.055)/1.055)**2.4});return .2126*e+.7152*o+.0722*r}function A(t,e){let[o,r]=[bt(t),bt(e)].sort((a,n)=>n-a);return(o+.05)/(r+.05)}function go(t){return A(t,"#000000")>A(t,"#ffffff")?"#000000":"#ffffff"}function yt(t,e,o){let[r,a]=[W(t),W(e)];return`#${r.map((n,i)=>Math.round(n+(a[i]-n)*o).toString(16).padStart(2,"0")).join("")}`}function ho(t,e){for(let o=.3;o>.001;o-=.05){let r=yt(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,a,n={}){this.handlers=o,this.events=r,this.onConnect=a,this.solo=n.solo===!0,this.demo=n.demo===!0,this.onActivity=n.onActivity??null,this.onPage=n.onPage??null,window.addEventListener("message",i=>{if(!(i.source!==e.contentWindow||i.origin!=="null")&&(i.data?.type===nt&&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,a=r.port1;this.port=a,a.onmessage=i=>this.receive(a,i.data);let n={type:it,...this.solo?{solo:!0}:{},...this.demo?{demo:!0}:{}};e.postMessage(n,"*",[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],a=await r(o.params);e.postMessage({kind:"res",id:o.id,ok:!0,result:a??null}),this.activity(String(o.method),null)}catch(r){let a=r instanceof Error?r.message:String(r);e.postMessage({kind:"res",id:o.id,ok:!1,error:a}),this.activity(String(o.method),a)}}}};var mo="ow-game-storage",uo=256,kt="guest";function Pe(t){let e=0,o=new Set,r=[t];for(;r.length;){let a=r.pop();if(typeof a=="string")e+=a.length*2;else if(typeof a!="object"||a===null)e+=8;else{if(o.has(a))continue;if(o.add(a),a instanceof ArrayBuffer)e+=a.byteLength;else if(ArrayBuffer.isView(a))e+=a.buffer.byteLength;else if(typeof Blob=="function"&&a instanceof Blob)e+=a.size;else if(a instanceof Map)for(let[n,i]of a)r.push(n,i);else if(a instanceof Set)for(let n of a)r.push(n);else if(Array.isArray(a))r.push(...a.slice(0,1e5),...a.length>1e5?[a.slice(1e5)]:[]);else for(let[n,i]of Object.entries(a))r.push(n,i)}}return e}function L(t){if(typeof t!="string"||t.length>uo)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 a=t[L(r)];if(typeof a!="object"||a===null||!Array.isArray(a.indexes)||a.indexes.length>1e3)throw new Error("Bad store");let n=Number(a.nextKey),i=a.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(a.keyPath),autoIncrement:a.autoIncrement===!0,nextKey:Number.isFinite(n)?n: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(mo,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
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 {
3
+ ${kt}`,r),r}),this.named}async adopt(e,o){let a=(await this.open()).transaction(["dbs","records"],"readwrite"),n=Me(a),i=a.objectStore("dbs"),s=a.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 m of x){let E=await k(s.get(m));s.put(E,[o,...m.slice(1)])}i.put({...c,owner:o})}s.delete(p),i.delete([e,c.db])}await n}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(),a=(await this.open()).transaction(["dbs","records"]),n=await k(a.objectStore("dbs").get([o,e]));if(!n)return null;let i=a.objectStore("records"),s=this.dbRange(o,e),[d,c]=await Promise.all([k(i.getAllKeys(s)),k(i.getAll(s))]);return{version:n.version,stores:n.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 a=e.ops;if(!Array.isArray(a))throw new Error("Bad changes");let n=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 m=await k(p.getAll(this.ownerRange(i))),E=m.find(l=>l.db===o)??{owner:i,db:o,version:r,stores:{},bytes:0},K=m.reduce((l,f)=>l+(f===E?0:f.bytes),0),b=E.bytes;for(let l of a){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 ve=[i,o,f,"put"in l?l.put:l.remove],Ge=await k(x.get(ve));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},ve)}else x.delete(ve)}if(n)for(let l of Object.keys(E.stores))Object.hasOwn(n,l)||(b-=await this.sum(x,this.storeRange(i,o,l)),x.delete(this.storeRange(i,o,l)));if(K+=Pe(n??E.stores),K+b>this.limit)throw new Error("QuotaExceededError");p.put({owner:i,db:o,version:r,stores:n??E.stores,bytes:Math.max(0,b)})}catch(m){try{d.abort()}catch{}throw c.catch(()=>{}),m}return await c,null}async sum(e,o){return(await k(e.getAll(o))).reduce((a,n)=>a+n.bytes,0)}async remove({db:e}){L(e);let o=await this.who(),a=(await this.open()).transaction(["dbs","records"],"readwrite"),n=Me(a);return a.objectStore("records").delete(this.dbRange(o,e)),a.objectStore("dbs").delete([o,e]),await n,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(a=>({name:a.db,version:a.version}))}};var ae=class{pressed=new Set;press(e){this.pressed.add(e)}take(e){let o=new Set(e),r=!1;for(let a of this.pressed)o.has(a)||(o.add(a),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 v(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"]=v(o,.09),e["--line-strong"]=v(o,.16),e["--fill"]=v(o,.06),e["--fill-strong"]=v(o,.1),e["--ow-hover"]=v(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"]=v(t.text,.4),e["--ow-ctl-knob"]=v(t.text,.9),e["--ow-ctl-label"]=t.text,e["--ow-ctl-held"]=v(t.text,.35)),t.panel&&(e["--ow-ctl-fill"]=v(t.panel,.4),e["--ow-ctl-stick"]=v(t.panel,.3),e["--ow-ctl-shadow"]=v(t.panel,.5)),t.accent&&t.accentHover&&t.onAccent&&(e["--ow-ctl-main"]=v(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 ne(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 ae;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",a=>this.stickDown(a)),this.zone.addEventListener("pointermove",a=>this.stickMove(a));for(let a of["pointerup","pointercancel","lostpointercapture"])this.zone.addEventListener(a,n=>this.stickUp(n));this.root.addEventListener("contextmenu",a=>a.preventDefault())}setLayout(e){this.layout=Ze(e);let o=this.buttons;this.buttons=new Map,(this.layout?.buttons??[]).forEach((r,a)=>{let n=o.get(r.id)??this.button(r.id);o.delete(r.id),n.className=`ow-control-btn ow-control-btn-${a}`,n.classList.toggle("ow-held",[...this.held.values()].includes(r.id)),n.textContent=r.label,n.isConnected||this.buttonBox.append(n),this.buttons.set(r.id,n)});for(let[r,a]of o){for(let[n,i]of this.held)i===r&&this.letGo(n);a.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){ne(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 a=At(r);!a.width||!a.height||(o=o?vo(o,a):a)}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",a=>{a.preventDefault(),Mt(o,a.pointerId),o.classList.add("ow-held"),this.held.set(a.pointerId,e),this.report.press(e),this.fingers.set(a.pointerId,{x:a.clientX,y:a.clientY}),this.changed()}),o.addEventListener("pointermove",a=>{this.held.get(a.pointerId)===e&&this.fingers.set(a.pointerId,{x:a.clientX,y:a.clientY})});let r=a=>{this.held.get(a.pointerId)===e&&(this.held.delete(a.pointerId),this.fingers.delete(a.pointerId),[...this.held.values()].includes(e)||o.classList.remove("ow-held"),this.changed())};for(let a of["pointerup","pointercancel","lostpointercapture"])o.addEventListener(a,n=>r(n));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(),a=$+8;this.center={x:Math.min(Math.max(e.clientX,o.left+a),o.right-a),y:Math.min(Math.max(e.clientY,o.top+a),o.bottom-a)},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,a=Math.hypot(o,r);a>$&&(o=o/a*$,r=r/a*$),this.knob.style.transform=`translate(${o}px, ${r}px)`;let n=Math.min(a,$)/$,i=n<Ae?0:(n-Ae)/(1-Ae)/(n||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 a=JSON.stringify(r);a!==this.sent&&(this.sent=a,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 a=setTimeout(()=>r.remove(),bo),n=()=>{clearTimeout(a),a=setTimeout(()=>r.remove(),fo)};for(let i of["pointerup","pointercancel","lostpointercapture"])r.addEventListener(i,s=>s.pointerId===e&&n());r.addEventListener("contextmenu",i=>i.preventDefault());try{r.setPointerCapture(e)}catch{n()}}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 a=e.width/Math.abs(r.a),n=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-a/2,top:s-n/2,width:a,height:n}}function vo(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:a}of e){if(!a||!(a.width>0)||!(a.height>0))continue;let n=Math.max(0,a.left-t.left),i=Math.max(0,a.top-t.top),s=Math.min(t.width,a.left+a.width-t.left),d=Math.min(t.height,a.top+a.height-t.top);if(!(s-n>.01&&d-i>.01))continue;let c=Math.floor(n+.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=a=>requestAnimationFrame(a)){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 yo(t){let{you:e,host:o,kind:r,match:a,now:n}=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&&a.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},m={surface:"none",rows:i,count:`${t.players.length} / ${t.max}`,ready:x,status:"",action:{kind:"none",label:"",disabled:!0},settings:p,seconds:null},E=a.participants?.includes(e)??!1,K=o===e&&r!=="public";if(a.phase==="starting"){if(!E)return{...m,surface:"watching",status:"Watching"};let l=K?{kind:"stop",label:"Stop",disabled:!1}:{kind:"unready",label:"Not ready",disabled:!1};return t.ownCountdown?{...m,surface:"countdown",action:l,seconds:null,status:"Get ready"}:{...m,surface:"countdown",action:l,seconds:Math.max(1,$t((a.startsAt??n)-n)),status:"Get ready"}}if(a.phase==="playing"){if(a.paused){let l=s.filter(f=>a.participants?.includes(f.id)).length;return a.paused.reason==="host"?{...m,surface:"paused",status:"Paused"}:{...m,surface:"paused",seconds:$t(a.paused.since+P.matchAbandonMs-n),status:`Waiting for players \xB7 ${l} / ${a.min}`}}return E?m:{...m,surface:"watching",status:"Watching"}}let b=s.filter(l=>!l.ready&&(r==="public"||l.id!==o));if(m.surface="lobby",K){let l=s.length<a.min;return m.action={kind:"start",label:"Start",disabled:l||b.length>0},m.status=l?`Need ${a.min} players`:b.length?`Waiting for ${$e(b)}`:"",m}if(m.action={kind:d?.ready?"unready":"ready",label:d?.ready?"Not ready":"Ready",disabled:!1},r==="public")s.length<a.min?m.status=`Need ${a.min} players`:a.waitUntil!==void 0&&b.length?m.status=b.some(l=>l.id===e)?"Waiting for you":`Waiting for ${$e(b)}`:m.status=`${s.length-b.length} / ${s.length} ready`;else{let l=b.filter(f=>f.id!==e);m.status=d?.ready?l.length?`Waiting for ${$e(l)}`:`Waiting for ${t.players.find(f=>f.id===o)?.name??"the host"}`:""}return m}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 a=h("div","ow-lobby-actions");a.append(this.action,this.invite),this.card.append(r,this.list,this.settingsBox,this.status,a),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 n=h("span","","Get ready");n.setAttribute("aria-hidden","true"),this.cancel=this.button("ow-btn ow-lobby-cancel",()=>this.press()),this.countdown.append(this.numeral,n,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){ne(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[n]=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!n||!i?{keys:o,button:null,cover:null}:{keys:o,button:{x:n.x,y:n.y,w:n.w,h:n.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:a,...n}=r;return n});break;case"ready":o.players=o.players.map(r=>{if(r.id!==e.id)return r;let{ready:a,...n}=r;return e.ready?{...n,ready:!0}:n});break;case"unready":o.players=o.players.map(({ready:r,...a})=>a);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:a,...n}=r;return e.idle?{...n,idle:!0}:n});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,a=this.schema.find(i=>i.id===e);if(!r||!a||!a.options.some(i=>i.value===o))return null;let n={...r.written!==null&&typeof r.written=="object"?r.written:{},[e]:o};return r.written=n,this.render(),n}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",a=>a.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=yo({...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[a,...n]=e.status.split(" \xB7 "),i=h("span","ow-lobby-chip-more",n.length?` \xB7 ${n.join(" \xB7 ")}`:"");this.chip.replaceChildren(a,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(a=>this.settingRow(a))));let r=JSON.stringify(e.rows);r!==this.listSignature&&(this.listSignature=r,this.list.replaceChildren(...e.rows.map(a=>{let n=h("li",a.away||a.idle?"ow-lobby-away":a.ready?"ow-lobby-ready":""),i=h("img","ow-headshot");i.src=`/avatar/${encodeURIComponent(a.id)}/head.svg`,i.alt="";let s=h("span","ow-lobby-name",a.name),d=[a.away?"Reconnecting":a.idle?"Idle":"",a.you?"You":"",a.host?"Host":""].filter(Boolean).join(" \xB7 ");return n.append(i,s),d&&n.append(h("span","ow-player-notes",d)),n.append(h("span",`ow-lobby-check${a.ready?" ow-lobby-check-on":""}`,a.ready?"Ready":"")),n})))}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(a=>a.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 a of e.options){let n=this.button(`ow-segment${a.value===e.value?" ow-segment-on":""}`,()=>this.opts.onSetting(e.id,a.value));n.textContent=a.label,n.setAttribute("role","radio"),n.setAttribute("aria-checked",String(a.value===e.value)),r.append(n)}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 a=h("img",`ow-headshot${r.ready?" ow-lobby-face-ready":""}`);return a.src=`/avatar/${encodeURIComponent(r.id)}/head.svg`,a.alt="",a})))}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 j(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 j(t,null),null}var de=class extends Error{constructor(o,r=0,a=0,n=""){super(o);this.status=r;this.retryAfterMs=a;this.code=n;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,jt=()=>Array.from(crypto.getRandomValues(new Uint8Array(10)),t=>"abcdefghijklmnopqrstuvwxyz0123456789"[t%36]).join(""),It=jt();function Bt(){It=jt()}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=It;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,j(this.slug,null),this.dispose(),this.ws?.close(1e3)}reload(){return this.closed=!0,this.dispose(),this.ws?.close(at,"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 a=Dt();a&&r.searchParams.set("tester",a),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 n=new WebSocket(r);this.ws=n,this.lastHeard=Date.now();let i=!1;n.onopen=()=>{this.lastHeard=Date.now(),window.clearInterval(this.pingTimer),window.clearInterval(this.watchTimer),this.pingTimer=window.setInterval(()=>n.readyState===WebSocket.OPEN&&this.ping(),Eo),this.watchTimer=window.setInterval(()=>{n===this.ws&&n.readyState===WebSocket.OPEN&&Date.now()-this.lastHeard>Po&&this.lost(n)},5e3)},n.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&&j(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,...m}=p;e(m),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||n!==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(),j(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()}};n.onclose=d,n.onerror=()=>{window.setTimeout(()=>{n.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(),j(this.slug,null),this.callbacks.onClose(e)}};var Ut=`:root {
4
4
  color-scheme: light;
5
5
  /* Site pages: as wide as this at most, with gutters that grow with the window. */
6
6
  --page: 1440px;
@@ -73,9 +73,9 @@ ${kt}`,r),r}),this.named}async adopt(e,o){let n=(await this.open()).transaction(
73
73
  /* The top bar's height (popups opened from it hang under it). */
74
74
  --bar-h: 60px;
75
75
  --radius: 8px;
76
- /* Panels, sheets and big pictures; a game's picture is --radius-art. */
76
+ /* Panels and sheets; every picture, game icon and video is --radius-art. */
77
77
  --radius-widget: 12px;
78
- --radius-art: 6px;
78
+ --radius-art: 2px;
79
79
  --font: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
80
80
  --font-display: var(--font);
81
81
  --mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
@@ -95,25 +95,25 @@ ${kt}`,r),r}),this.named}async adopt(e,o){let n=(await this.open()).transaction(
95
95
  */
96
96
  :root[data-theme='dark'] {
97
97
  color-scheme: dark;
98
- --bg: #0f1114;
99
- --bg-soft: #171a1f;
100
- --bg-raised: #1a1d23;
101
- --bg-card: #1a1d23;
102
- --bg-hover: #23272e;
103
- --bar: #0a0b0d;
98
+ --bg: #121212;
99
+ --bg-soft: #1a1a1a;
100
+ --bg-raised: #1e1e1e;
101
+ --bg-card: #1e1e1e;
102
+ --bg-hover: #282828;
103
+ --bar: #0a0a0a;
104
104
  --line: rgba(255, 255, 255, 0.07);
105
105
  --line-strong: rgba(255, 255, 255, 0.14);
106
- --text: #eceef1;
107
- --muted: #959ba6;
106
+ --text: #ececec;
107
+ --muted: #9e9e9e;
108
108
  --accent: #ff7a5c;
109
109
  --accent-hover: #ff9177;
110
110
  --accent-fill: #d23c1b;
111
111
  --accent-fill-hover: #b93314;
112
112
  --accent-soft: rgba(255, 122, 92, 0.16);
113
113
  --accent-text: #ff9a80;
114
- --ink: #eceef1;
114
+ --ink: #ececec;
115
115
  --ink-hover: #ffffff;
116
- --ink-text: #0f1114;
116
+ --ink-text: #121212;
117
117
  --ok: #3ddc84;
118
118
  --ok-soft: rgba(61, 220, 132, 0.14);
119
119
  --online: #60a5fa;
@@ -129,12 +129,12 @@ ${kt}`,r),r}),this.named}async adopt(e,o){let n=(await this.open()).transaction(
129
129
  --stat-play: #60a5fa;
130
130
  --play-text: #5fe08f;
131
131
  --live-text: #3ddc84;
132
- --dock-bg: #0a0b0d;
132
+ --dock-bg: #0a0a0a;
133
133
  --dock-edge: rgba(255, 255, 255, 0.08);
134
- --edit-page: #0f0f12;
135
- --edit-bar: #17171c;
136
- --edit-screen: #1a1a1f;
137
- --edit-field: #1f1f25;
134
+ --edit-page: #121212;
135
+ --edit-bar: #1a1a1a;
136
+ --edit-screen: #1e1e1e;
137
+ --edit-field: #222222;
138
138
  --edit-line: rgba(255, 255, 255, 0.08);
139
139
  --edit-line-strong: rgba(255, 255, 255, 0.15);
140
140
  --edit-go: #d33e00;
@@ -143,25 +143,25 @@ ${kt}`,r),r}),this.named}async adopt(e,o){let n=(await this.open()).transaction(
143
143
  @media (prefers-color-scheme: dark) {
144
144
  :root:not([data-theme='light']) {
145
145
  color-scheme: dark;
146
- --bg: #0f1114;
147
- --bg-soft: #171a1f;
148
- --bg-raised: #1a1d23;
149
- --bg-card: #1a1d23;
150
- --bg-hover: #23272e;
151
- --bar: #0a0b0d;
146
+ --bg: #121212;
147
+ --bg-soft: #1a1a1a;
148
+ --bg-raised: #1e1e1e;
149
+ --bg-card: #1e1e1e;
150
+ --bg-hover: #282828;
151
+ --bar: #0a0a0a;
152
152
  --line: rgba(255, 255, 255, 0.07);
153
153
  --line-strong: rgba(255, 255, 255, 0.14);
154
- --text: #eceef1;
155
- --muted: #959ba6;
154
+ --text: #ececec;
155
+ --muted: #9e9e9e;
156
156
  --accent: #ff7a5c;
157
157
  --accent-hover: #ff9177;
158
158
  --accent-fill: #d23c1b;
159
159
  --accent-fill-hover: #b93314;
160
160
  --accent-soft: rgba(255, 122, 92, 0.16);
161
161
  --accent-text: #ff9a80;
162
- --ink: #eceef1;
162
+ --ink: #ececec;
163
163
  --ink-hover: #ffffff;
164
- --ink-text: #0f1114;
164
+ --ink-text: #121212;
165
165
  --ok: #3ddc84;
166
166
  --ok-soft: rgba(61, 220, 132, 0.14);
167
167
  --online: #60a5fa;
@@ -177,12 +177,12 @@ ${kt}`,r),r}),this.named}async adopt(e,o){let n=(await this.open()).transaction(
177
177
  --stat-play: #60a5fa;
178
178
  --play-text: #5fe08f;
179
179
  --live-text: #3ddc84;
180
- --dock-bg: #0a0b0d;
180
+ --dock-bg: #0a0a0a;
181
181
  --dock-edge: rgba(255, 255, 255, 0.08);
182
- --edit-page: #0f0f12;
183
- --edit-bar: #17171c;
184
- --edit-screen: #1a1a1f;
185
- --edit-field: #1f1f25;
182
+ --edit-page: #121212;
183
+ --edit-bar: #1a1a1a;
184
+ --edit-screen: #1e1e1e;
185
+ --edit-field: #222222;
186
186
  --edit-line: rgba(255, 255, 255, 0.08);
187
187
  --edit-line-strong: rgba(255, 255, 255, 0.15);
188
188
  --edit-go: #d33e00;
@@ -796,11 +796,10 @@ label.check input {
796
796
  background: var(--bar);
797
797
  }
798
798
 
799
+ /* Edge to edge at any width: the mark lines up with the sidebar's words, the account the same distance from the right. */
799
800
  .topbar-inner {
800
- max-width: var(--page);
801
- margin: 0 auto;
802
801
  height: var(--bar-h);
803
- padding: 0 var(--gutter);
802
+ padding: 0 22px;
804
803
  display: flex;
805
804
  align-items: center;
806
805
  gap: 8px;
@@ -1988,6 +1987,34 @@ body:has(.tabbar) .footer-inner {
1988
1987
  .store-shell > .page {
1989
1988
  padding-bottom: 56px;
1990
1989
  }
1990
+
1991
+ /* Home: Featured fills the column to the sidebar, the top bar and the window's edge; the rows under it keep the page's width. */
1992
+ .store-shell > .page.store:has(> .spotlight) {
1993
+ max-width: none;
1994
+ padding-top: 0;
1995
+ }
1996
+
1997
+ .page.store:has(> .spotlight) > * {
1998
+ max-width: calc(1680px - 2 * clamp(20px, 2.6vw, 44px));
1999
+ }
2000
+
2001
+ .page.store > .spotlight {
2002
+ max-width: none;
2003
+ margin-inline: calc(-1 * clamp(20px, 2.6vw, 44px));
2004
+ }
2005
+
2006
+ .page.store > .spotlight .spot-slide {
2007
+ border-radius: 0;
2008
+ }
2009
+
2010
+ /* Its words and dots line up with the rows under it. */
2011
+ .page.store > .spotlight .spot-info {
2012
+ padding-left: clamp(20px, 2.6vw, 44px);
2013
+ }
2014
+
2015
+ .page.store > .spotlight .spot-dots {
2016
+ right: clamp(20px, 2.6vw, 44px);
2017
+ }
1991
2018
  }
1992
2019
 
1993
2020
  .store-side {
@@ -2111,8 +2138,8 @@ body:has(.tabbar) .footer-inner {
2111
2138
  position: relative;
2112
2139
  min-width: 0;
2113
2140
  overflow: hidden;
2114
- border-radius: var(--radius-widget);
2115
- background: #0a0b0d;
2141
+ border-radius: var(--radius-art);
2142
+ background: #0a0a0a;
2116
2143
  opacity: 0;
2117
2144
  visibility: hidden;
2118
2145
  transition: opacity 0.45s ease, visibility 0s linear 0.45s;
@@ -2702,7 +2729,7 @@ body:has(.tabbar) .footer-inner {
2702
2729
  height: auto;
2703
2730
  margin: auto;
2704
2731
  aspect-ratio: 1;
2705
- border-radius: 22%;
2732
+ border-radius: var(--radius-art);
2706
2733
  }
2707
2734
 
2708
2735
  .app-art:has(.app-img-icon) {
@@ -2995,7 +3022,7 @@ body:has(.tabbar) .footer-inner {
2995
3022
  place-items: center;
2996
3023
  width: clamp(22px, 10.4cqi, 36px);
2997
3024
  height: clamp(22px, 10.4cqi, 36px);
2998
- border-radius: 5px;
3025
+ border-radius: var(--radius-art);
2999
3026
  object-fit: cover;
3000
3027
  font-size: 12px;
3001
3028
  font-weight: 800;
@@ -3013,7 +3040,6 @@ body:has(.tabbar) .footer-inner {
3013
3040
  }
3014
3041
 
3015
3042
  .lib-icon {
3016
- border-radius: 7px;
3017
3043
  font-size: 15px;
3018
3044
  }
3019
3045
  }
@@ -3042,7 +3068,7 @@ body:has(.tabbar) .footer-inner {
3042
3068
  height: clamp(220px, 27vw, 440px);
3043
3069
  aspect-ratio: auto;
3044
3070
  overflow: hidden;
3045
- border-radius: var(--radius-widget);
3071
+ border-radius: var(--radius-art);
3046
3072
  }
3047
3073
 
3048
3074
  .lib-hero::after {
@@ -3688,7 +3714,7 @@ body:has(.tabbar) .footer-inner {
3688
3714
  flex: none;
3689
3715
  width: 60px;
3690
3716
  height: 60px;
3691
- border-radius: 12px;
3717
+ border-radius: var(--radius-art);
3692
3718
  object-fit: cover;
3693
3719
  box-shadow: var(--ring);
3694
3720
  font-size: 28px;
@@ -3763,7 +3789,7 @@ body:has(.tabbar) .footer-inner {
3763
3789
  overflow-x: auto;
3764
3790
  scroll-snap-type: x mandatory;
3765
3791
  scrollbar-width: none;
3766
- border-radius: var(--radius-widget);
3792
+ border-radius: var(--radius-art);
3767
3793
  background: var(--bg-soft);
3768
3794
  box-shadow: var(--ring);
3769
3795
  aspect-ratio: 16 / 9;
@@ -3804,7 +3830,7 @@ body:has(.tabbar) .footer-inner {
3804
3830
  width: 30%;
3805
3831
  height: auto;
3806
3832
  aspect-ratio: 1;
3807
- border-radius: 22%;
3833
+ border-radius: var(--radius-art);
3808
3834
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
3809
3835
  }
3810
3836
 
@@ -3834,7 +3860,7 @@ body:has(.tabbar) .footer-inner {
3834
3860
  place-items: center;
3835
3861
  width: 100%;
3836
3862
  aspect-ratio: 16 / 9;
3837
- border-radius: 5px;
3863
+ border-radius: var(--radius-art);
3838
3864
  color: var(--text);
3839
3865
  text-decoration: none;
3840
3866
  opacity: 0.55;
@@ -5027,7 +5053,7 @@ body:has(.auth) .footer {
5027
5053
  aspect-ratio: 16 / 9;
5028
5054
  object-fit: cover;
5029
5055
  border: 1px solid var(--line);
5030
- border-radius: 10px;
5056
+ border-radius: var(--radius-art);
5031
5057
  background: var(--bg-soft);
5032
5058
  }
5033
5059
 
@@ -5795,7 +5821,7 @@ label.admin-changed > span::before {
5795
5821
  .admin-game .dash-icon {
5796
5822
  width: 36px;
5797
5823
  height: 36px;
5798
- border-radius: 10px;
5824
+ border-radius: var(--radius-art);
5799
5825
  }
5800
5826
 
5801
5827
  @media (max-width: 760px) {
@@ -5968,7 +5994,7 @@ label.admin-changed > span::before {
5968
5994
  flex: none;
5969
5995
  width: 44px;
5970
5996
  height: 44px;
5971
- border-radius: 12px;
5997
+ border-radius: var(--radius-art);
5972
5998
  object-fit: cover;
5973
5999
  display: grid;
5974
6000
  place-items: center;
@@ -6482,7 +6508,7 @@ label.admin-changed > span::before {
6482
6508
  flex: none;
6483
6509
  width: 96px;
6484
6510
  height: 96px;
6485
- border-radius: 22px;
6511
+ border-radius: var(--radius-art);
6486
6512
  object-fit: cover;
6487
6513
  display: grid;
6488
6514
  place-items: center;
@@ -6636,7 +6662,7 @@ label.admin-changed > span::before {
6636
6662
 
6637
6663
  .dz-shot {
6638
6664
  position: relative;
6639
- border-radius: 14px;
6665
+ border-radius: var(--radius-art);
6640
6666
  background: var(--bg-soft);
6641
6667
  cursor: grab;
6642
6668
  user-select: none;
@@ -6650,7 +6676,7 @@ label.admin-changed > span::before {
6650
6676
  width: 100%;
6651
6677
  aspect-ratio: 16 / 9;
6652
6678
  object-fit: cover;
6653
- border-radius: 14px;
6679
+ border-radius: var(--radius-art);
6654
6680
  pointer-events: none;
6655
6681
  }
6656
6682
 
@@ -6819,7 +6845,9 @@ label.admin-changed > span::before {
6819
6845
 
6820
6846
  .sell-modes label {
6821
6847
  display: inline-flex;
6848
+ flex-direction: row;
6822
6849
  align-items: center;
6850
+ justify-content: center;
6823
6851
  min-height: 32px;
6824
6852
  padding: 0 14px;
6825
6853
  border-radius: 999px;
@@ -6846,13 +6874,107 @@ label.admin-changed > span::before {
6846
6874
  outline-offset: 1px;
6847
6875
  }
6848
6876
 
6849
- .sell-form:has(input[name='mode'][value='free']:checked) :is(.sell-fixed, .sell-pwyw),
6877
+ .sell-form:has(input[name='mode'][value='free']:checked) :is(.sell-fixed, .sell-pwyw, .sell-setup),
6850
6878
  .sell-form:has(input[name='mode'][value='fixed']:checked) .sell-pwyw,
6851
6879
  .sell-form:has(input[name='mode'][value='pwyw']:checked) .sell-fixed,
6852
6880
  .sell-form:not(:has(select[name='license'] option[value='custom']:checked)) .sell-custom {
6853
6881
  display: none;
6854
6882
  }
6855
6883
 
6884
+ /* Sell: every card is its heading and then its contents, in the same two columns, so they all line up down the page. */
6885
+ .sell-card {
6886
+ display: grid;
6887
+ grid-template-columns: 160px minmax(0, 480px);
6888
+ gap: 12px 32px;
6889
+ align-items: start;
6890
+ }
6891
+
6892
+ .sell-card h2,
6893
+ .page .sell-card h2 {
6894
+ display: flex;
6895
+ flex-wrap: wrap;
6896
+ align-items: center;
6897
+ gap: 8px;
6898
+ margin: 0;
6899
+ line-height: 38px;
6900
+ }
6901
+
6902
+ .sell-body {
6903
+ min-width: 0;
6904
+ }
6905
+
6906
+ .sell-body > * {
6907
+ margin: 0;
6908
+ }
6909
+
6910
+ .sell-body > * + * {
6911
+ margin-top: 14px;
6912
+ }
6913
+
6914
+ .sell-body > p:first-child {
6915
+ line-height: 38px;
6916
+ }
6917
+
6918
+ .sell-body > .sell-fine {
6919
+ margin-top: 2px;
6920
+ font-size: 13px;
6921
+ }
6922
+
6923
+ .sell-body .stack-form {
6924
+ max-width: none;
6925
+ }
6926
+
6927
+ .sell-body :is(select, .inline-form input) {
6928
+ border-radius: 10px;
6929
+ background-color: var(--bg);
6930
+ }
6931
+
6932
+ .sell-body .inline-form label {
6933
+ color: var(--text);
6934
+ }
6935
+
6936
+ .sell-body .sell-modes {
6937
+ display: flex;
6938
+ align-self: stretch;
6939
+ }
6940
+
6941
+ .sell-body .sell-modes label {
6942
+ flex: 1 1 auto;
6943
+ }
6944
+
6945
+ .sell-actions,
6946
+ .sell-setup {
6947
+ display: flex;
6948
+ flex-wrap: wrap;
6949
+ align-items: center;
6950
+ gap: 8px;
6951
+ }
6952
+
6953
+ .sell-setup {
6954
+ gap: 8px 12px;
6955
+ }
6956
+
6957
+ .sell-actions form {
6958
+ margin: 0;
6959
+ }
6960
+
6961
+ .sell-body .inline-form {
6962
+ margin-bottom: 0;
6963
+ }
6964
+
6965
+ @media (max-width: 720px) {
6966
+ .sell-card {
6967
+ grid-template-columns: minmax(0, 1fr);
6968
+ gap: 8px;
6969
+ }
6970
+
6971
+ .sell-card h2,
6972
+ .page .sell-card h2,
6973
+ .sell-body > p:first-child {
6974
+ line-height: 1.4;
6975
+ }
6976
+ }
6977
+
6856
6978
  .sell-now {
6857
6979
  display: flex;
6858
6980
  flex-wrap: wrap;
@@ -8446,7 +8568,7 @@ button.ow-setting-icon:hover {
8446
8568
  .ow-loading-icon {
8447
8569
  width: 120px;
8448
8570
  height: 120px;
8449
- border-radius: 28px;
8571
+ border-radius: var(--radius-art);
8450
8572
  object-fit: cover;
8451
8573
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), 0 24px 60px rgba(0, 0, 0, 0.6);
8452
8574
  }
@@ -8651,7 +8773,7 @@ button.ow-setting-icon:hover {
8651
8773
  place-items: center;
8652
8774
  width: 44px;
8653
8775
  height: 44px;
8654
- border-radius: 12px;
8776
+ border-radius: var(--radius-art);
8655
8777
  object-fit: cover;
8656
8778
  color: #fff;
8657
8779
  font-size: 18px;
@@ -8993,7 +9115,7 @@ a.pager-btn:hover {
8993
9115
  place-items: center;
8994
9116
  width: 44px;
8995
9117
  height: 44px;
8996
- border-radius: 12px;
9118
+ border-radius: var(--radius-art);
8997
9119
  object-fit: cover;
8998
9120
  color: #fff;
8999
9121
  font-size: 18px;
@@ -11418,53 +11540,164 @@ body.ow-calm .ow-fold-caret {
11418
11540
 
11419
11541
  /* ------------------------------------------------------------ Create: describe a game, your games, Developers (create.ts) */
11420
11542
 
11421
- /* The top: the pitch, big, and the box under it, beside a game being made; on phones the game comes after. */
11422
- .create-intro {
11423
- display: grid;
11424
- grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
11543
+ /*
11544
+ * Create is a workbench in Edit's shape: the game's screen with the box under it (what Edit opens to), beside the games to start from.
11545
+ * The screen stays 16:9 and shrinks with a short window, so the box never falls below the fold; the rail is as tall as the screen and
11546
+ * box, and scrolls. On phones the rail is a strip under the box.
11547
+ */
11548
+ .make.page {
11549
+ padding-top: clamp(14px, 2.4vh, 28px);
11550
+ }
11551
+
11552
+ .make-head {
11553
+ display: flex;
11554
+ flex-wrap: wrap;
11425
11555
  align-items: center;
11426
- gap: clamp(28px, 4vw, 64px);
11427
- margin: clamp(8px, 4vh, 48px) 0 clamp(48px, 7vw, 96px);
11556
+ justify-content: space-between;
11557
+ gap: 10px 24px;
11558
+ margin-bottom: clamp(14px, 2vh, 22px);
11428
11559
  }
11429
11560
 
11430
- .create-pitch h1 {
11431
- margin: 0 0 30px;
11432
- font-size: clamp(44px, 5.2vw, 78px);
11561
+ .page .make-head h1 {
11562
+ margin: 0;
11563
+ font-size: clamp(30px, 3.9vw, 56px);
11433
11564
  font-weight: 700;
11434
- line-height: 0.98;
11565
+ line-height: 1;
11435
11566
  letter-spacing: -0.045em;
11436
11567
  }
11437
11568
 
11438
- .create-pitch h1 span {
11439
- display: block;
11569
+ .make-head h1 span {
11570
+ margin-left: 0.24em;
11440
11571
  color: var(--accent-text);
11441
11572
  }
11442
11573
 
11443
- .create-reel {
11574
+ .make-bench {
11575
+ display: grid;
11576
+ grid-template-columns: minmax(0, min(62%, max(520px, calc((100svh - 330px) * 16 / 9)))) minmax(0, 1fr);
11577
+ gap: clamp(16px, 1.8vw, 26px);
11578
+ }
11579
+
11580
+ .make-screen {
11581
+ position: relative;
11444
11582
  overflow: hidden;
11445
11583
  aspect-ratio: 16 / 9;
11446
- border-radius: var(--radius-widget);
11447
- background: #121318;
11448
- box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12), 0 30px 70px rgba(0, 0, 0, 0.18);
11584
+ border: 1px solid var(--line);
11585
+ border-radius: var(--radius-art);
11586
+ background: var(--edit-screen);
11587
+ }
11588
+
11589
+ /* The new game's empty place, as in Edit's first frame. */
11590
+ .make-empty {
11591
+ position: absolute;
11592
+ inset: 0;
11593
+ display: flex;
11594
+ flex-direction: column;
11595
+ align-items: center;
11596
+ justify-content: center;
11597
+ gap: 16px;
11598
+ color: var(--muted);
11599
+ }
11600
+
11601
+ .make-slot {
11602
+ display: grid;
11603
+ place-items: center;
11604
+ width: 84px;
11605
+ height: 84px;
11606
+ box-sizing: border-box;
11607
+ border: 2px dashed var(--edit-line-strong);
11608
+ border-radius: var(--radius-art);
11609
+ }
11610
+
11611
+ .make-slot svg {
11612
+ width: 30px;
11613
+ height: 30px;
11614
+ }
11615
+
11616
+ .make-empty strong {
11617
+ font-size: clamp(18px, 2vw, 26px);
11618
+ font-weight: 650;
11619
+ letter-spacing: -0.02em;
11449
11620
  }
11450
11621
 
11451
- .create-reel video,
11452
- .create-reel img {
11622
+ .make-shot {
11623
+ position: absolute;
11624
+ inset: 0;
11453
11625
  display: block;
11454
11626
  width: 100%;
11455
11627
  height: 100%;
11456
11628
  object-fit: cover;
11457
11629
  }
11458
11630
 
11459
- @media (max-width: 900px) {
11460
- .create-intro {
11461
- grid-template-columns: minmax(0, 1fr);
11462
- }
11631
+ .make-shot[hidden],
11632
+ .make-picked[hidden] {
11633
+ display: none;
11634
+ }
11635
+
11636
+ .make-picked {
11637
+ position: absolute;
11638
+ inset: auto 0 0;
11639
+ display: flex;
11640
+ align-items: center;
11641
+ gap: 12px;
11642
+ margin: 0;
11643
+ padding: 56px 18px 16px;
11644
+ background: linear-gradient(transparent, rgba(0, 0, 0, 0.82));
11645
+ color: #fff;
11646
+ }
11647
+
11648
+ .make-picked strong {
11649
+ overflow: hidden;
11650
+ min-width: 0;
11651
+ font-size: clamp(18px, 2.1vw, 30px);
11652
+ font-weight: 700;
11653
+ letter-spacing: -0.03em;
11654
+ text-overflow: ellipsis;
11655
+ white-space: nowrap;
11656
+ }
11657
+
11658
+ .make-remix-mark {
11659
+ display: inline-flex;
11660
+ flex: none;
11661
+ align-items: center;
11662
+ gap: 5px;
11663
+ padding: 4px 10px 4px 7px;
11664
+ border-radius: 999px;
11665
+ background: var(--play-fill);
11666
+ color: var(--play-ink);
11667
+ font-size: 13px;
11668
+ font-weight: 700;
11669
+ }
11670
+
11671
+ .make-remix-mark svg {
11672
+ width: 15px;
11673
+ height: 15px;
11674
+ }
11675
+
11676
+ .make-picked .btn {
11677
+ flex: none;
11678
+ margin-left: auto;
11679
+ border-color: rgba(255, 255, 255, 0.34);
11680
+ background: rgba(0, 0, 0, 0.35);
11681
+ color: #fff;
11682
+ }
11683
+
11684
+ .make-picked .btn:hover {
11685
+ background: rgba(0, 0, 0, 0.6);
11463
11686
  }
11464
11687
 
11465
- /* The box: a sheet raised off the wallpaper, the one thing to do here. */
11688
+ .make-problem {
11689
+ margin: 10px 0 0;
11690
+ }
11691
+
11692
+ /* The box: under the game, the one thing to do here. */
11466
11693
  .create-box {
11694
+ display: grid;
11695
+ grid-template-columns: minmax(0, 1fr) auto;
11696
+ align-items: end;
11697
+ gap: 8px;
11467
11698
  width: 100%;
11699
+ margin-top: 10px;
11700
+ padding: 8px;
11468
11701
  border: 1px solid var(--line);
11469
11702
  border-radius: var(--radius-widget);
11470
11703
  background: var(--bg-raised);
@@ -11481,14 +11714,13 @@ body.ow-calm .ow-fold-caret {
11481
11714
  .create-box textarea {
11482
11715
  display: block;
11483
11716
  width: 100%;
11484
- min-height: 150px;
11485
- max-height: 42vh;
11486
- padding: 24px 26px 8px;
11717
+ min-height: 56px;
11718
+ max-height: 24vh;
11719
+ padding: 8px 10px;
11487
11720
  border: 0;
11488
- border-radius: var(--radius-widget);
11489
11721
  background: none;
11490
11722
  color: var(--text);
11491
- font: 500 clamp(18px, 2vw, 22px) / 1.4 var(--font);
11723
+ font: 500 clamp(16px, 1.3vw, 18px) / 1.4 var(--font);
11492
11724
  resize: none;
11493
11725
  }
11494
11726
 
@@ -11501,22 +11733,16 @@ body.ow-calm .ow-fold-caret {
11501
11733
  opacity: 1;
11502
11734
  }
11503
11735
 
11504
- .create-box-foot {
11505
- display: flex;
11506
- justify-content: flex-end;
11507
- padding: 0 14px 14px;
11508
- }
11509
-
11510
11736
  .btn.create-go {
11511
- gap: 10px;
11512
- min-width: 160px;
11513
- min-height: 54px;
11514
- padding: 0 26px;
11737
+ gap: 8px;
11738
+ min-width: 132px;
11739
+ min-height: 52px;
11740
+ padding: 0 20px;
11515
11741
  border: 0;
11516
- border-radius: 18px;
11742
+ border-radius: 10px;
11517
11743
  background: var(--play-fill);
11518
11744
  color: var(--play-ink);
11519
- font-size: 18px;
11745
+ font-size: 17px;
11520
11746
  font-weight: 700;
11521
11747
  }
11522
11748
 
@@ -11540,25 +11766,175 @@ body.ow-calm .ow-fold-caret {
11540
11766
  flex-wrap: wrap;
11541
11767
  align-items: center;
11542
11768
  gap: 12px;
11543
- margin: 22px 0 0;
11769
+ margin: 0;
11544
11770
  color: var(--muted);
11545
11771
  font-size: 14px;
11546
11772
  }
11547
11773
 
11548
- /* Signed in: the creator's games, under the box. */
11549
- .create-page .create-games {
11550
- margin: 0 0 clamp(40px, 5vw, 64px);
11774
+ /* The games to start from: as tall as the screen and box, however many there are. */
11775
+ .make-rail {
11776
+ display: flex;
11777
+ flex-direction: column;
11778
+ min-width: 0;
11779
+ contain: size;
11551
11780
  }
11552
11781
 
11553
- .create-home {
11554
- width: 100%;
11555
- max-width: var(--page);
11556
- margin: 0 auto;
11557
- padding: 0 var(--gutter) 56px;
11782
+ .make-rail-head {
11783
+ display: flex;
11784
+ flex: none;
11785
+ align-items: center;
11786
+ justify-content: space-between;
11787
+ gap: 12px;
11788
+ margin-bottom: 12px;
11558
11789
  }
11559
11790
 
11560
- .create-home > .section {
11561
- margin-bottom: clamp(72px, 9vw, 128px);
11791
+ .make-rail-head h2 {
11792
+ flex: none;
11793
+ margin: 0;
11794
+ font-size: 18px;
11795
+ font-weight: 700;
11796
+ letter-spacing: -0.02em;
11797
+ }
11798
+
11799
+ .make-rail-head input {
11800
+ flex: 0 1 200px;
11801
+ min-width: 0;
11802
+ height: 34px;
11803
+ padding: 0 12px;
11804
+ border: 1px solid var(--line);
11805
+ border-radius: 999px;
11806
+ background: var(--bg-raised);
11807
+ color: var(--text);
11808
+ font: 500 14px var(--font);
11809
+ }
11810
+
11811
+ .make-rail-head input[hidden] {
11812
+ display: none;
11813
+ }
11814
+
11815
+ .make-tiles {
11816
+ display: grid;
11817
+ flex: 1;
11818
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
11819
+ align-content: start;
11820
+ gap: 14px 12px;
11821
+ min-height: 0;
11822
+ margin: 0;
11823
+ padding: 3px 6px 3px 3px;
11824
+ overflow-y: auto;
11825
+ list-style: none;
11826
+ scrollbar-width: thin;
11827
+ }
11828
+
11829
+ .make-tiles li[hidden] {
11830
+ display: none;
11831
+ }
11832
+
11833
+ .make-tile {
11834
+ display: block;
11835
+ color: var(--muted);
11836
+ font-size: 13px;
11837
+ font-weight: 600;
11838
+ text-decoration: none;
11839
+ }
11840
+
11841
+ .make-tile > span:last-child {
11842
+ display: block;
11843
+ overflow: hidden;
11844
+ margin-top: 6px;
11845
+ text-overflow: ellipsis;
11846
+ white-space: nowrap;
11847
+ }
11848
+
11849
+ .make-tile-art {
11850
+ display: grid;
11851
+ place-items: center;
11852
+ overflow: hidden;
11853
+ aspect-ratio: 16 / 9;
11854
+ border-radius: var(--radius-art);
11855
+ background: var(--edit-screen);
11856
+ transition: box-shadow 0.12s ease;
11857
+ }
11858
+
11859
+ .make-tile-art img {
11860
+ display: block;
11861
+ width: 100%;
11862
+ height: 100%;
11863
+ object-fit: cover;
11864
+ }
11865
+
11866
+ .make-tile-blank {
11867
+ box-sizing: border-box;
11868
+ border: 1.5px dashed var(--edit-line-strong);
11869
+ color: var(--muted);
11870
+ }
11871
+
11872
+ .make-tile-blank svg {
11873
+ width: 26px;
11874
+ height: 26px;
11875
+ }
11876
+
11877
+ .make-tile:hover {
11878
+ color: var(--text);
11879
+ }
11880
+
11881
+ .make-tile:hover .make-tile-art {
11882
+ box-shadow: 0 0 0 2px var(--text);
11883
+ }
11884
+
11885
+ .make-tile[aria-current] {
11886
+ color: var(--text);
11887
+ }
11888
+
11889
+ .make-tile[aria-current] .make-tile-art {
11890
+ box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);
11891
+ }
11892
+
11893
+ @media (max-width: 900px) {
11894
+ .make-head h1 span {
11895
+ display: block;
11896
+ margin: 2px 0 0;
11897
+ }
11898
+
11899
+ .make-bench {
11900
+ grid-template-columns: minmax(0, 1fr);
11901
+ }
11902
+
11903
+ .make-rail {
11904
+ contain: none;
11905
+ }
11906
+
11907
+ .make-tiles {
11908
+ display: flex;
11909
+ gap: 10px;
11910
+ margin: 0 calc(var(--gutter) * -1);
11911
+ padding: 3px var(--gutter) 8px;
11912
+ overflow: auto hidden;
11913
+ }
11914
+
11915
+ .make-tiles li {
11916
+ flex: 0 0 148px;
11917
+ }
11918
+
11919
+ .btn.create-go {
11920
+ min-width: 0;
11921
+ }
11922
+ }
11923
+
11924
+ /* Signed in: the creator's games, under the box. */
11925
+ .create-page .create-games {
11926
+ margin: 0 0 clamp(40px, 5vw, 64px);
11927
+ }
11928
+
11929
+ .create-home {
11930
+ width: 100%;
11931
+ max-width: var(--page);
11932
+ margin: 0 auto;
11933
+ padding: 0 var(--gutter) 56px;
11934
+ }
11935
+
11936
+ .create-home > .section {
11937
+ margin-bottom: clamp(72px, 9vw, 128px);
11562
11938
  }
11563
11939
 
11564
11940
  .create-home .section-head {
@@ -11660,7 +12036,7 @@ html.is-launching {
11660
12036
  height: 84px;
11661
12037
  box-sizing: border-box;
11662
12038
  border: 2px dashed var(--edit-line-strong);
11663
- border-radius: 20px;
12039
+ border-radius: var(--radius-art);
11664
12040
  color: var(--muted);
11665
12041
  }
11666
12042
 
@@ -11671,6 +12047,29 @@ html.is-launching {
11671
12047
  letter-spacing: -0.02em;
11672
12048
  }
11673
12049
 
12050
+ /* A remix: the game itself, and the word for what's happening over it. */
12051
+ .create-launch-stage.is-remix {
12052
+ position: relative;
12053
+ overflow: hidden;
12054
+ }
12055
+
12056
+ .create-launch-stage.is-remix img {
12057
+ position: absolute;
12058
+ inset: 0;
12059
+ width: 100%;
12060
+ height: 100%;
12061
+ object-fit: cover;
12062
+ opacity: 0.42;
12063
+ }
12064
+
12065
+ .create-launch-stage.is-remix strong {
12066
+ position: relative;
12067
+ color: #fff;
12068
+ font-size: clamp(40px, 7vw, 96px);
12069
+ font-weight: 800;
12070
+ letter-spacing: -0.045em;
12071
+ }
12072
+
11674
12073
  /* The box under it, where the description lands. */
11675
12074
  .create-launch-ask {
11676
12075
  display: flex;
@@ -11945,6 +12344,30 @@ html.is-launching {
11945
12344
  height: 30px;
11946
12345
  }
11947
12346
 
12347
+ /* Remix isn't an upload: its own row, with the dashed edge of the place a game is about to go. */
12348
+ .up-choices:has(.up-choice-remix) {
12349
+ grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
12350
+ }
12351
+
12352
+ .up-choice-remix {
12353
+ grid-column: 1 / -1;
12354
+ }
12355
+
12356
+ .up-choice-remix .up-choice {
12357
+ border: 1.5px dashed var(--accent);
12358
+ }
12359
+
12360
+ .up-choice-remix .up-choice:hover {
12361
+ border-style: solid;
12362
+ border-color: var(--accent);
12363
+ background: var(--accent-soft);
12364
+ }
12365
+
12366
+ .up-choice-remix .up-choice > svg:first-child,
12367
+ .up-choice-remix .up-chevron {
12368
+ color: var(--accent-text);
12369
+ }
12370
+
11948
12371
  .up-choice-text {
11949
12372
  display: flex;
11950
12373
  flex-direction: column;
@@ -12078,14 +12501,12 @@ html.is-launching {
12078
12501
  margin: 0 0 8px;
12079
12502
  }
12080
12503
 
12081
- /* Upload's helper, bottom right: a speech bubble beside a little character standing on the footer's line (the page's 24px bottom
12082
- padding and the footer's 56px margin, taken back). It hops in, then idles (its SVG breathes, blinks and looks around). */
12504
+ /* Upload's helper, bottom right: a card that sits just above the footer's line. */
12083
12505
  .up-buddy {
12084
12506
  display: flex;
12085
12507
  align-items: flex-end;
12086
12508
  justify-content: flex-end;
12087
- gap: 4px;
12088
- margin: 40px 0 -80px;
12509
+ margin: 40px 0 -16px;
12089
12510
  pointer-events: none;
12090
12511
  }
12091
12512
 
@@ -12096,7 +12517,6 @@ html.is-launching {
12096
12517
  .up-buddy-bubble {
12097
12518
  position: relative;
12098
12519
  width: min(380px, 100%);
12099
- margin-bottom: 64px;
12100
12520
  padding: 14px 16px;
12101
12521
  border: 1px solid var(--line);
12102
12522
  border-radius: 16px;
@@ -12107,20 +12527,6 @@ html.is-launching {
12107
12527
  animation: up-bubble 0.32s 0.45s cubic-bezier(0.2, 1.4, 0.4, 1) both;
12108
12528
  }
12109
12529
 
12110
- /* Its tail, pointing at the character's head. */
12111
- .up-buddy-bubble::after {
12112
- position: absolute;
12113
- right: -7px;
12114
- bottom: 18px;
12115
- width: 12px;
12116
- height: 12px;
12117
- border-top: 1px solid var(--line);
12118
- border-right: 1px solid var(--line);
12119
- background: var(--bg-raised);
12120
- transform: rotate(45deg);
12121
- content: '';
12122
- }
12123
-
12124
12530
  .up-buddy-head {
12125
12531
  margin: 0 0 8px;
12126
12532
  font-weight: 700;
@@ -12179,20 +12585,6 @@ html.is-launching {
12179
12585
  height: 14px;
12180
12586
  }
12181
12587
 
12182
- .up-buddy-face {
12183
- flex: none;
12184
- width: 64px;
12185
- height: 112px;
12186
- animation: up-hop 0.5s cubic-bezier(0.3, 1.5, 0.5, 1) both;
12187
- }
12188
-
12189
- @keyframes up-hop {
12190
- from {
12191
- opacity: 0;
12192
- transform: translateY(24px);
12193
- }
12194
- }
12195
-
12196
12588
  @keyframes up-bubble {
12197
12589
  from {
12198
12590
  opacity: 0;
@@ -12201,8 +12593,7 @@ html.is-launching {
12201
12593
  }
12202
12594
 
12203
12595
  @media (prefers-reduced-motion: reduce) {
12204
- .up-buddy-bubble,
12205
- .up-buddy-face {
12596
+ .up-buddy-bubble {
12206
12597
  animation: none;
12207
12598
  }
12208
12599
  }
@@ -12926,7 +13317,7 @@ body:not(:has(.tabbar)) .toast {
12926
13317
  .cover-wall-tile {
12927
13318
  overflow: hidden;
12928
13319
  aspect-ratio: 16 / 9;
12929
- border-radius: 12px;
13320
+ border-radius: var(--radius-art);
12930
13321
  background: rgba(255, 255, 255, 0.06);
12931
13322
  }
12932
13323
 
@@ -13525,7 +13916,7 @@ body.share-frame {
13525
13916
  place-items: center;
13526
13917
  aspect-ratio: 16 / 9;
13527
13918
  overflow: hidden;
13528
- border-radius: 14px;
13919
+ border-radius: var(--radius-art);
13529
13920
  background: #000;
13530
13921
  }
13531
13922
 
@@ -13585,7 +13976,7 @@ body.share-frame {
13585
13976
  position: relative;
13586
13977
  aspect-ratio: 16 / 9;
13587
13978
  overflow: hidden;
13588
- border-radius: 14px;
13979
+ border-radius: var(--radius-art);
13589
13980
  background: #000;
13590
13981
  }
13591
13982
 
@@ -13747,7 +14138,7 @@ body.share-frame {
13747
14138
  display: block;
13748
14139
  width: 100%;
13749
14140
  border: 0;
13750
- border-radius: 12px;
14141
+ border-radius: var(--radius-art);
13751
14142
  background: #000;
13752
14143
  }
13753
14144
 
@@ -13793,7 +14184,7 @@ body.share-frame {
13793
14184
  .file-page img {
13794
14185
  max-width: 100%;
13795
14186
  max-height: 82vh;
13796
- border-radius: 8px;
14187
+ border-radius: var(--radius-art);
13797
14188
  }
13798
14189
 
13799
14190
  .file-pager {
@@ -13803,7 +14194,531 @@ body.share-frame {
13803
14194
  gap: 16px;
13804
14195
  margin-top: 12px;
13805
14196
  }
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}
14197
+
14198
+
14199
+ /*
14200
+ * A game's About (protocol about.ts): text straight on the page and the creator's own pictures, the same way for every game, as on
14201
+ * Steam or itch. The art does the designing: nothing here adds a box, a colour or a shadow.
14202
+ */
14203
+ .game-about {
14204
+ scroll-margin-top: calc(var(--bar-h) + 16px);
14205
+ }
14206
+
14207
+ .game-about-text {
14208
+ max-width: 72ch;
14209
+ white-space: pre-line;
14210
+ }
14211
+
14212
+ .game-about-text + .game-about-more {
14213
+ margin-top: 20px;
14214
+ }
14215
+
14216
+ .ab {
14217
+ display: flow-root;
14218
+ color: var(--text);
14219
+ font-size: 15px;
14220
+ line-height: 1.6;
14221
+ overflow-wrap: anywhere;
14222
+ }
14223
+
14224
+ .ab-fig,
14225
+ .ab-quote {
14226
+ margin: 0;
14227
+ }
14228
+
14229
+ .ab > * + *,
14230
+ .ab-column > * + *,
14231
+ .ab-fold-body > * + *,
14232
+ .ab-quote > * + * {
14233
+ margin-top: 16px;
14234
+ }
14235
+
14236
+ :is(.ab, .ab-column, .ab-fold-body) > * + .ab-fig,
14237
+ :is(.ab, .ab-column, .ab-fold-body) > .ab-fig + * {
14238
+ margin-top: 24px;
14239
+ }
14240
+
14241
+ .ab p {
14242
+ margin: 0;
14243
+ font-size: inherit;
14244
+ line-height: inherit;
14245
+ white-space: normal;
14246
+ }
14247
+
14248
+ /* Pictures fill the column, like the gallery above them; lines of text stop where they're still easy to read. */
14249
+ .ab :is(p, ul, ol, figcaption),
14250
+ .ab-quote {
14251
+ max-width: 760px;
14252
+ }
14253
+
14254
+ .ab h3,
14255
+ .page .ab h3 {
14256
+ margin: 32px 0 0;
14257
+ color: var(--text);
14258
+ font-size: 17px;
14259
+ font-weight: 700;
14260
+ line-height: 1.3;
14261
+ letter-spacing: 0;
14262
+ }
14263
+
14264
+ .ab h4,
14265
+ .page .ab h4 {
14266
+ margin: 20px 0 0;
14267
+ color: var(--text);
14268
+ font-size: 15px;
14269
+ font-weight: 700;
14270
+ line-height: 1.4;
14271
+ letter-spacing: 0;
14272
+ }
14273
+
14274
+ .ab :is(h3, h4):first-child,
14275
+ .page .ab :is(h3, h4):first-child {
14276
+ margin-top: 0;
14277
+ }
14278
+
14279
+ .ab :is(h3, h4) + * {
14280
+ margin-top: 6px;
14281
+ }
14282
+
14283
+ .ab a:not(.btn, .ab-youtube) {
14284
+ color: inherit;
14285
+ text-decoration: underline;
14286
+ text-underline-offset: 2px;
14287
+ }
14288
+
14289
+ .ab a:not(.btn, .ab-youtube):hover {
14290
+ text-decoration-thickness: 2px;
14291
+ }
14292
+
14293
+ .ab-spoiler {
14294
+ background: var(--muted);
14295
+ color: transparent;
14296
+ cursor: default;
14297
+ }
14298
+
14299
+ .ab-spoiler:hover,
14300
+ .ab-spoiler:focus {
14301
+ background: none;
14302
+ color: inherit;
14303
+ }
14304
+
14305
+ .ab ul,
14306
+ .ab ol {
14307
+ margin-bottom: 0;
14308
+ padding-left: 20px;
14309
+ }
14310
+
14311
+ .ab li + li {
14312
+ margin-top: 4px;
14313
+ }
14314
+
14315
+ .ab hr {
14316
+ height: 1px;
14317
+ margin: 24px 0;
14318
+ border: 0;
14319
+ background: var(--line);
14320
+ }
14321
+
14322
+ /* A picture shows at its own size, up to the column. */
14323
+ .ab-fig img {
14324
+ display: block;
14325
+ max-width: 100%;
14326
+ height: auto;
14327
+ border-radius: var(--radius-art);
14328
+ }
14329
+
14330
+ .ab-fig video,
14331
+ .ab-youtube {
14332
+ display: block;
14333
+ width: 100%;
14334
+ aspect-ratio: 16 / 9;
14335
+ border-radius: var(--radius-art);
14336
+ background: #000;
14337
+ }
14338
+
14339
+ .ab-fig figcaption {
14340
+ margin-top: 6px;
14341
+ color: var(--muted);
14342
+ font-size: 13px;
14343
+ line-height: 1.4;
14344
+ }
14345
+
14346
+ .ab-youtube {
14347
+ position: relative;
14348
+ overflow: hidden;
14349
+ color: #fff;
14350
+ }
14351
+
14352
+ .ab-fig .ab-youtube img {
14353
+ width: 100%;
14354
+ height: 100%;
14355
+ border-radius: 0;
14356
+ object-fit: cover;
14357
+ }
14358
+
14359
+ .ab-yt-play {
14360
+ position: absolute;
14361
+ inset: 0;
14362
+ display: grid;
14363
+ width: 56px;
14364
+ height: 56px;
14365
+ margin: auto;
14366
+ border-radius: 50%;
14367
+ background: rgba(0, 0, 0, 0.6);
14368
+ place-items: center;
14369
+ }
14370
+
14371
+ .ab-youtube:hover .ab-yt-play {
14372
+ background: #000;
14373
+ }
14374
+
14375
+ .ab-yt-mark {
14376
+ width: 28px;
14377
+ height: 28px;
14378
+ }
14379
+
14380
+ .ab-missing {
14381
+ padding: 18px;
14382
+ border: 1.5px dashed var(--line-strong);
14383
+ color: var(--muted);
14384
+ font-size: 13px;
14385
+ text-align: center;
14386
+ }
14387
+
14388
+ .ab-gallery {
14389
+ display: grid;
14390
+ gap: 8px;
14391
+ }
14392
+
14393
+ .ab-gallery-2 {
14394
+ grid-template-columns: repeat(2, minmax(0, 1fr));
14395
+ }
14396
+
14397
+ .ab-gallery-3 {
14398
+ grid-template-columns: repeat(3, minmax(0, 1fr));
14399
+ }
14400
+
14401
+ .ab-gallery .ab-fig img {
14402
+ width: 100%;
14403
+ aspect-ratio: 16 / 9;
14404
+ object-fit: cover;
14405
+ }
14406
+
14407
+ .ab-buttons {
14408
+ display: flex;
14409
+ flex-wrap: wrap;
14410
+ gap: 8px;
14411
+ }
14412
+
14413
+ .ab-columns {
14414
+ display: grid;
14415
+ gap: 24px;
14416
+ align-items: start;
14417
+ }
14418
+
14419
+ .ab-columns-2 {
14420
+ grid-template-columns: repeat(2, minmax(0, 1fr));
14421
+ }
14422
+
14423
+ .ab-columns-3 {
14424
+ grid-template-columns: repeat(3, minmax(0, 1fr));
14425
+ }
14426
+
14427
+ .ab-column {
14428
+ min-width: 0;
14429
+ }
14430
+
14431
+ .ab-quote {
14432
+ padding-left: 20px;
14433
+ font-style: italic;
14434
+ }
14435
+
14436
+ .ab-quote cite {
14437
+ display: block;
14438
+ margin-top: 4px;
14439
+ color: var(--muted);
14440
+ font-size: 13px;
14441
+ font-style: normal;
14442
+ }
14443
+
14444
+ .ab-table {
14445
+ overflow-x: auto;
14446
+ }
14447
+
14448
+ .ab-table table {
14449
+ width: 100%;
14450
+ border-collapse: collapse;
14451
+ font-size: 14px;
14452
+ }
14453
+
14454
+ .ab-table th,
14455
+ .ab-table td {
14456
+ padding: 8px 16px 8px 0;
14457
+ border-bottom: 1px solid var(--line);
14458
+ text-align: left;
14459
+ vertical-align: top;
14460
+ }
14461
+
14462
+ .ab-table th {
14463
+ font-weight: 700;
14464
+ }
14465
+
14466
+ .ab-fold > summary {
14467
+ font-weight: 700;
14468
+ cursor: pointer;
14469
+ }
14470
+
14471
+ .ab-fold-body {
14472
+ padding-top: 8px;
14473
+ }
14474
+
14475
+ .game-about-more.is-folded {
14476
+ position: relative;
14477
+ overflow: hidden;
14478
+ max-height: 1400px;
14479
+ mask-image: linear-gradient(180deg, #000 calc(100% - 120px), transparent);
14480
+ }
14481
+
14482
+ .about-more {
14483
+ margin-top: 8px;
14484
+ }
14485
+
14486
+ @media (max-width: 720px) {
14487
+ .ab-columns-2,
14488
+ .ab-columns-3 {
14489
+ grid-template-columns: minmax(0, 1fr);
14490
+ }
14491
+
14492
+ .ab-gallery-3 {
14493
+ grid-template-columns: repeat(2, minmax(0, 1fr));
14494
+ }
14495
+ }
14496
+
14497
+ /* The dashboard's About tab: the source, the same drawing beside it, then its files and the commands. */
14498
+ .about-editor {
14499
+ padding-bottom: 16px;
14500
+ }
14501
+
14502
+ .about-tools {
14503
+ display: flex;
14504
+ flex-wrap: wrap;
14505
+ gap: 4px;
14506
+ margin-bottom: 10px;
14507
+ }
14508
+
14509
+ .about-tool {
14510
+ min-height: 30px;
14511
+ padding: 0 10px;
14512
+ border: 1px solid var(--line);
14513
+ border-radius: 6px;
14514
+ background: transparent;
14515
+ color: var(--text);
14516
+ font: 600 13px var(--font);
14517
+ cursor: pointer;
14518
+ }
14519
+
14520
+ .about-tool:hover {
14521
+ background: var(--bg-hover);
14522
+ }
14523
+
14524
+ .about-tool-example {
14525
+ margin-left: auto;
14526
+ color: var(--muted);
14527
+ }
14528
+
14529
+ .about-panes {
14530
+ display: grid;
14531
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
14532
+ gap: 12px;
14533
+ height: min(72vh, 780px);
14534
+ min-height: 420px;
14535
+ }
14536
+
14537
+ .about-pane {
14538
+ min-width: 0;
14539
+ min-height: 0;
14540
+ }
14541
+
14542
+ .about-source {
14543
+ display: block;
14544
+ width: 100%;
14545
+ height: 100%;
14546
+ padding: 14px;
14547
+ border: 1px solid var(--line-strong);
14548
+ border-radius: var(--radius);
14549
+ background: var(--bg-soft);
14550
+ color: var(--text);
14551
+ font: 13px/1.6 var(--mono);
14552
+ resize: none;
14553
+ tab-size: 2;
14554
+ }
14555
+
14556
+ .about-source:focus {
14557
+ border-color: var(--accent);
14558
+ outline: 1px solid var(--accent);
14559
+ outline-offset: -2px;
14560
+ }
14561
+
14562
+ .about-preview {
14563
+ overflow-y: auto;
14564
+ padding: 16px 18px;
14565
+ border: 1px solid var(--line);
14566
+ border-radius: var(--radius);
14567
+ background: var(--bg);
14568
+ }
14569
+
14570
+ .about-preview-empty {
14571
+ margin: 0;
14572
+ color: var(--muted);
14573
+ }
14574
+
14575
+ .about-problems {
14576
+ display: flex;
14577
+ flex-direction: column;
14578
+ gap: 4px;
14579
+ margin: 10px 0 0;
14580
+ padding: 10px 12px;
14581
+ border-radius: var(--radius);
14582
+ background: var(--danger-soft);
14583
+ font-size: 13px;
14584
+ list-style: none;
14585
+ }
14586
+
14587
+ .about-problem {
14588
+ margin-right: 4px;
14589
+ padding: 0;
14590
+ border: 0;
14591
+ background: none;
14592
+ color: var(--danger);
14593
+ font: 700 13px var(--font);
14594
+ cursor: pointer;
14595
+ text-decoration: underline;
14596
+ }
14597
+
14598
+ .about-foot {
14599
+ display: flex;
14600
+ align-items: center;
14601
+ gap: 12px;
14602
+ margin-top: 12px;
14603
+ }
14604
+
14605
+ .about-state {
14606
+ color: var(--muted);
14607
+ font-size: 13px;
14608
+ }
14609
+
14610
+ .about-count {
14611
+ margin-left: auto;
14612
+ color: var(--muted);
14613
+ font-size: 12px;
14614
+ font-variant-numeric: tabular-nums;
14615
+ }
14616
+
14617
+ .about-count.is-over {
14618
+ color: var(--danger);
14619
+ font-weight: 700;
14620
+ }
14621
+
14622
+ .about-files {
14623
+ display: grid;
14624
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
14625
+ gap: 10px;
14626
+ margin: 0;
14627
+ padding: 0;
14628
+ list-style: none;
14629
+ }
14630
+
14631
+ .about-file {
14632
+ position: relative;
14633
+ min-width: 0;
14634
+ }
14635
+
14636
+ .about-file-pick {
14637
+ display: block;
14638
+ overflow: hidden;
14639
+ width: 100%;
14640
+ padding: 0;
14641
+ border: 1px solid var(--line);
14642
+ border-radius: var(--radius);
14643
+ background: var(--bg-soft);
14644
+ color: var(--text);
14645
+ cursor: pointer;
14646
+ text-align: left;
14647
+ }
14648
+
14649
+ .about-file-pick:hover {
14650
+ border-color: var(--line-strong);
14651
+ }
14652
+
14653
+ .about-file-pick img,
14654
+ .about-file-video {
14655
+ display: flex;
14656
+ align-items: center;
14657
+ justify-content: center;
14658
+ width: 100%;
14659
+ aspect-ratio: 16 / 10;
14660
+ object-fit: cover;
14661
+ color: var(--muted);
14662
+ font-size: 22px;
14663
+ }
14664
+
14665
+ .about-file-name {
14666
+ display: block;
14667
+ overflow: hidden;
14668
+ padding: 6px 8px;
14669
+ font: 12px var(--mono);
14670
+ text-overflow: ellipsis;
14671
+ white-space: nowrap;
14672
+ }
14673
+
14674
+ .about-file-add .dz-wide {
14675
+ aspect-ratio: auto;
14676
+ min-height: 118px;
14677
+ }
14678
+
14679
+ .about-reference h3 {
14680
+ margin: 16px 0 6px;
14681
+ color: var(--muted);
14682
+ font-size: 12px;
14683
+ font-weight: 700;
14684
+ }
14685
+
14686
+ .about-commands {
14687
+ width: 100%;
14688
+ border-collapse: collapse;
14689
+ font-size: 13px;
14690
+ }
14691
+
14692
+ .about-commands td {
14693
+ padding: 6px 12px 6px 0;
14694
+ border-top: 1px solid var(--line);
14695
+ vertical-align: top;
14696
+ }
14697
+
14698
+ .about-commands td:first-child {
14699
+ width: 48%;
14700
+ overflow-wrap: anywhere;
14701
+ }
14702
+
14703
+ .about-commands td:last-child {
14704
+ color: var(--muted);
14705
+ }
14706
+
14707
+ @media (max-width: 860px) {
14708
+ .about-panes {
14709
+ grid-template-columns: minmax(0, 1fr);
14710
+ height: auto;
14711
+ }
14712
+
14713
+ .about-source {
14714
+ height: 52vh;
14715
+ }
14716
+
14717
+ .about-preview {
14718
+ max-height: 70vh;
14719
+ }
14720
+ }
14721
+ `;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"),I=De===null||De==="0"?null:{paid:De!=="free"};Gt(I!==null);var Vt=document.createElement("style");Vt.textContent=`${Ut}
13807
14722
  .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); }
13808
14723
  .ow-local-panel[hidden] { display: none; }
13809
14724
  .ow-local-panel b { font-weight: 650; }
@@ -13811,4 +14726,4 @@ body.share-frame {
13811
14726
  .ow-local-panel p { margin: 0 0 6px; }
13812
14727
  .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); }
13813
14728
  .ow-local-toast[hidden] { display: none; }
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()}`;})();
14729
+ `;document.head.append(Vt);document.body.classList.add("play");var y=document.getElementById("ow-game");y.setAttribute("sandbox",pt);y.setAttribute("allow",dt);var q=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"),Ie=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=Be("Local platform",$o),Yt=Be("Chat (not on this computer)",Co),Jt=Be("Another player",To);Ie.append(Wt,Yt,Jt);G.append(Ie);var O=z("div","ow-local-panel");O.hidden=!0;q.append(G,O);var J=z("div","ow-local-toast");J.hidden=!0;q.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 Be(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}),a=await r.json().catch(()=>null);if(!r.ok)throw new Error(a?.message??`The local platform answered ${r.status}`);return a}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="",B=null,we=!1,Zt=!1,je=0,Qt=0;fe.then(t=>Qt=t.timeOffset).catch(()=>{});var M=Ye.test(N.get("server")??"")?N.get("server"):null,me={value:Ct(Z)},R={hellos:0,joins:0,errors:[],lastAlive:0,closed:null},u=new le(q,{now:()=>Date.now()+Qt,onSetting:(t,e)=>{let o=u.chooseSetting(t,e);o&&(g?.send({t:"state",k:V,v:o}),g?.send({t:"unready"}),u.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(q,t=>w.emit("controls",t),()=>F.changed());u.setKeyMark(!C.touch);function eo(t){g?.send({t:"ready",ready:t}),u.setReadyLocal(t),w.emit("room",{t:"ready",id:be,ready:t})}function Ne(t,e=!1){C.touch!==t&&(C.setTouch(t),u.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)&&u.pressKey()});function to(){y.focus(),y.contentWindow?.focus()}function Ft(){B||Zt||(B="bar",u.enable(B,{ownCountdown:we}))}var F=new se(()=>{let t=oo();return t&&{areas:t,link:u.link(y.getBoundingClientRect())}},({areas:t,link:e})=>{w.emit("reserved",t),w.emit("lobby",e)}),ue=new re(async()=>({game:Z,player:null})),w=new oe(y,{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=>ue.read(t),"storage.commit":t=>ue.commit(t),"storage.delete":t=>ue.remove(t),"storage.list":()=>ue.list(),async"room.join"(t){await fe;let e=t??{};if(B=ut(e),Zt=e.lobby==="game",we=!mt(e),u.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&&me.value&&Io(me.value.key,e)?me.value:null;if(me.value=null,o){let r=await Kt({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 Kt(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})=>I?.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})=>I?.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 qt(t),null},"player.rename":()=>null,"demo.end":()=>I?_o(I.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":()=>u.pressTarget(),"lobby.target":t=>u.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}),u.setReadyLocal(t===!0)},"room.unready":()=>{g?.send({t:"unready"}),u.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"&&u.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++,Bt(),xe(),G.className="ow-hud ow-pos-top-left",C.setLayout(null),qt(null),w.emit("input",{touch:C.touch}),F.resend()},{demo:I!==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"),a=z("h2");a.textContent="End of demo";let n=z("p","ow-demo-name");n.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),y.focus(),e(!0)}),r.append(a,n,i,s),o.append(r),q.append(o),i.focus()}),Oe}function qt(t){let{look:e}=wt(t);u.setLook(Et(e)),C.setLook(Pt(e))}function oo(){let t=y.getBoundingClientRect();if(!t.width||!t.height)return null;let{stick:e,buttons:o}=C.reservedBoxes(),r=Ie.getBoundingClientRect(),a=parseFloat(getComputedStyle(G).paddingTop)||0,n=r.width&&r.height?{left:r.left-a,top:r.top-a,width:r.width+2*a,height:r.height+2*a}:null;return Y(t,[{kind:"menu",box:G.hidden?null:n},{kind:"lobby",box:u.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(y);function jo(t){return t.slice(0,t.lastIndexOf(":"))}function Io(t,e){let o=(e.teams??0)>=2?e.teams:0,r=Math.min(P.roomMaxPlayersCap,Math.max(2,e.maxPlayers??16)),a=Xe(e.minPlayers,r,ee);return jo(t)===`pub:${ke({mode:e.mode||"default",max:r,teams:o,ranked:e.ranked===!0,min:a})}`}function Bo(){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:a,mode:n,teams:i,ranked:s}=t,d=t.minPlayersPrivate??r;if(e)return{name:e,maxPlayers:o,minPlayers:d,countdown:a,teams:i};if(t.private&&!M){M=Bo(),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:a,teams:i,private:t.private}:{mode:n,maxPlayers:o,minPlayers:r,countdown:a,teams:i,ranked:s}}async function Kt(t){let e=new ge(Z,t,{onMessage:a=>e===g&&Go(a),onClose:a=>e===g&&Uo(a),onConnection:a=>{e===g&&(a||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++,je=Je(o.room)?.max??Math.min(t.maxPlayers??P.roomMaxPlayersDefault,P.roomMaxPlayersCap),u.enable(B,{ownCountdown:we}),u.setRoom(r,je),r}function Go(t){if(t.t==="update"||t.t==="move")return;if(t.t==="datareset"){U("This server\u2019s world was started over."),y.src=y.src;return}t.t==="chat"&&(t.entry.to||t.entry.channel)||t.t==="channel"||w.emit("room",t),t.t!=="welcome"&&u.handle(t),t.t==="welcome"?(u.setRoom(t,je),_=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),u.setReadyLocal(!1),w.emit("room",{t:"ready",id:be,ready:!1}))}function Uo(t){g=null,H=null,_=null,R.closed=t,u.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,u.setRoom(null))}window.__owLocal={get you(){return be},get room(){return H},get match(){return _},get lobby(){return B},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){q.style.visibility=t?"":"hidden"}};y.src=`${X.gameOrigin}/${Lo()}`;})();