handler-playable-sdk 0.2.5 → 0.3.1

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.
@@ -0,0 +1,17 @@
1
+ var u={};function I(e,t,n=!1){u[e]||(u[e]=[]),u[e].push({fn:t,once:n})}function V(e,t){if(u[e]){if(!t){delete u[e];return}u[e]=u[e].filter(n=>n.fn!==t)}}function P(e,...t){let n=u[e];if(n)for(let i of[...n])i.fn(...t),i.once&&V(e,i.fn)}function a(e,t){I(e,t,!0)}var R={name:"handler-playable-sdk",version:"0.3.1",description:"Handler Playable SDK v0.1 with contract-aligned surface (root sandbox, canonical event envelope).",main:"dist/index.js",module:"dist/index.mjs",types:"dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.mjs",require:"./dist/index.js"},"./pixi":{types:"./dist/pixi/index.d.ts",import:"./dist/pixi/index.mjs",require:"./dist/pixi/index.js"},"./three":{types:"./dist/three/index.d.ts",import:"./dist/three/index.mjs",require:"./dist/three/index.js"}},scripts:{build:"tsup src/index.ts src/pixi/index.ts src/three/index.ts --format cjs,esm --dts --clean --minify --external lottie-web && npm run obfuscate","build:dev":"tsup src/index.ts src/pixi/index.ts src/three/index.ts --format cjs,esm --dts --clean --external lottie-web",obfuscate:"javascript-obfuscator dist/index.js dist/index.mjs dist/pixi/index.js dist/pixi/index.mjs dist/three/index.js dist/three/index.mjs --output dist --options-preset high-obfuscation --compact true --self-defending true",lint:"eslint 'src/**/*.{ts,tsx}'",typecheck:"tsc --noEmit",prepublishOnly:"npm run build","publish:update":"node scripts/publish-and-update.js patch","publish:update:minor":"node scripts/publish-and-update.js minor","publish:update:major":"node scripts/publish-and-update.js major"},author:"Handler",license:"MIT",publishConfig:{access:"public"},repository:{type:"git",url:"https://github.com/HandlerAIGames/handler-playable-sdk.git"},files:["dist","LICENSE","README.md"],peerDependencies:{"lottie-web":"^5.0.0","pixi.js":"^8.0.0",three:"^0.160.0"},peerDependenciesMeta:{"pixi.js":{optional:!0},three:{optional:!0},"lottie-web":{optional:!0}},devDependencies:{"@types/three":"^0.160.0",eslint:"^8.57.1","javascript-obfuscator":"^5.1.0","pixi.js":"8.8.1",three:"^0.160.0","ts-node":"^10.9.2",tsup:"^8.4.0",typescript:"^5.7.2"}};var s=0,Se=s++,Z=s++,ee=s++,te=s++,ne=s++,ie=s++,oe=s++,re=s++,ae=s++,se=s++,de=s++,le=s++,r=Se;function ce(){return r===Z}function ue(){return r===ee}function pe(){return r===te}function fe(){return r===ne}function g(){return r===ie}function y(){return r===oe}function me(){return r===re}function ge(){return r===ae}function ye(){return r===se}function H(){return r===de}function F(){return r===le}function we(){let e=typeof AD_PROTOCOL!="undefined"?AD_PROTOCOL:"none",t=typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed";if(e==="mraid")try{mraid.getState(),r=Z;return}catch{}else if(e==="dapi")try{dapi.isReady(),r=ee;return}catch{}if(t==="facebook")try{typeof FbPlayableAd!="undefined"&&(r=te)}catch{}else if(t==="google")try{typeof ExitApi!="undefined"&&(r=ne)}catch{}else if(t==="mintegral")window.gameReady&&(r=ie);else if(t==="tapjoy")window.TJ_API&&(r=oe);else if(t==="tiktok")window.openAppStore&&(r=re);else if(t==="smadex")try{window.smxTracking&&(r=ae)}catch{}else if(t==="snapchat")try{window.ScPlayableAd&&(r=se)}catch{}else t==="vungle"?r=de:(e==="nucleo"||t==="nucleo")&&(r=le)}var Ee={mechanic_id:"TODO_mechanic_id",variant_id:"TODO_variant_id",deployment_id:"TODO_deployment_id",export_id:"TODO_export_id",profile_id:"TODO_profile_id",instance_id:"default"},Ce=Math.random().toString(36).slice(2),w=null,A={...Ee},Ae="web_embed",De={},G=!1,E=!1,T=!1,ke=!1,B=1,W=0,z=!1,d=!1,N="",h=Math.floor(window.innerWidth),b=Math.floor(window.innerHeight),K=h>b,l=!1,k=!1,he=!1,be=!1,U=!1,j=null;function xe(){if(w)return w;let e=document.createElement("div");return e.id="handler-root",e.setAttribute("data-handler-root","true"),document.body.appendChild(e),w=e,e}function M(e){switch(e){case"interaction":return"engagement";case"finish":return"complete";case"install":return"cta_click";default:return e}}function Te(e,t){return{event_name:e,ts:Date.now(),session_id:Ce,deployment_id:A.deployment_id,variant_id:A.variant_id,export_profile_id:A.profile_id,instance_id:A.instance_id||"default",env:Ae==="mraid"?"mraid":"web",payload:t}}function o(e,t){let n=M(e),i=Te(n,t);P(n,i),n!==e&&P(e,i)}function O(){j&&(j(h,b),j=null)}function x(e){B=e,o("volume",e)}function _(e){e&&(ke=!0),!T&&(T=!0,o("pause"),x(0))}function S(e){!e&&ke||T&&(T=!1,o("resume"),x(B))}function f(e,t){h=Math.floor(e||window.innerWidth),b=Math.floor(t||window.innerHeight),K=h>b,o("resize",{width:h,height:b})}function Le(){if(ce())try{let e=mraid.getMaxSize();f(e.width,e.height);let t=()=>{mraid.isViewable()&&mraid.getState()!=="hidden"?S():_()};if(mraid.addEventListener("viewableChange",t),mraid.addEventListener("stateChange",t),mraid.addEventListener("sizeChange",()=>{let n=mraid.getMaxSize();f(n.width,n.height)}),mraid.getAudioVolume){let n=mraid.getAudioVolume();x(n?1:0)}if(mraid.addEventListener("audioVolumeChange",n=>{n!==null&&x(n>0?1:0)}),mraid.addEventListener("error",(n,i)=>{console.warn("mraid error:",n,"action:",i)}),z=!0,mraid.isViewable()&&mraid.getState()!=="hidden")l=!0,o("boot"),o("view"),o("ready"),d=!0,O();else{let n=()=>{l=!0,o("boot"),o("view"),o("ready"),d=!0,O()};mraid.addEventListener("ready",n)}}catch(e){console.warn("MRAID hook skipped",e)}}function Ie(){if(ue())try{let e=dapi.getScreenSize();f(e.width,e.height),dapi.addEventListener("viewableChange",n=>{n.isViewable?S():_()}),dapi.addEventListener("adResized",n=>{let i=dapi.getScreenSize();f(n.width||i.width,n.height||i.height)});let t=dapi.getAudioVolume();if(x(t?1:0),dapi.addEventListener("audioVolumeChange",n=>x(n?1:0)),z=!0,dapi.isViewable())l=!0,o("boot"),o("view"),o("ready"),d=!0,O();else{let n=()=>{l=!0,o("boot"),o("view"),o("ready"),d=!0,O()};dapi.addEventListener("ready",n)}}catch(e){console.warn("DAPI hook skipped",e)}}function _e(){let e=()=>{l||document.visibilityState==="visible"&&(document.readyState==="complete"||document.readyState==="interactive")&&(l=!0,o("boot"),o("view"),o("ready"),d=!0,O(),k&&(k=!1,p.start()))};window.addEventListener("resize",()=>f()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"?(S(),e()):_()}),document.readyState==="complete"||document.readyState==="interactive"?e():window.addEventListener("load",e),z=!0}function Pe(){let e=t=>{typeof TouchEvent!="undefined"&&t instanceof TouchEvent&&(he=!0),!(he&&t instanceof MouseEvent)&&(W+=1,o("interaction",W))};document.addEventListener("mousedown",e),document.addEventListener("touchstart",e)}function Re(e){var i,c,v,C,J,D,q,L,$,X,Y,Q;let t=typeof AD_PROTOCOL!="undefined"?AD_PROTOCOL:"none";if((typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed")==="google")try{(i=window.ExitApi)==null||i.exit();return}catch{}if(t==="mraid"&&typeof mraid!="undefined")mraid.open(e||"");else if(t==="dapi"&&typeof dapi!="undefined")dapi.openStoreUrl();else if(y())(v=(c=window.TJ_API)==null?void 0:c.click)==null||v.call(c);else if(pe())(J=(C=window.FbPlayableAd)==null?void 0:C.onCTAClick)==null||J.call(C);else if(ye())(q=(D=window.ScPlayableAd)==null?void 0:D.onCTAClick)==null||q.call(D);else if(ge())try{($=(L=window.smxTracking)==null?void 0:L.redirect)==null||$.call(L)}catch(m){console.warn("Smadex redirect failed",m)}else if(fe()){let m=window.ExitApi;m&&typeof m.exit=="function"?m.exit(e||N||""):e&&window.open(e)}else g()?(X=window.install)==null||X.call(window):me()?(Y=window.openAppStore)==null||Y.call(window):H()?(Q=parent==null?void 0:parent.postMessage)==null||Q.call(parent,"download","*"):e&&window.open(e)}function je(){let e=typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed",t=n=>{if(!n)return;let i=new Image;i.src=n};if(e==="bigabid"){let n=window.BIGABID_BIDTIMEMACROS;if(!n)return;a("view",()=>t(n.mraid_viewable)),a("start",()=>t(n.game_viewable)),a("engagement",()=>t(n.engagement));let i=()=>t(n.complete);a("complete",i),I("engagement",c=>{var v;((v=c==null?void 0:c.payload)==null?void 0:v.count)>3&&i()}),a("cta_click",()=>t(n.click))}else if(e==="inmobi"){let n=window.INMOBI_DSPMACROS;if(!n)return;a("view",()=>t(n.Ad_Load_Start)),a("start",()=>t(n.Ad_Viewable)),a("engagement",()=>t(n.First_Engagement)),a("complete",()=>t(n.Gameplay_Complete)),a("cta_click",()=>t(n.DSP_Click)),a("start",()=>{[5,10,15,20,25,30].forEach(i=>setTimeout(()=>t(n[`Spent_${i}_Seconds`]),i*1e3))})}}function Me(){if(!y())return;let e=window.TJ_API;e&&e.setPlayableAPI&&e.setPlayableAPI({skipAd:()=>{try{p.finish()}catch(t){console.warn("Tapjoy skip failed",t)}}})}function ve(){var t,n,i;let e=window.TJ_API;(t=e==null?void 0:e.objectiveComplete)==null||t.call(e),(n=e==null?void 0:e.playableFinished)==null||n.call(e),(i=e==null?void 0:e.gameplayFinished)==null||i.call(e)}function Ne(){g()&&(window.mintGameStart=()=>{S(!0),f()},window.mintGameClose=()=>{_(!0)})}function ze(){if(!F())return;let e=window.NUC;!e||!e.trigger||(p.on("cta_click",()=>{var t,n;return(n=(t=e.trigger).convert)==null?void 0:n.call(t,N)}),p.on("complete",()=>{var t,n;return(n=(t=e.trigger).tryAgain)==null?void 0:n.call(t)}))}var p={init(e={},t){if(Ae=e.profile||"web_embed",De=e.consent||{},A={...Ee,...e.ids||{}},w=e.rootEl||w,N=e.destinationUrl||(/android/i.test(navigator.userAgent)?"https://play.google.com/store":"https://www.apple.com/app-store/"),t&&(j=t),o("init"),document.body.oncontextmenu=()=>!1,xe(),Ve(w),we(),Le(),Ie(),!z){if(document.readyState==="complete")_e();else if(!be){be=!0;let n=()=>{_e(),window.removeEventListener("load",n),document.removeEventListener("DOMContentLoaded",n)};window.addEventListener("load",n),document.addEventListener("DOMContentLoaded",n)}}Pe(),je(),Me(),Ne(),ze(),console.log(`%c @handler/playable-sdk %c v${R.version||"0.0.0"} `,"background: #007acc; color: #fff; font-size: 14px; padding: 4px 8px; border-top-left-radius: 4px; border-bottom-left-radius: 4px;","background: #e1e4e8; color: #333; font-size: 14px; padding: 4px 8px; border-top-right-radius: 4px; border-bottom-right-radius: 4px;"),l&&!d&&(o("boot"),o("view"),o("ready"),k&&(k=!1,p.start()),d=!0),d=l},getRoot(){return xe()},get version(){return R.version||"0.0.0"},get maxWidth(){return h},get maxHeight(){return b},get isLandscape(){return K},get isReady(){return d},get isStarted(){return G},get isPaused(){return T},get isFinished(){return E},get volume(){return B},get interactions(){return W},on(e,t){I(M(e),t)},off(e,t){V(M(e),t)},start(){var e,t;if(!G){if(!l){k=!0;return}if(G=!0,o("start"),f(),g())_(),(e=window.gameReady)==null||e.call(window);else if(y()){let n=window.TJ_API;(t=n==null?void 0:n.setPlayableBuild)==null||t.call(n,{orientation:K?"landscape":"portrait",buildID:R.version||"dev"})}}},finish(){var e,t;E||(E=!0,o("complete"),g()?(e=window.gameEnd)==null||e.call(window):H()?(t=parent==null?void 0:parent.postMessage)==null||t.call(parent,"complete","*"):y()&&ve())},install(e){if(!E){E=!0,y()?(ve(),setTimeout(()=>p.install(e),300)):(o("complete"),setTimeout(()=>p.install(e),0));return}U||(U=!0,setTimeout(()=>U=!1,500),o("cta_click"),o("conversion"),Re(e||N))},emit(e,t){let n=M(e);if(!["view","boot","start","engagement","complete","cta_click","conversion","retry","pause","resume","resize","volume","error"].includes(n)&&!n.startsWith("custom."))throw new Error(`Event ${e} must be canonical or namespaced as custom.<mechanic_id>.<event>`);let i=Te(n,t);P(n,i)},retry(){var e,t,n;if(g())(e=window.gameRetry)==null||e.call(window);else if(F()){let i=window.NUC;(n=(t=i==null?void 0:i.trigger)==null?void 0:t.tryAgain)==null||n.call(t)}o("engagement",{action:"retry"})},pause(){_(!0)},resume(){S(!0)},resize(e,t){f(e,t)}},Be=p;function Ve(e){let t=document.createElement("script");t.type="text/javascript",t.textContent=`
2
+ (function(){
3
+ var events = ['touchstart','touchend','mousedown','keydown'];
4
+ function unlock(){
5
+ if(window.AudioContext && AudioContext.prototype.resume){
6
+ if(!window.__handler_audio_ctx){
7
+ window.__handler_audio_ctx = new AudioContext();
8
+ }
9
+ if(window.__handler_audio_ctx.state === 'suspended'){
10
+ window.__handler_audio_ctx.resume();
11
+ }
12
+ }
13
+ events.forEach(function(e){ document.removeEventListener(e, unlock); });
14
+ }
15
+ events.forEach(function(e){ document.addEventListener(e, unlock, false); });
16
+ })();
17
+ `,e.appendChild(t)}export{p as a,Be as b};
package/dist/index.js CHANGED
@@ -1,17 +1 @@
1
- "use strict";var V=Object.defineProperty;var Se=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var De=Object.prototype.hasOwnProperty;var Le=(e,t)=>{for(var n in t)V(e,n,{get:t[n],enumerable:!0})},Ie=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of Ce(t))!De.call(e,a)&&a!==n&&V(e,a,{get:()=>t[a],enumerable:!(i=Se(t,a))||i.enumerable});return e};var Pe=e=>Ie(V({},"__esModule",{value:!0}),e);var qe={};Le(qe,{Handler:()=>u,default:()=>Be});module.exports=Pe(qe);var p={};function I(e,t,n=!1){p[e]||(p[e]=[]),p[e].push({fn:t,once:n})}function H(e,t){if(p[e]){if(!t){delete p[e];return}p[e]=p[e].filter(n=>n.fn!==t)}}function P(e,...t){let n=p[e];if(n)for(let i of[...n])i.fn(...t),i.once&&H(e,i.fn)}function s(e,t){I(e,t,!0)}var R={name:"handler-playable-sdk",version:"0.2.5",description:"Handler Playable SDK v0.1 with contract-aligned surface (root sandbox, canonical event envelope).",main:"dist/index.js",module:"dist/index.mjs",types:"dist/index.d.ts",exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.mjs",require:"./dist/index.js"},"./pixi":{types:"./dist/pixi/index.d.ts",import:"./dist/pixi/index.mjs",require:"./dist/pixi/index.js"},"./three":{types:"./dist/three/index.d.ts",import:"./dist/three/index.mjs",require:"./dist/three/index.js"}},scripts:{build:"tsup src/index.ts src/pixi/index.ts src/three/index.ts --format cjs,esm --dts --clean --minify",lint:"eslint 'src/**/*.{ts,tsx}'",typecheck:"tsc --noEmit",prepublishOnly:"npm run build","publish:update":"node scripts/publish-and-update.js patch","publish:update:minor":"node scripts/publish-and-update.js minor","publish:update:major":"node scripts/publish-and-update.js major"},author:"Handler",license:"MIT",publishConfig:{access:"public"},repository:{type:"git",url:"https://github.com/HandlerAIGames/handler-playable-sdk.git"},files:["dist","LICENSE","README.md"],peerDependencies:{"pixi.js":"^8.0.0",three:"^0.160.0"},peerDependenciesMeta:{"pixi.js":{optional:!0},three:{optional:!0}},devDependencies:{"@types/three":"^0.160.0",eslint:"^8.57.1","pixi.js":"^8.8.1",three:"^0.160.0","ts-node":"^10.9.2",tsup:"^8.4.0",typescript:"^5.7.2"}};var d=0,Me=d++,ee=d++,te=d++,ne=d++,ie=d++,oe=d++,re=d++,ae=d++,se=d++,de=d++,le=d++,ce=d++,r=Me;function ue(){return r===ee}function pe(){return r===te}function fe(){return r===ne}function me(){return r===ie}function g(){return r===oe}function y(){return r===re}function ge(){return r===ae}function ye(){return r===se}function we(){return r===de}function F(){return r===le}function G(){return r===ce}function he(){let e=typeof AD_PROTOCOL!="undefined"?AD_PROTOCOL:"none",t=typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed";if(e==="mraid")try{mraid.getState(),r=ee;return}catch{}else if(e==="dapi")try{dapi.isReady(),r=te;return}catch{}if(t==="facebook")try{typeof FbPlayableAd!="undefined"&&(r=ne)}catch{}else if(t==="google")try{typeof ExitApi!="undefined"&&(r=ie)}catch{}else if(t==="mintegral")window.gameReady&&(r=oe);else if(t==="tapjoy")window.TJ_API&&(r=re);else if(t==="tiktok")window.openAppStore&&(r=ae);else if(t==="smadex")try{window.smxTracking&&(r=se)}catch{}else if(t==="snapchat")try{window.ScPlayableAd&&(r=de)}catch{}else t==="vungle"?r=le:(e==="nucleo"||t==="nucleo")&&(r=ce)}var Ae={mechanic_id:"TODO_mechanic_id",variant_id:"TODO_variant_id",deployment_id:"TODO_deployment_id",export_id:"TODO_export_id",profile_id:"TODO_profile_id",instance_id:"default"},je=Math.random().toString(36).slice(2),w=null,A={...Ae},ke="web_embed",Ne={},U=!1,E=!1,T=!1,Te=!1,J=1,K=0,z=!1,l=!1,N="",h=Math.floor(window.innerWidth),b=Math.floor(window.innerHeight),B=h>b,c=!1,k=!1,be=!1,_e=!1,W=!1,M=null;function ve(){if(w)return w;let e=document.createElement("div");return e.id="handler-root",e.setAttribute("data-handler-root","true"),document.body.appendChild(e),w=e,e}function j(e){switch(e){case"interaction":return"engagement";case"finish":return"complete";case"install":return"cta_click";default:return e}}function Oe(e,t){return{event_name:e,ts:Date.now(),session_id:je,deployment_id:A.deployment_id,variant_id:A.variant_id,export_profile_id:A.profile_id,instance_id:A.instance_id||"default",env:ke==="mraid"?"mraid":"web",payload:t}}function o(e,t){let n=j(e),i=Oe(n,t);P(n,i),n!==e&&P(e,i)}function O(){M&&(M(h,b),M=null)}function _(e){J=e,o("volume",e)}function v(e){e&&(Te=!0),!T&&(T=!0,o("pause"),_(0))}function S(e){!e&&Te||T&&(T=!1,o("resume"),_(J))}function f(e,t){h=Math.floor(e||window.innerWidth),b=Math.floor(t||window.innerHeight),B=h>b,o("resize",{width:h,height:b})}function ze(){if(ue())try{let e=mraid.getMaxSize();f(e.width,e.height);let t=()=>{mraid.isViewable()&&mraid.getState()!=="hidden"?S():v()};if(mraid.addEventListener("viewableChange",t),mraid.addEventListener("stateChange",t),mraid.addEventListener("sizeChange",()=>{let n=mraid.getMaxSize();f(n.width,n.height)}),mraid.getAudioVolume){let n=mraid.getAudioVolume();_(n?1:0)}if(mraid.addEventListener("audioVolumeChange",n=>{n!==null&&_(n>0?1:0)}),mraid.addEventListener("error",(n,i)=>{console.warn("mraid error:",n,"action:",i)}),z=!0,mraid.isViewable()&&mraid.getState()!=="hidden")c=!0,o("boot"),o("view"),o("ready"),l=!0,O();else{let n=()=>{c=!0,o("boot"),o("view"),o("ready"),l=!0,O()};mraid.addEventListener("ready",n)}}catch(e){console.warn("MRAID hook skipped",e)}}function Ve(){if(pe())try{let e=dapi.getScreenSize();f(e.width,e.height),dapi.addEventListener("viewableChange",n=>{n.isViewable?S():v()}),dapi.addEventListener("adResized",n=>{let i=dapi.getScreenSize();f(n.width||i.width,n.height||i.height)});let t=dapi.getAudioVolume();if(_(t?1:0),dapi.addEventListener("audioVolumeChange",n=>_(n?1:0)),z=!0,dapi.isViewable())c=!0,o("boot"),o("view"),o("ready"),l=!0,O();else{let n=()=>{c=!0,o("boot"),o("view"),o("ready"),l=!0,O()};dapi.addEventListener("ready",n)}}catch(e){console.warn("DAPI hook skipped",e)}}function xe(){let e=()=>{c||document.visibilityState==="visible"&&(document.readyState==="complete"||document.readyState==="interactive")&&(c=!0,o("boot"),o("view"),o("ready"),l=!0,O(),k&&(k=!1,u.start()))};window.addEventListener("resize",()=>f()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"?(S(),e()):v()}),document.readyState==="complete"||document.readyState==="interactive"?e():window.addEventListener("load",e),z=!0}function He(){let e=t=>{typeof TouchEvent!="undefined"&&t instanceof TouchEvent&&(be=!0),!(be&&t instanceof MouseEvent)&&(K+=1,o("interaction",K))};document.addEventListener("mousedown",e),document.addEventListener("touchstart",e)}function Fe(e){var i,a,x,C,q,D,$,L,X,Y,Q,Z;let t=typeof AD_PROTOCOL!="undefined"?AD_PROTOCOL:"none";if((typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed")==="google")try{(i=window.ExitApi)==null||i.exit();return}catch{}if(t==="mraid"&&typeof mraid!="undefined")mraid.open(e||"");else if(t==="dapi"&&typeof dapi!="undefined")dapi.openStoreUrl();else if(y())(x=(a=window.TJ_API)==null?void 0:a.click)==null||x.call(a);else if(fe())(q=(C=window.FbPlayableAd)==null?void 0:C.onCTAClick)==null||q.call(C);else if(we())($=(D=window.ScPlayableAd)==null?void 0:D.onCTAClick)==null||$.call(D);else if(ye())try{(X=(L=window.smxTracking)==null?void 0:L.redirect)==null||X.call(L)}catch(m){console.warn("Smadex redirect failed",m)}else if(me()){let m=window.ExitApi;m&&typeof m.exit=="function"?m.exit(e||N||""):e&&window.open(e)}else g()?(Y=window.install)==null||Y.call(window):ge()?(Q=window.openAppStore)==null||Q.call(window):F()?(Z=parent==null?void 0:parent.postMessage)==null||Z.call(parent,"download","*"):e&&window.open(e)}function Ge(){let e=typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed",t=n=>{if(!n)return;let i=new Image;i.src=n};if(e==="bigabid"){let n=window.BIGABID_BIDTIMEMACROS;if(!n)return;s("view",()=>t(n.mraid_viewable)),s("start",()=>t(n.game_viewable)),s("engagement",()=>t(n.engagement));let i=()=>t(n.complete);s("complete",i),I("engagement",a=>{var x;((x=a==null?void 0:a.payload)==null?void 0:x.count)>3&&i()}),s("cta_click",()=>t(n.click))}else if(e==="inmobi"){let n=window.INMOBI_DSPMACROS;if(!n)return;s("view",()=>t(n.Ad_Load_Start)),s("start",()=>t(n.Ad_Viewable)),s("engagement",()=>t(n.First_Engagement)),s("complete",()=>t(n.Gameplay_Complete)),s("cta_click",()=>t(n.DSP_Click)),s("start",()=>{[5,10,15,20,25,30].forEach(i=>setTimeout(()=>t(n[`Spent_${i}_Seconds`]),i*1e3))})}}function Ue(){if(!y())return;let e=window.TJ_API;e&&e.setPlayableAPI&&e.setPlayableAPI({skipAd:()=>{try{u.finish()}catch(t){console.warn("Tapjoy skip failed",t)}}})}function Ee(){var t,n,i;let e=window.TJ_API;(t=e==null?void 0:e.objectiveComplete)==null||t.call(e),(n=e==null?void 0:e.playableFinished)==null||n.call(e),(i=e==null?void 0:e.gameplayFinished)==null||i.call(e)}function We(){g()&&(window.mintGameStart=()=>{S(!0),f()},window.mintGameClose=()=>{v(!0)})}function Ke(){if(!G())return;let e=window.NUC;!e||!e.trigger||(u.on("cta_click",()=>{var t,n;return(n=(t=e.trigger).convert)==null?void 0:n.call(t,N)}),u.on("complete",()=>{var t,n;return(n=(t=e.trigger).tryAgain)==null?void 0:n.call(t)}))}var u={init(e={},t){if(ke=e.profile||"web_embed",Ne=e.consent||{},A={...Ae,...e.ids||{}},w=e.rootEl||w,N=e.destinationUrl||(/android/i.test(navigator.userAgent)?"https://play.google.com/store":"https://www.apple.com/app-store/"),t&&(M=t),o("init"),document.body.oncontextmenu=()=>!1,ve(),Je(w),he(),ze(),Ve(),!z){if(document.readyState==="complete")xe();else if(!_e){_e=!0;let n=()=>{xe(),window.removeEventListener("load",n),document.removeEventListener("DOMContentLoaded",n)};window.addEventListener("load",n),document.addEventListener("DOMContentLoaded",n)}}He(),Ge(),Ue(),We(),Ke(),console.log(`%c @handler/playable-sdk %c v${R.version||"0.0.0"} `,"background: #007acc; color: #fff; font-size: 14px; padding: 4px 8px; border-top-left-radius: 4px; border-bottom-left-radius: 4px;","background: #e1e4e8; color: #333; font-size: 14px; padding: 4px 8px; border-top-right-radius: 4px; border-bottom-right-radius: 4px;"),c&&!l&&(o("boot"),o("view"),o("ready"),k&&(k=!1,u.start()),l=!0),l=c},getRoot(){return ve()},get version(){return R.version||"0.0.0"},get maxWidth(){return h},get maxHeight(){return b},get isLandscape(){return B},get isReady(){return l},get isStarted(){return U},get isPaused(){return T},get isFinished(){return E},get volume(){return J},get interactions(){return K},on(e,t){I(j(e),t)},off(e,t){H(j(e),t)},start(){var e,t;if(!U){if(!c){k=!0;return}if(U=!0,o("start"),f(),g())v(),(e=window.gameReady)==null||e.call(window);else if(y()){let n=window.TJ_API;(t=n==null?void 0:n.setPlayableBuild)==null||t.call(n,{orientation:B?"landscape":"portrait",buildID:R.version||"dev"})}}},finish(){var e,t;E||(E=!0,o("complete"),g()?(e=window.gameEnd)==null||e.call(window):F()?(t=parent==null?void 0:parent.postMessage)==null||t.call(parent,"complete","*"):y()&&Ee())},install(e){if(!E){E=!0,y()?(Ee(),setTimeout(()=>u.install(e),300)):(o("complete"),setTimeout(()=>u.install(e),0));return}W||(W=!0,setTimeout(()=>W=!1,500),o("cta_click"),o("conversion"),Fe(e||N))},emit(e,t){let n=j(e);if(!["view","boot","start","engagement","complete","cta_click","conversion","retry","pause","resume","resize","volume","error"].includes(n)&&!n.startsWith("custom."))throw new Error(`Event ${e} must be canonical or namespaced as custom.<mechanic_id>.<event>`);let i=Oe(n,t);P(n,i)},retry(){var e,t,n;if(g())(e=window.gameRetry)==null||e.call(window);else if(G()){let i=window.NUC;(n=(t=i==null?void 0:i.trigger)==null?void 0:t.tryAgain)==null||n.call(t)}o("engagement",{action:"retry"})},pause(){v(!0)},resume(){S(!0)},resize(e,t){f(e,t)}},Be=u;function Je(e){let t=document.createElement("script");t.type="text/javascript",t.textContent=`
2
- (function(){
3
- var events = ['touchstart','touchend','mousedown','keydown'];
4
- function unlock(){
5
- if(window.AudioContext && AudioContext.prototype.resume){
6
- if(!window.__handler_audio_ctx){
7
- window.__handler_audio_ctx = new AudioContext();
8
- }
9
- if(window.__handler_audio_ctx.state === 'suspended'){
10
- window.__handler_audio_ctx.resume();
11
- }
12
- }
13
- events.forEach(function(e){ document.removeEventListener(e, unlock); });
14
- }
15
- events.forEach(function(e){ document.addEventListener(e, unlock, false); });
16
- })();
17
- `,e.appendChild(t)}0&&(module.exports={Handler});
1
+ const a0_0x41c49b=a0_0x5038;(function(_0x2e8f6c,_0xce20bc){const _0x1592b6=a0_0x5038,_0x4dd4fe=_0x2e8f6c();while(!![]){try{const _0x3ef8de=parseInt(_0x1592b6(0x9e))/0x1*(-parseInt(_0x1592b6(0xa3))/0x2)+parseInt(_0x1592b6(0x133))/0x3*(parseInt(_0x1592b6(0x102))/0x4)+-parseInt(_0x1592b6(0xfb))/0x5*(-parseInt(_0x1592b6(0xda))/0x6)+-parseInt(_0x1592b6(0x135))/0x7*(-parseInt(_0x1592b6(0xc6))/0x8)+parseInt(_0x1592b6(0xe8))/0x9+-parseInt(_0x1592b6(0xa0))/0xa+-parseInt(_0x1592b6(0xb3))/0xb*(parseInt(_0x1592b6(0x12d))/0xc);if(_0x3ef8de===_0xce20bc)break;else _0x4dd4fe['push'](_0x4dd4fe['shift']());}catch(_0x27b45e){_0x4dd4fe['push'](_0x4dd4fe['shift']());}}}(a0_0x1b1b,0x9dc96));const a0_0x3f27b5=(function(){let _0x146592=!![];return function(_0x4a09da,_0x3c8b38){const _0x6421e6=_0x146592?function(){const _0x42da5d=a0_0x5038;if(_0x3c8b38){const _0xd13f89=_0x3c8b38[_0x42da5d(0x123)](_0x4a09da,arguments);return _0x3c8b38=null,_0xd13f89;}}:function(){};return _0x146592=![],_0x6421e6;};}()),a0_0x40e9ef=a0_0x3f27b5(this,function(){const _0x35446e=a0_0x5038;return a0_0x40e9ef[_0x35446e(0xb5)]()[_0x35446e(0x119)](_0x35446e(0x117))['toString']()['constructor'](a0_0x40e9ef)[_0x35446e(0x119)](_0x35446e(0x117));});a0_0x40e9ef();'use strict';var V=Object[a0_0x41c49b(0xed)],Se=Object[a0_0x41c49b(0x131)],Ce=Object[a0_0x41c49b(0xd0)],De=Object['prototype'][a0_0x41c49b(0xbd)],Le=(_0x4d0ed0,_0x91d053)=>{for(var _0x26bed1 in _0x91d053)V(_0x4d0ed0,_0x26bed1,{'get':_0x91d053[_0x26bed1],'enumerable':!0x0});},Ie=(_0x131043,_0xb8d10a,_0x43a080,_0x423bbb)=>{const _0x34b637=a0_0x41c49b;if(_0xb8d10a&&typeof _0xb8d10a==_0x34b637(0x11f)||typeof _0xb8d10a==_0x34b637(0xec)){for(let _0x458239 of Ce(_0xb8d10a))!De[_0x34b637(0x113)](_0x131043,_0x458239)&&_0x458239!==_0x43a080&&V(_0x131043,_0x458239,{'get':()=>_0xb8d10a[_0x458239],'enumerable':!(_0x423bbb=Se(_0xb8d10a,_0x458239))||_0x423bbb[_0x34b637(0x10a)]});}return _0x131043;},Pe=_0x3a949a=>Ie(V({},a0_0x41c49b(0x10f),{'value':!0x0}),_0x3a949a),qe={};Le(qe,{'Handler':()=>u,'default':()=>Be}),module[a0_0x41c49b(0x90)]=Pe(qe);var p={};function I(_0x246e08,_0x1bcd0f,_0x43733d=!0x1){const _0x23bc90=a0_0x41c49b;p[_0x246e08]||(p[_0x246e08]=[]),p[_0x246e08][_0x23bc90(0xf4)]({'fn':_0x1bcd0f,'once':_0x43733d});}function H(_0x4cad81,_0x59563f){const _0x49da68=a0_0x41c49b;if(p[_0x4cad81]){if(!_0x59563f){delete p[_0x4cad81];return;}p[_0x4cad81]=p[_0x4cad81][_0x49da68(0xa8)](_0x2e3d97=>_0x2e3d97['fn']!==_0x59563f);}}function P(_0x3ec2cb,..._0x5c09a5){const _0x35590e=a0_0x41c49b;let _0x4ecce1=p[_0x3ec2cb];if(_0x4ecce1){for(let _0x10fecf of[..._0x4ecce1])_0x10fecf['fn'](..._0x5c09a5),_0x10fecf[_0x35590e(0xf9)]&&H(_0x3ec2cb,_0x10fecf['fn']);}}function s(_0x5b8f1c,_0x47a409){I(_0x5b8f1c,_0x47a409,!0x0);}var R={'name':a0_0x41c49b(0xd9),'version':a0_0x41c49b(0x10b),'description':a0_0x41c49b(0xdd),'main':a0_0x41c49b(0xf6),'module':a0_0x41c49b(0x121),'types':'dist/index.d.ts','exports':{'.':{'types':a0_0x41c49b(0x126),'import':'./dist/index.mjs','require':'./dist/index.js'},'./pixi':{'types':a0_0x41c49b(0x11b),'import':a0_0x41c49b(0xc9),'require':'./dist/pixi/index.js'},'./three':{'types':a0_0x41c49b(0x10d),'import':a0_0x41c49b(0xe2),'require':'./dist/three/index.js'}},'scripts':{'build':a0_0x41c49b(0xf2),'build:dev':a0_0x41c49b(0xca),'obfuscate':a0_0x41c49b(0x141),'lint':a0_0x41c49b(0x9c),'typecheck':'tsc\x20--noEmit','prepublishOnly':'npm\x20run\x20build','publish:update':a0_0x41c49b(0x8d),'publish:update:minor':a0_0x41c49b(0xdb),'publish:update:major':a0_0x41c49b(0xb6)},'author':a0_0x41c49b(0x118),'license':a0_0x41c49b(0xcd),'publishConfig':{'access':a0_0x41c49b(0xb7)},'repository':{'type':a0_0x41c49b(0x12c),'url':a0_0x41c49b(0xc0)},'files':[a0_0x41c49b(0xef),'LICENSE',a0_0x41c49b(0x8a)],'peerDependencies':{'lottie-web':'^5.0.0','pixi.js':a0_0x41c49b(0xee),'three':a0_0x41c49b(0x143)},'peerDependenciesMeta':{'pixi.js':{'optional':!0x0},'three':{'optional':!0x0},'lottie-web':{'optional':!0x0}},'devDependencies':{'@types/three':'^0.160.0','eslint':'^8.57.1','javascript-obfuscator':a0_0x41c49b(0xab),'pixi.js':a0_0x41c49b(0x14c),'three':'^0.160.0','ts-node':'^10.9.2','tsup':a0_0x41c49b(0xae),'typescript':a0_0x41c49b(0xbc)}},d=0x0,je=d++,ee=d++,te=d++,ne=d++,ie=d++,oe=d++,re=d++,ae=d++,se=d++,de=d++,le=d++,ce=d++,r=je;function a0_0x5038(_0x5ac738,_0x49e263){_0x5ac738=_0x5ac738-0x8a;const _0x2768de=a0_0x1b1b();let _0x40e9ef=_0x2768de[_0x5ac738];return _0x40e9ef;}function ue(){return r===ee;}function pe(){return r===te;}function fe(){return r===ne;}function me(){return r===ie;}function g(){return r===oe;}function y(){return r===re;}function ge(){return r===ae;}function ye(){return r===se;}function we(){return r===de;}function F(){return r===le;}function G(){return r===ce;}function he(){const _0x13d52a=a0_0x41c49b;let _0x43fe78=typeof AD_PROTOCOL!=_0x13d52a(0xc4)?AD_PROTOCOL:_0x13d52a(0x120),_0x3257ae=typeof AD_NETWORK!=_0x13d52a(0xc4)?AD_NETWORK:_0x13d52a(0x111);if(_0x43fe78===_0x13d52a(0x9f))try{mraid[_0x13d52a(0x140)](),r=ee;return;}catch{}else{if(_0x43fe78===_0x13d52a(0xa7))try{dapi[_0x13d52a(0xd8)](),r=te;return;}catch{}}if(_0x3257ae===_0x13d52a(0xff))try{typeof FbPlayableAd!=_0x13d52a(0xc4)&&(r=ne);}catch{}else{if(_0x3257ae===_0x13d52a(0x14b))try{typeof ExitApi!=_0x13d52a(0xc4)&&(r=ie);}catch{}else{if(_0x3257ae===_0x13d52a(0x13d))window['gameReady']&&(r=oe);else{if(_0x3257ae===_0x13d52a(0x139))window[_0x13d52a(0x149)]&&(r=re);else{if(_0x3257ae==='tiktok')window[_0x13d52a(0x122)]&&(r=ae);else{if(_0x3257ae===_0x13d52a(0xe7))try{window[_0x13d52a(0xdf)]&&(r=se);}catch{}else{if(_0x3257ae===_0x13d52a(0xd1))try{window[_0x13d52a(0x13b)]&&(r=de);}catch{}else _0x3257ae===_0x13d52a(0xac)?r=le:(_0x43fe78===_0x13d52a(0x12b)||_0x3257ae===_0x13d52a(0x12b))&&(r=ce);}}}}}}}var Ae={'mechanic_id':a0_0x41c49b(0x145),'variant_id':a0_0x41c49b(0x110),'deployment_id':'TODO_deployment_id','export_id':a0_0x41c49b(0x108),'profile_id':a0_0x41c49b(0xeb),'instance_id':'default'},Me=Math[a0_0x41c49b(0x144)]()[a0_0x41c49b(0xb5)](0x24)[a0_0x41c49b(0x94)](0x2),w=null,A={...Ae},ke=a0_0x41c49b(0x111),Ne={},U=!0x1,E=!0x1,T=!0x1,Te=!0x1,J=0x1,K=0x0,z=!0x1,l=!0x1,N='',h=Math['floor'](window[a0_0x41c49b(0x107)]),b=Math['floor'](window['innerHeight']),B=h>b,c=!0x1,k=!0x1,be=!0x1,xe=!0x1,W=!0x1,j=null;function _e(){const _0xde877d=a0_0x41c49b;if(w)return w;let _0x15312a=document[_0xde877d(0xb0)](_0xde877d(0x8f));return _0x15312a['id']='handler-root',_0x15312a[_0xde877d(0x14a)]('data-handler-root',_0xde877d(0x130)),document[_0xde877d(0x12a)][_0xde877d(0xc7)](_0x15312a),w=_0x15312a,_0x15312a;}function M(_0x3b45c4){const _0x9fdf6b=a0_0x41c49b;switch(_0x3b45c4){case _0x9fdf6b(0xad):return _0x9fdf6b(0x125);case _0x9fdf6b(0x9d):return _0x9fdf6b(0x129);case'install':return _0x9fdf6b(0xea);default:return _0x3b45c4;}}function Oe(_0xa1bf93,_0x19fba4){const _0x2d192f=a0_0x41c49b;return{'event_name':_0xa1bf93,'ts':Date[_0x2d192f(0xfa)](),'session_id':Me,'deployment_id':A[_0x2d192f(0x124)],'variant_id':A['variant_id'],'export_profile_id':A['profile_id'],'instance_id':A['instance_id']||_0x2d192f(0x13a),'env':ke===_0x2d192f(0x9f)?_0x2d192f(0x9f):_0x2d192f(0x8e),'payload':_0x19fba4};}function a0_0x1b1b(){const _0x3a462b=['^5.7.2','hasOwnProperty','conversion','consent','https://github.com/HandlerAIGames/handler-playable-sdk.git','count','rootEl','init','undefined','playableFinished','4421512wDFgUJ','appendChild','includes','./dist/pixi/index.mjs','tsup\x20src/index.ts\x20src/pixi/index.ts\x20src/three/index.ts\x20--format\x20cjs,esm\x20--dts\x20--clean\x20--external\x20lottie-web','objectiveComplete','0.0.0','MIT','Gameplay_Complete','interactive','getOwnPropertyNames','snapchat','test','action:','hidden','getMaxSize','start','https://play.google.com/store','isReady','handler-playable-sdk','18Dlkpzo','node\x20scripts/publish-and-update.js\x20minor','ready','Handler\x20Playable\x20SDK\x20v0.1\x20with\x20contract-aligned\x20surface\x20(root\x20sandbox,\x20canonical\x20event\x20envelope).','touchstart','smxTracking','setPlayableBuild','ids','./dist/three/index.mjs','getAudioVolume','mousedown','text/javascript','redirect','smadex','11388069uvkgXO','%c\x20@handler/playable-sdk\x20%c\x20v','cta_click','TODO_profile_id','function','defineProperty','^8.0.0','dist','setPlayableAPI','Event\x20','tsup\x20src/index.ts\x20src/pixi/index.ts\x20src/three/index.ts\x20--format\x20cjs,esm\x20--dts\x20--clean\x20--minify\x20--external\x20lottie-web\x20&&\x20npm\x20run\x20obfuscate','userAgent','push','addEventListener','dist/index.js','exit','_Seconds','once','now','24520iHoqeg','mintGameClose','retry','bigabid','facebook','resize','NUC','20QwgwmA','log','FbPlayableAd','INMOBI_DSPMACROS','visible','innerWidth','TODO_export_id','install','enumerable','0.3.1','\x0a\x20\x20\x20\x20(function(){\x0a\x20\x20\x20\x20\x20\x20var\x20events\x20=\x20[\x27touchstart\x27,\x27touchend\x27,\x27mousedown\x27,\x27keydown\x27];\x0a\x20\x20\x20\x20\x20\x20function\x20unlock(){\x0a\x20\x20\x20\x20\x20\x20\x20\x20if(window.AudioContext\x20&&\x20AudioContext.prototype.resume){\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if(!window.__handler_audio_ctx){\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20window.__handler_audio_ctx\x20=\x20new\x20AudioContext();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20if(window.__handler_audio_ctx.state\x20===\x20\x27suspended\x27){\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20window.__handler_audio_ctx.resume();\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20\x20\x20events.forEach(function(e){\x20document.removeEventListener(e,\x20unlock);\x20});\x0a\x20\x20\x20\x20\x20\x20}\x0a\x20\x20\x20\x20\x20\x20events.forEach(function(e){\x20document.addEventListener(e,\x20unlock,\x20false);\x20});\x0a\x20\x20\x20\x20})();\x0a\x20\x20','./dist/three/index.d.ts','visibilityState','__esModule','TODO_variant_id','web_embed','Ad_Viewable','call','volume','MRAID\x20hook\x20skipped','viewableChange','(((.+)+)+)+$','Handler','search','removeEventListener','./dist/pixi/index.d.ts','visibilitychange','readyState','\x20must\x20be\x20canonical\x20or\x20namespaced\x20as\x20custom.<mechanic_id>.<event>','object','none','dist/index.mjs','openAppStore','apply','deployment_id','engagement','./dist/index.d.ts','adResized','game_viewable','complete','body','nucleo','git','125640CJaeVx','onCTAClick','background:\x20#007acc;\x20color:\x20#fff;\x20font-size:\x2014px;\x20padding:\x204px\x208px;\x20border-top-left-radius:\x204px;\x20border-bottom-left-radius:\x204px;','true','getOwnPropertyDescriptor','DOMContentLoaded','587550XRTtRt','startsWith','14YUOdLV','textContent','BIGABID_BIDTIMEMACROS','mraid_viewable','tapjoy','default','ScPlayableAd','Smadex\x20redirect\x20failed','mintegral','warn','width','getState','javascript-obfuscator\x20dist/index.js\x20dist/index.mjs\x20dist/pixi/index.js\x20dist/pixi/index.mjs\x20dist/three/index.js\x20dist/three/index.mjs\x20--output\x20dist\x20--options-preset\x20high-obfuscation\x20--compact\x20true\x20--self-defending\x20true','openStoreUrl','^0.160.0','random','TODO_mechanic_id','gameRetry','custom.','tryAgain','TJ_API','setAttribute','google','8.8.1','README.md','sizeChange','ExitApi','node\x20scripts/publish-and-update.js\x20patch','web','div','exports','postMessage','mraid\x20error:','resume','slice','forEach','DSP_Click','gameReady','height','Ad_Load_Start','mintGameStart','landscape','eslint\x20\x27src/**/*.{ts,tsx}\x27','finish','3832CnDrus','mraid','5593290gKpOPx','floor','trigger','258bKJYqC','Tapjoy\x20skip\x20failed','Spent_','gameplayFinished','dapi','filter','open','isViewable','^5.1.0','vungle','interaction','^8.4.0','boot','createElement','profile','view','1749yWomuv','load','toString','node\x20scripts/publish-and-update.js\x20major','public','error','https://www.apple.com/app-store/','version','innerHeight'];a0_0x1b1b=function(){return _0x3a462b;};return a0_0x1b1b();}function o(_0x1f5ab0,_0x466242){let _0xc0e8bb=M(_0x1f5ab0),_0x30834a=Oe(_0xc0e8bb,_0x466242);P(_0xc0e8bb,_0x30834a),_0xc0e8bb!==_0x1f5ab0&&P(_0x1f5ab0,_0x30834a);}function O(){j&&(j(h,b),j=null);}function x(_0x28a56d){const _0x3bbc55=a0_0x41c49b;J=_0x28a56d,o(_0x3bbc55(0x114),_0x28a56d);}function _(_0x523f23){_0x523f23&&(Te=!0x0),!T&&(T=!0x0,o('pause'),x(0x0));}function S(_0x4be844){!_0x4be844&&Te||T&&(T=!0x1,o('resume'),x(J));}function f(_0x35b478,_0x6dabf6){const _0x1fc32f=a0_0x41c49b;h=Math['floor'](_0x35b478||window[_0x1fc32f(0x107)]),b=Math[_0x1fc32f(0xa1)](_0x6dabf6||window[_0x1fc32f(0xbb)]),B=h>b,o(_0x1fc32f(0x100),{'width':h,'height':b});}function ze(){const _0x1760a8=a0_0x41c49b;if(ue())try{let _0xb6dfa1=mraid[_0x1760a8(0xd5)]();f(_0xb6dfa1[_0x1760a8(0x13f)],_0xb6dfa1['height']);let _0x526bb1=()=>{const _0x4753e4=_0x1760a8;mraid[_0x4753e4(0xaa)]()&&mraid[_0x4753e4(0x140)]()!==_0x4753e4(0xd4)?S():_();};if(mraid[_0x1760a8(0xf5)](_0x1760a8(0x116),_0x526bb1),mraid[_0x1760a8(0xf5)]('stateChange',_0x526bb1),mraid[_0x1760a8(0xf5)](_0x1760a8(0x8b),()=>{const _0x540641=_0x1760a8;let _0x620e6f=mraid['getMaxSize']();f(_0x620e6f['width'],_0x620e6f[_0x540641(0x98)]);}),mraid['getAudioVolume']){let _0x25dceb=mraid['getAudioVolume']();x(_0x25dceb?0x1:0x0);}if(mraid[_0x1760a8(0xf5)]('audioVolumeChange',_0x5e3ec9=>{_0x5e3ec9!==null&&x(_0x5e3ec9>0x0?0x1:0x0);}),mraid[_0x1760a8(0xf5)]('error',(_0x3aeec9,_0x417a5b)=>{const _0x3a183d=_0x1760a8;console[_0x3a183d(0x13e)](_0x3a183d(0x92),_0x3aeec9,_0x3a183d(0xd3),_0x417a5b);}),z=!0x0,mraid[_0x1760a8(0xaa)]()&&mraid[_0x1760a8(0x140)]()!=='hidden')c=!0x0,o(_0x1760a8(0xaf)),o(_0x1760a8(0xb2)),o('ready'),l=!0x0,O();else{let _0x31dc1d=()=>{const _0x70adc5=_0x1760a8;c=!0x0,o(_0x70adc5(0xaf)),o('view'),o(_0x70adc5(0xdc)),l=!0x0,O();};mraid[_0x1760a8(0xf5)](_0x1760a8(0xdc),_0x31dc1d);}}catch(_0x25ca0d){console['warn'](_0x1760a8(0x115),_0x25ca0d);}}function Ve(){const _0x24b5e4=a0_0x41c49b;if(pe())try{let _0x5134e1=dapi['getScreenSize']();f(_0x5134e1[_0x24b5e4(0x13f)],_0x5134e1[_0x24b5e4(0x98)]),dapi[_0x24b5e4(0xf5)]('viewableChange',_0x18e660=>{const _0x210e35=_0x24b5e4;_0x18e660[_0x210e35(0xaa)]?S():_();}),dapi['addEventListener'](_0x24b5e4(0x127),_0x281d67=>{const _0x5d1738=_0x24b5e4;let _0x599674=dapi['getScreenSize']();f(_0x281d67[_0x5d1738(0x13f)]||_0x599674['width'],_0x281d67[_0x5d1738(0x98)]||_0x599674[_0x5d1738(0x98)]);});let _0x1f0168=dapi[_0x24b5e4(0xe3)]();if(x(_0x1f0168?0x1:0x0),dapi['addEventListener']('audioVolumeChange',_0x332eab=>x(_0x332eab?0x1:0x0)),z=!0x0,dapi[_0x24b5e4(0xaa)]())c=!0x0,o(_0x24b5e4(0xaf)),o(_0x24b5e4(0xb2)),o(_0x24b5e4(0xdc)),l=!0x0,O();else{let _0x17ab8f=()=>{const _0x5a6587=_0x24b5e4;c=!0x0,o(_0x5a6587(0xaf)),o('view'),o(_0x5a6587(0xdc)),l=!0x0,O();};dapi['addEventListener'](_0x24b5e4(0xdc),_0x17ab8f);}}catch(_0x527889){console[_0x24b5e4(0x13e)]('DAPI\x20hook\x20skipped',_0x527889);}}function ve(){const _0x3e1032=a0_0x41c49b;let _0x699053=()=>{const _0x13b0c3=a0_0x5038;c||document['visibilityState']===_0x13b0c3(0x106)&&(document[_0x13b0c3(0x11d)]===_0x13b0c3(0x129)||document[_0x13b0c3(0x11d)]===_0x13b0c3(0xcf))&&(c=!0x0,o('boot'),o('view'),o(_0x13b0c3(0xdc)),l=!0x0,O(),k&&(k=!0x1,u[_0x13b0c3(0xd6)]()));};window[_0x3e1032(0xf5)](_0x3e1032(0x100),()=>f()),document['addEventListener'](_0x3e1032(0x11c),()=>{const _0x3924e9=_0x3e1032;document[_0x3924e9(0x10e)]===_0x3924e9(0x106)?(S(),_0x699053()):_();}),document[_0x3e1032(0x11d)]==='complete'||document[_0x3e1032(0x11d)]===_0x3e1032(0xcf)?_0x699053():window[_0x3e1032(0xf5)]('load',_0x699053),z=!0x0;}function He(){const _0x4cb0ca=a0_0x41c49b;let _0x2acfa8=_0x438dd0=>{const _0x499063=a0_0x5038;typeof TouchEvent!=_0x499063(0xc4)&&_0x438dd0 instanceof TouchEvent&&(be=!0x0),!(be&&_0x438dd0 instanceof MouseEvent)&&(K+=0x1,o('interaction',K));};document['addEventListener'](_0x4cb0ca(0xe4),_0x2acfa8),document[_0x4cb0ca(0xf5)](_0x4cb0ca(0xde),_0x2acfa8);}function Fe(_0x40472a){const _0x363074=a0_0x41c49b;var _0x294637,_0x440345,_0x42219e,_0x4d4d4c,_0x11697e,_0x29b3da,_0x177fde,_0x595784,_0x4ca5da,_0x195163,_0x3fcac9,_0x3c6266;let _0x68d1f9=typeof AD_PROTOCOL!='undefined'?AD_PROTOCOL:_0x363074(0x120);if((typeof AD_NETWORK!=_0x363074(0xc4)?AD_NETWORK:'web_embed')===_0x363074(0x14b))try{(_0x294637=window[_0x363074(0x8c)])==null||_0x294637[_0x363074(0xf7)]();return;}catch{}if(_0x68d1f9==='mraid'&&typeof mraid!='undefined')mraid[_0x363074(0xa9)](_0x40472a||'');else{if(_0x68d1f9==='dapi'&&typeof dapi!=_0x363074(0xc4))dapi[_0x363074(0x142)]();else{if(y())(_0x42219e=(_0x440345=window[_0x363074(0x149)])==null?void 0x0:_0x440345['click'])==null||_0x42219e[_0x363074(0x113)](_0x440345);else{if(fe())(_0x11697e=(_0x4d4d4c=window[_0x363074(0x104)])==null?void 0x0:_0x4d4d4c[_0x363074(0x12e)])==null||_0x11697e[_0x363074(0x113)](_0x4d4d4c);else{if(we())(_0x177fde=(_0x29b3da=window['ScPlayableAd'])==null?void 0x0:_0x29b3da[_0x363074(0x12e)])==null||_0x177fde['call'](_0x29b3da);else{if(ye())try{(_0x4ca5da=(_0x595784=window[_0x363074(0xdf)])==null?void 0x0:_0x595784[_0x363074(0xe6)])==null||_0x4ca5da['call'](_0x595784);}catch(_0x39f765){console[_0x363074(0x13e)](_0x363074(0x13c),_0x39f765);}else{if(me()){let _0x4f5170=window[_0x363074(0x8c)];_0x4f5170&&typeof _0x4f5170[_0x363074(0xf7)]==_0x363074(0xec)?_0x4f5170['exit'](_0x40472a||N||''):_0x40472a&&window['open'](_0x40472a);}else g()?(_0x195163=window[_0x363074(0x109)])==null||_0x195163['call'](window):ge()?(_0x3fcac9=window[_0x363074(0x122)])==null||_0x3fcac9[_0x363074(0x113)](window):F()?(_0x3c6266=parent==null?void 0x0:parent[_0x363074(0x91)])==null||_0x3c6266['call'](parent,'download','*'):_0x40472a&&window[_0x363074(0xa9)](_0x40472a);}}}}}}}function Ge(){const _0x10e832=a0_0x41c49b;let _0x35a3cd=typeof AD_NETWORK!=_0x10e832(0xc4)?AD_NETWORK:'web_embed',_0x549b2f=_0x3216a4=>{if(!_0x3216a4)return;let _0x20fd2c=new Image();_0x20fd2c['src']=_0x3216a4;};if(_0x35a3cd===_0x10e832(0xfe)){let _0x3ba2f0=window[_0x10e832(0x137)];if(!_0x3ba2f0)return;s(_0x10e832(0xb2),()=>_0x549b2f(_0x3ba2f0[_0x10e832(0x138)])),s(_0x10e832(0xd6),()=>_0x549b2f(_0x3ba2f0[_0x10e832(0x128)])),s('engagement',()=>_0x549b2f(_0x3ba2f0['engagement']));let _0x40823c=()=>_0x549b2f(_0x3ba2f0['complete']);s(_0x10e832(0x129),_0x40823c),I(_0x10e832(0x125),_0x2cf874=>{const _0x3d1c28=_0x10e832;var _0x1bd954;((_0x1bd954=_0x2cf874==null?void 0x0:_0x2cf874['payload'])==null?void 0x0:_0x1bd954[_0x3d1c28(0xc1)])>0x3&&_0x40823c();}),s('cta_click',()=>_0x549b2f(_0x3ba2f0['click']));}else{if(_0x35a3cd==='inmobi'){let _0x5ca1c3=window[_0x10e832(0x105)];if(!_0x5ca1c3)return;s(_0x10e832(0xb2),()=>_0x549b2f(_0x5ca1c3[_0x10e832(0x99)])),s('start',()=>_0x549b2f(_0x5ca1c3[_0x10e832(0x112)])),s(_0x10e832(0x125),()=>_0x549b2f(_0x5ca1c3['First_Engagement'])),s('complete',()=>_0x549b2f(_0x5ca1c3[_0x10e832(0xce)])),s(_0x10e832(0xea),()=>_0x549b2f(_0x5ca1c3[_0x10e832(0x96)])),s('start',()=>{const _0x4f0496=_0x10e832;[0x5,0xa,0xf,0x14,0x19,0x1e][_0x4f0496(0x95)](_0x4d148d=>setTimeout(()=>_0x549b2f(_0x5ca1c3[_0x4f0496(0xa5)+_0x4d148d+_0x4f0496(0xf8)]),_0x4d148d*0x3e8));});}}}function Ue(){const _0x497c2f=a0_0x41c49b;if(!y())return;let _0xed1593=window[_0x497c2f(0x149)];_0xed1593&&_0xed1593[_0x497c2f(0xf0)]&&_0xed1593[_0x497c2f(0xf0)]({'skipAd':()=>{const _0x1db61f=_0x497c2f;try{u['finish']();}catch(_0x29deb7){console[_0x1db61f(0x13e)](_0x1db61f(0xa4),_0x29deb7);}}});}function Ee(){const _0xa6b9ad=a0_0x41c49b;var _0x3c5197,_0x39a95b,_0x5c6e06;let _0xa33029=window[_0xa6b9ad(0x149)];(_0x3c5197=_0xa33029==null?void 0x0:_0xa33029[_0xa6b9ad(0xcb)])==null||_0x3c5197[_0xa6b9ad(0x113)](_0xa33029),(_0x39a95b=_0xa33029==null?void 0x0:_0xa33029[_0xa6b9ad(0xc5)])==null||_0x39a95b[_0xa6b9ad(0x113)](_0xa33029),(_0x5c6e06=_0xa33029==null?void 0x0:_0xa33029[_0xa6b9ad(0xa6)])==null||_0x5c6e06[_0xa6b9ad(0x113)](_0xa33029);}function We(){const _0x2a72ac=a0_0x41c49b;g()&&(window[_0x2a72ac(0x9a)]=()=>{S(!0x0),f();},window[_0x2a72ac(0xfc)]=()=>{_(!0x0);});}function Ke(){const _0x2b1057=a0_0x41c49b;if(!G())return;let _0x4a24ed=window[_0x2b1057(0x101)];!_0x4a24ed||!_0x4a24ed[_0x2b1057(0xa2)]||(u['on'](_0x2b1057(0xea),()=>{const _0x182aa4=_0x2b1057;var _0x536c6c,_0x2a1784;return(_0x2a1784=(_0x536c6c=_0x4a24ed[_0x182aa4(0xa2)])['convert'])==null?void 0x0:_0x2a1784[_0x182aa4(0x113)](_0x536c6c,N);}),u['on'](_0x2b1057(0x129),()=>{const _0xe8573e=_0x2b1057;var _0x46c810,_0x4c64fb;return(_0x4c64fb=(_0x46c810=_0x4a24ed[_0xe8573e(0xa2)])[_0xe8573e(0x148)])==null?void 0x0:_0x4c64fb['call'](_0x46c810);}));}var u={'init'(_0x3daa5c={},_0x1fedb8){const _0x45b8dc=a0_0x41c49b;if(ke=_0x3daa5c[_0x45b8dc(0xb1)]||_0x45b8dc(0x111),Ne=_0x3daa5c[_0x45b8dc(0xbf)]||{},A={...Ae,..._0x3daa5c[_0x45b8dc(0xe1)]||{}},w=_0x3daa5c[_0x45b8dc(0xc2)]||w,N=_0x3daa5c['destinationUrl']||(/android/i[_0x45b8dc(0xd2)](navigator[_0x45b8dc(0xf3)])?_0x45b8dc(0xd7):_0x45b8dc(0xb9)),_0x1fedb8&&(j=_0x1fedb8),o(_0x45b8dc(0xc3)),document[_0x45b8dc(0x12a)]['oncontextmenu']=()=>!0x1,_e(),Je(w),he(),ze(),Ve(),!z){if(document[_0x45b8dc(0x11d)]===_0x45b8dc(0x129))ve();else{if(!xe){xe=!0x0;let _0x48ba61=()=>{const _0x229fbb=_0x45b8dc;ve(),window[_0x229fbb(0x11a)](_0x229fbb(0xb4),_0x48ba61),document[_0x229fbb(0x11a)]('DOMContentLoaded',_0x48ba61);};window[_0x45b8dc(0xf5)]('load',_0x48ba61),document[_0x45b8dc(0xf5)](_0x45b8dc(0x132),_0x48ba61);}}}He(),Ge(),Ue(),We(),Ke(),console[_0x45b8dc(0x103)](_0x45b8dc(0xe9)+(R['version']||_0x45b8dc(0xcc))+'\x20',_0x45b8dc(0x12f),'background:\x20#e1e4e8;\x20color:\x20#333;\x20font-size:\x2014px;\x20padding:\x204px\x208px;\x20border-top-right-radius:\x204px;\x20border-bottom-right-radius:\x204px;'),c&&!l&&(o(_0x45b8dc(0xaf)),o(_0x45b8dc(0xb2)),o(_0x45b8dc(0xdc)),k&&(k=!0x1,u[_0x45b8dc(0xd6)]()),l=!0x0),l=c;},'getRoot'(){return _e();},get 'version'(){const _0x2ddd87=a0_0x41c49b;return R[_0x2ddd87(0xba)]||_0x2ddd87(0xcc);},get 'maxWidth'(){return h;},get 'maxHeight'(){return b;},get 'isLandscape'(){return B;},get 'isReady'(){return l;},get 'isStarted'(){return U;},get 'isPaused'(){return T;},get 'isFinished'(){return E;},get 'volume'(){return J;},get 'interactions'(){return K;},'on'(_0x2e7bd,_0x54455b){I(M(_0x2e7bd),_0x54455b);},'off'(_0x523a33,_0x281e23){H(M(_0x523a33),_0x281e23);},'start'(){const _0x1d1e2c=a0_0x41c49b;var _0x22ebdc,_0x3bc106;if(!U){if(!c){k=!0x0;return;}if(U=!0x0,o(_0x1d1e2c(0xd6)),f(),g())_(),(_0x22ebdc=window[_0x1d1e2c(0x97)])==null||_0x22ebdc['call'](window);else{if(y()){let _0x146f2f=window[_0x1d1e2c(0x149)];(_0x3bc106=_0x146f2f==null?void 0x0:_0x146f2f[_0x1d1e2c(0xe0)])==null||_0x3bc106[_0x1d1e2c(0x113)](_0x146f2f,{'orientation':B?_0x1d1e2c(0x9b):'portrait','buildID':R[_0x1d1e2c(0xba)]||'dev'});}}}},'finish'(){const _0x584c31=a0_0x41c49b;var _0x347e07,_0x405bbc;E||(E=!0x0,o(_0x584c31(0x129)),g()?(_0x347e07=window['gameEnd'])==null||_0x347e07[_0x584c31(0x113)](window):F()?(_0x405bbc=parent==null?void 0x0:parent[_0x584c31(0x91)])==null||_0x405bbc[_0x584c31(0x113)](parent,_0x584c31(0x129),'*'):y()&&Ee());},'install'(_0x5e8335){const _0x42cbc6=a0_0x41c49b;if(!E){E=!0x0,y()?(Ee(),setTimeout(()=>u[_0x42cbc6(0x109)](_0x5e8335),0x12c)):(o(_0x42cbc6(0x129)),setTimeout(()=>u[_0x42cbc6(0x109)](_0x5e8335),0x0));return;}W||(W=!0x0,setTimeout(()=>W=!0x1,0x1f4),o(_0x42cbc6(0xea)),o(_0x42cbc6(0xbe)),Fe(_0x5e8335||N));},'emit'(_0x2b1963,_0x5ad9f4){const _0x3d756d=a0_0x41c49b;let _0x476d26=M(_0x2b1963);if(!['view',_0x3d756d(0xaf),_0x3d756d(0xd6),'engagement',_0x3d756d(0x129),'cta_click',_0x3d756d(0xbe),_0x3d756d(0xfd),'pause',_0x3d756d(0x93),_0x3d756d(0x100),_0x3d756d(0x114),_0x3d756d(0xb8)][_0x3d756d(0xc8)](_0x476d26)&&!_0x476d26[_0x3d756d(0x134)](_0x3d756d(0x147)))throw new Error(_0x3d756d(0xf1)+_0x2b1963+_0x3d756d(0x11e));let _0x2fe3e8=Oe(_0x476d26,_0x5ad9f4);P(_0x476d26,_0x2fe3e8);},'retry'(){const _0x2cf9b4=a0_0x41c49b;var _0x30343b,_0x362819,_0x3a8c31;if(g())(_0x30343b=window[_0x2cf9b4(0x146)])==null||_0x30343b[_0x2cf9b4(0x113)](window);else{if(G()){let _0x497a56=window[_0x2cf9b4(0x101)];(_0x3a8c31=(_0x362819=_0x497a56==null?void 0x0:_0x497a56[_0x2cf9b4(0xa2)])==null?void 0x0:_0x362819[_0x2cf9b4(0x148)])==null||_0x3a8c31[_0x2cf9b4(0x113)](_0x362819);}}o(_0x2cf9b4(0x125),{'action':'retry'});},'pause'(){_(!0x0);},'resume'(){S(!0x0);},'resize'(_0x59c109,_0x50914b){f(_0x59c109,_0x50914b);}},Be=u;function Je(_0x5204a2){const _0x16f63d=a0_0x41c49b;let _0x34f9ef=document[_0x16f63d(0xb0)]('script');_0x34f9ef['type']=_0x16f63d(0xe5),_0x34f9ef[_0x16f63d(0x136)]=_0x16f63d(0x10c),_0x5204a2[_0x16f63d(0xc7)](_0x34f9ef);}0x0&&(module['exports']={'Handler':Handler});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{a,b}from"./chunk-AOCUS265.mjs";export{a as Handler,b as default};
1
+ import{a,b}from"./chunk-U4PCKCX6.mjs";export{a as Handler,b as default};
@@ -136,6 +136,14 @@ declare class GameObject {
136
136
  * Update config and sync (for hot-reload)
137
137
  */
138
138
  updateConfig(newConfig: any): void;
139
+ /**
140
+ * Apply anchor from render/transform config (sprites only)
141
+ */
142
+ private applyAnchor;
143
+ /**
144
+ * Apply optional non-uniform scale from effects (if provided)
145
+ */
146
+ private applyEffectsScale;
139
147
  /**
140
148
  * Get component value
141
149
  */
@@ -276,6 +284,10 @@ interface ObjectConfig {
276
284
  background_color?: string;
277
285
  background_alpha?: number;
278
286
  border_color?: string;
287
+ anchor?: {
288
+ x: number;
289
+ y: number;
290
+ };
279
291
  };
280
292
  gameplay?: {
281
293
  rules?: Record<string, unknown>;
@@ -413,42 +425,141 @@ declare function createTutorialLabel(config: ObjectCentricConfig): Text;
413
425
  declare function updateHandAnimation(hand: Sprite, baseCharacterPos: Point, time: number, isDragging: boolean, config: ObjectCentricConfig): void;
414
426
 
415
427
  /**
416
- * Handler SDK - Asset Loader Utilities
428
+ * Handler SDK - Lottie Overlay Helper
417
429
  *
418
- * Asset loading and texture creation utilities for PixiJS.
419
- * Config requirement: All asset paths from config.assets, colors from config.theme.
430
+ * Manages Lottie animations as DOM overlays with config-driven positioning and styling.
431
+ * Student never touches DOM - this helper handles all overlay lifecycle.
432
+ *
433
+ * RULES:
434
+ * - Overlay creation/cleanup is SDK-controlled
435
+ * - Transform/render/effects params come from object config
436
+ * - Lottie JSON comes from Assets system (inline-safe)
437
+ * - Root sandbox discipline maintained
420
438
  *
421
439
  * DO NOT EDIT - Handler SDK Core
422
440
  */
423
441
 
442
+ type AnimationItem = any;
443
+ declare function setLottieInstance(instance: any): void;
424
444
  /**
425
- * Load an asset with fallback placeholder
426
- * Asset path comes from config.assets
445
+ * Play Lottie overlay animation
427
446
  *
428
- * @param path - Asset path
429
- * @param app - PixiJS application instance
430
- * @param fallbackColor - Color for fallback placeholder
431
- * @param isChar - Whether this is a character sprite (affects placeholder shape)
447
+ * @param objectId - Object instance ID (e.g., 'effects_confetti_1')
448
+ * @param root - Root HTML element (from Handler.getRoot())
449
+ * @param config - Object-centric configuration
450
+ * @param Assets - Assets proxy instance (for getting Lottie JSON)
451
+ * @returns Animation item and cleanup function
432
452
  */
433
- declare function loadAsset(path: string, app: any, fallbackColor?: number, isChar?: boolean): Promise<Texture>;
453
+ declare function playLottieOverlay(objectId: string, root: HTMLElement, config: ObjectCentricConfig, Assets: any): {
454
+ animation: AnimationItem;
455
+ cleanup: () => void;
456
+ } | null;
457
+
434
458
  /**
435
- * Load character frames from sprite sheet
436
- * Uses config.assets.character_sprite for path
437
- * Character sheet dimensions come from config (cols: 3, rows: 2)
459
+ * Handler SDK - Object-Centric Asset Loader
438
460
  *
439
- * @param path - Path to the sprite sheet
440
- * @param app - PixiJS application instance
441
- * @param config - Object-centric configuration
461
+ * Asset loading system using object-centric approach.
462
+ * Assets are defined in object configs and loaded by object ID.
463
+ *
464
+ * RULES (LOCKED):
465
+ * - INLINE_ASSETS[objectId] key format (NOT path-based)
466
+ * - Cache key = objectId ONLY
467
+ * - SDK does NOT detect dev/build mode
468
+ * - Build mode injected via __BUILD_MODE__ flag
469
+ * - JSON assets are deep-frozen (immutable)
470
+ * - Dev mode: placeholder on missing
471
+ * - Publish mode: runtime throws (build-time must prevent this)
472
+ *
473
+ * DO NOT EDIT - Handler SDK Core
442
474
  */
443
- declare function loadCharacterFrames(path: string, app: any, config: ObjectCentricConfig | any): Promise<Texture[]>;
475
+ type BuildMode = 'dev' | 'brand' | 'publish';
476
+ type BuildSettings = {
477
+ buildMode?: BuildMode;
478
+ assetsInlined?: boolean;
479
+ };
480
+ declare global {
481
+ interface Window {
482
+ INLINE_ASSETS?: Record<string, string>;
483
+ __BUILD_SETTINGS__?: BuildSettings;
484
+ }
485
+ }
486
+ type AssetDefinition = {
487
+ type: string;
488
+ path: string;
489
+ };
490
+ type TypeLoader = (path: string, inlineData: string | undefined, objectId: string, app: any) => Promise<any>;
491
+ declare function registerType(type: string, loader: TypeLoader): void;
492
+ declare class AssetLoader {
493
+ static load(objectId: string, assetDef: AssetDefinition, app: any): Promise<any>;
494
+ private static loadImage;
495
+ private static loadJSON;
496
+ private static handleFailure;
497
+ }
498
+
444
499
  /**
445
- * Create brush texture
446
- * Uses config.theme.brush_color for color
447
- * Brush size comes from config.gameplay.brush
500
+ * Handler SDK - Asset Cache
501
+ *
502
+ * Centralized cache for all asset data (textures, parsed JSON, inline data).
503
+ * Global, long-lived cache that survives scene resets for performance.
504
+ *
505
+ * RULE: NEVER cleared during normal runtime - only for testing/cleanup
448
506
  *
507
+ * DO NOT EDIT - Handler SDK Core
508
+ */
509
+ /**
510
+ * Global asset cache - stores decoded textures, parsed JSON, inline data
511
+ *
512
+ * Rules:
513
+ * - Global and long-lived
514
+ * - Survives scene resets
515
+ * - NEVER cleared during normal runtime
516
+ * - Only clear() for testing/cleanup scenarios
517
+ */
518
+ declare class AssetCache {
519
+ private static store;
520
+ /**
521
+ * Get cached asset data by ID
522
+ */
523
+ static get(id: string): any;
524
+ /**
525
+ * Set cached asset data by ID
526
+ */
527
+ static set(id: string, data: any): void;
528
+ /**
529
+ * Check if asset is cached
530
+ */
531
+ static has(id: string): boolean;
532
+ /**
533
+ * Clear cache (only for testing/cleanup - NOT used during normal runtime)
534
+ */
535
+ static clear(): void;
536
+ }
537
+
538
+ /**
539
+ * Handler SDK - Object Factory
540
+ *
541
+ * Creates game objects from object configs with asset loading and transform application.
542
+ *
543
+ * DO NOT EDIT - Handler SDK Core
544
+ */
545
+
546
+ /**
547
+ * Create a game object from object config
548
+ *
549
+ * @param objectId - Object instance ID (e.g., 'character_1')
550
+ * @param objectConfig - Object config from ObjectCentricConfig
449
551
  * @param app - PixiJS application instance
450
- * @param config - Object-centric configuration
552
+ * @returns Ready-to-use game object (Sprite, Container, etc.)
451
553
  */
452
- declare function createBrushTexture(app: any, config: ObjectCentricConfig): Texture;
554
+ declare class ObjectFactory {
555
+ /**
556
+ * Create game object from config
557
+ */
558
+ static create(objectId: string, objectConfig: any, app: any): Promise<Container | Sprite | any>;
559
+ /**
560
+ * Apply transform from config to object
561
+ */
562
+ private static applyTransform;
563
+ }
453
564
 
454
- export { type EndGamePanelElements, GameObject, GameObjectManager, type ObjectCentricConfig, type PixiBaseContext, type PixiTheme, Renderer, Transform, animateHandClick, animatePanelEntrance, createBrushTexture, createEndGamePanel, createHandTutorial, createPixiBase, createTutorialLabel, getRegisteredFontIds, loadAsset, loadCharacterFrames, registerFont, resolveFont, resolveFontWeight, updateHandAnimation };
565
+ export { AssetCache, type AssetDefinition, AssetLoader, type EndGamePanelElements, GameObject, GameObjectManager, type ObjectCentricConfig, ObjectFactory, type PixiBaseContext, type PixiTheme, Renderer, Transform, animateHandClick, animatePanelEntrance, createEndGamePanel, createHandTutorial, createPixiBase, createTutorialLabel, getRegisteredFontIds, playLottieOverlay, registerFont, registerType, resolveFont, resolveFontWeight, setLottieInstance, updateHandAnimation };
@@ -136,6 +136,14 @@ declare class GameObject {
136
136
  * Update config and sync (for hot-reload)
137
137
  */
138
138
  updateConfig(newConfig: any): void;
139
+ /**
140
+ * Apply anchor from render/transform config (sprites only)
141
+ */
142
+ private applyAnchor;
143
+ /**
144
+ * Apply optional non-uniform scale from effects (if provided)
145
+ */
146
+ private applyEffectsScale;
139
147
  /**
140
148
  * Get component value
141
149
  */
@@ -276,6 +284,10 @@ interface ObjectConfig {
276
284
  background_color?: string;
277
285
  background_alpha?: number;
278
286
  border_color?: string;
287
+ anchor?: {
288
+ x: number;
289
+ y: number;
290
+ };
279
291
  };
280
292
  gameplay?: {
281
293
  rules?: Record<string, unknown>;
@@ -413,42 +425,141 @@ declare function createTutorialLabel(config: ObjectCentricConfig): Text;
413
425
  declare function updateHandAnimation(hand: Sprite, baseCharacterPos: Point, time: number, isDragging: boolean, config: ObjectCentricConfig): void;
414
426
 
415
427
  /**
416
- * Handler SDK - Asset Loader Utilities
428
+ * Handler SDK - Lottie Overlay Helper
417
429
  *
418
- * Asset loading and texture creation utilities for PixiJS.
419
- * Config requirement: All asset paths from config.assets, colors from config.theme.
430
+ * Manages Lottie animations as DOM overlays with config-driven positioning and styling.
431
+ * Student never touches DOM - this helper handles all overlay lifecycle.
432
+ *
433
+ * RULES:
434
+ * - Overlay creation/cleanup is SDK-controlled
435
+ * - Transform/render/effects params come from object config
436
+ * - Lottie JSON comes from Assets system (inline-safe)
437
+ * - Root sandbox discipline maintained
420
438
  *
421
439
  * DO NOT EDIT - Handler SDK Core
422
440
  */
423
441
 
442
+ type AnimationItem = any;
443
+ declare function setLottieInstance(instance: any): void;
424
444
  /**
425
- * Load an asset with fallback placeholder
426
- * Asset path comes from config.assets
445
+ * Play Lottie overlay animation
427
446
  *
428
- * @param path - Asset path
429
- * @param app - PixiJS application instance
430
- * @param fallbackColor - Color for fallback placeholder
431
- * @param isChar - Whether this is a character sprite (affects placeholder shape)
447
+ * @param objectId - Object instance ID (e.g., 'effects_confetti_1')
448
+ * @param root - Root HTML element (from Handler.getRoot())
449
+ * @param config - Object-centric configuration
450
+ * @param Assets - Assets proxy instance (for getting Lottie JSON)
451
+ * @returns Animation item and cleanup function
432
452
  */
433
- declare function loadAsset(path: string, app: any, fallbackColor?: number, isChar?: boolean): Promise<Texture>;
453
+ declare function playLottieOverlay(objectId: string, root: HTMLElement, config: ObjectCentricConfig, Assets: any): {
454
+ animation: AnimationItem;
455
+ cleanup: () => void;
456
+ } | null;
457
+
434
458
  /**
435
- * Load character frames from sprite sheet
436
- * Uses config.assets.character_sprite for path
437
- * Character sheet dimensions come from config (cols: 3, rows: 2)
459
+ * Handler SDK - Object-Centric Asset Loader
438
460
  *
439
- * @param path - Path to the sprite sheet
440
- * @param app - PixiJS application instance
441
- * @param config - Object-centric configuration
461
+ * Asset loading system using object-centric approach.
462
+ * Assets are defined in object configs and loaded by object ID.
463
+ *
464
+ * RULES (LOCKED):
465
+ * - INLINE_ASSETS[objectId] key format (NOT path-based)
466
+ * - Cache key = objectId ONLY
467
+ * - SDK does NOT detect dev/build mode
468
+ * - Build mode injected via __BUILD_MODE__ flag
469
+ * - JSON assets are deep-frozen (immutable)
470
+ * - Dev mode: placeholder on missing
471
+ * - Publish mode: runtime throws (build-time must prevent this)
472
+ *
473
+ * DO NOT EDIT - Handler SDK Core
442
474
  */
443
- declare function loadCharacterFrames(path: string, app: any, config: ObjectCentricConfig | any): Promise<Texture[]>;
475
+ type BuildMode = 'dev' | 'brand' | 'publish';
476
+ type BuildSettings = {
477
+ buildMode?: BuildMode;
478
+ assetsInlined?: boolean;
479
+ };
480
+ declare global {
481
+ interface Window {
482
+ INLINE_ASSETS?: Record<string, string>;
483
+ __BUILD_SETTINGS__?: BuildSettings;
484
+ }
485
+ }
486
+ type AssetDefinition = {
487
+ type: string;
488
+ path: string;
489
+ };
490
+ type TypeLoader = (path: string, inlineData: string | undefined, objectId: string, app: any) => Promise<any>;
491
+ declare function registerType(type: string, loader: TypeLoader): void;
492
+ declare class AssetLoader {
493
+ static load(objectId: string, assetDef: AssetDefinition, app: any): Promise<any>;
494
+ private static loadImage;
495
+ private static loadJSON;
496
+ private static handleFailure;
497
+ }
498
+
444
499
  /**
445
- * Create brush texture
446
- * Uses config.theme.brush_color for color
447
- * Brush size comes from config.gameplay.brush
500
+ * Handler SDK - Asset Cache
501
+ *
502
+ * Centralized cache for all asset data (textures, parsed JSON, inline data).
503
+ * Global, long-lived cache that survives scene resets for performance.
504
+ *
505
+ * RULE: NEVER cleared during normal runtime - only for testing/cleanup
448
506
  *
507
+ * DO NOT EDIT - Handler SDK Core
508
+ */
509
+ /**
510
+ * Global asset cache - stores decoded textures, parsed JSON, inline data
511
+ *
512
+ * Rules:
513
+ * - Global and long-lived
514
+ * - Survives scene resets
515
+ * - NEVER cleared during normal runtime
516
+ * - Only clear() for testing/cleanup scenarios
517
+ */
518
+ declare class AssetCache {
519
+ private static store;
520
+ /**
521
+ * Get cached asset data by ID
522
+ */
523
+ static get(id: string): any;
524
+ /**
525
+ * Set cached asset data by ID
526
+ */
527
+ static set(id: string, data: any): void;
528
+ /**
529
+ * Check if asset is cached
530
+ */
531
+ static has(id: string): boolean;
532
+ /**
533
+ * Clear cache (only for testing/cleanup - NOT used during normal runtime)
534
+ */
535
+ static clear(): void;
536
+ }
537
+
538
+ /**
539
+ * Handler SDK - Object Factory
540
+ *
541
+ * Creates game objects from object configs with asset loading and transform application.
542
+ *
543
+ * DO NOT EDIT - Handler SDK Core
544
+ */
545
+
546
+ /**
547
+ * Create a game object from object config
548
+ *
549
+ * @param objectId - Object instance ID (e.g., 'character_1')
550
+ * @param objectConfig - Object config from ObjectCentricConfig
449
551
  * @param app - PixiJS application instance
450
- * @param config - Object-centric configuration
552
+ * @returns Ready-to-use game object (Sprite, Container, etc.)
451
553
  */
452
- declare function createBrushTexture(app: any, config: ObjectCentricConfig): Texture;
554
+ declare class ObjectFactory {
555
+ /**
556
+ * Create game object from config
557
+ */
558
+ static create(objectId: string, objectConfig: any, app: any): Promise<Container | Sprite | any>;
559
+ /**
560
+ * Apply transform from config to object
561
+ */
562
+ private static applyTransform;
563
+ }
453
564
 
454
- export { type EndGamePanelElements, GameObject, GameObjectManager, type ObjectCentricConfig, type PixiBaseContext, type PixiTheme, Renderer, Transform, animateHandClick, animatePanelEntrance, createBrushTexture, createEndGamePanel, createHandTutorial, createPixiBase, createTutorialLabel, getRegisteredFontIds, loadAsset, loadCharacterFrames, registerFont, resolveFont, resolveFontWeight, updateHandAnimation };
565
+ export { AssetCache, type AssetDefinition, AssetLoader, type EndGamePanelElements, GameObject, GameObjectManager, type ObjectCentricConfig, ObjectFactory, type PixiBaseContext, type PixiTheme, Renderer, Transform, animateHandClick, animatePanelEntrance, createEndGamePanel, createHandTutorial, createPixiBase, createTutorialLabel, getRegisteredFontIds, playLottieOverlay, registerFont, registerType, resolveFont, resolveFontWeight, setLottieInstance, updateHandAnimation };