adam-sdk
Version:
A JavaScript SDK for integrating A.D.A.M. 3D avatars into web applications.
2 lines (1 loc) • 3.63 kB
JavaScript
(function(r,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(r=typeof globalThis<"u"?globalThis:r||self,a(r.AvatarSDK={}))})(this,function(r){"use strict";class a{iframe;targetOrigin;eventListeners=new Map;pendingCommands=new Map;isReady=!1;handshakeInterval;fastPollInterval;logLevel;constructor(e,t={}){this.iframe=e,this.targetOrigin=t.targetOrigin||new URL(e.src).origin,this.logLevel=t.logLevel||"info",window.addEventListener("message",this._handleMessage.bind(this)),this._log("info","AvatarSDK: Message listener attached")}connect(){return new Promise((e,t)=>{if(this.isReady)return e();const s=setTimeout(()=>{clearInterval(this.handshakeInterval),clearInterval(this.fastPollInterval),t(new Error("Connection timed out. The avatar did not respond."))},1e4);this.iframe.onerror=()=>{clearTimeout(s),clearInterval(this.handshakeInterval),clearInterval(this.fastPollInterval),t(new Error("The avatar iframe failed to load."))},this.on("ready",()=>{clearTimeout(s),clearInterval(this.handshakeInterval),clearInterval(this.fastPollInterval),e()}),this._postMessage({type:"CHECK_READY_STATUS"});let n=0;this.fastPollInterval=setInterval(()=>{n<8?(this._postMessage({type:"CHECK_READY_STATUS"}),n++):(clearInterval(this.fastPollInterval),this.handshakeInterval=setInterval(()=>{this.isReady||this._postMessage({type:"CHECK_READY_STATUS"})},500))},250)})}speak(e,t={}){return console.log("[AvatarSDK] speak",e,t),typeof e!="string"||!e.trim()?Promise.reject(new Error("Text must be a non-empty string")):this._sendCommand("speak",{text:e,...t})}playAnimation(e,t=!1){return this._sendCommand("playAnimation",{name:e,loop:t})}setExpression(e){return this._sendCommand("setExpression",{name:e})}interrupt(){return this._sendCommand("interrupt")}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,[]),this.eventListeners.get(e)?.push(t)}off(e,t){const s=this.eventListeners.get(e);if(s){const n=s.indexOf(t);n>-1&&s.splice(n,1)}}destroy(){window.removeEventListener("message",this._handleMessage.bind(this)),clearInterval(this.handshakeInterval),clearInterval(this.fastPollInterval),this.eventListeners.clear(),this.pendingCommands.clear(),this.isReady=!1}_sendCommand(e,t={}){if(!this.isReady)return Promise.reject(new Error("Not connected to avatar."));const s=`cmd_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,n={type:"AVATAR_COMMAND",command:e,payload:t,commandId:s};return new Promise((i,o)=>{const l=setTimeout(()=>{this.pendingCommands.has(s)&&(this.pendingCommands.delete(s),o(new Error(`Command '${e}' timed out after 30s`)))},3e4);this.pendingCommands.set(s,{resolve:i,reject:o,timeout:l}),this._postMessage(n)})}_handleMessage(e){if(e.origin!==this.targetOrigin)return;const{type:t,commandId:s,event:n,payload:i}=e.data;if(t==="AVATAR_READY"){this.isReady=!0,this._emitEvent("ready",void 0);return}if(t==="AVATAR_EVENT"&&(this._emitEvent(n,i),s&&this.pendingCommands.has(s))){const{resolve:o,reject:l,timeout:d}=this.pendingCommands.get(s);clearTimeout(d),n==="command:success"?o(i):n==="command:error"&&l(new Error(i?.error||"Command failed")),this.pendingCommands.delete(s)}}_postMessage(e){this.iframe.contentWindow&&this.iframe.contentWindow.postMessage(e,this.targetOrigin)}_log(e,t){if(this.logLevel==="none"||e==="none")return;const s={error:1,warn:2,info:3};s[e]<=s[this.logLevel]&&console[e](t)}_emitEvent(e,t){const s=this.eventListeners.get(e);s&&s.forEach(n=>{try{n(t)}catch(i){console.error(`Error in event listener for ${e}:`,i)}})}}r.AvatarSDK=a,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})});