@hopple/sdk 0.0.0-stage → 0.1.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +729 -2
- package/config.schema.json +784 -0
- package/hopple-sdk.min.js +155 -0
- package/index.d.ts +3664 -0
- package/index.js +3585 -0
- package/manifest.md +281 -0
- package/package.json +30 -4
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/*! @hopple/sdk 0.1.0-rc.2 */
|
|
2
|
+
"use strict";var Hopple=(()=>{var ve=Object.defineProperty;var Nn=Object.getOwnPropertyDescriptor;var Dn=Object.getOwnPropertyNames;var jn=Object.prototype.hasOwnProperty;var $n=(e,t,n)=>t in e?ve(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Un=(e,t)=>{for(var n in t)ve(e,n,{get:t[n],enumerable:!0})},zn=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Dn(t))!jn.call(e,r)&&r!==n&&ve(e,r,{get:()=>t[r],enumerable:!(o=Nn(t,r))||o.enumerable});return e};var Gn=e=>zn(ve({},"__esModule",{value:!0}),e);var Pt=(e,t,n)=>$n(e,typeof t!="symbol"?t+"":t,n);var Fr={};Un(Fr,{ACHIEVEMENT_VALUE_MAX:()=>Ue,AUDIO_FULL:()=>K,AUDIO_MASTER:()=>q,AUDIO_VOLUME_MAX:()=>re,BridgeError:()=>L,DEADZONE:()=>_e,INPUT_CONTRACT:()=>he,INPUT_SCHEMES:()=>ke,INPUT_SHIM:()=>me,MANIFEST_FILE:()=>wt,MANIFEST_SCHEMA:()=>xt,MAX_STEP:()=>St,PAD_BUTTONS:()=>ee,PAGES:()=>ae,PAUSE_NONE:()=>ce,PAUSE_STATES:()=>nt,SAVE_BYTES:()=>J,SCORE_VALUE_MAX:()=>at,SET_SHIM:()=>z,SHARE_BYTES:()=>lt,SHARE_META_BYTES:()=>pt,SHIM:()=>V,SHIM_WAIT_MS:()=>At,audioVolumeOf:()=>oe,findShim:()=>Oe,hostTransport:()=>Te,init:()=>Pn,insetsFrom:()=>ge,isInputShim:()=>ye,isShim:()=>be,labelFor:()=>fe,preferredBinding:()=>de,servesScheme:()=>Re,shimTransport:()=>Se});var Mt=/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;var Ue=9007199254740991;function ze(e){return typeof e=="string"&&e.length<=48&&Mt.test(e)}function ne(e){return typeof e=="number"&&Number.isFinite(e)&&Math.abs(e)<=9007199254740991}function Lt(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;if(typeof t.unlocked!="boolean")return null;let n={unlocked:t.unlocked};return typeof t.at=="number"&&Number.isFinite(t.at)&&(n.at=t.at),ne(t.progress)&&(n.progress=t.progress),n}function Ae(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;if(typeof t.unlocked!="boolean"||typeof t.earned!="boolean")return null;let n={unlocked:t.unlocked,earned:t.earned};return ne(t.progress)&&(n.progress=t.progress),n}function Ge(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e,o={ids:Array.isArray(t.ids)?t.ids.filter(ze):[]},r=Rt(t.state);return r!==void 0&&(o.state=r),o}function Be(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=Rt(e.state);return t===void 0?null:{state:t}}function Rt(e){if(e===null)return null;if(typeof e!="object"||e===void 0||Array.isArray(e))return;let t={};for(let[n,o]of Object.entries(e)){if(!ze(n))continue;let r=Lt(o);r!==null&&(t[n]=r)}return t}var Ct="hopple.",He=/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;function Ot(e){return typeof e=="string"&&!e.startsWith(Ct)&&He.test(e)}function We(e,t,n){let o=typeof e=="string"?e:"";if(!Ot(e))return{ok:!1,reason:"name",name:o};let r=n?.[e];if(n!==void 0&&r===void 0)return{ok:!1,reason:"undeclared",name:e};if(t!==void 0&&!_t(t))return{ok:!1,reason:"props",name:e};let s={},a=[];for(let[p,u]of Object.entries(_t(t)?t:{})){let d=r?.[p];if(r!==void 0&&d===void 0||!He.test(p)||!Bn(u,d)){a.push(p);continue}s[p]=u}return{ok:!0,name:e,props:s,dropped:a}}function _t(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Bn(e,t){return typeof e=="string"?t===void 0||t==="string":typeof e=="number"?Number.isFinite(e)&&(t===void 0||t==="number"):typeof e=="boolean"?t===void 0||t==="boolean":!1}var re=1,q="master";var Tt=/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;function Nt(e){return typeof e=="string"&&e.length<=48&&Tt.test(e)}var K=Object.freeze({muted:!1,master:1,channels:Object.freeze({})});function Dt(e,t){return typeof e!="number"||!Number.isFinite(e)?t:Math.min(1,Math.max(0,e))}function we(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e,n={};if(typeof t.channels=="object"&&t.channels!==null&&!Array.isArray(t.channels))for(let[o,r]of Object.entries(t.channels))!Nt(o)||o===q||typeof r!="number"||!Number.isFinite(r)||(n[o]=Math.min(1,Math.max(0,r)));return{muted:t.muted===!0,master:Dt(t.master,K.master),channels:n}}function Fe(e,t){if(e.muted!==t.muted||e.master!==t.master)return!1;let n=Object.keys(e.channels);return n.length!==Object.keys(t.channels).length?!1:n.every(o=>e.channels[o]===t.channels[o])}function oe(e,t){return e.muted?0:t===void 0||t===q?e.master:e.master*(e.channels[t]??1)}var Hn=Object.freeze({audio:!0,loop:!0,resources:!0});function Ve(e){let t=typeof e=="object"&&e!==null?e:{};return{audio:t.audio!==!1,loop:t.loop!==!1,resources:t.resources!==!1}}function se(e){if(typeof e!="object"||e===null)return!1;let t=e;if(t.p!==1)return!1;switch(t.kind){case"req":return typeof t.id=="string"&&typeof t.method=="string";case"res":return typeof t.id!="string"?!1:t.ok===!0?!0:t.ok===!1?Wn(t.error):!1;case"evt":return typeof t.topic=="string";default:return!1}}function Wn(e){if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.code=="string"&&typeof t.message=="string"}var L=class extends Error{constructor(n){super(n.message);Pt(this,"code");this.name="BridgeError",this.code=n.code}};function Xe(e){return e instanceof L?{code:e.code,message:e.message}:{code:"internal",message:"The handler failed."}}function xe(e,t){let n,o;try{Fn(t)?(n=t.message===""?String(t.name):`${String(t.name)}: ${t.message}`,o=typeof t.stack=="string"?t.stack:void 0):typeof t=="string"?n=t:typeof t=="object"&&t!==null?n=JSON.stringify(t)??String(t):n=String(t)}catch{n="An error that could not be described."}let r={kind:e,message:jt(n,1e3)};return o!==void 0&&o!==""&&(r.stack=jt(o,8e3)),r}function Fn(e){if(e instanceof Error)return!0;let t=Object.prototype.toString.call(e);return(t==="[object Error]"||t==="[object DOMException]")&&typeof e.message=="string"}function jt(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e}var ke=["keyboard","mouse","touch","gamepad"];var Ut=/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;function Z(e){return typeof e=="string"&&e.length<=48&&Ut.test(e)}var zt=["row","column","diamond","cluster"],Gt=["left","right","full"];var Bt=["remap","scheme","host","setting"];function Ke(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;if(!Array.isArray(t.bind))return null;let o={bind:t.bind.filter(r=>typeof r=="string"&&r.length<=96)};return typeof t.title=="string"&&(o.title=t.title),typeof t.label=="string"&&(o.label=t.label),o}function Ze(e){let t=Wt(e);if(t===null)return null;let n=e,o={};for(let[s,a]of qe(n.actions)){if(!Z(s))continue;let p=Ke(a);p!==null&&(o[s]=p)}let r={};for(let[s,a]of qe(n.layouts)){if(!Z(s))continue;let p=Ht(a);p!==null&&(r[s]=p)}return{...t,actions:o,layouts:r}}function Ht(e){if(!Y(e))return null;let t={};for(let n of Gt){let o=e[n];if(!Y(o))continue;let r={};for(let[s,a]of Object.entries(o)){if(!Z(s))continue;let p=Vn(a);p!==null&&(r[s]=p)}t[n]=r}return t}function Vn(e){if(!Y(e))return null;let t=e.type;if(t!=="buttons"&&t!=="thumbstick")return null;let n={type:t},o=e.buttons;Array.isArray(o)&&(n.buttons=o.filter(Z));let r=e.shape;zt.includes(r)&&(n.shape=r);let s=e.as;if($t(s))n.as=s;else if(Y(s)){let p={};for(let[u,d]of Object.entries(s))Z(u)&&$t(d)&&(p[u]=d);n.as=p}let a=e.axis;return t==="thumbstick"&&(a==="x"||a==="y")&&(n.axis=a),n}function Ye(e){let t=Wt(e);if(t===null)return null;let n=e.cause;return{...t,cause:Bt.includes(n)?n:"host"}}function Wt(e){if(!Y(e))return null;let t=e,n={};for(let[o,r]of qe(t.mapping)){if(!Z(o))continue;let s=Ke(r);s!==null&&(n[o]=s)}return{mapping:n,scheme:ke.includes(t.scheme)?t.scheme:"keyboard",controls:t.controls===!0,sticks:t.sticks==="fixed"?"fixed":"floating"}}function Y(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function qe(e){return Y(e)?Object.entries(e):[]}function $t(e){return typeof e=="string"&&e.length<=96}var Je=["app","web","dev"],Qe=["low","mid","high"],B={app:{id:"",version:"",surface:"web"},game:{id:"",version:""},player:{id:null,returning:!1,locale:"en"},device:{tier:"mid"}};function R(e){let t=new Set;function n(o,r){try{return o.listener(...r)}catch(s){e(s);return}}return{on(o){let r={listener:o};return t.add(r),()=>{t.delete(r)}},emit(...o){for(let r of[...t]){if(!t.has(r))continue;let s=n(r,o);s instanceof Promise&&s.catch(e)}},async settle(...o){await Promise.all([...t].map(async r=>{if(t.has(r))try{await n(r,o)}catch(s){e(s)}}))},get size(){return t.size},clear(){t.clear()}}}var Ft=/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;var ae=["about","scores","achievements","input"];function ie(e){return typeof e=="string"&&e.length<=32&&Ft.test(e)}function et(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e,n={ids:Array.isArray(t.ids)?t.ids.filter(ie):[]};return(t.isOpen===!0||ie(t.page))&&(n.isOpen=!0),ie(t.page)&&(n.page=t.page),n}function tt(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e,n=ie(t.page)?t.page:null,o=t.isOpen===!0||n!==null;return{isOpen:o,page:o?n:null}}var nt=["running","paused","unpausable"],ce="unpausable";function rt(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;return typeof t.paused=="boolean"?{paused:t.paused}:null}var J=65536;function st(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;if(typeof t.state!="string"||typeof t.version!="number"||!Number.isFinite(t.version)||t.encoding!=="json"&&t.encoding!=="text")return null;let n={version:t.version,encoding:t.encoding,state:t.state};return typeof t.rev=="string"&&(n.rev=t.rev),n}function Ee(e){return new TextEncoder().encode(e).length}function Ie(e){if(typeof e!="object"||e===null)return null;let t=e;return!ot(t.at)||!ot(t.version)||!ot(t.bytes)?null:{at:t.at,version:t.version,bytes:t.bytes}}function ot(e){return typeof e=="number"&&Number.isFinite(e)}var at=9007199254740991,Vt=/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/;function it(e){return typeof e=="string"&&e.length<=48&&Vt.test(e)}function ue(e){return typeof e=="number"&&Number.isFinite(e)&&Math.abs(e)<=9007199254740991}function Xt(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;if(!ue(t.best)||!Q(t.at)||!Q(t.runs))return null;let n={best:t.best,at:t.at,runs:t.runs};return Q(t.rank)&&(n.rank=t.rank),Q(t.of)&&(n.of=t.of),n}function Pe(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e,o={boards:Array.isArray(t.boards)?t.boards.filter(it):[]};if(t.standing===null)o.standing=null;else if(typeof t.standing=="object"&&t.standing!==void 0){let r={};for(let[s,a]of Object.entries(t.standing)){if(!it(s))continue;let p=Xt(a);p!==null&&(r[s]=p)}o.standing=r}return o}function ct(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;if(t.standing===null)return{standing:null};let n=Pe({boards:[],standing:t.standing});return n?.standing===void 0?null:{standing:n.standing}}function ut(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;let t=e;if(typeof t.improved!="boolean"||!ue(t.best))return null;let n={improved:t.improved,best:t.best};return Q(t.rank)&&(n.rank=t.rank),Q(t.of)&&(n.of=t.of),n}function Q(e){return typeof e=="number"&&Number.isFinite(e)}var lt=512,pt=1024;function dt(e){if(typeof e!="object"||e===null)return null;let t=e,n={};return typeof t.data=="string"&&t.data!==""&&(n.data=t.data),typeof t.offers=="boolean"&&(n.offers=t.offers),n}function ft(e){if(typeof e!="object"||e===null||Array.isArray(e))return null;try{let t=JSON.parse(JSON.stringify(e));return typeof t=="object"&&t!==null&&!Array.isArray(t)?t:null}catch{return null}}var Xn=1e4;function mt(e){let{transport:t}=e,n=e.timeoutMs??Xn,o=e.onError??(h=>console.error(h)),r=e.handlers,s=new Map,a=new Map,p=0,u=null,d=null,c=!1,i=t.receive(m);function m(h){c||(h.kind==="req"?f(h):h.kind==="res"?l(h):b(h))}async function f(h){if(w(h.id)){v({p:1,kind:"res",id:h.id,ok:!1,error:{code:"stale",message:"That conversation has ended; introduce yourself again."}});return}let x=r[h.method];if(!x){v({p:1,kind:"res",id:h.id,ok:!1,error:{code:"unknown_method",message:`No handler for "${h.method}".`}});return}try{let _=await x(h.params);if(c)return;v({p:1,kind:"res",id:h.id,ok:!0,value:_})}catch(_){if(c)return;v({p:1,kind:"res",id:h.id,ok:!1,error:Xe(_)})}}function l(h){let x=s.get(h.id);x&&(s.delete(h.id),clearTimeout(x.timer),h.ok?x.resolve(h.value):x.reject(new L(h.error)))}function b(h){a.get(h.topic)?.emit(h.data)}function v(h){try{t.send(h)}catch(x){o(x)}}function P(h,x,_){if(c)return Promise.reject(new L({code:"disposed",message:`"${h}" was not sent: peer disposed.`}));p+=1;let T=u===null?String(p):`${u}-${p}`,j=_?.timeoutMs??n;return new Promise((C,U)=>{let X=setTimeout(()=>{s.delete(T),U(new L({code:"timeout",message:`"${h}" got no reply within ${j}ms.`}))},j);s.set(T,{resolve:C,reject:U,timer:X}),v({p:1,kind:"req",id:T,method:h,params:x})})}function I(h,x){c||v({p:1,kind:"evt",topic:h,data:x})}function O(h,x){let _=a.get(h);_===void 0&&(_=R(o),a.set(h,_));let T=_.on(x),j=_;return()=>{T(),j.size===0&&a.get(h)===j&&a.delete(h)}}function A(h){for(let x of s.values())clearTimeout(x.timer),x.reject(h);s.clear()}function y(h){u=h}function k(h){c||(d=h,A(new L({code:"stale",message:"The other side started over; this call belonged to the conversation before it."})))}function w(h){if(d===null)return!1;let x=h.indexOf("-");return x===-1?!1:h.slice(0,x)!==d}function E(){c||(c=!0,i(),A(new L({code:"disposed",message:"The peer was disposed mid-call."})),a.clear(),t.close())}return{call:P,emit:I,on:O,useSession:y,expectSession:k,dispose:E}}var V="__HOPPLE_SHIM__",z="__HOPPLE_SET_SHIM__";var qt={version:"0.1.0-rc.2"};function Kt(e){return{...e,call:(n,o,r)=>e.call(n,o,r).catch(s=>{throw Kn(s)})}}function W(e,t,n){let o;try{o=e()}catch(r){o=Promise.reject(r)}o.then(n,r=>{r instanceof L&&(r.code==="unsupported"||r.code==="disposed")||t(r)})}function Kn(e){return!(e instanceof L)||e.code!=="unknown_method"?e:new L({code:"unsupported",message:e.message})}function Zt(e){let t=!1,n=[],o,r=yt(n,o),s=R(e.onError);function a(d){o=d;let c=r;r=yt(n,o),Zn(c,r)||s.emit(r,c)}function p(d,c){if(o===void 0)return;let i=o??{},m=i[d],f={unlocked:c.unlocked,...c.unlocked?{at:m?.at??Date.now()}:{},...c.progress===void 0?{}:{progress:c.progress}};a({...i,[d]:f})}return{achievements:{get available(){return t},get standing(){return r},on:s.on,unlock(d){t&&W(()=>e.peer().call("achievement.unlock",{id:d}),e.onError,c=>{p(d,Ae(c)??{unlocked:!0,earned:!0})})},progress(d,c){if(!ne(c)){e.onError(new Error(`achievements: progress on "${d}" must be a finite number an achievement can hold.`));return}t&&W(()=>e.peer().call("achievement.progress",{id:d,progress:c}),e.onError,i=>{p(d,Ae(i)??{unlocked:!1,earned:!1,progress:c})})}},adopt(d){let c=Ge(d);t=c!==null,n=c?.ids??[],o=c?.state,r=yt(n,o)},onChange(d){let c=Be(d);c!==null&&a(c.state)}}}function yt(e,t){if(t===void 0)return Object.freeze({known:!1,items:Object.freeze(e.map(r=>Object.freeze({id:r})))});let n=t??{},o=e.map(r=>Object.freeze({id:r,...n[r]??{unlocked:!1}}));return Object.freeze({known:!0,items:Object.freeze(o)})}function Zn(e,t){return e.known!==t.known||e.items.length!==t.items.length?!1:!e.known||!t.known?!0:e.items.every((n,o)=>{let r=t.items[o];return r!==void 0&&n.id===r.id&&n.unlocked===r.unlocked&&n.at===r.at&&n.progress===r.progress})}function Yt(e){return{refused(t){let n=t,o=typeof n=="object"&&n!==null?n:null;(e.onRefused??e.onError)(new Error(`analytics: the host refused "${String(o?.name)}" (${String(o?.reason)}).`))},analytics:{track(t,n){let o=We(t,n);if(!o.ok){e.onError(new Error(`analytics: "${o.name}" was not sent (${o.reason}).`));return}o.dropped.length>0&&e.onError(new Error(`analytics: "${o.name}" dropped ${o.dropped.join(", ")}.`));let r={name:o.name};Object.keys(o.props).length>0&&(r.props=o.props),e.peer().emit("analytics.event",r)}}}}var Jt=["pointerdown","pointerup","touchend","keydown"];function Qt(e){let t=ht(K),n=!0,o=!1,r=R(e.onError),s=new Map,a=new Map,p=!1;function u(l){return n?oe(t,l):0}function d(){for(let l of s.values())for(let[b,v]of l)v.gain.value=u(b);for(let[l,b]of a)l.volume=u(b.channel)}function c(){if(n){for(let l of s.keys())l.state==="suspended"&&l.resume().catch(()=>{});for(let[l,b]of a)b.stopped&&l.play().then(()=>{b.stopped=!1},()=>{})}}async function i(){for(let[l,b]of a)l.paused||(l.pause(),b.stopped=!0);await Promise.all([...s.keys()].map(l=>l.state==="running"?l.suspend().catch(()=>{}):void 0))}function m(){if(!(p||e.scope===null)){p=!0;for(let l of Jt)e.scope.addEventListener(l,c,{capture:!0})}}return{audio:{get allowed(){return n},get muted(){return t.muted},get master(){return t.master},get state(){return t},volume(l){return u(l)},channel(l){return l===q?t.master:t.channels[l]??1},on:r.on,output(l,b){let v=s.get(l);v===void 0&&(v=new Map,s.set(l,v),!n&&l.state==="running"&&l.suspend().catch(()=>{}));let P=v.get(b);return P===void 0&&(P=l.createGain(),P.gain.value=u(b),P.connect(l.destination),v.set(b,P)),m(),c(),P},media(l,b){if(a.set(l,{channel:b,stopped:!1}),l.volume=u(b),!n&&!l.paused){l.pause();let v=a.get(l);v!==void 0&&(v.stopped=!0)}return m(),()=>{a.delete(l)}}},async onAllow(l){return o=!0,l.allowed!==n&&(n=l.allowed,d(),r.emit(),n?c():await i()),{allowed:n}},dispose(){if(p&&e.scope!==null)for(let l of Jt)e.scope.removeEventListener(l,c,{capture:!0});p=!1,s.clear(),a.clear()},adopt(l,b){o||(n=b),t=ht(we(l)??K),d()},onSet(l){let b=ht(we(l)??t);return Fe(t,b)||(t=b,d(),r.emit()),t}}}function ht(e){return Object.freeze({muted:e.muted,master:e.master,channels:Object.freeze({...e.channels})})}var Yn=20,Jn=1e3,Qn=32;function en(e){let t=null,n=[],o=new Map;function r(c){if(t!==null){t.emit("error.report",c);return}n.length<Yn&&n.push(c)}function s(c,i){let m={error:i,again:0,timer:setTimeout(()=>{o.delete(c),m.again!==0&&(r({...i,count:m.again}),s(c,i))},Jn)};o.set(c,m)}function a(c){let i=`${c.kind}
|
|
3
|
+
${c.message}
|
|
4
|
+
${c.stack??""}`,m=o.get(i);if(m!==void 0){m.again+=1;return}r(c),o.size<Qn&&s(i,c)}function p(c,i){a(xe(c,i))}let u=c=>{let i=c;if(i.error!==void 0&&i.error!==null){p("uncaught",i.error);return}if(typeof i.message!="string"||i.message==="")return;let m=xe("uncaught",i.message);typeof i.filename=="string"&&i.filename!==""&&(m.stack=`at ${i.filename}:${i.lineno}:${i.colno}`),a(m)},d=c=>{p("rejection",c.reason)};return e?.addEventListener("error",u),e?.addEventListener("unhandledrejection",d),{report:p,connect(c){t=c;let i=n;n=[];for(let m of i)c.emit("error.report",m)},dispose(){e?.removeEventListener("error",u),e?.removeEventListener("unhandledrejection",d);for(let{error:c,again:i,timer:m}of o.values())clearTimeout(m),i>0&&r({...c,count:i});o.clear(),n=[]}}}function nn(e){let t=le(e),n=le(t.app),o=le(t.game),r=le(t.player),s=le(t.device);return Object.freeze({app:Object.freeze({id:pe(n.id,B.app.id),version:pe(n.version,B.app.version),surface:tn(n.surface,Je,B.app.surface)}),game:Object.freeze({id:pe(o.id,B.game.id),version:pe(o.version,B.game.version)}),player:Object.freeze({id:typeof r.id=="string"&&r.id!==""?r.id:null,returning:r.returning===!0,locale:pe(r.locale,B.player.locale)}),device:Object.freeze({tier:tn(s.tier,Qe,B.device.tier)})})}function le(e){return typeof e=="object"&&e!==null?e:{}}function pe(e,t){return typeof e=="string"?e:t}function tn(e,t,n){return t.includes(e)?e:n}var ee=["pad.right.south","pad.right.east","pad.right.west","pad.right.north","pad.left.bumper","pad.right.bumper","pad.left.trigger","pad.right.trigger","pad.select","pad.start",null,null,"pad.left.north","pad.left.south","pad.left.west","pad.left.east"],gt=["pad.left.stick","pad.right.stick"],er=["pad.left.stick","pad.right.stick"];function Me(e,t){if(e===t)return!0;if(e.startsWith("pad.")&&t.startsWith("pad.")){let n=e.slice(4),o=t.slice(4).split(".");return o.length===2&&o[1]===n}return e==="pointer.primary"?t==="mouse.left"||t==="touch.tap":e==="pointer.secondary"?t==="mouse.right":!1}function Le(e,t){return e===t?!0:e==="pad.stick"&&er.includes(t)}function de(e,t){return e.find(n=>Re(n,t))??e[0]}function Re(e,t){if(e.startsWith("pointer."))return t==="mouse"||t==="touch";if(e.startsWith("controls."))return t==="touch";switch(t){case"keyboard":return e.startsWith("key.");case"gamepad":return e.startsWith("pad.");case"mouse":return e.startsWith("mouse.");case"touch":return e.startsWith("touch.");default:return!1}}function fe(e,t){if(e.startsWith("key."))return nr(e.slice(4));if(e==="mouse.left")return"Click";if(e==="mouse.right")return"Right click";if(e==="mouse.middle")return"Middle click";if(e==="touch.tap")return"Tap";if(e==="pointer.primary")return t==="touch"?"Tap":"Click";if(e==="pointer.secondary")return"Right click";if(!e.startsWith("pad."))return"";let n=e.slice(4).split("."),[o,r]=n;if(n.length===1)return o==="start"?"Start":o==="select"?"Select":rn[o]??"";if(o==="left"&&r!==void 0){let s=tr[r];return s!==void 0?s:r==="bumper"?"LB":r==="trigger"?"LT":""}if(o==="right"&&r!==void 0){let s=rn[r];return s!==void 0?s:r==="bumper"?"RB":r==="trigger"?"RT":""}return""}var rn={south:"A",east:"B",west:"X",north:"Y"},tr={north:"\u2191",south:"\u2193",west:"\u2190",east:"\u2192"};function nr(e){return e.startsWith("Key")&&e.length===4?e.slice(3):e.startsWith("Digit")&&e.length===6?e.slice(5):e.startsWith("Numpad")?`Num ${e.slice(6)}`:{ArrowUp:"\u2191",ArrowDown:"\u2193",ArrowLeft:"\u2190",ArrowRight:"\u2192",Space:"Space",Enter:"Enter",Tab:"Tab",Backspace:"Backspace",ShiftLeft:"Shift",ShiftRight:"Shift",ControlLeft:"Ctrl",ControlRight:"Ctrl",AltLeft:"Alt",AltRight:"Alt"}[e]??e}var me="__HOPPLE_INPUT__";function ye(e){return typeof e!="object"||e===null?!1:e.v===1}var he=4,rr=["top","right","bottom","left"],or=["row","column","diamond","cluster"],sr=["left","right","full"];function on(e,t,n,o,r,s){let a=[];for(let p of sr){let u=t[p];if(u===void 0)continue;let d=[];for(let[c,i]of Object.entries(u))d.push(ir(c,i,n));d.length>0&&a.push({zone:p,controls:d})}return{layout:e,zones:a,frame:o,insets:r,sticks:s}}function ir(e,t,n){let o=or.includes(t.shape)?t.shape:"column";if(t.type==="thumbstick"){let a=typeof t.as=="string"?t.as:`controls.${e}`,p={id:e,type:"thumbstick",shape:o,buttons:[],stick:a};return t.axis!==void 0&&(p.axis=t.axis),p}let r=typeof t.as=="object"&&t.as!==null?t.as:{},s=(t.buttons??[]).map(a=>{let p={action:a,label:ar(n[a])??a},u=r[a];return typeof u=="string"&&(p.as=u),p});return{id:e,type:"buttons",shape:o,buttons:s,stick:""}}function ar(e){let t=e?.label;return typeof t=="string"&&t!==""?t:void 0}function sn(e){let{scope:t}=e,n=t.document,o=null,r=null,s=null,a=!1;function p(){return r!==null||(o=n.createElement("div"),o.setAttribute("data-hopple-controls",""),o.style.cssText="position:fixed;inset:0;pointer-events:none;z-index:2147483000;touch-action:none;",r=o.attachShadow({mode:"open"}),(n.body??n.documentElement).append(o)),r}return{render(u){this.clear();let d=p();for(let i of rr)o?.style.setProperty(`--hopple-pad-${i}`,`${u.insets[i]}px`);let c=e.shim();if(c!==null&&!a&&typeof c.style=="function")try{c.style(d,{layout:u.layout,frame:u.frame}),a=!0}catch(i){e.onError(i)}if(c!==null&&typeof c.render=="function")try{let i=c.render(d,u,e.report);s=typeof i=="function"?i:null;return}catch(i){e.onError(i),d.replaceChildren(),s=null}s=cr(d,u,e.report,n,e.onError)},clear(){if(s!==null){try{s()}catch(u){e.onError(u)}s=null}r?.replaceChildren()},rects(){let u=[];if(r===null)return u;for(let d of r.querySelectorAll("[data-control]")){let c=d.getBoundingClientRect();c.width<=0||c.height<=0||u.push({x:c.x,y:c.y,width:c.width,height:c.height})}return u},fits(u,d){if(u.width<=0||u.height<=0)return!0;let c=u.width-d.right,i=u.height-d.bottom;for(let m of this.rects())if(m.x<d.left||m.y<d.top||m.x+m.width>c||m.y+m.height>i)return!1;return!0},owns(u){return o===null?!1:(typeof u.composedPath=="function"?u.composedPath():[]).includes(o)?!0:u.target===o},dispose(){this.clear(),o?.remove(),o=null,r=null}}}function cr(e,t,n,o,r){let s=o.createElement("style");s.textContent=pr,e.append(s);let a=[],p=t.sticks==="floating",u=()=>e.host.setAttribute("data-used","");for(let{zone:d,controls:c}of t.zones){let i=o.createElement("div");i.className=`zone zone-${d}`;for(let m of c){if(m.type==="buttons"){i.append(ur(m,n,o,a,r));continue}let f=lr(m,p?d:null,n,u,o,a,r);i.append(f.well),f.reach!==null&&s.after(f.reach)}e.append(i)}return()=>{for(let d of a)d()}}function ur(e,t,n,o,r){let s=n.createElement("div");s.className=`control buttons shape-${e.shape}`,s.setAttribute("data-control",e.id);for(let[a,p]of e.buttons.entries()){let u=n.createElement("button");u.className="btn",u.type="button",u.textContent=p.label,u.setAttribute("aria-label",p.action),u.setAttribute("data-action",p.action);let d=m=>f=>{f.preventDefault(),f.stopPropagation(),u.classList.toggle("down",m);try{t.press(e.id,a,m)}catch(l){r(l)}},c=d(!0),i=d(!1);u.addEventListener("pointerdown",c),u.addEventListener("pointerup",i),u.addEventListener("pointercancel",i),u.addEventListener("pointerleave",i),o.push(()=>{u.removeEventListener("pointerdown",c),u.removeEventListener("pointerup",i),u.removeEventListener("pointercancel",i),u.removeEventListener("pointerleave",i)}),s.append(u)}return s}function lr(e,t,n,o,r,s,a){let{axis:p}=e,u=r.createElement("div");if(u.className=p===void 0?"control stick":`control stick track track-${p}`,t!==null&&u.classList.add("floating"),u.setAttribute("data-control",e.id),u.setAttribute("aria-label",e.stick),p!==void 0)for(let A of["start","end"]){let y=r.createElement("span");y.className=`chevron chevron-${A}`,u.append(y)}let d=r.createElement("div");d.className="knob",u.append(d);let c=null;t!==null&&(c=r.createElement("div"),c.className=`reach reach-${t}`,c.setAttribute("data-reach",e.id));let i=null,m=null,f=null;function l(A,y){d.style.setProperty("--x",String(A)),d.style.setProperty("--y",String(y));try{n.move(e.id,A,y)}catch(k){a(k)}}function b(A){f=A;let y=m??A;u.style.setProperty("--dx",`${A.x-y.x}px`),u.style.setProperty("--dy",`${A.y-y.y}px`)}let v=A=>{let y=A;if(A.preventDefault(),A.stopPropagation(),t!==null&&m===null){let k=u.getBoundingClientRect();m={x:k.x+k.width/2,y:k.y+k.height/2}}i=y.pointerId;try{A.currentTarget?.setPointerCapture?.(y.pointerId)}catch{}u.classList.add("held"),t!==null&&(b({x:y.clientX,y:y.clientY}),o()),P(y)},P=A=>{let y=u.getBoundingClientRect(),k=f??{x:y.x+y.width/2,y:y.y+y.height/2};if(p!==void 0){let _=p==="x"?y.width:y.height,T=p==="x"?y.height:y.width,j=_>T?(_-T)/2:_/2;if(j<=0)return;let C=p==="x"?A.clientX:A.clientY,U=C-(p==="x"?k.x:k.y),X=Math.max(-1,Math.min(1,U/j));if(f!==null&&Math.abs(U)>j){let F=C-X*j;b(p==="x"?{x:F,y:f.y}:{x:f.x,y:F})}l(p==="x"?X:0,p==="y"?X:0);return}let w=Math.min(y.width,y.height)/2;if(w<=0)return;let E=(A.clientX-k.x)/w,h=(A.clientY-k.y)/w,x=Math.hypot(E,h);x>1&&(E/=x,h/=x,f!==null&&b({x:A.clientX-E*w,y:A.clientY-h*w})),l(E,h)},I=A=>{let y=A;i===y.pointerId&&(A.preventDefault(),A.stopPropagation(),P(y))},O=A=>{i===A.pointerId&&(A.stopPropagation(),i=null,u.classList.remove("held"),t!==null&&(f=null,u.classList.add("let-go")),l(0,0))};for(let A of c===null?[u]:[u,c])A.addEventListener("pointerdown",v),A.addEventListener("pointermove",I),A.addEventListener("pointerup",O),A.addEventListener("pointercancel",O),s.push(()=>{A.removeEventListener("pointerdown",v),A.removeEventListener("pointermove",I),A.removeEventListener("pointerup",O),A.removeEventListener("pointercancel",O)});return{well:u,reach:c}}var pr=`
|
|
5
|
+
:host, * { box-sizing: border-box; }
|
|
6
|
+
:host {
|
|
7
|
+
--hopple-pad-size: 56px;
|
|
8
|
+
--hopple-pad-stick: 116px;
|
|
9
|
+
/* The length of a stick held to one axis; its thickness is a button's. */
|
|
10
|
+
--hopple-pad-track: 148px;
|
|
11
|
+
--hopple-pad-gap: 12px;
|
|
12
|
+
--hopple-pad-inset: 20px;
|
|
13
|
+
/* What the host has taken, written onto the element by render(). Kept apart
|
|
14
|
+
from --hopple-pad-inset deliberately: that one is the gap the pad likes to
|
|
15
|
+
keep off an edge and is a shim's to set, these are a fact about the frame
|
|
16
|
+
and are not. The zones spend the sum, so a shim restyling the gap does not
|
|
17
|
+
have to know the rail exists. */
|
|
18
|
+
--hopple-pad-top: 0px;
|
|
19
|
+
--hopple-pad-right: 0px;
|
|
20
|
+
--hopple-pad-bottom: 0px;
|
|
21
|
+
--hopple-pad-left: 0px;
|
|
22
|
+
--hopple-pad-tint: rgba(255, 255, 255, 0.14);
|
|
23
|
+
--hopple-pad-edge: rgba(255, 255, 255, 0.55);
|
|
24
|
+
--hopple-pad-ink: #fff;
|
|
25
|
+
--hopple-pad-opacity: 0.85;
|
|
26
|
+
--hopple-pad-radius: 999px;
|
|
27
|
+
/* How high a floating stick's side of the screen reaches, from the bottom. */
|
|
28
|
+
--hopple-pad-reach: 60%;
|
|
29
|
+
/* A floating stick at rest is a mark that there is one, drawn quieter than
|
|
30
|
+
the stick under a thumb, and quieter again once the player has used it. */
|
|
31
|
+
--hopple-pad-idle: 0.55;
|
|
32
|
+
--hopple-pad-used: 0.3;
|
|
33
|
+
}
|
|
34
|
+
.zone {
|
|
35
|
+
position: fixed;
|
|
36
|
+
bottom: calc(var(--hopple-pad-inset) + var(--hopple-pad-bottom));
|
|
37
|
+
display: flex; align-items: flex-end; gap: var(--hopple-pad-gap);
|
|
38
|
+
opacity: var(--hopple-pad-opacity); pointer-events: none;
|
|
39
|
+
}
|
|
40
|
+
.zone-left { left: calc(var(--hopple-pad-inset) + var(--hopple-pad-left)); }
|
|
41
|
+
.zone-right {
|
|
42
|
+
right: calc(var(--hopple-pad-inset) + var(--hopple-pad-right));
|
|
43
|
+
flex-direction: row-reverse;
|
|
44
|
+
}
|
|
45
|
+
.zone-full {
|
|
46
|
+
left: calc(var(--hopple-pad-inset) + var(--hopple-pad-left));
|
|
47
|
+
right: calc(var(--hopple-pad-inset) + var(--hopple-pad-right));
|
|
48
|
+
justify-content: center;
|
|
49
|
+
}
|
|
50
|
+
.control { pointer-events: auto; touch-action: none; }
|
|
51
|
+
.buttons { display: grid; gap: var(--hopple-pad-gap); }
|
|
52
|
+
.shape-column { grid-auto-flow: row; }
|
|
53
|
+
.shape-row { grid-auto-flow: column; }
|
|
54
|
+
.shape-cluster { grid-template-columns: repeat(2, auto); }
|
|
55
|
+
.shape-diamond {
|
|
56
|
+
grid-template-columns: repeat(3, auto); grid-template-rows: repeat(3, auto);
|
|
57
|
+
}
|
|
58
|
+
/* North, west, east, south \u2014 the order a diamond is declared in. */
|
|
59
|
+
.shape-diamond .btn:nth-child(1) { grid-area: 1 / 2; }
|
|
60
|
+
.shape-diamond .btn:nth-child(2) { grid-area: 2 / 1; }
|
|
61
|
+
.shape-diamond .btn:nth-child(3) { grid-area: 2 / 3; }
|
|
62
|
+
.shape-diamond .btn:nth-child(4) { grid-area: 3 / 2; }
|
|
63
|
+
.btn {
|
|
64
|
+
width: var(--hopple-pad-size); height: var(--hopple-pad-size);
|
|
65
|
+
border-radius: var(--hopple-pad-radius);
|
|
66
|
+
border: 1.5px solid var(--hopple-pad-edge);
|
|
67
|
+
background: var(--hopple-pad-tint); color: var(--hopple-pad-ink);
|
|
68
|
+
font: 600 15px/1 system-ui, sans-serif;
|
|
69
|
+
display: grid; place-items: center; padding: 0;
|
|
70
|
+
touch-action: none; user-select: none; -webkit-user-select: none;
|
|
71
|
+
-webkit-tap-highlight-color: transparent; cursor: pointer;
|
|
72
|
+
}
|
|
73
|
+
.btn.down { background: var(--hopple-pad-edge); }
|
|
74
|
+
.stick {
|
|
75
|
+
width: var(--hopple-pad-stick); height: var(--hopple-pad-stick);
|
|
76
|
+
border-radius: 50%; border: 1.5px solid var(--hopple-pad-edge);
|
|
77
|
+
background: var(--hopple-pad-tint);
|
|
78
|
+
display: grid; place-items: center;
|
|
79
|
+
touch-action: none; user-select: none; -webkit-user-select: none;
|
|
80
|
+
-webkit-tap-highlight-color: transparent;
|
|
81
|
+
}
|
|
82
|
+
.knob {
|
|
83
|
+
width: 44%; height: 44%; border-radius: 50%;
|
|
84
|
+
background: var(--hopple-pad-edge);
|
|
85
|
+
/* As far as the thumb has gone: all the way over is the knob on the rim. */
|
|
86
|
+
transform: translate(
|
|
87
|
+
calc(var(--x, 0) * var(--hopple-pad-stick) / 2),
|
|
88
|
+
calc(var(--y, 0) * var(--hopple-pad-stick) / 2)
|
|
89
|
+
);
|
|
90
|
+
will-change: transform;
|
|
91
|
+
}
|
|
92
|
+
.track {
|
|
93
|
+
position: relative;
|
|
94
|
+
--hopple-pad-travel: calc((var(--hopple-pad-track) - var(--hopple-pad-size)) / 2);
|
|
95
|
+
}
|
|
96
|
+
.track-x { width: var(--hopple-pad-track); height: var(--hopple-pad-size); border-radius: var(--hopple-pad-radius); }
|
|
97
|
+
.track-y { width: var(--hopple-pad-size); height: var(--hopple-pad-track); border-radius: var(--hopple-pad-radius); }
|
|
98
|
+
.track .knob {
|
|
99
|
+
position: relative; z-index: 1;
|
|
100
|
+
width: calc(var(--hopple-pad-size) - 14px); height: calc(var(--hopple-pad-size) - 14px);
|
|
101
|
+
transform: translate(
|
|
102
|
+
calc(var(--x, 0) * var(--hopple-pad-travel)),
|
|
103
|
+
calc(var(--y, 0) * var(--hopple-pad-travel))
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
/* A groove along the track for the knob to ride in. */
|
|
107
|
+
.track::before {
|
|
108
|
+
content: ''; position: absolute; border-radius: 2px;
|
|
109
|
+
background: var(--hopple-pad-edge); opacity: 0.35;
|
|
110
|
+
}
|
|
111
|
+
.track-x::before { left: 30%; right: 30%; top: calc(50% - 1px); height: 2px; }
|
|
112
|
+
.track-y::before { top: 30%; bottom: 30%; left: calc(50% - 1px); width: 2px; }
|
|
113
|
+
/* An open arrow at each end: which way the track goes, before a thumb is on it. */
|
|
114
|
+
.chevron {
|
|
115
|
+
position: absolute; width: 9px; height: 9px;
|
|
116
|
+
border: solid var(--hopple-pad-edge); border-width: 0 0 2px 2px;
|
|
117
|
+
}
|
|
118
|
+
.track-x .chevron { top: calc(50% - 4.5px); }
|
|
119
|
+
.track-x .chevron-start { left: 14px; transform: rotate(45deg); }
|
|
120
|
+
.track-x .chevron-end { right: 14px; transform: rotate(-135deg); }
|
|
121
|
+
.track-y .chevron { left: calc(50% - 4.5px); }
|
|
122
|
+
.track-y .chevron-start { top: 14px; transform: rotate(135deg); }
|
|
123
|
+
.track-y .chevron-end { bottom: 14px; transform: rotate(-45deg); }
|
|
124
|
+
/* Where a floating stick listens. The host's furniture is left alone; the
|
|
125
|
+
pad's own gap off the edge is not kept, since a thumb is not a drawing. */
|
|
126
|
+
.reach {
|
|
127
|
+
position: fixed; pointer-events: auto; touch-action: none;
|
|
128
|
+
bottom: var(--hopple-pad-bottom);
|
|
129
|
+
height: calc(var(--hopple-pad-reach) - var(--hopple-pad-bottom));
|
|
130
|
+
-webkit-tap-highlight-color: transparent;
|
|
131
|
+
}
|
|
132
|
+
.reach-left { left: var(--hopple-pad-left); right: 50%; }
|
|
133
|
+
.reach-right { left: 50%; right: var(--hopple-pad-right); }
|
|
134
|
+
.reach-full { left: var(--hopple-pad-left); right: var(--hopple-pad-right); }
|
|
135
|
+
.floating.held { translate: var(--dx, 0px) var(--dy, 0px); }
|
|
136
|
+
/* At rest a mark and not a stick: an outline and a dot, with nothing on it that
|
|
137
|
+
looks like it has to be pressed there. */
|
|
138
|
+
.floating:not(.held) { opacity: var(--hopple-pad-idle); background: transparent; }
|
|
139
|
+
:host([data-used]) .floating:not(.held) { opacity: var(--hopple-pad-used); }
|
|
140
|
+
.floating:not(.held) .knob { scale: 0.3; }
|
|
141
|
+
.floating.track:not(.held) .knob { scale: 0; }
|
|
142
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
143
|
+
/* Back to the middle gently; under a thumb at once, since it is already there. */
|
|
144
|
+
.stick:not(.held) .knob { transition: transform 60ms linear, scale 60ms linear; }
|
|
145
|
+
/* Let go, it goes out where the thumb left it and the mark comes back where
|
|
146
|
+
it rests, rather than travelling there as if that were where it lives. */
|
|
147
|
+
.floating.let-go:not(.held) { animation: let-go 280ms ease-out; }
|
|
148
|
+
}
|
|
149
|
+
@keyframes let-go {
|
|
150
|
+
0% { translate: var(--dx, 0px) var(--dy, 0px); opacity: 1; }
|
|
151
|
+
40% { translate: var(--dx, 0px) var(--dy, 0px); opacity: 0; }
|
|
152
|
+
41% { translate: 0px 0px; opacity: 0; }
|
|
153
|
+
}
|
|
154
|
+
`;function dr(e){let t=e.document.activeElement;if(t===null)return!1;if(t.isContentEditable)return!0;let n=t.tagName;return n==="INPUT"||n==="TEXTAREA"||n==="SELECT"}function an(e){let{scope:t,store:n}=e,o=t.document,r=[],s=[],a=!1,p=null,u=new Map,d=new Set,c=!0;function i(y,k,w,E,h=!1){let x=_=>{try{w(_)}catch(T){e.onError(T)}};y.addEventListener(k,x,h),E.push(()=>y.removeEventListener(k,x,h))}function m(y,k){let w=y;if(e.suspended()||dr(t))return;let E=`key.${w.code}`;e.isBound(E)&&(w.preventDefault(),e.onScheme("keyboard"),n.press(E,k))}function f(y){return y.pointerType!=="mouse"?"touch.tap":y.button===0?"mouse.left":y.button===1?"mouse.middle":y.button===2?"mouse.right":null}function l(y,k){let w=y;if(e.fromControls(y))return;if(e.onScheme(w.pointerType==="mouse"?"mouse":"touch"),k==="move"){n.movePointer({x:w.clientX,y:w.clientY,down:n.pointer?.down??!1});return}let E=k==="down";if(n.movePointer({x:w.clientX,y:w.clientY,down:E}),e.suspended())return;let h=f(w);h!==null&&n.press(h,E),(h==="touch.tap"||h==="mouse.left")&&n.press("pointer.primary",E)}function b(y,k){let w=e.deadzone(),E=Math.hypot(y,k);if(E<=w)return{x:0,y:0};if(w<=0||E===0)return{x:y,y:k};let h=(E-w)/(1-w)/E;return{x:y*h,y:k*h}}function v(){for(let y of t.navigator.getGamepads?.()??[])if(y!==null){if(y.mapping==="standard"){let k=u.get(y.index)??[],w=[];for(let[E,h]of y.buttons.entries()){let x=h.pressed;if(w[E]=x,x===(k[E]??!1)||!c)continue;let _=ee[E];_!=null&&(e.onScheme("gamepad"),e.suspended()||n.press(_,x))}u.set(y.index,w)}for(let[k,w]of gt.entries()){let E=c?b(y.axes[k*2]??0,y.axes[k*2+1]??0):{x:0,y:0};(E.x!==0||E.y!==0)&&e.onScheme("gamepad"),n.moveStick(w,E.x,E.y)}}}function P(){let y=()=>{p=null;try{v()}catch(k){e.onError(k)}d.size>0&&p===null&&P()};p=typeof t.requestAnimationFrame=="function"?t.requestAnimationFrame(y):setTimeout(y,16)}function I(){p!==null&&(typeof t.cancelAnimationFrame=="function"?t.cancelAnimationFrame(p):clearTimeout(p),p=null)}function O(y){d.add(y),p===null&&P()}function A(y){d.delete(y);let k=u.get(y)??[];u.delete(y);for(let[w,E]of k.entries()){let h=ee[w];E&&h!==null&&h!==void 0&&n.press(h,!1)}for(let w of gt)n.moveStick(w,0,0);d.size===0&&I()}return{attach(){i(t,"keydown",y=>m(y,!0),r),i(t,"keyup",y=>m(y,!1),r),i(t,"pointerdown",y=>l(y,"down"),r),i(t,"pointerup",y=>l(y,"up"),r),i(t,"pointercancel",y=>l(y,"up"),r),i(t,"blur",()=>{c=!1,n.releaseAll()},r),i(t,"focus",()=>{c=!0},r),i(o,"visibilitychange",()=>{o.visibilityState==="hidden"&&n.releaseAll()},r),i(t,"contextmenu",y=>{e.isBound("mouse.right")&&y.preventDefault()},r),i(t,"gamepadconnected",y=>{O(y.gamepad.index)},r),i(t,"gamepaddisconnected",y=>{A(y.gamepad.index)},r);for(let y of t.navigator.getGamepads?.()??[])y!==null&&O(y.index)},watchPointer(y){if(y!==a){if(a=y,y){i(t,"pointermove",k=>l(k,"move"),s),i(o,"pointerleave",()=>n.movePointer(null),s);return}for(let k of s.splice(0))k()}},detach(){this.watchPointer(!1);for(let y of r.splice(0))y();I(),d.clear(),u.clear()}}}var cn={x:0,y:0};function un(e){let t={},n=new Map,o=new Set,r=new Set,s=new Map,a=null,p=new Map,u=new Map,d=R(e.onError);function c(f,l){let b=f.get(l);return b===void 0&&(b=R(e.onError),f.set(l,b)),b}function i(f,l){(l?o:r).add(f),p.get(f)?.emit(l,f)}function m(f,l,b){let v=n.get(f);v===void 0&&(v=new Set,n.set(f,v));let P=v.size>0;b?v.add(l):v.delete(l);let I=v.size>0;P!==I&&i(f,I)}return{setMapping(f,l){t=f,l?.release!==!1&&this.releaseAll()},get mapping(){return t},press(f,l,b){for(let[v,P]of Object.entries(t))P.bind.some(I=>Me(I,f))&&m(v,b??f,l)},pressAction(f,l,b){m(f,l,b)},moveStick(f,l,b){let v=s.get(f);if(v!==void 0&&v.x===l&&v.y===b)return;let P={x:l,y:b};s.set(f,P);for(let[I,O]of u)Le(I,f)&&O.emit(P,f)},movePointer(f){f===null&&a===null||f!==null&&a!==null&&f.x===a.x&&f.y===a.y&&f.down===a.down||(a=f,d.emit(f))},releaseAll(){for(let[f,l]of n)l.size!==0&&(l.clear(),i(f,!1));for(let f of[...s.keys()])this.moveStick(f,0,0);this.movePointer(null)},releaseFrom(f){for(let[l,b]of n)if(b.size!==0){for(let v of[...b])f(v)&&b.delete(v);b.size===0&&i(l,!1)}},pressed(f){return(n.get(f)?.size??0)>0},stick(f){let l=s.get(f);if(l!==void 0)return l;for(let[b,v]of s)if(Le(f,b)&&(v.x!==0||v.y!==0))return v;return cn},get pointer(){return a},read(){let f=o,l=r;o=new Set,r=new Set;let b=new Set;for(let[I,O]of n)O.size>0&&b.add(I);let v=new Map(s),P=a===null?null:{...a};return Object.freeze({pressed:I=>b.has(I),started:I=>f.has(I),ended:I=>l.has(I),stick(I){let O=v.get(I);if(O!==void 0)return O;for(let[A,y]of v)if(Le(I,A)&&(y.x!==0||y.y!==0))return y;return cn},pointer:P})},onAction(f,l){return c(p,f).on(l)},onStick(f,l){return c(u,f).on(l)},onPointer(f){return d.on(f)},get watchingPointer(){return d.size>0},dispose(){p.clear(),u.clear(),d.clear(),n.clear(),s.clear(),a=null}}}var _e=.15;function pn(e){let t=e.scope,n={},o={},r=un({onError:e.onError}),s=Object.freeze({}),a={},p="keyboard",u="keyboard",d=!1,c="floating",i=!1,m=!1,f={scheme:u},l=null,b=!1,v=null,P=R(e.onError),I=!1,O=new Set;function A(S,g){let M=S==="action"?g in n||g in a:g in o;!I||M||O.has(`${S}:${g}`)||(O.add(`${S}:${g}`),e.onError(new Error(`input: the manifest declares no ${S} "${g}".`)))}function y(){if(t===null)return null;let S=t[me];return ye(S)?S:null}function k(S,g){let M=y();if(M===null)return g;try{let N=S(M);return N===void 0?g:N}catch(N){return e.onError(N),g}}function w(){let S=k(g=>g.deadzone,_e);return typeof S=="number"&&S>=0&&S<1?S:_e}function E(){let S={},g=!1;for(let[D,G]of Object.entries(n)){let De=a[D],je=De?.bind??G.bind,$e={bind:je},Et=De?.title??G.title;typeof Et=="string"&&($e.title=Et);let It=h(D,je,De);It!==""&&($e.label=It),S[D]=$e,dn(s[D]?.bind,je)||(g=!0)}for(let[D,G]of Object.entries(a))S[D]===void 0&&(S[D]=G,g=!0);for(let D of Object.keys(s))S[D]===void 0&&(g=!0);let M=s;s=Object.freeze(S),r.setMapping(S,{release:g});let N=f,$=N.scheme!==u||!fr(M,s);f={scheme:u},$&&P.emit(Object.freeze({mapping:s,scheme:u}),Object.freeze({mapping:M,scheme:N.scheme}))}function h(S,g,M){if(M?.label!==void 0&&p===u)return M.label;let N=de(g,u),$=N===void 0?"":fe(N,u);if($!=="")return $;let D=n[S]?.label;return typeof D=="string"?D:""}function x(S){S!==u&&(u=S,E())}let T=t===null?null:sn({scope:t,report:{press(S,g,M){let $=v?.zones.flatMap(G=>G.controls).find(G=>G.id===S)?.buttons[g];if($===void 0||(x("touch"),i))return;let D=`${ln}${S}.${g}`;r.pressAction($.action,D,M),$.as!==void 0&&r.press($.as,M,`${D}.as`),k(G=>G.haptic?.(M?"press":"release"),void 0)},move(S,g,M){let N=v?.zones.flatMap($=>$.controls).find($=>$.id===S);N!==void 0&&(x("touch"),!i&&(N.axis==="x"?r.moveStick(N.stick,g,0):N.axis==="y"?r.moveStick(N.stick,0,M):r.moveStick(N.stick,g,M)))}},shim:y,onError:e.onError}),j=t===null?null:an({scope:t,store:r,onScheme:x,isBound:C,suspended:()=>i,deadzone:w,fromControls:S=>T?.owns(S)??!1,onError:e.onError});function C(S){for(let g of Object.values(s))if(g.bind.some(M=>Me(M,S)))return!0;return!1}function U(){j?.watchPointer(m||r.watchingPointer)}function X(){let S=Object.keys(o);return S.length===1?S[0]:null}function F(){let S=e.frame(),g=e.insets(),M=l,N=M===null?void 0:o[M];if(!(T!==null&&M!==null&&N!==void 0&&d&&k(D=>D.decide?.({layout:M,frame:S,insets:g,contract:he}),!0)!==!1)||T===null||M===null||N===void 0){kt();return}if(v=on(M,N,n,S,g,c),T.render(v),!T.fits(S,g)){kt();return}b=!0,e.setDrawn(T.rects())}function kt(){!b&&v===null||(T?.clear(),v=null,b=!1,e.setDrawn([]))}function Ne(){r.releaseFrom(S=>S.startsWith(ln));for(let S of v?.zones??[])for(let g of S.controls)g.type==="thumbstick"&&r.moveStick(g.stick,0,0)}let On={show(S){let g=S??X();g!==null&&(A("layout",g),g!==l&&Ne(),l=g,F())},hide(){l!==null&&(Ne(),l=null,F())},get showing(){return b},get asked(){return l},get available(){return d}},Tn={onAction(S,g){return A("action",S),r.onAction(S,g)},onStick:(S,g)=>r.onStick(S,g),onPointer(S){let g=r.onPointer(S);return U(),()=>{g(),U()}},get mapping(){return s},on:P.on,get scheme(){return u},controls:On,get poll(){return m},set poll(S){m=S,U()},read(){let S=r.read();return Object.freeze({pressed:g=>(A("action",g),S.pressed(g)),started:g=>(A("action",g),S.started(g)),ended:g=>(A("action",g),S.ended(g)),stick:g=>S.stick(g),pointer:S.pointer})},suspend(){i||(i=!0,r.releaseAll())},resume(){i=!1},get suspended(){return i}};return E(),j?.attach(),{input:Tn,adopt(S){let g=Ze(S);g!==null&&(I=!0,n=g.actions,o=g.layouts,a=g.mapping,p=g.scheme,u=g.scheme,d=g.controls,c=g.sticks,E(),F())},onChange(S){let g=Ye(S);if(g===null)return;a=g.mapping,p=g.scheme,u=g.scheme;let M={available:d,sticks:c};d=g.controls,c=g.sticks,E(),M.sticks!==c&&Ne(),(M.available!==d||M.sticks!==c)&&F()},relayout(){F()},release:()=>r.releaseAll(),dispose(){j?.detach(),T?.dispose(),r.dispose(),P.clear()}}}var ln="controls.";function dn(e,t){return e===void 0?!1:e.length===t.length&&e.every((n,o)=>n===t[o])}function fr(e,t){let n=Object.keys(e);return n.length!==Object.keys(t).length?!1:n.every(o=>{let r=e[o],s=t[o];return r===void 0||s===void 0?!1:r.title===s.title&&r.label===s.label&&dn(r.bind,s.bind)})}var mr={top:0,right:0,bottom:0,left:0},yr=["top","right","bottom","left"],bt={width:0,height:0};function fn(e){let t=bt,n=[],o=[],r=[],s=null,a=R(e.onError);function p(){return s??(s=ge(r,t)),s}function u(){return{frame:t,obstructions:r,insets:p()}}function d(){if(e.root===null)return;let m=p();for(let f of yr)e.root.style.setProperty(`--hopple-inset-${f}`,`${m[f]}px`)}function c(m){let f=u(),l=Sr(m);t=l.frame,n=l.obstructions,i(f)}function i(m){if(r=o.length===0?n:[...n,...o],s=null,d(),m.frame.width===t.width&&m.frame.height===t.height&&br(m.obstructions,r))return;let f=u();a.emit(f,m)}return{adopt:c,onChange:c,setDrawn(m){let f=u();o=m.map(l=>({rect:l,kind:"controls",reserved:!0})),i(f)},dispose(){a.clear()},layout:{get frame(){return t},get insets(){return p()},get obstructions(){return r},on:a.on}}}function ge(e,t,n={}){let o={...mr};if(t.width<=0||t.height<=0)return o;let r=n.only==="strips";for(let s of e){if(!s.reserved)continue;let a=gr(s.rect,t);if(a===null||r&&!hr(a,t))continue;let p=[["top",a.y+a.height,t.width],["bottom",t.height-a.y,t.width],["left",a.x+a.width,t.height],["right",t.width-a.x,t.height]],u=p[0];for(let d of p)d[1]*d[2]<u[1]*u[2]&&(u=d);o[u[0]]=Math.max(o[u[0]],u[1])}return o}var Ce=1;function hr(e,t){return e.x<=Ce&&e.x+e.width>=t.width-Ce||e.y<=Ce&&e.y+e.height>=t.height-Ce}function gr(e,t){let n=Math.max(0,e.x),o=Math.max(0,e.y),r=Math.min(t.width,e.x+e.width),s=Math.min(t.height,e.y+e.height);return r<=n||s<=o?null:{x:n,y:o,width:r-n,height:s-o}}function br(e,t){return e===t?!0:e.length!==t.length?!1:e.every((n,o)=>{let r=t[o];return r!==void 0&&n.kind===r.kind&&n.reserved===r.reserved&&n.rect.x===r.rect.x&&n.rect.y===r.rect.y&&n.rect.width===r.rect.width&&n.rect.height===r.rect.height})}function Sr(e){let t=e;if(typeof t!="object"||t===null)return{frame:bt,obstructions:[]};let n=Ar(t.frame)?t.frame:bt;if(!Array.isArray(t.obstructions))return{frame:n,obstructions:[]};let o=[];for(let r of t.obstructions){if(typeof r!="object"||r===null)continue;let{rect:s,kind:a,reserved:p}=r;!vr(s)||typeof p!="boolean"||o.push({rect:s,reserved:p,kind:a??"chrome"})}return{frame:n,obstructions:o}}function vr(e){if(typeof e!="object"||e===null)return!1;let t=e;return te(t.x)&&te(t.y)&&te(t.width)&&te(t.height)}function Ar(e){if(typeof e!="object"||e===null)return!1;let t=e;return te(t.width)&&te(t.height)}function te(e){return typeof e=="number"&&Number.isFinite(e)}function mn(e){let t="loading",n=!1,o=R(e.onError);async function r(s){let a=t;t=s,await o.settle(s,a)}return{async onDispose(){return t!=="disposed"&&await r("disposed"),{}},lifecycle:{get phase(){return t},ready(){t!=="loading"||n||(n=!0,W(()=>e.peer().call("lifecycle.ready",{}),s=>{n=!1,e.onError(s)},()=>{t==="loading"&&r("ready")}))},on:o.on}}}var St=.1;function yn(e){let t=!0,n=!1,o=!1,r=R(e.onError),s=new Set;function a(){return t&&!o}function p(i){i.stopped||i.handle!==0||!a()||(i.last=void 0,i.handle=e.frames.request(m=>d(i,m)))}function u(i){i.handle!==0&&(e.frames.cancel(i.handle),i.handle=0)}function d(i,m){i.handle=0;let f=i.last===void 0?0:Math.min(Math.max(m-i.last,0)/1e3,St);i.last=m;try{i.frame(f,m)}catch(l){e.onError(l)}i.handle===0&&!i.stopped&&a()&&(i.handle=e.frames.request(l=>d(i,l)))}function c(){for(let i of s)a()?p(i):u(i)}return{adopt(i){n||(t=i),c()},async onAllow(i){return n=!0,i.allowed!==t&&(t=i.allowed,c(),await r.settle(t)),{allowed:t}},dispose(){o=!0;for(let i of s)i.stopped=!0,u(i);s.clear()},loop:{get allowed(){return t},on:r.on,tick(i){let m={frame:i,handle:0,last:void 0,stopped:!1};return s.add(m),p(m),()=>{m.stopped=!0,u(m),s.delete(m)}}}}}var wr=Object.freeze({isOpen:!1,page:null});function gn(e){let t=[],n=wr,o=R(e.onError),r={get available(){return t.length>0},get pages(){return t},get isOpen(){return n.isOpen},get page(){return n.page},on:o.on,open(a){W(()=>e.peer().call("panel.open",{id:a}),e.onError)}};function s(a){if(a.isOpen===n.isOpen&&a.page===n.page)return;let p=n;n=Object.freeze({isOpen:a.isOpen,page:a.page}),o.emit(n,p)}return{panel:r,adopt(a){let p=et(a);t=(p?.ids??[]).filter(bn),n=Object.freeze({isOpen:p?.isOpen===!0,page:hn(p?.page)})},onChange(a){let p=tt(a);p!==null&&s({isOpen:p.isOpen,page:hn(p.page)})},dispose(){o.clear()}}}function bn(e){return ae.includes(e)}function hn(e){return typeof e=="string"&&bn(e)?e:null}function Sn(e){let t=ce,n=R(e.onError);async function o(s){await n.settle(s)}return{pause:{get state(){return t},set(s){s!==t&&(t=s,e.peer().emit("pause.change",{state:t}))},on:n.on},async onSet(s){let a=rt(s);return a!==null&&await o(a.paused),{state:t}}}}function vn(e){let t=!0,n=!1,o=R(e.onError);return{adopt(r){n||(t=r)},async onAllow(r){return n=!0,r.allowed!==t&&(t=r.allowed,await o.settle(t)),{allowed:t}},resources:{get allowed(){return t},on:o.on}}}var xr=1,kr=[{what:"a Map",is:e=>e instanceof Map,becomes:"{}"},{what:"a Set",is:e=>e instanceof Set,becomes:"{}"},{what:"a Date",is:e=>e instanceof Date,becomes:"a string"},{what:"a typed array",is:e=>ArrayBuffer.isView(e),becomes:"an object keyed by index"},{what:"a function",is:e=>typeof e=="function",becomes:"nothing at all"},{what:"undefined",is:e=>e===void 0,becomes:"nothing at all"}],Er=6;function An(e){let t=65536,n=!1,o=Ir,r=!1,s=R(e.onError);function a(i){let m=o;m.known&&Pr(m.stored,i)||(o=Object.freeze({known:!0,stored:i===null?null:Object.freeze({...i})}),s.emit(o,m))}let p;function u(i,m){if(r=m==="dev",typeof i!="object"||i===null)return;n=!0;let f=i;typeof f.bytes=="number"&&Number.isFinite(f.bytes)&&(t=Math.max(65536,f.bytes));let l=f.stored===null?null:Ie(f.stored);(f.stored===null||l!==null)&&(o=Object.freeze({known:!0,stored:l===null?null:Object.freeze(l)}))}function d(i){if(typeof i=="string")return[i,"text"];let m;try{m=JSON.stringify(i)}catch(f){throw new L({code:"bad_params",message:`That state cannot be saved: ${f instanceof Error?f.message:String(f)}`})}if(m===void 0)throw new L({code:"bad_params",message:"That state cannot be saved: it is not a JSON value."});return[m,"json"]}function c(i){for(let m of vt(i,Er,new Set))e.onError(new Error(`save: ${m.at} is ${m.what}, which JSON turns into ${m.becomes}.`))}return{adopt:u,save:{get available(){return n},get status(){return o},on:s.on,get maxBytes(){return t},async read(){let i=await e.peer().call("save.read",{}),m=st(i?.record);if(m===null)return a(null),null;if(p=m.rev,a(Ie(i?.stored)??{at:o.known&&o.stored!==null?o.stored.at:Date.now(),version:m.version,bytes:Ee(m.state)}),m.encoding==="text")return{version:m.version,state:m.state};try{return{version:m.version,state:JSON.parse(m.state)}}catch(f){return e.onError(new Error(`save: the stored state could not be parsed (${f instanceof Error?f.message:String(f)}).`)),null}},async write(i,m){let[f,l]=d(i);r&&c(i);let b=Ee(f);if(b>t)throw new L({code:"too_large",message:`That save is ${b} bytes and this host takes ${t}.`});let v={version:m?.version??xr,encoding:l,state:f};p!==void 0&&(v.rev=p);let I=(await e.peer().call("save.write",v))?.rev;p=typeof I=="string"?I:void 0,a({at:Date.now(),version:v.version,bytes:b})},async clear(){await e.peer().call("save.clear",{}),p=void 0,a(null)}}}}var Ir=Object.freeze({known:!1});function Pr(e,t){return e===null||t===null?e===t:e.at===t.at&&e.version===t.version&&e.bytes===t.bytes}function vt(e,t,n,o="the state"){for(let s of kr)if(s.is(e))return[{at:o,what:s.what,becomes:s.becomes}];if(t<=0||typeof e!="object"||e===null)return[];if(n.has(e))return[];n.add(e);let r=[];if(Array.isArray(e))return e.forEach((s,a)=>{r.push(...vt(s,t-1,n,`${o}[${a}]`))}),r;for(let[s,a]of Object.entries(e))r.push(...vt(a,t-1,n,`${o}.${s}`));return r}function xn(e){let t=!1,n=[],o,r=kn,s=R(e.onError);function a(d){o=d;let c=r;r=wn(n,o),Mr(c,r)||s.emit(r,c)}function p(d){return d!==void 0?d:n.length===1?n[0]:""}return{score:{get available(){return t},get boards(){return n},get standing(){return r},on:s.on,async submit(d,c){if(!ue(d))throw new L({code:"bad_params",message:"A score must be a finite number that a board can hold."});let i=c?.board,m=await e.peer().call("score.submit",i===void 0?{value:d}:{board:i,value:d}),f=ut(m)??{improved:!1,best:d},l=p(i);if(l!==""&&o!==void 0){let b=o??{},v=b[l];a({...b,[l]:{best:f.best,at:f.improved||v===void 0?Date.now():v.at,runs:(v?.runs??0)+1,...f.rank===void 0?{}:{rank:f.rank},...f.of===void 0?{}:{of:f.of}}})}return f}},adopt(d){let c=Pe(d);t=c!==null,n=c?.boards??[],o=c?.standing,r=wn(n,o)},onChange(d){let c=ct(d);c!==null&&a(c.standing)}}}var kn=Object.freeze({known:!1});function wn(e,t){if(t===void 0)return kn;let n={};for(let o of e)n[o]=t?.[o]??null;for(let[o,r]of Object.entries(t??{}))n[o]=r;return Object.freeze({known:!0,boards:Object.freeze(n)})}function Mr(e,t){if(!e.known||!t.known)return e.known===t.known;let n=Object.keys(e.boards);return n.length!==Object.keys(t.boards).length?!1:n.every(o=>{let r=e.boards[o],s=t.boards[o];return r==null||s===null||s===void 0?r===s:r.best===s.best&&r.at===s.at&&r.runs===s.runs&&r.rank===s.rank&&r.of===s.of})}function En(e){let t=null,n=!1;return{share:{get available(){return n},get data(){return t},offer(r){let s=r?.data,a=r?.meta;if(s!==void 0&&typeof s!="string"){e.onError(new L({code:"bad_params",message:"Share data must be a string: encode it however this game reads it back."}));return}if(a!==void 0&&ft(a)===null){e.onError(new L({code:"bad_params",message:"Share meta must be an object JSON can carry."}));return}W(()=>e.peer().call("share.offer",{...s===void 0?{}:{data:s},...a===void 0?{}:{meta:a}}),e.onError)}},adopt(r){let s=dt(r);t=s?.data??null,n=s?.offers===!0}}}function be(e){if(typeof e!="object"||e===null)return!1;let t=e;return t.v!==1?!1:typeof t.send=="function"&&typeof t.receive=="function"}function Oe(e){let t=e[V];return be(t)?t:null}function Se(e){let t=null;return{send(n){e.send(JSON.stringify(n))},receive(n){return t=e.receive(o=>{let r;try{r=JSON.parse(o)}catch{return}se(r)&&n(r)}),()=>{t?.(),t=null}},close(){}}}var At=2e3;function Te(e={}){let t=e.scope??window,n=t,o=e.onError??(a=>console.error(a)),r=Oe(t);if(r)return Promise.resolve(Se(r));if(t.parent!==t)return Promise.resolve(Lr(t,t.parent));let s=e.shimWaitMs??At;return new Promise((a,p)=>{let u=!1,d=m=>{if(!be(m)){o(new Error(`${z} was called with something that is not a v1 shim.`));return}if(u){o(new Error(`${z} was called twice; this game already has a channel.`));return}u=!0,clearTimeout(c),i(),a(Se(m))},c=setTimeout(()=>{i(),p(new Error(`No host: there is no ${V} on the global and no parent frame to talk to. A Hopple game runs inside a Hopple host rather than on its own: while developing, run it with \`npx hopple dev\`. A native shell installs a shim before the game's bundle runs, or calls ${z} afterwards; neither happened within ${s}ms.`))},s);n[z]=d;function i(){n[z]===d&&delete n[z]}})}function Lr(e,t){return{send(n){t.postMessage(n,"*")},receive(n){let o=r=>{r.source===t&&se(r.data)&&n(r.data)};return e.addEventListener("message",o),()=>e.removeEventListener("message",o)},close(){}}}async function Pn(e={}){let t=e.onError??(C=>console.error(C)),n=en(Cr(e.scope)),o=C=>{n.report("sdk",C),t(C)},r;try{r=e.transport??await Te({scope:e.scope,shimWaitMs:e.shimWaitMs,onError:o})}catch(C){throw n.dispose(),C}let s=Dr(e.scope),a=()=>E,{lifecycle:p,onDispose:u}=mn({peer:a,onError:o}),d=yn({frames:Or(s),onError:o}),c=vn({onError:o}),i=fn({root:s?.document.documentElement??null,onError:o}),m=Yt({peer:a,onError:o,onRefused:t}),f=An({peer:a,onError:o}),l=xn({peer:a,onError:o}),b=Zt({peer:a,onError:o}),v=En({peer:a,onError:o}),P=Qt({scope:s,onError:o}),I=gn({peer:a,onError:o}),O=Sn({peer:a,onError:o}),A=()=>ge(i.layout.obstructions.filter(C=>C.kind!=="controls"),i.layout.frame),y=pn({scope:s,frame:()=>i.layout.frame,insets:A,setDrawn:i.setDrawn,onError:o}),k={frame:i.layout.frame,insets:A()};i.layout.on(()=>{let C={frame:i.layout.frame,insets:A()};C.frame.width===k.frame.width&&C.frame.height===k.frame.height&&Nr.every(U=>C.insets[U]===k.insets[U])||(k=C,y.relayout())});let w=mt({transport:r,handlers:{"system.ping":C=>({nonce:C.nonce}),"audio.allow":P.onAllow,"loop.allow":d.onAllow,"resources.allow":c.onAllow,"lifecycle.dispose":()=>(d.dispose(),u()),"audio.set":P.onSet,"pause.set":O.onSet},timeoutMs:e.timeoutMs,onError:o}),E=Kt(w),h=Math.max(e.timeoutMs??In,In),x;try{x=await w.call("system.hello",{protocol:1,sdk:qt.version},{timeoutMs:h})}catch(C){throw w.dispose(),n.dispose(),Tr(C,h)}w.useSession(x.peer),n.connect(w);let _=Ve(x.allowed);d.adopt(_.loop),c.adopt(_.resources),i.adopt(x.layout),w.on("layout.change",i.onChange),w.on("analytics.refused",m.refused),w.on("input.change",y.onChange),w.on("panel.change",I.onChange),w.on("achievement.change",b.onChange),w.on("score.change",l.onChange),d.loop.on(C=>{C||y.release()});let T=nn(x.info);return f.adopt(x.save,T.app.surface),l.adopt(x.score),b.adopt(x.achievements),v.adopt(x.share),P.adopt(x.audio,_.audio),I.adopt(x.panel),y.adopt(x.input),await _r(s,()=>i.layout.frame,o),{lifecycle:p,loop:d.loop,resources:c.resources,layout:i.layout,info:T,analytics:m.analytics,save:f.save,score:l.score,achievements:b.achievements,share:v.share,panel:I.panel,pause:O.pause,input:y.input,audio:P.audio,ping:()=>jr(w),dispose:()=>{d.dispose(),I.dispose(),y.dispose(),P.dispose(),i.dispose(),n.dispose(),w.dispose()}}}var Rr=1e3;async function _r(e,t,n){if(e===null)return;let o=()=>{let{width:r,height:s}=t();return r<=0||s<=0?!0:Math.abs(e.innerWidth-r)<=1&&Math.abs(e.innerHeight-s)<=1};o()||await new Promise(r=>{let s=()=>{o()&&p()},a=setTimeout(()=>{let{width:u,height:d}=t();n(new Error(`layout: the host says the frame is ${u}\xD7${d} but the window is ${e.innerWidth}\xD7${e.innerHeight}.`)),p()},Rr);function p(){clearTimeout(a),e?.removeEventListener("resize",s),r()}e.addEventListener("resize",s)})}function Cr(e){let t=e??(typeof window>"u"?void 0:window);return t===void 0?null:typeof t.addEventListener=="function"?t:null}function Or(e){let t=e??(typeof requestAnimationFrame=="function"?globalThis:null);return t!==null&&typeof t.requestAnimationFrame=="function"?{request:n=>t.requestAnimationFrame(n),cancel:n=>t.cancelAnimationFrame(n)}:{request:n=>setTimeout(()=>n(performance.now()),16),cancel:n=>clearTimeout(n)}}var In=1e4;function Tr(e,t){return!(e instanceof L)||e.code!=="timeout"?e:new L({code:"timeout",message:`No host answered: nothing replied to this game's hello within ${t}ms. A Hopple game runs inside a Hopple host, and whatever is holding this page is not one, or has stopped answering. While developing, run the game with \`npx hopple dev\`.`})}var Nr=["top","right","bottom","left"];function Dr(e){let t=e??(typeof window>"u"?void 0:window);if(t===void 0)return null;let n=t;return typeof n.addEventListener=="function"&&n.document!=null?t:null}async function jr(e){let t=$r(),n=performance.now(),o=await e.call("system.ping",{nonce:t}),r=performance.now()-n;if(o.nonce!==t)throw new Error(`The host answered a different ping: sent ${t}, got ${o.nonce}.`);return r}function $r(){return Math.random().toString(36).slice(2,10)}var Mn={type:"object",properties:{schema:{type:"number",const:1},id:{type:"string",pattern:"^[a-z0-9]+(?:-[a-z0-9]+)*$",maxLength:64,errorMessage:"must be lowercase letters, digits and hyphens"},owner:{type:"string",pattern:"^[a-z0-9]+(?:-[a-z0-9]+)*$",maxLength:64,errorMessage:"must be a handle: lowercase letters, digits and hyphens"},version:{type:"string",pattern:"^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$",errorMessage:"must look like 1.0.0"},title:{type:"string",pattern:"\\S",maxLength:60,errorMessage:"must not be blank"},description:{type:"string",pattern:"\\S",maxLength:500,errorMessage:"must not be blank"},cover:{type:"string",pattern:"^(?!/)(?!.*\\.\\.)[A-Za-z0-9._/-]+\\.(?:png|jpe?g|webp)$",maxLength:200,errorMessage:'must be the path of a .png, .jpg or .webp file beside the config, like "cover.png"'},orientation:{$ref:"#/definitions/Orientation"},sdk:{type:"string",pattern:"^[\\^~]?\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$",errorMessage:"must be a version like 1.0.0, ^1.0.0 or ~1.0.0"},layout:{$ref:"#/definitions/LayoutDeclaration"},analytics:{$ref:"#/definitions/AnalyticsDeclaration"},save:{$ref:"#/definitions/SaveDeclaration"},score:{$ref:"#/definitions/ScoreDeclaration"},achievements:{$ref:"#/definitions/AchievementDeclaration"},input:{$ref:"#/definitions/InputDeclaration"},audio:{anyOf:[{$ref:"#/definitions/AudioDeclaration"},{type:"null"}]}},required:["schema","id","version","title","orientation","sdk","audio"],additionalProperties:{}};var Ln={type:"object",properties:{target:{type:"number",minimum:-9007199254740991,maximum:9007199254740991},direction:{$ref:"#/definitions/ScoreDirection"},format:{$ref:"#/definitions/ScoreFormat"},tiers:{type:"array",items:{$ref:"#/definitions/AchievementTier"},maxItems:8}},required:["target"],additionalProperties:{}};var Rn={type:"string",pattern:"^(?:key\\.(?!Escape$)(?=.{1,48}$)[A-Za-z][A-Za-z0-9]*|pointer\\.(?:primary|secondary)|mouse\\.(?:left|middle|right)|touch\\.tap|controls\\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\\.(?:north|south|east|west|start|select)|pad\\.(?:left|right)\\.(?:north|south|east|west|bumper|trigger))$",errorMessage:"is not a binding this SDK knows (a thumbstick is read rather than bound, and Escape is the host's key)"},_n={type:"object",properties:{left:{$ref:"#/definitions/ControlZoneSlots"},right:{$ref:"#/definitions/ControlZoneSlots"},full:{$ref:"#/definitions/ControlZoneSlots"}},additionalProperties:{}};var Cn={type:"string",pattern:"^(?:controls\\.(?=.{1,48}$)[a-z0-9]+(?:[_-][a-z0-9]+)*|pad\\.stick|pad\\.(?:left|right)\\.stick)$",errorMessage:"must name a thumbstick, such as pad.left.stick"};var wt="game.manifest.json",zr=1024*1024;var xt=1,Gr=Number.MAX_SAFE_INTEGER;var Br=Ln.properties.target.maximum;var Hr=Mn.required,Wr=Object.keys(_n.properties),xi=new RegExp(Rn.pattern),ki=new RegExp(Cn.pattern);return Gn(Fr);})();
|
|
155
|
+
/*! @hopple/sdk | Copyright (c) 2026 The Hopple authors | MIT License */
|