handler-playable-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/chunk-CJIYY5BP.mjs +17 -0
- package/dist/index.d.mts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +17 -0
- package/dist/index.mjs +1 -0
- package/dist/pixi/index.d.mts +454 -0
- package/dist/pixi/index.d.ts +454 -0
- package/dist/pixi/index.js +17 -0
- package/dist/pixi/index.mjs +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Handler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @handler/playable-sdk
|
|
2
|
+
|
|
3
|
+
Contract-aligned Handler Playable SDK v0.1. Surface is fixed: `init`, `getRoot`, `on`, `off`, `start`, `finish`, `install`, `emit`. Provides a single root sandbox, canonical event envelope, and ID requirements for publish builds.
|
|
4
|
+
|
|
5
|
+
## API (v0.1)
|
|
6
|
+
|
|
7
|
+
- `Handler.init({ root?, ids, profile, consent })`: creates or adopts a single root. `ids` must include mechanic_id, variant_id, deployment_id, export_id, profile_id, instance_id (instance default “default” only allowed in dev). Consent/telemetry pulled from export profile.
|
|
8
|
+
- `Handler.getRoot()`: returns the sandbox root element.
|
|
9
|
+
- `Handler.on(name, cb)`, `Handler.off(name, cb)`: subscribe/unsubscribe to canonical events or custom namespaced ones.
|
|
10
|
+
- `Handler.start()`, `Handler.finish()`: lifecycle markers.
|
|
11
|
+
- `Handler.install(url?)`: emits `cta_click` and, if profile policy demands, `conversion`. Direct network open is deferred to capability policy.
|
|
12
|
+
- `Handler.emit(name, payload)`: emits canonical or namespaced custom events. Reserved envelope keys are always added/overwritten.
|
|
13
|
+
|
|
14
|
+
Canonical event mapping from Smoud: `interaction -> engagement`, `finish -> complete`, `install -> cta_click (+conversion policy)`, `pause/resume/resize/volume` mapped 1:1 inside the envelope. Custom events must use `custom.<mechanic_id>.<event>`.
|
|
15
|
+
|
|
16
|
+
## Build
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm run build
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Outputs ESM/CJS + d.ts to `dist/`.
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
|
|
26
|
+
MIT
|
|
@@ -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.1.0",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"}},scripts:{build:"tsup src/index.ts src/pixi/index.ts --format cjs,esm --dts --clean --minify",lint:"eslint 'src/**/*.{ts,tsx}'",typecheck:"tsc --noEmit",prepublishOnly:"npm run build"},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"},peerDependenciesMeta:{"pixi.js":{optional:!0}},devDependencies:{eslint:"^8.57.1","pixi.js":"^8.8.1","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 fe(){return r===te}function pe(){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,j="",b=Math.floor(window.innerWidth),h=Math.floor(window.innerHeight),K=b>h,l=!1,k=!1,be=!1,he=!1,U=!1,M=null;function _e(){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 N(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=N(e),i=Te(n,t);P(n,i),n!==e&&P(e,i)}function O(){M&&(M(b,h),M=null)}function _(e){B=e,o("volume",e)}function v(e){e&&(ke=!0),!T&&(T=!0,o("pause"),_(0))}function S(e){!e&&ke||T&&(T=!1,o("resume"),_(B))}function p(e,t){b=Math.floor(e||window.innerWidth),h=Math.floor(t||window.innerHeight),K=b>h,o("resize",{width:b,height:h})}function Le(){if(ce())try{let e=mraid.getMaxSize();p(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();p(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")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();p(e.width,e.height),dapi.addEventListener("viewableChange",n=>{n.isViewable?S():v()}),dapi.addEventListener("adResized",n=>{let i=dapi.getScreenSize();p(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())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 ve(){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,f.start()))};window.addEventListener("resize",()=>p()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"?(S(),e()):v()}),document.readyState==="complete"||document.readyState==="interactive"?e():window.addEventListener("load",e),z=!0}function Pe(){let e=t=>{typeof TouchEvent!="undefined"&&t instanceof TouchEvent&&(be=!0),!(be&&t instanceof MouseEvent)&&(W+=1,o("interaction",W))};document.addEventListener("mousedown",e),document.addEventListener("touchstart",e)}function Re(e){var i,c,x,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())(x=(c=window.TJ_API)==null?void 0:c.click)==null||x.call(c);else if(fe())(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(pe()){let m=window.ExitApi;m&&typeof m.exit=="function"?m.exit(e||j||""):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 Me(){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 x;((x=c==null?void 0:c.payload)==null?void 0:x.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 Ne(){if(!y())return;let e=window.TJ_API;e&&e.setPlayableAPI&&e.setPlayableAPI({skipAd:()=>{try{f.finish()}catch(t){console.warn("Tapjoy skip failed",t)}}})}function xe(){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 je(){g()&&(window.mintGameStart=()=>{S(!0),p()},window.mintGameClose=()=>{v(!0)})}function ze(){if(!F())return;let e=window.NUC;!e||!e.trigger||(f.on("cta_click",()=>{var t,n;return(n=(t=e.trigger).convert)==null?void 0:n.call(t,j)}),f.on("complete",()=>{var t,n;return(n=(t=e.trigger).tryAgain)==null?void 0:n.call(t)}))}var f={init(e={},t){if(Ae=e.profile||"web_embed",De=e.consent||{},A={...Ee,...e.ids||{}},w=e.rootEl||w,j=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,_e(),Ve(w),we(),Le(),Ie(),!z){if(document.readyState==="complete")ve();else if(!he){he=!0;let n=()=>{ve(),window.removeEventListener("load",n),document.removeEventListener("DOMContentLoaded",n)};window.addEventListener("load",n),document.addEventListener("DOMContentLoaded",n)}}Pe(),Me(),Ne(),je(),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,f.start()),d=!0),d=l},getRoot(){return _e()},get version(){return R.version||"0.0.0"},get maxWidth(){return b},get maxHeight(){return h},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(N(e),t)},off(e,t){V(N(e),t)},start(){var e,t;if(!G){if(!l){k=!0;return}if(G=!0,o("start"),p(),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: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()&&xe())},install(e){if(!E){E=!0,y()?(xe(),setTimeout(()=>f.install(e),300)):(o("complete"),setTimeout(()=>f.install(e),0));return}U||(U=!0,setTimeout(()=>U=!1,500),o("cta_click"),o("conversion"),Re(e||j))},emit(e,t){let n=N(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(){v(!0)},resume(){S(!0)},resize(e,t){p(e,t)}},Be=f;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{f as a,Be as b};
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
const mraid: any;
|
|
3
|
+
const dapi: any;
|
|
4
|
+
const AD_PROTOCOL: string;
|
|
5
|
+
const AD_NETWORK: string;
|
|
6
|
+
}
|
|
7
|
+
type IDs = {
|
|
8
|
+
mechanic_id: string;
|
|
9
|
+
variant_id: string;
|
|
10
|
+
deployment_id: string;
|
|
11
|
+
export_id: string;
|
|
12
|
+
profile_id: string;
|
|
13
|
+
instance_id: string;
|
|
14
|
+
};
|
|
15
|
+
type Consent = {
|
|
16
|
+
analytics?: boolean;
|
|
17
|
+
personalization?: boolean;
|
|
18
|
+
};
|
|
19
|
+
type InitOptions = {
|
|
20
|
+
rootEl?: HTMLElement;
|
|
21
|
+
ids?: Partial<IDs>;
|
|
22
|
+
profile?: 'web_embed' | 'mraid' | string;
|
|
23
|
+
consent?: Consent;
|
|
24
|
+
destinationUrl?: string;
|
|
25
|
+
};
|
|
26
|
+
declare const Handler: {
|
|
27
|
+
init(options?: InitOptions, callback?: (w: number, h: number) => void): void;
|
|
28
|
+
getRoot(): HTMLElement;
|
|
29
|
+
readonly version: any;
|
|
30
|
+
readonly maxWidth: number;
|
|
31
|
+
readonly maxHeight: number;
|
|
32
|
+
readonly isLandscape: boolean;
|
|
33
|
+
readonly isReady: boolean;
|
|
34
|
+
readonly isStarted: boolean;
|
|
35
|
+
readonly isPaused: boolean;
|
|
36
|
+
readonly isFinished: boolean;
|
|
37
|
+
readonly volume: number;
|
|
38
|
+
readonly interactions: number;
|
|
39
|
+
on(event: string, fn: (...args: any[]) => void): void;
|
|
40
|
+
off(event: string, fn?: (...args: any[]) => void): void;
|
|
41
|
+
start(): void;
|
|
42
|
+
finish(): void;
|
|
43
|
+
install(url?: string): void;
|
|
44
|
+
emit(name: string, payload?: any): void;
|
|
45
|
+
retry(): void;
|
|
46
|
+
pause(): void;
|
|
47
|
+
resume(): void;
|
|
48
|
+
resize(width?: number, height?: number): void;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { Handler, Handler as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
const mraid: any;
|
|
3
|
+
const dapi: any;
|
|
4
|
+
const AD_PROTOCOL: string;
|
|
5
|
+
const AD_NETWORK: string;
|
|
6
|
+
}
|
|
7
|
+
type IDs = {
|
|
8
|
+
mechanic_id: string;
|
|
9
|
+
variant_id: string;
|
|
10
|
+
deployment_id: string;
|
|
11
|
+
export_id: string;
|
|
12
|
+
profile_id: string;
|
|
13
|
+
instance_id: string;
|
|
14
|
+
};
|
|
15
|
+
type Consent = {
|
|
16
|
+
analytics?: boolean;
|
|
17
|
+
personalization?: boolean;
|
|
18
|
+
};
|
|
19
|
+
type InitOptions = {
|
|
20
|
+
rootEl?: HTMLElement;
|
|
21
|
+
ids?: Partial<IDs>;
|
|
22
|
+
profile?: 'web_embed' | 'mraid' | string;
|
|
23
|
+
consent?: Consent;
|
|
24
|
+
destinationUrl?: string;
|
|
25
|
+
};
|
|
26
|
+
declare const Handler: {
|
|
27
|
+
init(options?: InitOptions, callback?: (w: number, h: number) => void): void;
|
|
28
|
+
getRoot(): HTMLElement;
|
|
29
|
+
readonly version: any;
|
|
30
|
+
readonly maxWidth: number;
|
|
31
|
+
readonly maxHeight: number;
|
|
32
|
+
readonly isLandscape: boolean;
|
|
33
|
+
readonly isReady: boolean;
|
|
34
|
+
readonly isStarted: boolean;
|
|
35
|
+
readonly isPaused: boolean;
|
|
36
|
+
readonly isFinished: boolean;
|
|
37
|
+
readonly volume: number;
|
|
38
|
+
readonly interactions: number;
|
|
39
|
+
on(event: string, fn: (...args: any[]) => void): void;
|
|
40
|
+
off(event: string, fn?: (...args: any[]) => void): void;
|
|
41
|
+
start(): void;
|
|
42
|
+
finish(): void;
|
|
43
|
+
install(url?: string): void;
|
|
44
|
+
emit(name: string, payload?: any): void;
|
|
45
|
+
retry(): void;
|
|
46
|
+
pause(): void;
|
|
47
|
+
resume(): void;
|
|
48
|
+
resize(width?: number, height?: number): void;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { Handler, Handler as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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 f={};function I(e,t,n=!1){f[e]||(f[e]=[]),f[e].push({fn:t,once:n})}function H(e,t){if(f[e]){if(!t){delete f[e];return}f[e]=f[e].filter(n=>n.fn!==t)}}function P(e,...t){let n=f[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.1.0",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"}},scripts:{build:"tsup src/index.ts src/pixi/index.ts --format cjs,esm --dts --clean --minify",lint:"eslint 'src/**/*.{ts,tsx}'",typecheck:"tsc --noEmit",prepublishOnly:"npm run build"},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"},peerDependenciesMeta:{"pixi.js":{optional:!0}},devDependencies:{eslint:"^8.57.1","pixi.js":"^8.8.1","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 fe(){return r===te}function pe(){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 be(){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"},Ne=Math.random().toString(36).slice(2),w=null,A={...Ae},ke="web_embed",je={},U=!1,E=!1,T=!1,Te=!1,J=1,K=0,z=!1,l=!1,j="",b=Math.floor(window.innerWidth),h=Math.floor(window.innerHeight),B=b>h,c=!1,k=!1,he=!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 N(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:Ne,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=N(e),i=Oe(n,t);P(n,i),n!==e&&P(e,i)}function O(){M&&(M(b,h),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 p(e,t){b=Math.floor(e||window.innerWidth),h=Math.floor(t||window.innerHeight),B=b>h,o("resize",{width:b,height:h})}function ze(){if(ue())try{let e=mraid.getMaxSize();p(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();p(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(fe())try{let e=dapi.getScreenSize();p(e.width,e.height),dapi.addEventListener("viewableChange",n=>{n.isViewable?S():v()}),dapi.addEventListener("adResized",n=>{let i=dapi.getScreenSize();p(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",()=>p()),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&&(he=!0),!(he&&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(pe())(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||j||""):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),p()},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,j)}),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",je=e.consent||{},A={...Ae,...e.ids||{}},w=e.rootEl||w,j=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),be(),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 b},get maxHeight(){return h},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(N(e),t)},off(e,t){H(N(e),t)},start(){var e,t;if(!U){if(!c){k=!0;return}if(U=!0,o("start"),p(),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||j))},emit(e,t){let n=N(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){p(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});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b}from"./chunk-CJIYY5BP.mjs";export{a as Handler,b as default};
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { Application, Container, Texture, Sprite, Text, Graphics, Point } from 'pixi.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler SDK - PixiJS Base Context
|
|
5
|
+
*
|
|
6
|
+
* Creates the base PixiJS application with Handler SDK lifecycle integration.
|
|
7
|
+
* Handles resize, pause/resume, and provides the overlay for UI elements.
|
|
8
|
+
*
|
|
9
|
+
* DO NOT EDIT - Handler SDK Core
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Theme configuration for PixiJS base
|
|
14
|
+
*/
|
|
15
|
+
type PixiTheme = {
|
|
16
|
+
background?: string;
|
|
17
|
+
text?: string;
|
|
18
|
+
text_muted?: string;
|
|
19
|
+
primary?: string;
|
|
20
|
+
cta_text?: string;
|
|
21
|
+
surface_shadow?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Context returned by createPixiBase
|
|
25
|
+
*/
|
|
26
|
+
type PixiBaseContext = {
|
|
27
|
+
app: Application;
|
|
28
|
+
stage: Application['stage'];
|
|
29
|
+
overlay: HTMLElement;
|
|
30
|
+
applySize: (size?: {
|
|
31
|
+
width?: number;
|
|
32
|
+
height?: number;
|
|
33
|
+
}) => void;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Create the base PixiJS context with Handler SDK integration
|
|
37
|
+
*
|
|
38
|
+
* @param root - The root HTML element to render into (from Handler.getRoot())
|
|
39
|
+
* @param theme - Optional theme configuration
|
|
40
|
+
* @returns PixiJS application context with overlay
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const root = Handler.getRoot();
|
|
45
|
+
* const { app, stage, overlay } = await createPixiBase(root, {
|
|
46
|
+
* background: '#160a17',
|
|
47
|
+
* text: '#fef4dd',
|
|
48
|
+
* primary: '#ffb43b'
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function createPixiBase(root: HTMLElement, theme?: PixiTheme): Promise<PixiBaseContext>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Handler SDK - GameObject System
|
|
56
|
+
*
|
|
57
|
+
* Unity-style component-based architecture for PixiJS objects.
|
|
58
|
+
* Automatically syncs config values to PixiJS objects and enables hot-reload.
|
|
59
|
+
*
|
|
60
|
+
* DO NOT EDIT - Handler SDK Core
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Transform Component - Position, scale, rotation
|
|
65
|
+
*/
|
|
66
|
+
declare class Transform {
|
|
67
|
+
position: {
|
|
68
|
+
x: number;
|
|
69
|
+
y: number;
|
|
70
|
+
};
|
|
71
|
+
scale: number;
|
|
72
|
+
rotation: number;
|
|
73
|
+
constructor(config?: {
|
|
74
|
+
position?: {
|
|
75
|
+
x: number;
|
|
76
|
+
y: number;
|
|
77
|
+
};
|
|
78
|
+
scale?: number;
|
|
79
|
+
rotation?: number;
|
|
80
|
+
});
|
|
81
|
+
update(config: {
|
|
82
|
+
position?: {
|
|
83
|
+
x: number;
|
|
84
|
+
y: number;
|
|
85
|
+
};
|
|
86
|
+
scale?: number;
|
|
87
|
+
rotation?: number;
|
|
88
|
+
}): void;
|
|
89
|
+
syncToPixi(pixiObject: Container | any): void;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Renderer Component - Visual properties
|
|
93
|
+
*/
|
|
94
|
+
declare class Renderer {
|
|
95
|
+
z_index: number;
|
|
96
|
+
alpha: number;
|
|
97
|
+
visible: boolean;
|
|
98
|
+
tint: number | null;
|
|
99
|
+
constructor(config?: {
|
|
100
|
+
z_index?: number;
|
|
101
|
+
alpha?: number;
|
|
102
|
+
visible?: boolean;
|
|
103
|
+
tint?: number | null;
|
|
104
|
+
});
|
|
105
|
+
update(config: {
|
|
106
|
+
z_index?: number;
|
|
107
|
+
alpha?: number;
|
|
108
|
+
visible?: boolean;
|
|
109
|
+
tint?: number | null;
|
|
110
|
+
}): void;
|
|
111
|
+
syncToPixi(pixiObject: Container | any): void;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Base GameObject class - Unity-style entity with components
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const characterGO = gameObjectManager.create('character_1', characterSprite);
|
|
119
|
+
* characterGO.setPosition(100, 200);
|
|
120
|
+
* characterGO.setAlpha(0.8);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare class GameObject {
|
|
124
|
+
instanceId: string;
|
|
125
|
+
objectConfig: string;
|
|
126
|
+
pixiObject: Container | any;
|
|
127
|
+
transform: Transform;
|
|
128
|
+
renderer: Renderer;
|
|
129
|
+
private _config;
|
|
130
|
+
constructor(instanceId: string, objectConfig: string, pixiObject: Container | any, config: any);
|
|
131
|
+
/**
|
|
132
|
+
* Sync all components to PixiJS object
|
|
133
|
+
*/
|
|
134
|
+
sync(): void;
|
|
135
|
+
/**
|
|
136
|
+
* Update config and sync (for hot-reload)
|
|
137
|
+
*/
|
|
138
|
+
updateConfig(newConfig: any): void;
|
|
139
|
+
/**
|
|
140
|
+
* Get component value
|
|
141
|
+
*/
|
|
142
|
+
getComponent<T>(componentName: string): T | undefined;
|
|
143
|
+
/**
|
|
144
|
+
* Get transform position
|
|
145
|
+
*/
|
|
146
|
+
getPosition(): {
|
|
147
|
+
x: number;
|
|
148
|
+
y: number;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Set transform position
|
|
152
|
+
*/
|
|
153
|
+
setPosition(x: number, y: number): void;
|
|
154
|
+
/**
|
|
155
|
+
* Get renderer alpha
|
|
156
|
+
*/
|
|
157
|
+
getAlpha(): number;
|
|
158
|
+
/**
|
|
159
|
+
* Set renderer alpha
|
|
160
|
+
*/
|
|
161
|
+
setAlpha(alpha: number): void;
|
|
162
|
+
/**
|
|
163
|
+
* Get renderer visible
|
|
164
|
+
*/
|
|
165
|
+
getVisible(): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Set renderer visible
|
|
168
|
+
*/
|
|
169
|
+
setVisible(visible: boolean): void;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* GameObject Manager - Manages all game objects and enables hot-reload
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const gameObjectManager = new GameObjectManager(config);
|
|
177
|
+
* const characterGO = gameObjectManager.create('character_1', characterSprite);
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
declare class GameObjectManager {
|
|
181
|
+
private objects;
|
|
182
|
+
private config;
|
|
183
|
+
constructor(config: any);
|
|
184
|
+
/**
|
|
185
|
+
* Create a GameObject from config
|
|
186
|
+
*/
|
|
187
|
+
create(instanceId: string, pixiObject: Container | any): GameObject;
|
|
188
|
+
/**
|
|
189
|
+
* Get GameObject by instance ID
|
|
190
|
+
*/
|
|
191
|
+
get(instanceId: string): GameObject | undefined;
|
|
192
|
+
/**
|
|
193
|
+
* Update config and sync all objects (for hot-reload)
|
|
194
|
+
*/
|
|
195
|
+
updateConfig(newConfig: any): void;
|
|
196
|
+
/**
|
|
197
|
+
* Get all GameObjects
|
|
198
|
+
*/
|
|
199
|
+
getAll(): GameObject[];
|
|
200
|
+
/**
|
|
201
|
+
* Remove GameObject
|
|
202
|
+
*/
|
|
203
|
+
remove(instanceId: string): void;
|
|
204
|
+
/**
|
|
205
|
+
* Clear all GameObjects
|
|
206
|
+
*/
|
|
207
|
+
clear(): void;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Handler SDK - Font Registry
|
|
212
|
+
*
|
|
213
|
+
* Maps font IDs to actual font families/paths.
|
|
214
|
+
* UI config references fonts by ID only (e.g., "brand.primary").
|
|
215
|
+
* This registry resolves IDs to actual font values.
|
|
216
|
+
*
|
|
217
|
+
* Font paths and platform differences are handled here, NOT in config.
|
|
218
|
+
*
|
|
219
|
+
* DO NOT EDIT - Handler SDK Core
|
|
220
|
+
*/
|
|
221
|
+
type FontDefinition = {
|
|
222
|
+
family: string;
|
|
223
|
+
weight?: string | number;
|
|
224
|
+
style?: string;
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Resolve font ID to font family string
|
|
228
|
+
* @param fontId Font ID from UI config (e.g., "brand.primary")
|
|
229
|
+
* @returns CSS font-family string
|
|
230
|
+
*/
|
|
231
|
+
declare function resolveFont(fontId: string): string;
|
|
232
|
+
/**
|
|
233
|
+
* Resolve font ID to font weight
|
|
234
|
+
* @param fontId Font ID from UI config
|
|
235
|
+
* @returns Font weight (string or number)
|
|
236
|
+
*/
|
|
237
|
+
declare function resolveFontWeight(fontId: string): string | number;
|
|
238
|
+
/**
|
|
239
|
+
* Register a new font (for engine initialization)
|
|
240
|
+
* @param fontId Font ID
|
|
241
|
+
* @param definition Font definition
|
|
242
|
+
*/
|
|
243
|
+
declare function registerFont(fontId: string, definition: FontDefinition): void;
|
|
244
|
+
/**
|
|
245
|
+
* Get all registered font IDs
|
|
246
|
+
*/
|
|
247
|
+
declare function getRegisteredFontIds(): string[];
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Handler SDK - Type Definitions for PixiJS Integration
|
|
251
|
+
*
|
|
252
|
+
* DO NOT EDIT - Handler SDK Core
|
|
253
|
+
*/
|
|
254
|
+
/**
|
|
255
|
+
* Object configuration from JSON files
|
|
256
|
+
*/
|
|
257
|
+
interface ObjectConfig {
|
|
258
|
+
object_config?: string;
|
|
259
|
+
transform?: {
|
|
260
|
+
position?: {
|
|
261
|
+
x: number;
|
|
262
|
+
y: number;
|
|
263
|
+
};
|
|
264
|
+
scale?: number;
|
|
265
|
+
rotation?: number;
|
|
266
|
+
offset?: {
|
|
267
|
+
x?: number;
|
|
268
|
+
y?: number;
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
render?: {
|
|
272
|
+
z_index?: number;
|
|
273
|
+
alpha?: number;
|
|
274
|
+
visible?: boolean;
|
|
275
|
+
tint?: number | string | null;
|
|
276
|
+
background_color?: string;
|
|
277
|
+
background_alpha?: number;
|
|
278
|
+
border_color?: string;
|
|
279
|
+
};
|
|
280
|
+
gameplay?: {
|
|
281
|
+
rules?: Record<string, unknown>;
|
|
282
|
+
tuning?: Record<string, unknown>;
|
|
283
|
+
};
|
|
284
|
+
ui?: {
|
|
285
|
+
text?: string;
|
|
286
|
+
font?: string;
|
|
287
|
+
fontSize?: number;
|
|
288
|
+
letterSpacing?: number;
|
|
289
|
+
align?: string;
|
|
290
|
+
};
|
|
291
|
+
effects?: Record<string, unknown>;
|
|
292
|
+
audio?: Record<string, unknown>;
|
|
293
|
+
physics?: Record<string, unknown>;
|
|
294
|
+
interaction?: Record<string, unknown>;
|
|
295
|
+
identity?: Record<string, unknown>;
|
|
296
|
+
visibility?: Record<string, unknown>;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Engine configuration
|
|
300
|
+
*/
|
|
301
|
+
interface EngineConfig {
|
|
302
|
+
assets?: Record<string, string>;
|
|
303
|
+
runtime?: {
|
|
304
|
+
ui?: Record<string, unknown>;
|
|
305
|
+
theme?: Record<string, unknown>;
|
|
306
|
+
ui_styles?: Record<string, unknown>;
|
|
307
|
+
timeline?: Record<string, number>;
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Theme configuration
|
|
312
|
+
*/
|
|
313
|
+
interface ThemeConfig {
|
|
314
|
+
background_color?: string;
|
|
315
|
+
text_color?: string;
|
|
316
|
+
square_color?: string;
|
|
317
|
+
cta_background?: string;
|
|
318
|
+
cta_text?: string;
|
|
319
|
+
melt_color?: string;
|
|
320
|
+
danger_color?: string;
|
|
321
|
+
brush_color?: string;
|
|
322
|
+
success_color?: string;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Gameplay configuration
|
|
326
|
+
*/
|
|
327
|
+
interface GameplayConfig {
|
|
328
|
+
[key: string]: unknown;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Object-centric configuration
|
|
332
|
+
* This is the main config type that students work with
|
|
333
|
+
*/
|
|
334
|
+
interface ObjectCentricConfig {
|
|
335
|
+
/** Map of object instance IDs to their configurations */
|
|
336
|
+
objects: Map<string, ObjectConfig>;
|
|
337
|
+
/** Engine configuration (assets, runtime settings) */
|
|
338
|
+
engine: EngineConfig;
|
|
339
|
+
/** Theme configuration */
|
|
340
|
+
theme: ThemeConfig;
|
|
341
|
+
/** Gameplay configuration */
|
|
342
|
+
gameplay: GameplayConfig;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Handler SDK - EndGame UI Panel
|
|
347
|
+
*
|
|
348
|
+
* Success screen with logo, text, CTA button, and tutorial hand.
|
|
349
|
+
* Fully configurable via UI config system.
|
|
350
|
+
*
|
|
351
|
+
* DO NOT EDIT - Handler SDK Core
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
interface EndGamePanelElements {
|
|
355
|
+
panel: Container;
|
|
356
|
+
logo: Sprite;
|
|
357
|
+
title: Text;
|
|
358
|
+
subtitle: Text;
|
|
359
|
+
footer: Text;
|
|
360
|
+
ctaButton: Graphics;
|
|
361
|
+
ctaText: Text;
|
|
362
|
+
ctaHint: Text;
|
|
363
|
+
hand: Sprite;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Create EndGame success panel with all UI elements
|
|
367
|
+
*/
|
|
368
|
+
declare function createEndGamePanel(config: ObjectCentricConfig, handTexture: Texture | null, logoTexture: Texture | null): EndGamePanelElements;
|
|
369
|
+
/**
|
|
370
|
+
* Animate panel entrance with staggered animations
|
|
371
|
+
*/
|
|
372
|
+
declare function animatePanelEntrance(elements: EndGamePanelElements, config: ObjectCentricConfig, onComplete?: () => void): void;
|
|
373
|
+
/**
|
|
374
|
+
* Animate tutorial hand clicking CTA button
|
|
375
|
+
*/
|
|
376
|
+
declare function animateHandClick(hand: Sprite, ctaButton: Graphics, config: ObjectCentricConfig, onClick: () => void): void;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Handler SDK - Tutorial UI Components
|
|
380
|
+
*
|
|
381
|
+
* Tutorial hand and label components for game tutorials.
|
|
382
|
+
* Config requirement: All UI properties from object-centric config.
|
|
383
|
+
*
|
|
384
|
+
* DO NOT EDIT - Handler SDK Core
|
|
385
|
+
*/
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Create hand tutorial sprite
|
|
389
|
+
* Hand properties from object-centric config (hand_tutorial_1)
|
|
390
|
+
*
|
|
391
|
+
* @param handTexture - Texture for the hand sprite
|
|
392
|
+
* @param config - Object-centric configuration
|
|
393
|
+
* @param baseCharacterPos - Base position of the character for animation reference
|
|
394
|
+
*/
|
|
395
|
+
declare function createHandTutorial(handTexture: Texture, config: ObjectCentricConfig, baseCharacterPos: Point): Sprite;
|
|
396
|
+
/**
|
|
397
|
+
* Create tutorial label text
|
|
398
|
+
* Uses ui.tutorial config object with UI component schema
|
|
399
|
+
*
|
|
400
|
+
* @param config - Object-centric configuration
|
|
401
|
+
*/
|
|
402
|
+
declare function createTutorialLabel(config: ObjectCentricConfig): Text;
|
|
403
|
+
/**
|
|
404
|
+
* Update hand animation
|
|
405
|
+
* Animation parameters from object-centric config (hand_tutorial_1)
|
|
406
|
+
*
|
|
407
|
+
* @param hand - The hand sprite
|
|
408
|
+
* @param baseCharacterPos - Base character position
|
|
409
|
+
* @param time - Current time for animation
|
|
410
|
+
* @param isDragging - Whether the user is currently dragging
|
|
411
|
+
* @param config - Object-centric configuration
|
|
412
|
+
*/
|
|
413
|
+
declare function updateHandAnimation(hand: Sprite, baseCharacterPos: Point, time: number, isDragging: boolean, config: ObjectCentricConfig): void;
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Handler SDK - Asset Loader Utilities
|
|
417
|
+
*
|
|
418
|
+
* Asset loading and texture creation utilities for PixiJS.
|
|
419
|
+
* Config requirement: All asset paths from config.assets, colors from config.theme.
|
|
420
|
+
*
|
|
421
|
+
* DO NOT EDIT - Handler SDK Core
|
|
422
|
+
*/
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Load an asset with fallback placeholder
|
|
426
|
+
* Asset path comes from config.assets
|
|
427
|
+
*
|
|
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)
|
|
432
|
+
*/
|
|
433
|
+
declare function loadAsset(path: string, app: any, fallbackColor?: number, isChar?: boolean): Promise<Texture>;
|
|
434
|
+
/**
|
|
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)
|
|
438
|
+
*
|
|
439
|
+
* @param path - Path to the sprite sheet
|
|
440
|
+
* @param app - PixiJS application instance
|
|
441
|
+
* @param config - Object-centric configuration
|
|
442
|
+
*/
|
|
443
|
+
declare function loadCharacterFrames(path: string, app: any, config: ObjectCentricConfig): Promise<Texture[]>;
|
|
444
|
+
/**
|
|
445
|
+
* Create brush texture
|
|
446
|
+
* Uses config.theme.brush_color for color
|
|
447
|
+
* Brush size comes from config.gameplay.brush
|
|
448
|
+
*
|
|
449
|
+
* @param app - PixiJS application instance
|
|
450
|
+
* @param config - Object-centric configuration
|
|
451
|
+
*/
|
|
452
|
+
declare function createBrushTexture(app: any, config: ObjectCentricConfig): Texture;
|
|
453
|
+
|
|
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 };
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { Application, Container, Texture, Sprite, Text, Graphics, Point } from 'pixi.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler SDK - PixiJS Base Context
|
|
5
|
+
*
|
|
6
|
+
* Creates the base PixiJS application with Handler SDK lifecycle integration.
|
|
7
|
+
* Handles resize, pause/resume, and provides the overlay for UI elements.
|
|
8
|
+
*
|
|
9
|
+
* DO NOT EDIT - Handler SDK Core
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Theme configuration for PixiJS base
|
|
14
|
+
*/
|
|
15
|
+
type PixiTheme = {
|
|
16
|
+
background?: string;
|
|
17
|
+
text?: string;
|
|
18
|
+
text_muted?: string;
|
|
19
|
+
primary?: string;
|
|
20
|
+
cta_text?: string;
|
|
21
|
+
surface_shadow?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Context returned by createPixiBase
|
|
25
|
+
*/
|
|
26
|
+
type PixiBaseContext = {
|
|
27
|
+
app: Application;
|
|
28
|
+
stage: Application['stage'];
|
|
29
|
+
overlay: HTMLElement;
|
|
30
|
+
applySize: (size?: {
|
|
31
|
+
width?: number;
|
|
32
|
+
height?: number;
|
|
33
|
+
}) => void;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Create the base PixiJS context with Handler SDK integration
|
|
37
|
+
*
|
|
38
|
+
* @param root - The root HTML element to render into (from Handler.getRoot())
|
|
39
|
+
* @param theme - Optional theme configuration
|
|
40
|
+
* @returns PixiJS application context with overlay
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const root = Handler.getRoot();
|
|
45
|
+
* const { app, stage, overlay } = await createPixiBase(root, {
|
|
46
|
+
* background: '#160a17',
|
|
47
|
+
* text: '#fef4dd',
|
|
48
|
+
* primary: '#ffb43b'
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function createPixiBase(root: HTMLElement, theme?: PixiTheme): Promise<PixiBaseContext>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Handler SDK - GameObject System
|
|
56
|
+
*
|
|
57
|
+
* Unity-style component-based architecture for PixiJS objects.
|
|
58
|
+
* Automatically syncs config values to PixiJS objects and enables hot-reload.
|
|
59
|
+
*
|
|
60
|
+
* DO NOT EDIT - Handler SDK Core
|
|
61
|
+
*/
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Transform Component - Position, scale, rotation
|
|
65
|
+
*/
|
|
66
|
+
declare class Transform {
|
|
67
|
+
position: {
|
|
68
|
+
x: number;
|
|
69
|
+
y: number;
|
|
70
|
+
};
|
|
71
|
+
scale: number;
|
|
72
|
+
rotation: number;
|
|
73
|
+
constructor(config?: {
|
|
74
|
+
position?: {
|
|
75
|
+
x: number;
|
|
76
|
+
y: number;
|
|
77
|
+
};
|
|
78
|
+
scale?: number;
|
|
79
|
+
rotation?: number;
|
|
80
|
+
});
|
|
81
|
+
update(config: {
|
|
82
|
+
position?: {
|
|
83
|
+
x: number;
|
|
84
|
+
y: number;
|
|
85
|
+
};
|
|
86
|
+
scale?: number;
|
|
87
|
+
rotation?: number;
|
|
88
|
+
}): void;
|
|
89
|
+
syncToPixi(pixiObject: Container | any): void;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Renderer Component - Visual properties
|
|
93
|
+
*/
|
|
94
|
+
declare class Renderer {
|
|
95
|
+
z_index: number;
|
|
96
|
+
alpha: number;
|
|
97
|
+
visible: boolean;
|
|
98
|
+
tint: number | null;
|
|
99
|
+
constructor(config?: {
|
|
100
|
+
z_index?: number;
|
|
101
|
+
alpha?: number;
|
|
102
|
+
visible?: boolean;
|
|
103
|
+
tint?: number | null;
|
|
104
|
+
});
|
|
105
|
+
update(config: {
|
|
106
|
+
z_index?: number;
|
|
107
|
+
alpha?: number;
|
|
108
|
+
visible?: boolean;
|
|
109
|
+
tint?: number | null;
|
|
110
|
+
}): void;
|
|
111
|
+
syncToPixi(pixiObject: Container | any): void;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Base GameObject class - Unity-style entity with components
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const characterGO = gameObjectManager.create('character_1', characterSprite);
|
|
119
|
+
* characterGO.setPosition(100, 200);
|
|
120
|
+
* characterGO.setAlpha(0.8);
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
declare class GameObject {
|
|
124
|
+
instanceId: string;
|
|
125
|
+
objectConfig: string;
|
|
126
|
+
pixiObject: Container | any;
|
|
127
|
+
transform: Transform;
|
|
128
|
+
renderer: Renderer;
|
|
129
|
+
private _config;
|
|
130
|
+
constructor(instanceId: string, objectConfig: string, pixiObject: Container | any, config: any);
|
|
131
|
+
/**
|
|
132
|
+
* Sync all components to PixiJS object
|
|
133
|
+
*/
|
|
134
|
+
sync(): void;
|
|
135
|
+
/**
|
|
136
|
+
* Update config and sync (for hot-reload)
|
|
137
|
+
*/
|
|
138
|
+
updateConfig(newConfig: any): void;
|
|
139
|
+
/**
|
|
140
|
+
* Get component value
|
|
141
|
+
*/
|
|
142
|
+
getComponent<T>(componentName: string): T | undefined;
|
|
143
|
+
/**
|
|
144
|
+
* Get transform position
|
|
145
|
+
*/
|
|
146
|
+
getPosition(): {
|
|
147
|
+
x: number;
|
|
148
|
+
y: number;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Set transform position
|
|
152
|
+
*/
|
|
153
|
+
setPosition(x: number, y: number): void;
|
|
154
|
+
/**
|
|
155
|
+
* Get renderer alpha
|
|
156
|
+
*/
|
|
157
|
+
getAlpha(): number;
|
|
158
|
+
/**
|
|
159
|
+
* Set renderer alpha
|
|
160
|
+
*/
|
|
161
|
+
setAlpha(alpha: number): void;
|
|
162
|
+
/**
|
|
163
|
+
* Get renderer visible
|
|
164
|
+
*/
|
|
165
|
+
getVisible(): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Set renderer visible
|
|
168
|
+
*/
|
|
169
|
+
setVisible(visible: boolean): void;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* GameObject Manager - Manages all game objects and enables hot-reload
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const gameObjectManager = new GameObjectManager(config);
|
|
177
|
+
* const characterGO = gameObjectManager.create('character_1', characterSprite);
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
declare class GameObjectManager {
|
|
181
|
+
private objects;
|
|
182
|
+
private config;
|
|
183
|
+
constructor(config: any);
|
|
184
|
+
/**
|
|
185
|
+
* Create a GameObject from config
|
|
186
|
+
*/
|
|
187
|
+
create(instanceId: string, pixiObject: Container | any): GameObject;
|
|
188
|
+
/**
|
|
189
|
+
* Get GameObject by instance ID
|
|
190
|
+
*/
|
|
191
|
+
get(instanceId: string): GameObject | undefined;
|
|
192
|
+
/**
|
|
193
|
+
* Update config and sync all objects (for hot-reload)
|
|
194
|
+
*/
|
|
195
|
+
updateConfig(newConfig: any): void;
|
|
196
|
+
/**
|
|
197
|
+
* Get all GameObjects
|
|
198
|
+
*/
|
|
199
|
+
getAll(): GameObject[];
|
|
200
|
+
/**
|
|
201
|
+
* Remove GameObject
|
|
202
|
+
*/
|
|
203
|
+
remove(instanceId: string): void;
|
|
204
|
+
/**
|
|
205
|
+
* Clear all GameObjects
|
|
206
|
+
*/
|
|
207
|
+
clear(): void;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Handler SDK - Font Registry
|
|
212
|
+
*
|
|
213
|
+
* Maps font IDs to actual font families/paths.
|
|
214
|
+
* UI config references fonts by ID only (e.g., "brand.primary").
|
|
215
|
+
* This registry resolves IDs to actual font values.
|
|
216
|
+
*
|
|
217
|
+
* Font paths and platform differences are handled here, NOT in config.
|
|
218
|
+
*
|
|
219
|
+
* DO NOT EDIT - Handler SDK Core
|
|
220
|
+
*/
|
|
221
|
+
type FontDefinition = {
|
|
222
|
+
family: string;
|
|
223
|
+
weight?: string | number;
|
|
224
|
+
style?: string;
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Resolve font ID to font family string
|
|
228
|
+
* @param fontId Font ID from UI config (e.g., "brand.primary")
|
|
229
|
+
* @returns CSS font-family string
|
|
230
|
+
*/
|
|
231
|
+
declare function resolveFont(fontId: string): string;
|
|
232
|
+
/**
|
|
233
|
+
* Resolve font ID to font weight
|
|
234
|
+
* @param fontId Font ID from UI config
|
|
235
|
+
* @returns Font weight (string or number)
|
|
236
|
+
*/
|
|
237
|
+
declare function resolveFontWeight(fontId: string): string | number;
|
|
238
|
+
/**
|
|
239
|
+
* Register a new font (for engine initialization)
|
|
240
|
+
* @param fontId Font ID
|
|
241
|
+
* @param definition Font definition
|
|
242
|
+
*/
|
|
243
|
+
declare function registerFont(fontId: string, definition: FontDefinition): void;
|
|
244
|
+
/**
|
|
245
|
+
* Get all registered font IDs
|
|
246
|
+
*/
|
|
247
|
+
declare function getRegisteredFontIds(): string[];
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Handler SDK - Type Definitions for PixiJS Integration
|
|
251
|
+
*
|
|
252
|
+
* DO NOT EDIT - Handler SDK Core
|
|
253
|
+
*/
|
|
254
|
+
/**
|
|
255
|
+
* Object configuration from JSON files
|
|
256
|
+
*/
|
|
257
|
+
interface ObjectConfig {
|
|
258
|
+
object_config?: string;
|
|
259
|
+
transform?: {
|
|
260
|
+
position?: {
|
|
261
|
+
x: number;
|
|
262
|
+
y: number;
|
|
263
|
+
};
|
|
264
|
+
scale?: number;
|
|
265
|
+
rotation?: number;
|
|
266
|
+
offset?: {
|
|
267
|
+
x?: number;
|
|
268
|
+
y?: number;
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
render?: {
|
|
272
|
+
z_index?: number;
|
|
273
|
+
alpha?: number;
|
|
274
|
+
visible?: boolean;
|
|
275
|
+
tint?: number | string | null;
|
|
276
|
+
background_color?: string;
|
|
277
|
+
background_alpha?: number;
|
|
278
|
+
border_color?: string;
|
|
279
|
+
};
|
|
280
|
+
gameplay?: {
|
|
281
|
+
rules?: Record<string, unknown>;
|
|
282
|
+
tuning?: Record<string, unknown>;
|
|
283
|
+
};
|
|
284
|
+
ui?: {
|
|
285
|
+
text?: string;
|
|
286
|
+
font?: string;
|
|
287
|
+
fontSize?: number;
|
|
288
|
+
letterSpacing?: number;
|
|
289
|
+
align?: string;
|
|
290
|
+
};
|
|
291
|
+
effects?: Record<string, unknown>;
|
|
292
|
+
audio?: Record<string, unknown>;
|
|
293
|
+
physics?: Record<string, unknown>;
|
|
294
|
+
interaction?: Record<string, unknown>;
|
|
295
|
+
identity?: Record<string, unknown>;
|
|
296
|
+
visibility?: Record<string, unknown>;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Engine configuration
|
|
300
|
+
*/
|
|
301
|
+
interface EngineConfig {
|
|
302
|
+
assets?: Record<string, string>;
|
|
303
|
+
runtime?: {
|
|
304
|
+
ui?: Record<string, unknown>;
|
|
305
|
+
theme?: Record<string, unknown>;
|
|
306
|
+
ui_styles?: Record<string, unknown>;
|
|
307
|
+
timeline?: Record<string, number>;
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Theme configuration
|
|
312
|
+
*/
|
|
313
|
+
interface ThemeConfig {
|
|
314
|
+
background_color?: string;
|
|
315
|
+
text_color?: string;
|
|
316
|
+
square_color?: string;
|
|
317
|
+
cta_background?: string;
|
|
318
|
+
cta_text?: string;
|
|
319
|
+
melt_color?: string;
|
|
320
|
+
danger_color?: string;
|
|
321
|
+
brush_color?: string;
|
|
322
|
+
success_color?: string;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Gameplay configuration
|
|
326
|
+
*/
|
|
327
|
+
interface GameplayConfig {
|
|
328
|
+
[key: string]: unknown;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Object-centric configuration
|
|
332
|
+
* This is the main config type that students work with
|
|
333
|
+
*/
|
|
334
|
+
interface ObjectCentricConfig {
|
|
335
|
+
/** Map of object instance IDs to their configurations */
|
|
336
|
+
objects: Map<string, ObjectConfig>;
|
|
337
|
+
/** Engine configuration (assets, runtime settings) */
|
|
338
|
+
engine: EngineConfig;
|
|
339
|
+
/** Theme configuration */
|
|
340
|
+
theme: ThemeConfig;
|
|
341
|
+
/** Gameplay configuration */
|
|
342
|
+
gameplay: GameplayConfig;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Handler SDK - EndGame UI Panel
|
|
347
|
+
*
|
|
348
|
+
* Success screen with logo, text, CTA button, and tutorial hand.
|
|
349
|
+
* Fully configurable via UI config system.
|
|
350
|
+
*
|
|
351
|
+
* DO NOT EDIT - Handler SDK Core
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
interface EndGamePanelElements {
|
|
355
|
+
panel: Container;
|
|
356
|
+
logo: Sprite;
|
|
357
|
+
title: Text;
|
|
358
|
+
subtitle: Text;
|
|
359
|
+
footer: Text;
|
|
360
|
+
ctaButton: Graphics;
|
|
361
|
+
ctaText: Text;
|
|
362
|
+
ctaHint: Text;
|
|
363
|
+
hand: Sprite;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Create EndGame success panel with all UI elements
|
|
367
|
+
*/
|
|
368
|
+
declare function createEndGamePanel(config: ObjectCentricConfig, handTexture: Texture | null, logoTexture: Texture | null): EndGamePanelElements;
|
|
369
|
+
/**
|
|
370
|
+
* Animate panel entrance with staggered animations
|
|
371
|
+
*/
|
|
372
|
+
declare function animatePanelEntrance(elements: EndGamePanelElements, config: ObjectCentricConfig, onComplete?: () => void): void;
|
|
373
|
+
/**
|
|
374
|
+
* Animate tutorial hand clicking CTA button
|
|
375
|
+
*/
|
|
376
|
+
declare function animateHandClick(hand: Sprite, ctaButton: Graphics, config: ObjectCentricConfig, onClick: () => void): void;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Handler SDK - Tutorial UI Components
|
|
380
|
+
*
|
|
381
|
+
* Tutorial hand and label components for game tutorials.
|
|
382
|
+
* Config requirement: All UI properties from object-centric config.
|
|
383
|
+
*
|
|
384
|
+
* DO NOT EDIT - Handler SDK Core
|
|
385
|
+
*/
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Create hand tutorial sprite
|
|
389
|
+
* Hand properties from object-centric config (hand_tutorial_1)
|
|
390
|
+
*
|
|
391
|
+
* @param handTexture - Texture for the hand sprite
|
|
392
|
+
* @param config - Object-centric configuration
|
|
393
|
+
* @param baseCharacterPos - Base position of the character for animation reference
|
|
394
|
+
*/
|
|
395
|
+
declare function createHandTutorial(handTexture: Texture, config: ObjectCentricConfig, baseCharacterPos: Point): Sprite;
|
|
396
|
+
/**
|
|
397
|
+
* Create tutorial label text
|
|
398
|
+
* Uses ui.tutorial config object with UI component schema
|
|
399
|
+
*
|
|
400
|
+
* @param config - Object-centric configuration
|
|
401
|
+
*/
|
|
402
|
+
declare function createTutorialLabel(config: ObjectCentricConfig): Text;
|
|
403
|
+
/**
|
|
404
|
+
* Update hand animation
|
|
405
|
+
* Animation parameters from object-centric config (hand_tutorial_1)
|
|
406
|
+
*
|
|
407
|
+
* @param hand - The hand sprite
|
|
408
|
+
* @param baseCharacterPos - Base character position
|
|
409
|
+
* @param time - Current time for animation
|
|
410
|
+
* @param isDragging - Whether the user is currently dragging
|
|
411
|
+
* @param config - Object-centric configuration
|
|
412
|
+
*/
|
|
413
|
+
declare function updateHandAnimation(hand: Sprite, baseCharacterPos: Point, time: number, isDragging: boolean, config: ObjectCentricConfig): void;
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Handler SDK - Asset Loader Utilities
|
|
417
|
+
*
|
|
418
|
+
* Asset loading and texture creation utilities for PixiJS.
|
|
419
|
+
* Config requirement: All asset paths from config.assets, colors from config.theme.
|
|
420
|
+
*
|
|
421
|
+
* DO NOT EDIT - Handler SDK Core
|
|
422
|
+
*/
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Load an asset with fallback placeholder
|
|
426
|
+
* Asset path comes from config.assets
|
|
427
|
+
*
|
|
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)
|
|
432
|
+
*/
|
|
433
|
+
declare function loadAsset(path: string, app: any, fallbackColor?: number, isChar?: boolean): Promise<Texture>;
|
|
434
|
+
/**
|
|
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)
|
|
438
|
+
*
|
|
439
|
+
* @param path - Path to the sprite sheet
|
|
440
|
+
* @param app - PixiJS application instance
|
|
441
|
+
* @param config - Object-centric configuration
|
|
442
|
+
*/
|
|
443
|
+
declare function loadCharacterFrames(path: string, app: any, config: ObjectCentricConfig): Promise<Texture[]>;
|
|
444
|
+
/**
|
|
445
|
+
* Create brush texture
|
|
446
|
+
* Uses config.theme.brush_color for color
|
|
447
|
+
* Brush size comes from config.gameplay.brush
|
|
448
|
+
*
|
|
449
|
+
* @param app - PixiJS application instance
|
|
450
|
+
* @param config - Object-centric configuration
|
|
451
|
+
*/
|
|
452
|
+
declare function createBrushTexture(app: any, config: ObjectCentricConfig): Texture;
|
|
453
|
+
|
|
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 };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";var Ke=Object.defineProperty;var Ka=Object.getOwnPropertyDescriptor;var $a=Object.getOwnPropertyNames;var Ja=Object.prototype.hasOwnProperty;var Qa=(e,t)=>{for(var n in t)Ke(e,n,{get:t[n],enumerable:!0})},Za=(e,t,n,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $a(t))!Ja.call(e,o)&&o!==n&&Ke(e,o,{get:()=>t[o],enumerable:!(a=Ka(t,o))||a.enumerable});return e};var Ua=e=>Za(Ke({},"__esModule",{value:!0}),e);var bi={};Qa(bi,{GameObject:()=>Ae,GameObjectManager:()=>Ie,Renderer:()=>Ce,Transform:()=>Se,animateHandClick:()=>ia,animatePanelEntrance:()=>aa,createBrushTexture:()=>ca,createEndGamePanel:()=>na,createHandTutorial:()=>oa,createPixiBase:()=>Un,createTutorialLabel:()=>sa,getRegisteredFontIds:()=>ta,loadAsset:()=>at,loadCharacterFrames:()=>la,registerFont:()=>ea,resolveFont:()=>G,resolveFontWeight:()=>j,updateHandAnimation:()=>ra});module.exports=Ua(bi);var Zn=require("pixi.js");var ee={};function Re(e,t,n=!1){ee[e]||(ee[e]=[]),ee[e].push({fn:t,once:n})}function $e(e,t){if(ee[e]){if(!t){delete ee[e];return}ee[e]=ee[e].filter(n=>n.fn!==t)}}function ze(e,...t){let n=ee[e];if(n)for(let a of[...n])a.fn(...t),a.once&&$e(e,a.fn)}function W(e,t){Re(e,t,!0)}var He={name:"handler-playable-sdk",version:"0.1.0",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"}},scripts:{build:"tsup src/index.ts src/pixi/index.ts --format cjs,esm --dts --clean --minify",lint:"eslint 'src/**/*.{ts,tsx}'",typecheck:"tsc --noEmit",prepublishOnly:"npm run build"},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"},peerDependenciesMeta:{"pixi.js":{optional:!0}},devDependencies:{eslint:"^8.57.1","pixi.js":"^8.8.1","ts-node":"^10.9.2",tsup:"^8.4.0",typescript:"^5.7.2"}};var N=0,ti=N++,Sn=N++,Cn=N++,An=N++,En=N++,kn=N++,Dn=N++,Pn=N++,Mn=N++,Fn=N++,Ln=N++,Rn=N++,_=ti;function zn(){return _===Sn}function Hn(){return _===Cn}function On(){return _===An}function Wn(){return _===En}function de(){return _===kn}function ue(){return _===Dn}function Nn(){return _===Pn}function Yn(){return _===Mn}function Bn(){return _===Fn}function Je(){return _===Ln}function Qe(){return _===Rn}function In(){let e=typeof AD_PROTOCOL!="undefined"?AD_PROTOCOL:"none",t=typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed";if(e==="mraid")try{mraid.getState(),_=Sn;return}catch{}else if(e==="dapi")try{dapi.isReady(),_=Cn;return}catch{}if(t==="facebook")try{typeof FbPlayableAd!="undefined"&&(_=An)}catch{}else if(t==="google")try{typeof ExitApi!="undefined"&&(_=En)}catch{}else if(t==="mintegral")window.gameReady&&(_=kn);else if(t==="tapjoy")window.TJ_API&&(_=Dn);else if(t==="tiktok")window.openAppStore&&(_=Pn);else if(t==="smadex")try{window.smxTracking&&(_=Mn)}catch{}else if(t==="snapchat")try{window.ScPlayableAd&&(_=Fn)}catch{}else t==="vungle"?_=Ln:(e==="nucleo"||t==="nucleo")&&(_=Rn)}var Kn={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"},ni=Math.random().toString(36).slice(2),pe=null,be={...Kn},$n="web_embed",ai={},Ze=!1,_e=!1,xe=!1,Jn=!1,nt=1,et=0,Ye=!1,J=!1,Ne="",fe=Math.floor(window.innerWidth),me=Math.floor(window.innerHeight),tt=fe>me,Q=!1,we=!1,Gn=!1,jn=!1,Ue=!1,Oe=null;function Vn(){if(pe)return pe;let e=document.createElement("div");return e.id="handler-root",e.setAttribute("data-handler-root","true"),document.body.appendChild(e),pe=e,e}function We(e){switch(e){case"interaction":return"engagement";case"finish":return"complete";case"install":return"cta_click";default:return e}}function Qn(e,t){return{event_name:e,ts:Date.now(),session_id:ni,deployment_id:be.deployment_id,variant_id:be.variant_id,export_profile_id:be.profile_id,instance_id:be.instance_id||"default",env:$n==="mraid"?"mraid":"web",payload:t}}function y(e,t){let n=We(e),a=Qn(n,t);ze(n,a),n!==e&&ze(e,a)}function Te(){Oe&&(Oe(fe,me),Oe=null)}function he(e){nt=e,y("volume",e)}function ye(e){e&&(Jn=!0),!xe&&(xe=!0,y("pause"),he(0))}function ve(e){!e&&Jn||xe&&(xe=!1,y("resume"),he(nt))}function ne(e,t){fe=Math.floor(e||window.innerWidth),me=Math.floor(t||window.innerHeight),tt=fe>me,y("resize",{width:fe,height:me})}function ii(){if(zn())try{let e=mraid.getMaxSize();ne(e.width,e.height);let t=()=>{mraid.isViewable()&&mraid.getState()!=="hidden"?ve():ye()};if(mraid.addEventListener("viewableChange",t),mraid.addEventListener("stateChange",t),mraid.addEventListener("sizeChange",()=>{let n=mraid.getMaxSize();ne(n.width,n.height)}),mraid.getAudioVolume){let n=mraid.getAudioVolume();he(n?1:0)}if(mraid.addEventListener("audioVolumeChange",n=>{n!==null&&he(n>0?1:0)}),mraid.addEventListener("error",(n,a)=>{console.warn("mraid error:",n,"action:",a)}),Ye=!0,mraid.isViewable()&&mraid.getState()!=="hidden")Q=!0,y("boot"),y("view"),y("ready"),J=!0,Te();else{let n=()=>{Q=!0,y("boot"),y("view"),y("ready"),J=!0,Te()};mraid.addEventListener("ready",n)}}catch(e){console.warn("MRAID hook skipped",e)}}function oi(){if(Hn())try{let e=dapi.getScreenSize();ne(e.width,e.height),dapi.addEventListener("viewableChange",n=>{n.isViewable?ve():ye()}),dapi.addEventListener("adResized",n=>{let a=dapi.getScreenSize();ne(n.width||a.width,n.height||a.height)});let t=dapi.getAudioVolume();if(he(t?1:0),dapi.addEventListener("audioVolumeChange",n=>he(n?1:0)),Ye=!0,dapi.isViewable())Q=!0,y("boot"),y("view"),y("ready"),J=!0,Te();else{let n=()=>{Q=!0,y("boot"),y("view"),y("ready"),J=!0,Te()};dapi.addEventListener("ready",n)}}catch(e){console.warn("DAPI hook skipped",e)}}function qn(){let e=()=>{Q||document.visibilityState==="visible"&&(document.readyState==="complete"||document.readyState==="interactive")&&(Q=!0,y("boot"),y("view"),y("ready"),J=!0,Te(),we&&(we=!1,te.start()))};window.addEventListener("resize",()=>ne()),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"?(ve(),e()):ye()}),document.readyState==="complete"||document.readyState==="interactive"?e():window.addEventListener("load",e),Ye=!0}function si(){let e=t=>{typeof TouchEvent!="undefined"&&t instanceof TouchEvent&&(Gn=!0),!(Gn&&t instanceof MouseEvent)&&(et+=1,y("interaction",et))};document.addEventListener("mousedown",e),document.addEventListener("touchstart",e)}function ri(e){var a,o,i,s,r,l,d,p,f,u,c,h;let t=typeof AD_PROTOCOL!="undefined"?AD_PROTOCOL:"none";if((typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed")==="google")try{(a=window.ExitApi)==null||a.exit();return}catch{}if(t==="mraid"&&typeof mraid!="undefined")mraid.open(e||"");else if(t==="dapi"&&typeof dapi!="undefined")dapi.openStoreUrl();else if(ue())(i=(o=window.TJ_API)==null?void 0:o.click)==null||i.call(o);else if(On())(r=(s=window.FbPlayableAd)==null?void 0:s.onCTAClick)==null||r.call(s);else if(Bn())(d=(l=window.ScPlayableAd)==null?void 0:l.onCTAClick)==null||d.call(l);else if(Yn())try{(f=(p=window.smxTracking)==null?void 0:p.redirect)==null||f.call(p)}catch(m){console.warn("Smadex redirect failed",m)}else if(Wn()){let m=window.ExitApi;m&&typeof m.exit=="function"?m.exit(e||Ne||""):e&&window.open(e)}else de()?(u=window.install)==null||u.call(window):Nn()?(c=window.openAppStore)==null||c.call(window):Je()?(h=parent==null?void 0:parent.postMessage)==null||h.call(parent,"download","*"):e&&window.open(e)}function li(){let e=typeof AD_NETWORK!="undefined"?AD_NETWORK:"web_embed",t=n=>{if(!n)return;let a=new Image;a.src=n};if(e==="bigabid"){let n=window.BIGABID_BIDTIMEMACROS;if(!n)return;W("view",()=>t(n.mraid_viewable)),W("start",()=>t(n.game_viewable)),W("engagement",()=>t(n.engagement));let a=()=>t(n.complete);W("complete",a),Re("engagement",o=>{var i;((i=o==null?void 0:o.payload)==null?void 0:i.count)>3&&a()}),W("cta_click",()=>t(n.click))}else if(e==="inmobi"){let n=window.INMOBI_DSPMACROS;if(!n)return;W("view",()=>t(n.Ad_Load_Start)),W("start",()=>t(n.Ad_Viewable)),W("engagement",()=>t(n.First_Engagement)),W("complete",()=>t(n.Gameplay_Complete)),W("cta_click",()=>t(n.DSP_Click)),W("start",()=>{[5,10,15,20,25,30].forEach(a=>setTimeout(()=>t(n[`Spent_${a}_Seconds`]),a*1e3))})}}function ci(){if(!ue())return;let e=window.TJ_API;e&&e.setPlayableAPI&&e.setPlayableAPI({skipAd:()=>{try{te.finish()}catch(t){console.warn("Tapjoy skip failed",t)}}})}function Xn(){var t,n,a;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),(a=e==null?void 0:e.gameplayFinished)==null||a.call(e)}function di(){de()&&(window.mintGameStart=()=>{ve(!0),ne()},window.mintGameClose=()=>{ye(!0)})}function ui(){if(!Qe())return;let e=window.NUC;!e||!e.trigger||(te.on("cta_click",()=>{var t,n;return(n=(t=e.trigger).convert)==null?void 0:n.call(t,Ne)}),te.on("complete",()=>{var t,n;return(n=(t=e.trigger).tryAgain)==null?void 0:n.call(t)}))}var te={init(e={},t){if($n=e.profile||"web_embed",ai=e.consent||{},be={...Kn,...e.ids||{}},pe=e.rootEl||pe,Ne=e.destinationUrl||(/android/i.test(navigator.userAgent)?"https://play.google.com/store":"https://www.apple.com/app-store/"),t&&(Oe=t),y("init"),document.body.oncontextmenu=()=>!1,Vn(),pi(pe),In(),ii(),oi(),!Ye){if(document.readyState==="complete")qn();else if(!jn){jn=!0;let n=()=>{qn(),window.removeEventListener("load",n),document.removeEventListener("DOMContentLoaded",n)};window.addEventListener("load",n),document.addEventListener("DOMContentLoaded",n)}}si(),li(),ci(),di(),ui(),console.log(`%c @handler/playable-sdk %c v${He.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;"),Q&&!J&&(y("boot"),y("view"),y("ready"),we&&(we=!1,te.start()),J=!0),J=Q},getRoot(){return Vn()},get version(){return He.version||"0.0.0"},get maxWidth(){return fe},get maxHeight(){return me},get isLandscape(){return tt},get isReady(){return J},get isStarted(){return Ze},get isPaused(){return xe},get isFinished(){return _e},get volume(){return nt},get interactions(){return et},on(e,t){Re(We(e),t)},off(e,t){$e(We(e),t)},start(){var e,t;if(!Ze){if(!Q){we=!0;return}if(Ze=!0,y("start"),ne(),de())ye(),(e=window.gameReady)==null||e.call(window);else if(ue()){let n=window.TJ_API;(t=n==null?void 0:n.setPlayableBuild)==null||t.call(n,{orientation:tt?"landscape":"portrait",buildID:He.version||"dev"})}}},finish(){var e,t;_e||(_e=!0,y("complete"),de()?(e=window.gameEnd)==null||e.call(window):Je()?(t=parent==null?void 0:parent.postMessage)==null||t.call(parent,"complete","*"):ue()&&Xn())},install(e){if(!_e){_e=!0,ue()?(Xn(),setTimeout(()=>te.install(e),300)):(y("complete"),setTimeout(()=>te.install(e),0));return}Ue||(Ue=!0,setTimeout(()=>Ue=!1,500),y("cta_click"),y("conversion"),ri(e||Ne))},emit(e,t){let n=We(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 a=Qn(n,t);ze(n,a)},retry(){var e,t,n;if(de())(e=window.gameRetry)==null||e.call(window);else if(Qe()){let a=window.NUC;(n=(t=a==null?void 0:a.trigger)==null?void 0:t.tryAgain)==null||n.call(t)}y("engagement",{action:"retry"})},pause(){ye(!0)},resume(){ve(!0)},resize(e,t){ne(e,t)}},Be=te;function pi(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)}async function Un(e,t={}){let n=new Zn.Application;await n.init({resizeTo:e,autoDensity:!0,resolution:window.devicePixelRatio||1,antialias:!0,backgroundAlpha:0});let a=i=>{var l,d,p,f,u,c;let s=(p=(d=(l=i==null?void 0:i.width)!=null?l:e.clientWidth)!=null?d:window.innerWidth)!=null?p:320,r=(c=(u=(f=i==null?void 0:i.height)!=null?f:e.clientHeight)!=null?u:window.innerHeight)!=null?c:480;n.renderer.resize(s,r)};e.innerHTML="",e.style.position="relative",e.style.display="flex",e.style.flexDirection="column",e.style.alignItems="stretch",e.style.width="100%",e.style.height="100dvh",e.style.minHeight="100vh",e.style.maxWidth="100%",e.style.maxHeight="100%",e.style.boxSizing="border-box",e.style.overflow="hidden",t.background&&(e.style.background=t.background),e.appendChild(n.canvas);let o=document.createElement("div");return o.setAttribute("style",["position:absolute","inset:0","display:flex","flex-direction:column","align-items:center","justify-content:flex-start","gap:12px","pointer-events:none","font-family:Arial,sans-serif","padding:20px 16px","padding-bottom:clamp(24px, 6vh, 96px)","box-sizing:border-box","z-index:2"].join(";")),e.appendChild(o),Be.on("pause",()=>{n.ticker.stop(),document.querySelectorAll("audio").forEach(s=>s.pause())}),Be.on("resume",()=>{n.ticker.start(),document.querySelectorAll("audio").forEach(s=>{s.currentTime>0&&!s.ended&&s.play().catch(()=>{})})}),Be.on("resize",({payload:i})=>{a({width:i==null?void 0:i.width,height:i==null?void 0:i.height})}),window.addEventListener("resize",()=>a()),requestAnimationFrame(()=>a()),{app:n,stage:n.stage,overlay:o,applySize:a}}var Se=class{constructor(t){var n,a;this.position=(t==null?void 0:t.position)||{x:0,y:0},this.scale=(n=t==null?void 0:t.scale)!=null?n:1,this.rotation=(a=t==null?void 0:t.rotation)!=null?a:0}update(t){t.position!==void 0&&(this.position={...t.position}),t.scale!==void 0&&(this.scale=t.scale),t.rotation!==void 0&&(this.rotation=t.rotation)}syncToPixi(t){t.position.set(this.position.x,this.position.y),t.scale.set(this.scale),t.rotation=this.rotation}},Ce=class{constructor(t){var n,a,o,i;this.z_index=(n=t==null?void 0:t.z_index)!=null?n:0,this.alpha=(a=t==null?void 0:t.alpha)!=null?a:1,this.visible=(o=t==null?void 0:t.visible)!=null?o:!0,this.tint=(i=t==null?void 0:t.tint)!=null?i:null}update(t){t.z_index!==void 0&&(this.z_index=t.z_index),t.alpha!==void 0&&(this.alpha=t.alpha),t.visible!==void 0&&(this.visible=t.visible),t.tint!==void 0&&(this.tint=t.tint)}syncToPixi(t){t.zIndex=this.z_index,t.alpha=this.alpha,t.visible=this.visible,this.tint!==null&&"tint"in t&&(t.tint=this.tint)}},Ae=class{constructor(t,n,a,o){this.instanceId=t,this.objectConfig=n,this.pixiObject=a,this._config=o,this.transform=new Se(o.transform),this.renderer=new Ce(o.render),this.sync()}sync(){this.transform.syncToPixi(this.pixiObject),this.renderer.syncToPixi(this.pixiObject)}updateConfig(t){this._config=t,t.transform&&this.transform.update(t.transform),t.render&&this.renderer.update(t.render),this.sync()}getComponent(t){return this._config[t]}getPosition(){return{...this.transform.position}}setPosition(t,n){this.transform.position={x:t,y:n},this.transform.syncToPixi(this.pixiObject)}getAlpha(){return this.renderer.alpha}setAlpha(t){this.renderer.alpha=t,this.renderer.syncToPixi(this.pixiObject)}getVisible(){return this.renderer.visible}setVisible(t){this.renderer.visible=t,this.renderer.syncToPixi(this.pixiObject)}},Ie=class{constructor(t){this.objects=new Map;this.config=t}create(t,n){let a=this.config.objects.get(t);if(!a)throw new Error(`Object config not found: ${t}`);let o=new Ae(t,a.object_config||t,n,a);return this.objects.set(t,o),o}get(t){return this.objects.get(t)}updateConfig(t){this.config=t;for(let[n,a]of this.objects.entries()){let o=t.objects.get(n);o&&a.updateConfig(o)}}getAll(){return Array.from(this.objects.values())}remove(t){this.objects.delete(t)}clear(){this.objects.clear()}};var Ge={"brand.primary":{family:"Arial, sans-serif",weight:"400"},"brand.warning":{family:"Arial Black, Arial, sans-serif",weight:"900"},"brand.heading":{family:"Arial Black, Arial, sans-serif",weight:"800"},"brand.body":{family:"Arial, sans-serif",weight:"400"}};function G(e){let t=Ge[e];return t?t.family:(console.warn(`Font ID "${e}" not found in registry, using fallback`),"Arial, sans-serif")}function j(e){var n;let t=Ge[e];return t&&(n=t.weight)!=null?n:"400"}function ea(e,t){Ge[e]=t}function ta(){return Object.keys(Ge)}var w=require("pixi.js");function na(e,t,n){var ht,yt,gt,_t,bt,wt,xt,Tt,vt,St,Ct,At,Et,kt,Dt,Pt,Mt,Ft,Lt,Rt,zt,Ht,Ot,Wt,Nt,Yt,Bt,It,Gt,jt,Vt,qt,Xt,Kt,$t,Jt,Qt,Zt,Ut,en,tn,nn,an,on,sn,rn,ln,cn,dn,un,pn,fn,mn,hn,yn,gn,_n,bn,wn,xn;let a=e.objects.get("ui_endgame_1"),o=e.objects.get("ui_endgame_logo_1"),i=e.objects.get("ui_endgame_title_1"),s=e.objects.get("ui_endgame_subtitle_1"),r=e.objects.get("ui_endgame_footer_1"),l=e.objects.get("ui_endgame_cta_1"),d=e.objects.get("ui_endgame_cta_hint_1"),p=e.objects.get("ui_endgame_hand_1"),f=e.engine.runtime||{},u=new w.Container;u.alpha=0,u.visible=!1;let c=((ht=a==null?void 0:a.gameplay)==null?void 0:ht.tuning)||{},h=(a==null?void 0:a.render)||{},m=(yt=c.panel_width)!=null?yt:320,g=(gt=c.panel_height)!=null?gt:400,x=(_t=c.panel_padding)!=null?_t:32,T=(bt=c.panel_radius)!=null?bt:24,A=h.background_color||c.panel_bg_color||"#1a0a0a",v=h.background_alpha!==void 0&&h.background_alpha!==null?h.background_alpha:(wt=c.panel_bg_alpha)!=null?wt:.98,E=h.border_color||c.panel_border_color||"#ffffff",k=(xt=c.panel_border_width)!=null?xt:2,S=(Tt=c.panel_border_alpha)!=null?Tt:.3,C=new w.Graphics;C.roundRect(-m/2,-g/2,m,g,T);let b=A.replace("#","");C.fill({color:parseInt(b,16),alpha:v});let D=E.replace("#","");C.stroke({color:parseInt(D,16),width:k,alpha:S});let L=new w.Graphics;L.roundRect(-m/2+2,-g/2+2,m-4,g-4,T-2),L.stroke({color:16777215,width:1,alpha:.1}),C.addChild(L),u.addChild(C);let V=((vt=o==null?void 0:o.gameplay)==null?void 0:vt.tuning)||{},Z=(o==null?void 0:o.transform)||{},Y=(St=V.logo_size)!=null?St:56,q=(Ct=Z.scale)!=null?Ct:1,ae=(Et=(At=Z.offset)==null?void 0:At.y)!=null?Et:-130,da=(kt=V.logo_alpha)!=null?kt:1,M=new w.Sprite(n||w.Texture.EMPTY);M.anchor.set(.5);let oe=0,se=0;if(n&&n!==w.Texture.EMPTY){let F=n.frame,$=n.baseTexture;F&&F.width&&F.height?(oe=F.width,se=F.height):$&&$.width&&$.height?(oe=$.width,se=$.height):n.width&&n.height&&(oe=n.width,se=n.height)}if(oe>0&&se>0){let F=oe/se,$,Xe;F>1?($=Y,Xe=Y/F):(Xe=Y,$=Y*F);let Tn=$/oe,vn=Xe/se;Tn*=q,vn*=q,M.scale.set(Tn,vn)}else{let F=Y/100*q;M.scale.set(F)}M.position.set(0,ae),M.alpha=0,M.visible=!0,M.targetAlpha=da,M.baseScaleX=M.scale.x,M.baseScaleY=M.scale.y,u.addChild(M);let R=i==null?void 0:i.ui,B=((Dt=i==null?void 0:i.gameplay)==null?void 0:Dt.tuning)||{},ua=(R==null?void 0:R.text)||"MISSION ACCOMPLISHED",it=(R==null?void 0:R.font)||"brand.heading",pa=(R==null?void 0:R.fontSize)||24,fa=(Pt=R==null?void 0:R.letterSpacing)!=null?Pt:1,Ee=(Mt=i==null?void 0:i.render)==null?void 0:Mt.tint,ma=typeof Ee=="string"?Ee:Ee?`#${Ee.toString(16).padStart(6,"0")}`:"#00FF88",ot=m-x*2-30,ha=B.font_weight_override?B.font_weight_override:j(it),U=new w.Text({text:ua,style:{fontFamily:G(it),fontSize:pa,fontWeight:ha,fill:ma,align:"center",letterSpacing:fa,wordWrap:!1,stroke:{color:B.stroke_color||"#000000",width:(Ft=B.stroke_width)!=null?Ft:2},dropShadow:{color:B.shadow_color||"#000000",alpha:(Lt=B.shadow_alpha)!=null?Lt:.9,angle:(Rt=B.shadow_angle)!=null?Rt:0,blur:(zt=B.shadow_blur)!=null?zt:8,distance:(Ht=B.shadow_distance)!=null?Ht:4}}});if(U.width>ot){let F=ot/U.width;U.scale.set(F)}U.anchor.set(.5);let st=(Ot=c.title_offset_y)!=null?Ot:30,ya=st+((Wt=B.animation_start_y_offset)!=null?Wt:-20);U.position.set(0,ya),U.alpha=0,u.addChild(U);let z=s==null?void 0:s.ui,rt=((Nt=s==null?void 0:s.gameplay)==null?void 0:Nt.tuning)||{},ga=(z==null?void 0:z.text)||"RESCUE COMPLETE",lt=(z==null?void 0:z.font)||"brand.body",_a=(z==null?void 0:z.fontSize)||11,ba=(Yt=z==null?void 0:z.letterSpacing)!=null?Yt:.5,ke=(Bt=s==null?void 0:s.render)==null?void 0:Bt.tint,wa=typeof ke=="string"?ke:ke?`#${ke.toString(16).padStart(6,"0")}`:"#B0B0B0",re=new w.Text({text:ga,style:{fontFamily:G(lt),fontSize:_a,fontWeight:j(lt),fill:wa,align:"center",letterSpacing:ba}});re.anchor.set(.5);let xa=st+20+((It=rt.animation_start_y_offset)!=null?It:-10);re.position.set(0,xa),re.alpha=0,re.animationStartYOffset=(Gt=rt.animation_start_y_offset)!=null?Gt:-10,u.addChild(re);let X=r==null?void 0:r.ui,ct=((jt=r==null?void 0:r.gameplay)==null?void 0:jt.tuning)||{},Ta=(X==null?void 0:X.text)||((Vt=f.ui)==null?void 0:Vt.cta_hint)||"Continue the adventure!",dt=(X==null?void 0:X.font)||"brand.body",va=(X==null?void 0:X.fontSize)||16,De=(qt=r==null?void 0:r.render)==null?void 0:qt.tint,Sa=typeof De=="string"?De:De?`#${De.toString(16).padStart(6,"0")}`:"#FFFFFF",Ca=(Xt=ct.max_width)!=null?Xt:m-x*2,Aa=(Kt=ct.line_height)!=null?Kt:1.4,le=new w.Text({text:Ta,style:{fontFamily:G(dt),fontSize:va,fontWeight:j(dt),fill:Sa,align:"center",wordWrap:!0,wordWrapWidth:Ca,lineHeight:Aa}});le.anchor.set(.5);let Ea=($t=c.footer_offset_y)!=null?$t:120;le.position.set(0,Ea);let ka=((Jt=r==null?void 0:r.render)==null?void 0:Jt.alpha)!==void 0&&((Qt=r==null?void 0:r.render)==null?void 0:Qt.alpha)!==null?r.render.alpha:1;le.alpha=0,le.targetAlpha=ka,u.addChild(le);let K=((Zt=l==null?void 0:l.gameplay)==null?void 0:Zt.tuning)||{},H=l==null?void 0:l.ui,Pe=(Ut=K.button_width)!=null?Ut:260,Me=(en=K.button_height)!=null?en:56,ut=(tn=K.button_radius)!=null?tn:16,Da=K.button_bg_color||((nn=f.theme)==null?void 0:nn.cta_background)||"#ffb43b",Pa=(an=K.button_bg_alpha)!=null?an:1,Ma=K.button_border_color||"#ffffff",Fa=(on=K.button_border_width)!=null?on:2,La=(sn=K.button_border_alpha)!=null?sn:.2,Fe=(rn=c.cta_offset_y)!=null?rn:160,I=new w.Graphics;I.roundRect(-Pe/2,-Me/2,Pe,Me,ut);let Ra=Da.replace("#","");I.fill({color:parseInt(Ra,16),alpha:Pa});let za=Ma.replace("#","");I.stroke({color:parseInt(za,16),width:Fa,alpha:La});let Ve=new w.Graphics;Ve.roundRect(-Pe/2+2,-Me/2+2,Pe-4,Me-4,ut-2),Ve.stroke({color:0,width:1,alpha:.15}),I.addChild(Ve),I.position.set(0,Fe),I.alpha=0,I.eventMode="static",I.cursor="pointer",u.addChild(I);let Ha=(H==null?void 0:H.text)||((ln=f.ui)==null?void 0:ln.cta_label_end)||"DOWNLOAD",pt=(H==null?void 0:H.font)||"brand.heading",Oa=(H==null?void 0:H.fontSize)||20,Wa=K.button_text_color||((cn=f.theme)==null?void 0:cn.cta_text)||"#1a0a0a",ge=new w.Text({text:Ha,style:{fontFamily:G(pt),fontSize:Oa,fontWeight:j(pt),fill:Wa,align:"center",letterSpacing:(dn=H==null?void 0:H.letterSpacing)!=null?dn:1}});ge.anchor.set(.5),ge.position.set(0,Fe),ge.alpha=0,u.addChild(ge);let O=d==null?void 0:d.ui,ft=((un=d==null?void 0:d.gameplay)==null?void 0:un.tuning)||{},Na=(O==null?void 0:O.text)||"Play the full game",mt=(O==null?void 0:O.font)||"brand.body",Ya=(O==null?void 0:O.fontSize)||11,Ba=(pn=O==null?void 0:O.letterSpacing)!=null?pn:0,Le=(fn=d==null?void 0:d.render)==null?void 0:fn.tint,Ia=typeof Le=="string"?Le:Le?`#${Le.toString(16).padStart(6,"0")}`:"#CCCCCC",ce=new w.Text({text:Na,style:{fontFamily:G(mt),fontSize:Ya,fontWeight:j(mt),fill:Ia,align:"center",letterSpacing:Ba}});ce.anchor.set(.5);let Ga=Fe+35+((mn=ft.animation_start_y_offset)!=null?mn:5);ce.position.set(0,Ga),ce.alpha=0,ce.animationStartYOffset=(hn=ft.animation_start_y_offset)!=null?hn:5,u.addChild(ce);let qe=((yn=p==null?void 0:p.gameplay)==null?void 0:yn.tuning)||{},ja=(gn=qe.hand_offset_x)!=null?gn:50,Va=(_n=qe.hand_offset_y)!=null?_n:50,qa=(wn=(bn=p==null?void 0:p.transform)==null?void 0:bn.scale)!=null?wn:.1875,Xa=(xn=qe.hand_scale_multiplier)!=null?xn:2.5,ie=new w.Sprite(t||w.Texture.EMPTY);return ie.anchor.set(.5),ie.scale.set(qa*Xa),ie.position.set(ja,Fe+Va),ie.alpha=0,ie.visible=!1,u.addChild(ie),{panel:u,logo:M,title:U,subtitle:re,footer:le,ctaButton:I,ctaText:ge,ctaHint:ce,hand:ie}}function aa(e,t,n){var k,S,C,b,D,L,V,Z;let a=t.objects.get("ui_endgame_1"),o=((k=a==null?void 0:a.gameplay)==null?void 0:k.tuning)||{},i=(S=o.animation_duration_ms)!=null?S:800,s=(C=o.fade_in_duration_ms)!=null?C:600,r=(b=o.scale_animation_intensity)!=null?b:.1,l=(D=o.logo_animation_delay_ms)!=null?D:100,d=(L=o.title_animation_delay_ms)!=null?L:200,p=(V=o.footer_animation_delay_ms)!=null?V:300,f=(Z=o.cta_animation_delay_ms)!=null?Z:400,{panel:u,logo:c,title:h,subtitle:m,footer:g,ctaButton:x,ctaText:T,ctaHint:A}=e;u.visible=!0;let v=Date.now(),E=()=>{let Y=Date.now()-v,q=Math.min(Y/s,1),ae=1-Math.pow(1-q,3);u.alpha=ae,u.scale.set(1+r*(1-ae)),q<1?requestAnimationFrame(E):(setTimeout(()=>fi(c,i,t),l),setTimeout(()=>{mi(h,i),setTimeout(()=>hi(m,i),50)},d),setTimeout(()=>yi(g,i),p),setTimeout(()=>{gi(x,T,i),setTimeout(()=>_i(A,i),50),n&&n()},f))};E()}function fi(e,t,n){var u,c,h,m,g;let a=n==null?void 0:n.objects.get("ui_endgame_logo_1"),i=(c=(((u=a==null?void 0:a.gameplay)==null?void 0:u.tuning)||{}).animation_start_scale)!=null?c:1.2,s=Date.now(),r=e.alpha,l=(h=e.targetAlpha)!=null?h:1,d=(m=e.baseScaleX)!=null?m:e.scale.x,p=(g=e.baseScaleY)!=null?g:e.scale.y,f=()=>{let x=Date.now()-s,T=Math.min(x/t,1),A=1-Math.pow(1-T,2);e.alpha=r+(l-r)*A;let v=i+(1-i)*A;e.scale.set(d*v,p*v),T<1&&requestAnimationFrame(f)};f()}function mi(e,t){let n=Date.now(),a=e.alpha,o=e.y,i=()=>{let s=Date.now()-n,r=Math.min(s/t,1),l=1-Math.pow(1-r,2);e.alpha=a+(1-a)*l,e.y=o-20*(1-l),r<1&&requestAnimationFrame(i)};i()}function hi(e,t){var r;let n=Date.now(),a=e.alpha,o=e.position.y,i=o-((r=e.animationStartYOffset)!=null?r:-10),s=()=>{let l=Date.now()-n,d=Math.min(l/t,1),p=1-Math.pow(1-d,2);e.alpha=a+(1-a)*p,e.position.y=o+(i-o)*p,d<1&&requestAnimationFrame(s)};s()}function yi(e,t){var s;let n=Date.now(),a=e.alpha,o=(s=e.targetAlpha)!=null?s:1,i=()=>{let r=Date.now()-n,l=Math.min(r/t,1),d=1-Math.pow(1-l,2);e.alpha=a+(o-a)*d,l<1&&requestAnimationFrame(i)};i()}function gi(e,t,n){let a=Date.now(),o=e.alpha,i=()=>{let s=Date.now()-a,r=Math.min(s/n,1),l=1-Math.pow(1-r,2);e.alpha=o+(1-o)*l,t.alpha=o+(1-o)*l,e.scale.set(1+.1*(1-l)),r<1&&requestAnimationFrame(i)};i()}function _i(e,t){var r;let n=Date.now(),a=e.alpha,o=e.position.y,i=o-((r=e.animationStartYOffset)!=null?r:5),s=()=>{let l=Date.now()-n,d=Math.min(l/t,1),p=1-Math.pow(1-d,2);e.alpha=a+(1-a)*p,e.position.y=o+(i-o)*p,d<1&&requestAnimationFrame(s)};s()}function ia(e,t,n,a){var p,f,u,c;let o=n.objects.get("ui_endgame_hand_1"),i=((p=o==null?void 0:o.gameplay)==null?void 0:p.tuning)||{},s=(f=i.click_animation_duration_ms)!=null?f:600,r=(u=i.click_delay_ms)!=null?u:2e3,l=(c=i.click_repeat_delay_ms)!=null?c:3e3,d=()=>{var k,S;e.visible=!0,e.alpha=1;let h=e.x,m=e.y,g=(k=i.hand_offset_x)!=null?k:50,x=(S=i.hand_offset_y)!=null?S:50,T=t.x+g,A=t.y+x,v=Date.now(),E=()=>{var Y,q,ae;let C=Date.now()-v,b=Math.min(C/s,1),D=b<.5?2*b*b:1-Math.pow(-2*b+2,2)/2;e.x=h+(T-h)*D,e.y=m+(A-m)*D;let L=(q=(Y=o==null?void 0:o.transform)==null?void 0:Y.scale)!=null?q:.1875,V=(ae=i.hand_scale_multiplier)!=null?ae:2.5,Z=L*V;e.scale.set(Z+Z*.2*Math.sin(b*Math.PI)),b<1?requestAnimationFrame(E):(t.scale.set(.95),setTimeout(()=>{t.scale.set(1),a()},100),setTimeout(()=>{e.alpha=0,setTimeout(()=>{e.x=h,e.y=m,d()},l)},500))};E()};setTimeout(d,r)}var je=require("pixi.js");function oa(e,t,n){var p,f,u,c;let a=t.objects.get("hand_tutorial_1"),o=((p=a==null?void 0:a.gameplay)==null?void 0:p.tuning)||{},i=(a==null?void 0:a.render)||{},s=(a==null?void 0:a.transform)||{},r=new je.Sprite(e);r.anchor.set(.5),r.alpha=0;let l=(f=o.hand_scale_multiplier)!=null?f:2.5,d=(u=s.scale)!=null?u:.1875;return r.scale.set(d*l),r.zIndex=(c=i.z_index)!=null?c:99999,r}function sa(e){var h,m,g,x,T,A,v,E,k,S;let t=e.objects.get("ui_tutorial_1"),n=t==null?void 0:t.ui,a=(t==null?void 0:t.render)||{},o=((h=e.engine.runtime)==null?void 0:h.ui_styles)||{},i=((m=e.engine.runtime)==null?void 0:m.ui)||{},s=(n==null?void 0:n.text)||i.tutorial_label||i.label_text||"CLEAN!",r=(n==null?void 0:n.font)||"brand.warning",l=(n==null?void 0:n.fontSize)||o.label_font_size||52,d=(x=n==null?void 0:n.letterSpacing)!=null?x:(g=o.label_letter_spacing)!=null?g:-1,p=(n==null?void 0:n.align)||"center",f=a.tint,u=typeof f=="string"?f:f?`#${f.toString(16).padStart(6,"0")}`:o.label_fill||"#FFF1C1",c=new je.Text({text:s,style:{fontFamily:G(r),fontSize:l,fontWeight:j(r),fill:u,align:p,letterSpacing:d,stroke:{color:o.label_stroke||"#8B0000",width:2},dropShadow:{color:o.label_shadow_color||"#000000",alpha:(T=o.label_shadow_alpha)!=null?T:.8,angle:(A=o.label_shadow_angle)!=null?A:0,blur:(v=o.label_shadow_blur)!=null?v:4,distance:(E=o.label_shadow_distance)!=null?E:2}}});return c.anchor.set(.5,0),c.alpha=(k=a.alpha)!=null?k:0,c.visible=(S=a.visible)!=null?S:!0,c}function ra(e,t,n,a,o){var l,d,p,f,u,c,h;let i=o.objects.get("hand_tutorial_1"),s=((l=i==null?void 0:i.gameplay)==null?void 0:l.tuning)||{},r=(i==null?void 0:i.transform)||{};if(!a){let m=(d=s.animation_duration)!=null?d:1.5,g=n%m/m,x=g<.5?2*g*g:-1+(4-2*g)*g,T=(p=s.x_offset)!=null?p:0,A=(f=s.y_offset)!=null?f:0,v=(u=s.animation_range)!=null?u:40,E=v*.7,k=v,S=t.x+T+E,C=t.y+A+k,b=S+E,D=C+k;e.x=S+(b-S)*x,e.y=C+(D-C)*x;let L=(c=r.scale)!=null?c:.1875,V=(h=s.hand_scale_multiplier)!=null?h:2.5;e.scale.set(L*V)}}var P=require("pixi.js");async function at(e,t,n=16777215,a=!1){try{let i=(globalThis.INLINE_ASSETS||{})[e];return await P.Assets.load(i||e)}catch{console.warn(`Asset missing: ${e}. Using placeholder.`);let i=new P.Graphics;return a?i.roundRect(0,0,60,120,10).fill({color:n}):(i.circle(30,30,30).fill({color:n}),i.rect(25,30,10,40).fill({color:n})),t.renderer.generateTexture(i)}}async function la(e,t,n){var m,g,x,T,A,v,E,k,S,C;let o=(globalThis.INLINE_ASSETS||{})[e]||e,i;try{i=await P.Assets.load(o),console.log("[character] loaded sheet",{path:e,sourceUsed:o})}catch(b){let L=(n.gameplay.character_sheet||{}).fallback_color||"#ff00ff";i=await at(e,t,new P.Color(L).toNumber(),!0),console.warn("[character] fallback loadAsset used",{path:e,err:b})}let s=i.source||i.baseTexture||i;s&&"valid"in s&&s.valid===!1&&typeof s.once=="function"&&await new Promise(b=>s.once("loaded",b));let r=n.gameplay.character_sheet||{},l=(m=r.cols)!=null?m:3,d=(g=r.rows)!=null?g:2,p=(v=(A=(x=s==null?void 0:s.width)!=null?x:s==null?void 0:s.pixelWidth)!=null?A:(T=s==null?void 0:s.baseTexture)==null?void 0:T.width)!=null?v:i.width,f=(C=(S=(E=s==null?void 0:s.height)!=null?E:s==null?void 0:s.pixelHeight)!=null?S:(k=s==null?void 0:s.baseTexture)==null?void 0:k.height)!=null?C:i.height,u=p/l,c=f/d;if(!Number.isFinite(u)||!Number.isFinite(c)||u<=0||c<=0||!s)return[i];let h=[];for(let b=0;b<d;b++)for(let D=0;D<l;D++)h.push(new P.Texture({source:s,frame:new P.Rectangle(D*u,b*c,u,c)}));return h.length>2&&h.push(...h.slice(1,-1).reverse()),console.log("[character] frames prepared",{count:h.length}),h}function ca(e,t){var p,f,u,c;let n=t.gameplay.brush||{},a=new P.Color(t.theme.brush_color||"#ffffff").toNumber(),o=(p=n.radius)!=null?p:20,i=(f=n.inner_radius)!=null?f:15,s=(u=n.alpha)!=null?u:.8,r=(c=n.inner_alpha)!=null?c:.3,l=n.inner_color||"#ffffff",d=new P.Graphics;return d.circle(0,0,o).fill({color:a,alpha:s}),d.circle(0,0,i).fill({color:new P.Color(l).toNumber(),alpha:r}),e.renderer.generateTexture(d)}0&&(module.exports={GameObject,GameObjectManager,Renderer,Transform,animateHandClick,animatePanelEntrance,createBrushTexture,createEndGamePanel,createHandTutorial,createPixiBase,createTutorialLabel,getRegisteredFontIds,loadAsset,loadCharacterFrames,registerFont,resolveFont,resolveFontWeight,updateHandAnimation});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as lt}from"../chunk-CJIYY5BP.mjs";import{Application as Pn}from"pixi.js";async function Mn(e,t={}){let a=new Pn;await a.init({resizeTo:e,autoDensity:!0,resolution:window.devicePixelRatio||1,antialias:!0,backgroundAlpha:0});let o=n=>{var c,d,p,u,h,l;let i=(p=(d=(c=n==null?void 0:n.width)!=null?c:e.clientWidth)!=null?d:window.innerWidth)!=null?p:320,r=(l=(h=(u=n==null?void 0:n.height)!=null?u:e.clientHeight)!=null?h:window.innerHeight)!=null?l:480;a.renderer.resize(i,r)};e.innerHTML="",e.style.position="relative",e.style.display="flex",e.style.flexDirection="column",e.style.alignItems="stretch",e.style.width="100%",e.style.height="100dvh",e.style.minHeight="100vh",e.style.maxWidth="100%",e.style.maxHeight="100%",e.style.boxSizing="border-box",e.style.overflow="hidden",t.background&&(e.style.background=t.background),e.appendChild(a.canvas);let s=document.createElement("div");return s.setAttribute("style",["position:absolute","inset:0","display:flex","flex-direction:column","align-items:center","justify-content:flex-start","gap:12px","pointer-events:none","font-family:Arial,sans-serif","padding:20px 16px","padding-bottom:clamp(24px, 6vh, 96px)","box-sizing:border-box","z-index:2"].join(";")),e.appendChild(s),lt.on("pause",()=>{a.ticker.stop(),document.querySelectorAll("audio").forEach(i=>i.pause())}),lt.on("resume",()=>{a.ticker.start(),document.querySelectorAll("audio").forEach(i=>{i.currentTime>0&&!i.ended&&i.play().catch(()=>{})})}),lt.on("resize",({payload:n})=>{o({width:n==null?void 0:n.width,height:n==null?void 0:n.height})}),window.addEventListener("resize",()=>o()),requestAnimationFrame(()=>o()),{app:a,stage:a.stage,overlay:s,applySize:o}}var ct=class{constructor(t){var a,o;this.position=(t==null?void 0:t.position)||{x:0,y:0},this.scale=(a=t==null?void 0:t.scale)!=null?a:1,this.rotation=(o=t==null?void 0:t.rotation)!=null?o:0}update(t){t.position!==void 0&&(this.position={...t.position}),t.scale!==void 0&&(this.scale=t.scale),t.rotation!==void 0&&(this.rotation=t.rotation)}syncToPixi(t){t.position.set(this.position.x,this.position.y),t.scale.set(this.scale),t.rotation=this.rotation}},dt=class{constructor(t){var a,o,s,n;this.z_index=(a=t==null?void 0:t.z_index)!=null?a:0,this.alpha=(o=t==null?void 0:t.alpha)!=null?o:1,this.visible=(s=t==null?void 0:t.visible)!=null?s:!0,this.tint=(n=t==null?void 0:t.tint)!=null?n:null}update(t){t.z_index!==void 0&&(this.z_index=t.z_index),t.alpha!==void 0&&(this.alpha=t.alpha),t.visible!==void 0&&(this.visible=t.visible),t.tint!==void 0&&(this.tint=t.tint)}syncToPixi(t){t.zIndex=this.z_index,t.alpha=this.alpha,t.visible=this.visible,this.tint!==null&&"tint"in t&&(t.tint=this.tint)}},ht=class{constructor(t,a,o,s){this.instanceId=t,this.objectConfig=a,this.pixiObject=o,this._config=s,this.transform=new ct(s.transform),this.renderer=new dt(s.render),this.sync()}sync(){this.transform.syncToPixi(this.pixiObject),this.renderer.syncToPixi(this.pixiObject)}updateConfig(t){this._config=t,t.transform&&this.transform.update(t.transform),t.render&&this.renderer.update(t.render),this.sync()}getComponent(t){return this._config[t]}getPosition(){return{...this.transform.position}}setPosition(t,a){this.transform.position={x:t,y:a},this.transform.syncToPixi(this.pixiObject)}getAlpha(){return this.renderer.alpha}setAlpha(t){this.renderer.alpha=t,this.renderer.syncToPixi(this.pixiObject)}getVisible(){return this.renderer.visible}setVisible(t){this.renderer.visible=t,this.renderer.syncToPixi(this.pixiObject)}},gt=class{constructor(t){this.objects=new Map;this.config=t}create(t,a){let o=this.config.objects.get(t);if(!o)throw new Error(`Object config not found: ${t}`);let s=new ht(t,o.object_config||t,a,o);return this.objects.set(t,s),s}get(t){return this.objects.get(t)}updateConfig(t){this.config=t;for(let[a,o]of this.objects.entries()){let s=t.objects.get(a);s&&o.updateConfig(s)}}getAll(){return Array.from(this.objects.values())}remove(t){this.objects.delete(t)}clear(){this.objects.clear()}};var pt={"brand.primary":{family:"Arial, sans-serif",weight:"400"},"brand.warning":{family:"Arial Black, Arial, sans-serif",weight:"900"},"brand.heading":{family:"Arial Black, Arial, sans-serif",weight:"800"},"brand.body":{family:"Arial, sans-serif",weight:"400"}};function X(e){let t=pt[e];return t?t.family:(console.warn(`Font ID "${e}" not found in registry, using fallback`),"Arial, sans-serif")}function q(e){var a;let t=pt[e];return t&&(a=t.weight)!=null?a:"400"}function En(e,t){pt[e]=t}function Dn(){return Object.keys(pt)}import{Container as Yn,Graphics as ut,Text as tt,Sprite as Le,Texture as _t}from"pixi.js";function kn(e,t,a){var Dt,Yt,kt,zt,Ht,Wt,Bt,Rt,Lt,Gt,Nt,Xt,qt,$t,Vt,jt,Jt,Kt,Qt,Zt,Ot,It,Ut,te,ee,ne,ae,se,ie,oe,re,le,ce,de,he,pe,ue,me,fe,ye,ge,_e,be,xe,we,Te,Ce,Se,ve,Ae,Fe,Pe,Me,Ee,De,Ye,ke,ze,He,We;let o=e.objects.get("ui_endgame_1"),s=e.objects.get("ui_endgame_logo_1"),n=e.objects.get("ui_endgame_title_1"),i=e.objects.get("ui_endgame_subtitle_1"),r=e.objects.get("ui_endgame_footer_1"),c=e.objects.get("ui_endgame_cta_1"),d=e.objects.get("ui_endgame_cta_hint_1"),p=e.objects.get("ui_endgame_hand_1"),u=e.engine.runtime||{},h=new Yn;h.alpha=0,h.visible=!1;let l=((Dt=o==null?void 0:o.gameplay)==null?void 0:Dt.tuning)||{},m=(o==null?void 0:o.render)||{},f=(Yt=l.panel_width)!=null?Yt:320,y=(kt=l.panel_height)!=null?kt:400,_=(zt=l.panel_padding)!=null?zt:32,b=(Ht=l.panel_radius)!=null?Ht:24,C=m.background_color||l.panel_bg_color||"#1a0a0a",x=m.background_alpha!==void 0&&m.background_alpha!==null?m.background_alpha:(Wt=l.panel_bg_alpha)!=null?Wt:.98,S=m.border_color||l.panel_border_color||"#ffffff",v=(Bt=l.panel_border_width)!=null?Bt:2,w=(Rt=l.panel_border_alpha)!=null?Rt:.3,T=new ut;T.roundRect(-f/2,-y/2,f,y,b);let g=C.replace("#","");T.fill({color:parseInt(g,16),alpha:x});let A=S.replace("#","");T.stroke({color:parseInt(A,16),width:v,alpha:w});let M=new ut;M.roundRect(-f/2+2,-y/2+2,f-4,y-4,b-2),M.stroke({color:16777215,width:1,alpha:.1}),T.addChild(M),h.addChild(T);let B=((Lt=s==null?void 0:s.gameplay)==null?void 0:Lt.tuning)||{},$=(s==null?void 0:s.transform)||{},z=(Gt=B.logo_size)!=null?Gt:56,R=(Nt=$.scale)!=null?Nt:1,j=(qt=(Xt=$.offset)==null?void 0:Xt.y)!=null?qt:-130,qe=($t=B.logo_alpha)!=null?$t:1,F=new Le(a||_t.EMPTY);F.anchor.set(.5);let K=0,Q=0;if(a&&a!==_t.EMPTY){let P=a.frame,N=a.baseTexture;P&&P.width&&P.height?(K=P.width,Q=P.height):N&&N.width&&N.height?(K=N.width,Q=N.height):a.width&&a.height&&(K=a.width,Q=a.height)}if(K>0&&Q>0){let P=K/Q,N,yt;P>1?(N=z,yt=z/P):(yt=z,N=z*P);let Be=N/K,Re=yt/Q;Be*=R,Re*=R,F.scale.set(Be,Re)}else{let P=z/100*R;F.scale.set(P)}F.position.set(0,j),F.alpha=0,F.visible=!0,F.targetAlpha=qe,F.baseScaleX=F.scale.x,F.baseScaleY=F.scale.y,h.addChild(F);let E=n==null?void 0:n.ui,H=((Vt=n==null?void 0:n.gameplay)==null?void 0:Vt.tuning)||{},$e=(E==null?void 0:E.text)||"MISSION ACCOMPLISHED",xt=(E==null?void 0:E.font)||"brand.heading",Ve=(E==null?void 0:E.fontSize)||24,je=(jt=E==null?void 0:E.letterSpacing)!=null?jt:1,et=(Jt=n==null?void 0:n.render)==null?void 0:Jt.tint,Je=typeof et=="string"?et:et?`#${et.toString(16).padStart(6,"0")}`:"#00FF88",wt=f-_*2-30,Ke=H.font_weight_override?H.font_weight_override:q(xt),V=new tt({text:$e,style:{fontFamily:X(xt),fontSize:Ve,fontWeight:Ke,fill:Je,align:"center",letterSpacing:je,wordWrap:!1,stroke:{color:H.stroke_color||"#000000",width:(Kt=H.stroke_width)!=null?Kt:2},dropShadow:{color:H.shadow_color||"#000000",alpha:(Qt=H.shadow_alpha)!=null?Qt:.9,angle:(Zt=H.shadow_angle)!=null?Zt:0,blur:(Ot=H.shadow_blur)!=null?Ot:8,distance:(It=H.shadow_distance)!=null?It:4}}});if(V.width>wt){let P=wt/V.width;V.scale.set(P)}V.anchor.set(.5);let Tt=(Ut=l.title_offset_y)!=null?Ut:30,Qe=Tt+((te=H.animation_start_y_offset)!=null?te:-20);V.position.set(0,Qe),V.alpha=0,h.addChild(V);let D=i==null?void 0:i.ui,Ct=((ee=i==null?void 0:i.gameplay)==null?void 0:ee.tuning)||{},Ze=(D==null?void 0:D.text)||"RESCUE COMPLETE",St=(D==null?void 0:D.font)||"brand.body",Oe=(D==null?void 0:D.fontSize)||11,Ie=(ne=D==null?void 0:D.letterSpacing)!=null?ne:.5,nt=(ae=i==null?void 0:i.render)==null?void 0:ae.tint,Ue=typeof nt=="string"?nt:nt?`#${nt.toString(16).padStart(6,"0")}`:"#B0B0B0",Z=new tt({text:Ze,style:{fontFamily:X(St),fontSize:Oe,fontWeight:q(St),fill:Ue,align:"center",letterSpacing:Ie}});Z.anchor.set(.5);let tn=Tt+20+((se=Ct.animation_start_y_offset)!=null?se:-10);Z.position.set(0,tn),Z.alpha=0,Z.animationStartYOffset=(ie=Ct.animation_start_y_offset)!=null?ie:-10,h.addChild(Z);let L=r==null?void 0:r.ui,vt=((oe=r==null?void 0:r.gameplay)==null?void 0:oe.tuning)||{},en=(L==null?void 0:L.text)||((re=u.ui)==null?void 0:re.cta_hint)||"Continue the adventure!",At=(L==null?void 0:L.font)||"brand.body",nn=(L==null?void 0:L.fontSize)||16,at=(le=r==null?void 0:r.render)==null?void 0:le.tint,an=typeof at=="string"?at:at?`#${at.toString(16).padStart(6,"0")}`:"#FFFFFF",sn=(ce=vt.max_width)!=null?ce:f-_*2,on=(de=vt.line_height)!=null?de:1.4,O=new tt({text:en,style:{fontFamily:X(At),fontSize:nn,fontWeight:q(At),fill:an,align:"center",wordWrap:!0,wordWrapWidth:sn,lineHeight:on}});O.anchor.set(.5);let rn=(he=l.footer_offset_y)!=null?he:120;O.position.set(0,rn);let ln=((pe=r==null?void 0:r.render)==null?void 0:pe.alpha)!==void 0&&((ue=r==null?void 0:r.render)==null?void 0:ue.alpha)!==null?r.render.alpha:1;O.alpha=0,O.targetAlpha=ln,h.addChild(O);let G=((me=c==null?void 0:c.gameplay)==null?void 0:me.tuning)||{},Y=c==null?void 0:c.ui,st=(fe=G.button_width)!=null?fe:260,it=(ye=G.button_height)!=null?ye:56,Ft=(ge=G.button_radius)!=null?ge:16,cn=G.button_bg_color||((_e=u.theme)==null?void 0:_e.cta_background)||"#ffb43b",dn=(be=G.button_bg_alpha)!=null?be:1,hn=G.button_border_color||"#ffffff",pn=(xe=G.button_border_width)!=null?xe:2,un=(we=G.button_border_alpha)!=null?we:.2,ot=(Te=l.cta_offset_y)!=null?Te:160,W=new ut;W.roundRect(-st/2,-it/2,st,it,Ft);let mn=cn.replace("#","");W.fill({color:parseInt(mn,16),alpha:dn});let fn=hn.replace("#","");W.stroke({color:parseInt(fn,16),width:pn,alpha:un});let mt=new ut;mt.roundRect(-st/2+2,-it/2+2,st-4,it-4,Ft-2),mt.stroke({color:0,width:1,alpha:.15}),W.addChild(mt),W.position.set(0,ot),W.alpha=0,W.eventMode="static",W.cursor="pointer",h.addChild(W);let yn=(Y==null?void 0:Y.text)||((Ce=u.ui)==null?void 0:Ce.cta_label_end)||"DOWNLOAD",Pt=(Y==null?void 0:Y.font)||"brand.heading",gn=(Y==null?void 0:Y.fontSize)||20,_n=G.button_text_color||((Se=u.theme)==null?void 0:Se.cta_text)||"#1a0a0a",U=new tt({text:yn,style:{fontFamily:X(Pt),fontSize:gn,fontWeight:q(Pt),fill:_n,align:"center",letterSpacing:(ve=Y==null?void 0:Y.letterSpacing)!=null?ve:1}});U.anchor.set(.5),U.position.set(0,ot),U.alpha=0,h.addChild(U);let k=d==null?void 0:d.ui,Mt=((Ae=d==null?void 0:d.gameplay)==null?void 0:Ae.tuning)||{},bn=(k==null?void 0:k.text)||"Play the full game",Et=(k==null?void 0:k.font)||"brand.body",xn=(k==null?void 0:k.fontSize)||11,wn=(Fe=k==null?void 0:k.letterSpacing)!=null?Fe:0,rt=(Pe=d==null?void 0:d.render)==null?void 0:Pe.tint,Tn=typeof rt=="string"?rt:rt?`#${rt.toString(16).padStart(6,"0")}`:"#CCCCCC",I=new tt({text:bn,style:{fontFamily:X(Et),fontSize:xn,fontWeight:q(Et),fill:Tn,align:"center",letterSpacing:wn}});I.anchor.set(.5);let Cn=ot+35+((Me=Mt.animation_start_y_offset)!=null?Me:5);I.position.set(0,Cn),I.alpha=0,I.animationStartYOffset=(Ee=Mt.animation_start_y_offset)!=null?Ee:5,h.addChild(I);let ft=((De=p==null?void 0:p.gameplay)==null?void 0:De.tuning)||{},Sn=(Ye=ft.hand_offset_x)!=null?Ye:50,vn=(ke=ft.hand_offset_y)!=null?ke:50,An=(He=(ze=p==null?void 0:p.transform)==null?void 0:ze.scale)!=null?He:.1875,Fn=(We=ft.hand_scale_multiplier)!=null?We:2.5,J=new Le(t||_t.EMPTY);return J.anchor.set(.5),J.scale.set(An*Fn),J.position.set(Sn,ot+vn),J.alpha=0,J.visible=!1,h.addChild(J),{panel:h,logo:F,title:V,subtitle:Z,footer:O,ctaButton:W,ctaText:U,ctaHint:I,hand:J}}function zn(e,t,a){var v,w,T,g,A,M,B,$;let o=t.objects.get("ui_endgame_1"),s=((v=o==null?void 0:o.gameplay)==null?void 0:v.tuning)||{},n=(w=s.animation_duration_ms)!=null?w:800,i=(T=s.fade_in_duration_ms)!=null?T:600,r=(g=s.scale_animation_intensity)!=null?g:.1,c=(A=s.logo_animation_delay_ms)!=null?A:100,d=(M=s.title_animation_delay_ms)!=null?M:200,p=(B=s.footer_animation_delay_ms)!=null?B:300,u=($=s.cta_animation_delay_ms)!=null?$:400,{panel:h,logo:l,title:m,subtitle:f,footer:y,ctaButton:_,ctaText:b,ctaHint:C}=e;h.visible=!0;let x=Date.now(),S=()=>{let z=Date.now()-x,R=Math.min(z/i,1),j=1-Math.pow(1-R,3);h.alpha=j,h.scale.set(1+r*(1-j)),R<1?requestAnimationFrame(S):(setTimeout(()=>Hn(l,n,t),c),setTimeout(()=>{Wn(m,n),setTimeout(()=>Bn(f,n),50)},d),setTimeout(()=>Rn(y,n),p),setTimeout(()=>{Ln(_,b,n),setTimeout(()=>Gn(C,n),50),a&&a()},u))};S()}function Hn(e,t,a){var h,l,m,f,y;let o=a==null?void 0:a.objects.get("ui_endgame_logo_1"),n=(l=(((h=o==null?void 0:o.gameplay)==null?void 0:h.tuning)||{}).animation_start_scale)!=null?l:1.2,i=Date.now(),r=e.alpha,c=(m=e.targetAlpha)!=null?m:1,d=(f=e.baseScaleX)!=null?f:e.scale.x,p=(y=e.baseScaleY)!=null?y:e.scale.y,u=()=>{let _=Date.now()-i,b=Math.min(_/t,1),C=1-Math.pow(1-b,2);e.alpha=r+(c-r)*C;let x=n+(1-n)*C;e.scale.set(d*x,p*x),b<1&&requestAnimationFrame(u)};u()}function Wn(e,t){let a=Date.now(),o=e.alpha,s=e.y,n=()=>{let i=Date.now()-a,r=Math.min(i/t,1),c=1-Math.pow(1-r,2);e.alpha=o+(1-o)*c,e.y=s-20*(1-c),r<1&&requestAnimationFrame(n)};n()}function Bn(e,t){var r;let a=Date.now(),o=e.alpha,s=e.position.y,n=s-((r=e.animationStartYOffset)!=null?r:-10),i=()=>{let c=Date.now()-a,d=Math.min(c/t,1),p=1-Math.pow(1-d,2);e.alpha=o+(1-o)*p,e.position.y=s+(n-s)*p,d<1&&requestAnimationFrame(i)};i()}function Rn(e,t){var i;let a=Date.now(),o=e.alpha,s=(i=e.targetAlpha)!=null?i:1,n=()=>{let r=Date.now()-a,c=Math.min(r/t,1),d=1-Math.pow(1-c,2);e.alpha=o+(s-o)*d,c<1&&requestAnimationFrame(n)};n()}function Ln(e,t,a){let o=Date.now(),s=e.alpha,n=()=>{let i=Date.now()-o,r=Math.min(i/a,1),c=1-Math.pow(1-r,2);e.alpha=s+(1-s)*c,t.alpha=s+(1-s)*c,e.scale.set(1+.1*(1-c)),r<1&&requestAnimationFrame(n)};n()}function Gn(e,t){var r;let a=Date.now(),o=e.alpha,s=e.position.y,n=s-((r=e.animationStartYOffset)!=null?r:5),i=()=>{let c=Date.now()-a,d=Math.min(c/t,1),p=1-Math.pow(1-d,2);e.alpha=o+(1-o)*p,e.position.y=s+(n-s)*p,d<1&&requestAnimationFrame(i)};i()}function Nn(e,t,a,o){var p,u,h,l;let s=a.objects.get("ui_endgame_hand_1"),n=((p=s==null?void 0:s.gameplay)==null?void 0:p.tuning)||{},i=(u=n.click_animation_duration_ms)!=null?u:600,r=(h=n.click_delay_ms)!=null?h:2e3,c=(l=n.click_repeat_delay_ms)!=null?l:3e3,d=()=>{var v,w;e.visible=!0,e.alpha=1;let m=e.x,f=e.y,y=(v=n.hand_offset_x)!=null?v:50,_=(w=n.hand_offset_y)!=null?w:50,b=t.x+y,C=t.y+_,x=Date.now(),S=()=>{var z,R,j;let T=Date.now()-x,g=Math.min(T/i,1),A=g<.5?2*g*g:1-Math.pow(-2*g+2,2)/2;e.x=m+(b-m)*A,e.y=f+(C-f)*A;let M=(R=(z=s==null?void 0:s.transform)==null?void 0:z.scale)!=null?R:.1875,B=(j=n.hand_scale_multiplier)!=null?j:2.5,$=M*B;e.scale.set($+$*.2*Math.sin(g*Math.PI)),g<1?requestAnimationFrame(S):(t.scale.set(.95),setTimeout(()=>{t.scale.set(1),o()},100),setTimeout(()=>{e.alpha=0,setTimeout(()=>{e.x=m,e.y=f,d()},c)},500))};S()};setTimeout(d,r)}import{Sprite as Xn,Text as qn}from"pixi.js";function $n(e,t,a){var p,u,h,l;let o=t.objects.get("hand_tutorial_1"),s=((p=o==null?void 0:o.gameplay)==null?void 0:p.tuning)||{},n=(o==null?void 0:o.render)||{},i=(o==null?void 0:o.transform)||{},r=new Xn(e);r.anchor.set(.5),r.alpha=0;let c=(u=s.hand_scale_multiplier)!=null?u:2.5,d=(h=i.scale)!=null?h:.1875;return r.scale.set(d*c),r.zIndex=(l=n.z_index)!=null?l:99999,r}function Vn(e){var m,f,y,_,b,C,x,S,v,w;let t=e.objects.get("ui_tutorial_1"),a=t==null?void 0:t.ui,o=(t==null?void 0:t.render)||{},s=((m=e.engine.runtime)==null?void 0:m.ui_styles)||{},n=((f=e.engine.runtime)==null?void 0:f.ui)||{},i=(a==null?void 0:a.text)||n.tutorial_label||n.label_text||"CLEAN!",r=(a==null?void 0:a.font)||"brand.warning",c=(a==null?void 0:a.fontSize)||s.label_font_size||52,d=(_=a==null?void 0:a.letterSpacing)!=null?_:(y=s.label_letter_spacing)!=null?y:-1,p=(a==null?void 0:a.align)||"center",u=o.tint,h=typeof u=="string"?u:u?`#${u.toString(16).padStart(6,"0")}`:s.label_fill||"#FFF1C1",l=new qn({text:i,style:{fontFamily:X(r),fontSize:c,fontWeight:q(r),fill:h,align:p,letterSpacing:d,stroke:{color:s.label_stroke||"#8B0000",width:2},dropShadow:{color:s.label_shadow_color||"#000000",alpha:(b=s.label_shadow_alpha)!=null?b:.8,angle:(C=s.label_shadow_angle)!=null?C:0,blur:(x=s.label_shadow_blur)!=null?x:4,distance:(S=s.label_shadow_distance)!=null?S:2}}});return l.anchor.set(.5,0),l.alpha=(v=o.alpha)!=null?v:0,l.visible=(w=o.visible)!=null?w:!0,l}function jn(e,t,a,o,s){var c,d,p,u,h,l,m;let n=s.objects.get("hand_tutorial_1"),i=((c=n==null?void 0:n.gameplay)==null?void 0:c.tuning)||{},r=(n==null?void 0:n.transform)||{};if(!o){let f=(d=i.animation_duration)!=null?d:1.5,y=a%f/f,_=y<.5?2*y*y:-1+(4-2*y)*y,b=(p=i.x_offset)!=null?p:0,C=(u=i.y_offset)!=null?u:0,x=(h=i.animation_range)!=null?h:40,S=x*.7,v=x,w=t.x+b+S,T=t.y+C+v,g=w+S,A=T+v;e.x=w+(g-w)*_,e.y=T+(A-T)*_;let M=(l=r.scale)!=null?l:.1875,B=(m=i.hand_scale_multiplier)!=null?m:2.5;e.scale.set(M*B)}}import{Graphics as Ge,Assets as Ne,Texture as Jn,Rectangle as Kn,Color as bt}from"pixi.js";async function Xe(e,t,a=16777215,o=!1){try{let n=(globalThis.INLINE_ASSETS||{})[e];return await Ne.load(n||e)}catch{console.warn(`Asset missing: ${e}. Using placeholder.`);let n=new Ge;return o?n.roundRect(0,0,60,120,10).fill({color:a}):(n.circle(30,30,30).fill({color:a}),n.rect(25,30,10,40).fill({color:a})),t.renderer.generateTexture(n)}}async function Qn(e,t,a){var f,y,_,b,C,x,S,v,w,T;let s=(globalThis.INLINE_ASSETS||{})[e]||e,n;try{n=await Ne.load(s),console.log("[character] loaded sheet",{path:e,sourceUsed:s})}catch(g){let M=(a.gameplay.character_sheet||{}).fallback_color||"#ff00ff";n=await Xe(e,t,new bt(M).toNumber(),!0),console.warn("[character] fallback loadAsset used",{path:e,err:g})}let i=n.source||n.baseTexture||n;i&&"valid"in i&&i.valid===!1&&typeof i.once=="function"&&await new Promise(g=>i.once("loaded",g));let r=a.gameplay.character_sheet||{},c=(f=r.cols)!=null?f:3,d=(y=r.rows)!=null?y:2,p=(x=(C=(_=i==null?void 0:i.width)!=null?_:i==null?void 0:i.pixelWidth)!=null?C:(b=i==null?void 0:i.baseTexture)==null?void 0:b.width)!=null?x:n.width,u=(T=(w=(S=i==null?void 0:i.height)!=null?S:i==null?void 0:i.pixelHeight)!=null?w:(v=i==null?void 0:i.baseTexture)==null?void 0:v.height)!=null?T:n.height,h=p/c,l=u/d;if(!Number.isFinite(h)||!Number.isFinite(l)||h<=0||l<=0||!i)return[n];let m=[];for(let g=0;g<d;g++)for(let A=0;A<c;A++)m.push(new Jn({source:i,frame:new Kn(A*h,g*l,h,l)}));return m.length>2&&m.push(...m.slice(1,-1).reverse()),console.log("[character] frames prepared",{count:m.length}),m}function Zn(e,t){var p,u,h,l;let a=t.gameplay.brush||{},o=new bt(t.theme.brush_color||"#ffffff").toNumber(),s=(p=a.radius)!=null?p:20,n=(u=a.inner_radius)!=null?u:15,i=(h=a.alpha)!=null?h:.8,r=(l=a.inner_alpha)!=null?l:.3,c=a.inner_color||"#ffffff",d=new Ge;return d.circle(0,0,s).fill({color:o,alpha:i}),d.circle(0,0,n).fill({color:new bt(c).toNumber(),alpha:r}),e.renderer.generateTexture(d)}export{ht as GameObject,gt as GameObjectManager,dt as Renderer,ct as Transform,Nn as animateHandClick,zn as animatePanelEntrance,Zn as createBrushTexture,kn as createEndGamePanel,$n as createHandTutorial,Mn as createPixiBase,Vn as createTutorialLabel,Dn as getRegisteredFontIds,Xe as loadAsset,Qn as loadCharacterFrames,En as registerFont,X as resolveFont,q as resolveFontWeight,jn as updateHandAnimation};
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "handler-playable-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Handler Playable SDK v0.1 with contract-aligned surface (root sandbox, canonical event envelope).",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./pixi": {
|
|
15
|
+
"types": "./dist/pixi/index.d.ts",
|
|
16
|
+
"import": "./dist/pixi/index.mjs",
|
|
17
|
+
"require": "./dist/pixi/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts src/pixi/index.ts --format cjs,esm --dts --clean --minify",
|
|
22
|
+
"lint": "eslint 'src/**/*.{ts,tsx}'",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"author": "Handler",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/HandlerAIGames/handler-playable-sdk.git"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"pixi.js": "^8.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"pixi.js": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"eslint": "^8.57.1",
|
|
50
|
+
"pixi.js": "^8.8.1",
|
|
51
|
+
"ts-node": "^10.9.2",
|
|
52
|
+
"tsup": "^8.4.0",
|
|
53
|
+
"typescript": "^5.7.2"
|
|
54
|
+
}
|
|
55
|
+
}
|