0xfdb7…4e63

All memos sent from and to 0xfdb7…4e63.

data:text/html;charset=utf-8,%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D%22en%22%3E%3Chead%3E%3Cmeta%20charset%3D%22UTF-8%22%3E%3Cmeta%20name%3D%22viewport%22%20content%3D%22width%3Ddevice-width%2C%20initial-scale%3D1.0%2C%20maximum-scale%3D1.0%2C%20user-scalable%3Dno%22%3E%3Cmeta%20name%3D%22mobile-web-app-capable%22%20content%3D%22yes%22%3E%3Cmeta%20name%3D%22apple-mobile-web-app-capable%22%20content%3D%22yes%22%3E%3Ctitle%3EEmoji%20Metaverse%3C%2Ftitle%3E%3Cstyle%3E*%7Bmargin%3A0%3Bpadding%3A0%3Bbox-sizing%3Aborder-box%7Dbody%7Bbackground%3A%23000000%3Bmargin%3A0%3Bpadding%3A0%3Bwidth%3A100vw%3Bheight%3A100vh%3Bfont-family%3A-apple-system%2CBlinkMacSystemFont%2C'Segoe%20UI'%2Csans-serif%3Boverflow%3Ahidden%3B-webkit-tap-highlight-color%3Atransparent%3B-webkit-user-select%3Anone%3B-moz-user-select%3Anone%3B-ms-user-select%3Anone%3Buser-select%3Anone%3B-webkit-touch-callout%3Anone%7D%23game-container%7Bposition%3Aabsolute%3Bwidth%3A100%25%3Bheight%3A100%25%3B-webkit-user-select%3Anone%3B-moz-user-select%3Anone%3B-ms-user-select%3Anone%3Buser-select%3Anone%3Btouch-action%3Anone%7D%23ui-overlay%7Bposition%3Afixed%3Btop%3A0%3Bleft%3A0%3Bwidth%3A100%25%3Bheight%3A100%25%3Bpointer-events%3Anone%3Bz-index%3A1000%7D%23ui-overlay%3E*%7Bpointer-events%3Aauto%7D%23emoji-button%7Bposition%3Afixed%3Bbottom%3A20px%3Bleft%3A50%25%3Btransform%3AtranslateX(-50%25)%3Bwidth%3A60px%3Bheight%3A60px%3Bbackground%3Argba(0%2C0%2C0%2C0.8)%3Bborder%3A2px%20solid%20rgba(255%2C255%2C255%2C0.3)%3Bborder-radius%3A12px%3Bdisplay%3Aflex%3Balign-items%3Acenter%3Bjustify-content%3Acenter%3Bcursor%3Apointer%3Btransition%3Aall%200.2s%3Bfont-size%3A32px%3B-webkit-user-select%3Anone%3Buser-select%3Anone%7D%23emoji-button%3Ahover%7Bbackground%3Argba(51%2C51%2C51%2C0.9)%3Bborder-color%3Argba(255%2C255%2C255%2C0.5)%3Btransform%3AtranslateX(-50%25)%20scale(1.05)%7D%23emoji-button%3Aactive%7Btransform%3AtranslateX(-50%25)%20scale(0.95)%7D%23emoji-button.pulsing%7Banimation%3Apulse%200.6s%20ease-in-out%20infinite%7D%40keyframes%20pulse%7B0%25%2C100%25%7Btransform%3AtranslateX(-50%25)%20scale(1)%7D50%25%7Btransform%3AtranslateX(-50%25)%20scale(1.15)%7D%7D%23emoji-picker%7Bposition%3Afixed%3Bbottom%3A100px%3Bleft%3A50%25%3Btransform%3AtranslateX(-50%25)%3Bwidth%3A320px%3Bmax-height%3A460px%3Bbackground%3Argba(0%2C0%2C0%2C0.95)%3Bborder%3A3px%20solid%20rgba(255%2C255%2C255%2C0.3)%3Bborder-radius%3A16px%3Bpadding%3A20px%3Bdisplay%3Anone%3Bflex-direction%3Acolumn%3Bgap%3A15px%7D%23emoji-picker.visible%7Bdisplay%3Aflex%3Banimation%3AslideUp%200.2s%20ease-out%7D%40keyframes%20slideUp%7Bfrom%7Bopacity%3A0%3Btransform%3AtranslateX(-50%25)%20translateY(20px)%20scale(0.95)%7Dto%7Bopacity%3A1%3Btransform%3AtranslateX(-50%25)%20translateY(0)%20scale(1)%7D%7D%23emoji-picker%20h3%7Bcolor%3Awhite%3Bfont-size%3A18px%3Bmargin%3A0%3Btext-align%3Acenter%7D%23emoji-picker%20p%7Bcolor%3A%23aaa%3Bfont-size%3A11px%3Bmargin%3A0%3Btext-align%3Acenter%3Bline-height%3A1.4%7D%23emoji-grid%7Bdisplay%3Agrid%3Bgrid-template-columns%3Arepeat(6%2C1fr)%3Bgap%3A8px%3Bmax-height%3A320px%3Boverflow-y%3Aauto%3Bpadding%3A5px%7D%23emoji-grid%3A%3A-webkit-scrollbar%7Bwidth%3A6px%7D%23emoji-grid%3A%3A-webkit-scrollbar-track%7Bbackground%3Argba(255%2C255%2C255%2C0.1)%3Bborder-radius%3A3px%7D%23emoji-grid%3A%3A-webkit-scrollbar-thumb%7Bbackground%3Argba(255%2C255%2C255%2C0.3)%3Bborder-radius%3A3px%7D.emoji-item%7Bwidth%3A40px%3Bheight%3A40px%3Bdisplay%3Aflex%3Balign-items%3Acenter%3Bjustify-content%3Acenter%3Bfont-size%3A28px%3Bbackground%3Argba(34%2C34%2C34%2C0.5)%3Bborder-radius%3A8px%3Bcursor%3Apointer%3Btransition%3Aall%200.15s%3B-webkit-user-select%3Anone%3Buser-select%3Anone%7D.emoji-item%3Ahover%7Bbackground%3Argba(68%2C68%2C68%2C0.8)%3Btransform%3Ascale(1.2)%7D.emoji-item%3Aactive%7Btransform%3Ascale(1.1)%7D%23audio-unlock-button%7Bposition%3Afixed%3Btop%3A10px%3Bright%3A10px%3Bwidth%3A60px%3Bheight%3A60px%3Bbackground%3Argba(255%2C59%2C48%2C0.95)%3Bborder%3A3px%20solid%20rgba(255%2C255%2C255%2C0.8)%3Bborder-radius%3A50%25%3Bdisplay%3Aflex%3Balign-items%3Acenter%3Bjustify-content%3Acenter%3Bcursor%3Apointer%3Btransition%3Aall%200.2s%3Bfont-size%3A32px%3B-webkit-user-select%3Anone%3Buser-select%3Anone%3Bbox-shadow%3A0%204px%2012px%20rgba(0%2C0%2C0%2C0.5)%3Bz-index%3A10000%3Banimation%3Apulse-attention%202s%20ease-in-out%20infinite%7D%40keyframes%20pulse-attention%7B0%25%2C100%25%7Btransform%3Ascale(1)%3Bbox-shadow%3A0%204px%2012px%20rgba(0%2C0%2C0%2C0.5)%7D50%25%7Btransform%3Ascale(1.1)%3Bbox-shadow%3A0%206px%2016px%20rgba(255%2C59%2C48%2C0.6)%7D%7D%23audio-unlock-button%3Ahover%7Bbackground%3Argba(255%2C69%2C58%2C1)%3Btransform%3Ascale(1.15)%7D%23audio-unlock-button%3Aactive%7Btransform%3Ascale(0.9)%7D%23audio-unlock-button.unlocked%7Bbackground%3Argba(52%2C199%2C89%2C0.95)%3Banimation%3Asuccess-pulse%200.5s%20ease-out%2CfadeOut%200.5s%20ease-out%202s%20forwards%7D%40keyframes%20success-pulse%7B0%25%2C100%25%7Btransform%3Ascale(1)%7D50%25%7Btransform%3Ascale(1.3)%7D%7D%40keyframes%20fadeOut%7Bto%7Bopacity%3A0%3Bpointer-events%3Anone%7D%7D%23voice-chat-controls%7Bposition%3Afixed%3Btop%3A10px%3Bleft%3A10px%3Bdisplay%3Aflex%3Bflex-direction%3Acolumn%3Bgap%3A10px%3Bz-index%3A10000%7D.voice-button%7Bwidth%3A50px%3Bheight%3A50px%3Bbackground%3Argba(0%2C0%2C0%2C0.8)%3Bborder%3A2px%20solid%20rgba(255%2C255%2C255%2C0.3)%3Bborder-radius%3A12px%3Bdisplay%3Aflex%3Balign-items%3Acenter%3Bjustify-content%3Acenter%3Bcursor%3Apointer%3Btransition%3Aall%200.2s%3Bfont-size%3A24px%3B-webkit-user-select%3Anone%3Buser-select%3Anone%7D.voice-button%3Ahover%7Bbackground%3Argba(51%2C51%2C51%2C0.9)%3Bborder-color%3Argba(255%2C255%2C255%2C0.5)%3Btransform%3Ascale(1.05)%7D.voice-button%3Aactive%7Btransform%3Ascale(0.95)%7D.voice-button.active%7Bbackground%3Argba(52%2C199%2C89%2C0.9)%3Bborder-color%3Argba(52%2C199%2C89%2C1)%7D.voice-button.muted%7Bbackground%3Argba(255%2C59%2C48%2C0.9)%3Bborder-color%3Argba(255%2C59%2C48%2C1)%7D.voice-button.disabled%7Bopacity%3A0.4%3Bcursor%3Anot-allowed%7D%23voice-chat-status%7Bposition%3Afixed%3Btop%3A130px%3Bleft%3A10px%3Bbackground%3Argba(0%2C0%2C0%2C0.9)%3Bborder%3A2px%20solid%20rgba(255%2C255%2C255%2C0.3)%3Bborder-radius%3A12px%3Bpadding%3A8px%2012px%3Bcolor%3Awhite%3Bfont-size%3A12px%3Bdisplay%3Anone%3Bmax-width%3A200px%3Bz-index%3A10000%7D%23voice-chat-status.visible%7Bdisplay%3Ablock%7D.peer-speaking%7Bdisplay%3Aflex%3Balign-items%3Acenter%3Bgap%3A6px%3Bmargin%3A4px%200%7D.speaking-indicator%7Bwidth%3A8px%3Bheight%3A8px%3Bbackground%3A%2334C759%3Bborder-radius%3A50%25%3Banimation%3Apulse-speaking%200.8s%20ease-in-out%20infinite%7D%40keyframes%20pulse-speaking%7B0%25%2C100%25%7Bopacity%3A1%3Btransform%3Ascale(1)%7D50%25%7Bopacity%3A0.5%3Btransform%3Ascale(1.3)%7D%7D%3C%2Fstyle%3E%3Cscript%20type%3D%22importmap%22%3E%7B%22imports%22%3A%7B%22pixi.js%22%3A%22https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fpixi.js%407.3.2%2F%2Besm%22%2C%22peerjs%22%3A%22https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Fpeerjs%401.5.5%2F%2Besm%22%7D%7D%3C%2Fscript%3E%3Cscript%20type%3D%22module%22%3Eimport%7BGraphics%20as%20e%2CText%20as%20t%2CContainer%20as%20i%2CApplication%20as%20o%7Dfrom%22pixi.js%22%3Bimport%20a%20from%22peerjs%22%3B1%2Cfunction()%7Bconst%20e%3Ddocument.createElement(%22link%22).relList%3Bif(!(e%26%26e.supports%26%26e.supports(%22modulepreload%22)))%7Bfor(const%20e%20of%20document.querySelectorAll('link%5Brel%3D%22modulepreload%22%5D'))t(e)%3Bnew%20MutationObserver(e%3D%3E%7Bfor(const%20i%20of%20e)if(%22childList%22%3D%3D%3Di.type)for(const%20e%20of%20i.addedNodes)%22LINK%22%3D%3D%3De.tagName%26%26%22modulepreload%22%3D%3D%3De.rel%26%26t(e)%7D).observe(document%2C%7BchildList%3A!0%2Csubtree%3A!0%7D)%7Dfunction%20t(e)%7Bif(e.ep)return%3Be.ep%3D!0%3Bconst%20t%3Dfunction(e)%7Bconst%20t%3D%7B%7D%3Breturn%20e.integrity%26%26(t.integrity%3De.integrity)%2Ce.referrerPolicy%26%26(t.referrerPolicy%3De.referrerPolicy)%2C%22use-credentials%22%3D%3D%3De.crossOrigin%3Ft.credentials%3D%22include%22%3A%22anonymous%22%3D%3D%3De.crossOrigin%3Ft.credentials%3D%22omit%22%3At.credentials%3D%22same-origin%22%2Ct%7D(e)%3Bfetch(e.href%2Ct)%7D%7D()%3Bconst%20s%3D%7BGRID_SIZE%3A50%2CGRID_WIDTH%3A30%2CGRID_HEIGHT%3A20%2CMIN_ZOOM%3A.3%2CMAX_ZOOM%3A3%2CSWIPE_THRESHOLD%3A30%2CTAP_TIME_THRESHOLD%3A200%2CEMOJI_DRAG_THRESHOLD%3A10%2CEMOJI_TAP_TIME%3A200%2CEMOJI_HOLD_TIME%3A500%2CMOVE_DURATION%3A200%2CFAST_MOVE_DURATION%3A120%2CEMOJI_PLACE_DURATION%3A300%2CCAMERA_CENTER_DURATION%3A300%2CBOUNCE_SCALE%3A1.12%2CFAST_BOUNCE_SCALE%3A1.08%2Cget%20DOOR_X()%7Breturn%20this.GRID_WIDTH-3%7D%2Cget%20DOOR_Y()%7Breturn%20this.GRID_HEIGHT-3%7D%2Cget%20PLAYER_START_X()%7Breturn%20this.GRID_WIDTH-2%7D%2Cget%20PLAYER_START_Y()%7Breturn%20this.GRID_HEIGHT-3%7D%2CGRID_DRAW_THROTTLE%3A100%2CMAX_GRID_CELLS%3A3e3%2CGRID_DOT_RADIUS%3A1%2CBORDER_WIDTH%3A10%2CHOP_SOUND%3A%7Btype%3A%22sine%22%2CstartFreq%3A200%2CendFreq%3A210%2Cduration%3A.15%2Cvolume%3A.2%7D%2CPLACE_SOUND%3A%7Btype%3A%22triangle%22%2CstartFreq%3A200%2CendFreq%3A60%2Cduration%3A.18%2Cvolume%3A.2%7D%2CREMOVE_SOUND%3A%7Btype%3A%22square%22%2CstartFreq%3A200%2CendFreq%3A20%2Cduration%3A.25%2Cvolume%3A.1%7D%2CCOLLISION_SOUND%3A%7Btype%3A%22triangle%22%2CstartFreq%3A150%2CendFreq%3A80%2Cduration%3A.1%2Cvolume%3A.2%7D%2CVOICE_CHAT%3A%7Benabled%3A!1%2CspeakingThreshold%3A30%2CvolumeCheckInterval%3A100%7D%7D%2Cn%3D%5B%22%F0%9F%8E%99%EF%B8%8F%22%2C%22%F0%9F%9F%AA%22%2C%22%F0%9F%9F%A6%22%2C%22%F0%9F%9F%A9%22%2C%22%F0%9F%9F%A8%22%2C%22%F0%9F%9F%A7%22%2C%22%F0%9F%9F%A5%22%2C%22%F0%9F%9F%AB%22%2C%22%E2%AC%9B%EF%B8%8F%22%2C%22%E2%AC%9C%EF%B8%8F%22%5D%2Cr%3D%5B%22%F0%9F%8C%B2%22%5D%3Bfunction%20l()%7Btry%7Bconst%20e%3D%22__storage_test__%22%3Breturn%20localStorage.setItem(e%2Ce)%2ClocalStorage.removeItem(e)%2C!0%7Dcatch(e)%7Breturn!1%7D%7Dconst%20c%3D%7BisAvailable%3A()%3D%3El()%2CgetItem(e)%7Bif(!l())return%20null%3Btry%7Breturn%20localStorage.getItem(e)%7Dcatch(t)%7Breturn%20console.warn(%60localStorage.getItem('%24%7Be%7D')%20failed%3A%60%2Ct)%2Cnull%7D%7D%2CsetItem(e%2Ct)%7Bif(!l())return!1%3Btry%7Breturn%20localStorage.setItem(e%2Ct)%2C!0%7Dcatch(i)%7Breturn%20console.warn(%60localStorage.setItem('%24%7Be%7D')%20failed%3A%60%2Ci)%2C!1%7D%7D%2CremoveItem(e)%7Bif(!l())return!1%3Btry%7Breturn%20localStorage.removeItem(e)%2C!0%7Dcatch(t)%7Breturn%20console.warn(%60localStorage.removeItem('%24%7Be%7D')%20failed%3A%60%2Ct)%2C!1%7D%7D%7D%3Bclass%20h%7Bstate%3BaudioService%3BemojiContainer%3BnetworkService%3Dnull%3Bstatic%20STORAGE_KEY%3D%22emoji-metaverse-placed-emojis%22%3Bconstructor(e%2Ct%2Ci)%7Bthis.state%3De%2Cthis.audioService%3Dt%2Cthis.emojiContainer%3Di%7DsetNetworkService(e)%7Bthis.networkService%3De%7DsaveEmojis()%7Bconst%20e%3D%5B%5D%3Bthis.emojiContainer.children.forEach(i%3D%3E%7Bi%20instanceof%20t%26%26%22static%22%3D%3D%3Di.eventMode%26%26e.push(%7Bemoji%3Ai.text%2Cx%3Ai.x%2Cy%3Ai.y%7D)%7D)%2Cc.setItem(h.STORAGE_KEY%2CJSON.stringify(e))%3Fconsole.log(%60%F0%9F%92%BE%20Saved%20%24%7Be.length%7D%20emojis%20to%20localStorage%60)%3Aconsole.log(%60%F0%9F%92%BE%20Skipped%20saving%20%24%7Be.length%7D%20emojis%20(localStorage%20unavailable)%60)%7DloadEmojis()%7Bconst%20e%3Dc.getItem(h.STORAGE_KEY)%3Bif(!e)return%20console.log(%22No%20saved%20emojis%20found%22)%2Cvoid%200%3Btry%7Bconst%20i%3DJSON.parse(e)%3Bconsole.log(%60%F0%9F%93%82%20Loading%20%24%7Bi.length%7D%20emojis%20from%20localStorage%60)%2Ci.forEach((%7Bemoji%3Ae%2Cx%3Ai%2Cy%3Ao%7D)%3D%3E%7Bconst%20a%3Dnew%20t(e%2C%7BfontSize%3A48%2CfontFamily%3A%22Arial%22%7D)%3Ba.anchor.set(.5)%2Ca.position.set(i%2Co)%2Cthis.makeEmojiDraggable(a)%2Cthis.emojiContainer.addChild(a)%7D)%2Cconsole.log(%60%E2%9C%85%20Loaded%20%24%7Bi.length%7D%20emojis%20successfully%60)%7Dcatch(i)%7Bconsole.error(%22Failed%20to%20load%20emojis%20from%20localStorage%3A%22%2Ci)%7D%7DmakeEmojiDraggable(e)%7Be.eventMode%3D%22static%22%2Ce.cursor%3D%22pointer%22%2Ce.on(%22pointerdown%22%2Ct%3D%3E%7Bconst%20i%3Dt.data.global%3Bthis.audioService.isUnlocked()%7C%7Cthis.audioService.unlockAudio()%3Bconst%20o%3Dt.data.originalEvent%3Bo%26%26this.state.touches.push(o)%2Cthis.state.swipeStartX%3Di.x%2Cthis.state.swipeStartY%3Di.y%2Cthis.state.touchStartTime%3DDate.now()%2Cthis.state.isPinching%3D!1%2Cthis.state.twoFingerPanning%3D!1%2Cthis.state.draggedEmoji%3De%2Cthis.state.emojiDragStartTime%3DDate.now()%2Cthis.state.emojiOriginalX%3De.x%2Cthis.state.emojiOriginalY%3De.y%2Cthis.state.emojiReadyToDrag%3D!1%2Cthis.state.emojiDragStartX%3Di.x%2Cthis.state.emojiDragStartY%3Di.y%2Cthis.state.emojiHoldTimer%3DsetTimeout(()%3D%3E%7Bthis.state.draggedEmoji%3D%3D%3De%26%26(this.state.emojiReadyToDrag%3D!0%2Ce.alpha%3D.7%2Ce.scale.set(1.2))%7D%2Cs.EMOJI_HOLD_TIME)%2Ct.stopPropagation()%7D)%7DhandleEmojiDragMove(e%2Ct%2Ci)%7Bif(!this.state.draggedEmoji%7C%7C!this.state.emojiReadyToDrag)return%3Bconst%20o%3D(e-this.state.emojiDragStartX)%2Fi%2Ca%3D(t-this.state.emojiDragStartY)%2Fi%3Bthis.state.draggedEmoji.x%3Dthis.state.emojiOriginalX%2Bo%2Cthis.state.draggedEmoji.y%3Dthis.state.emojiOriginalY%2Ba%7DhandleEmojiDragEnd(e%2Ct)%7Bif(!this.state.draggedEmoji)return%3Bthis.state.clearEmojiHoldTimer()%3Bconst%20i%3DDate.now()-this.state.emojiDragStartTime%2Co%3DMath.sqrt(Math.pow(e-this.state.emojiDragStartX%2C2)%2BMath.pow(t-this.state.emojiDragStartY%2C2))%3Bif(i%3Cs.EMOJI_TAP_TIME%26%26o%3Cs.EMOJI_DRAG_THRESHOLD)%7Bconst%20e%3DMath.floor(this.state.draggedEmoji.x%2Fs.GRID_SIZE)%2Ct%3DMath.floor(this.state.draggedEmoji.y%2Fs.GRID_SIZE)%3Bthis.state.draggedEmoji.off(%22pointerdown%22)%2Cthis.emojiContainer.removeChild(this.state.draggedEmoji)%2Cthis.state.draggedEmoji.destroy(%7Bchildren%3A!0%2Ctexture%3A!1%2CbaseTexture%3A!1%7D)%2Cthis.audioService.playRemoveSound()%2Cconsole.log(%22Emoji%20deleted%22)%2Cthis.saveEmojis()%2Cthis.networkService%26%26this.networkService.removeEmoji(e%2Ct)%7Delse%20if(this.state.emojiReadyToDrag)%7Bconst%20e%3DMath.floor(this.state.draggedEmoji.x%2Fs.GRID_SIZE)%2Ct%3DMath.floor(this.state.draggedEmoji.y%2Fs.GRID_SIZE)%3Bif(e%3E%3D0%26%26e%3Cs.GRID_WIDTH%26%26t%3E%3D0%26%26t%3Cs.GRID_HEIGHT)%7Bconst%20i%3De*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Co%3Dt*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%3Bif(this.emojiContainer.children.filter(i%3D%3E%7Bif(i%3D%3D%3Dthis.state.draggedEmoji)return!1%3Bconst%20o%3DMath.floor(i.x%2Fs.GRID_SIZE)%2Ca%3DMath.floor(i.y%2Fs.GRID_SIZE)%3Breturn%20o%3D%3D%3De%26%26a%3D%3D%3Dt%7D).length%3E0)this.state.draggedEmoji.x%3Dthis.state.emojiOriginalX%2Cthis.state.draggedEmoji.y%3Dthis.state.emojiOriginalY%2Cthis.audioService.playCollisionSound()%3Belse%7Bconst%20a%3Dthis.state.draggedEmoji.text%2Cn%3DMath.floor(this.state.emojiOriginalX%2Fs.GRID_SIZE)%2Cr%3DMath.floor(this.state.emojiOriginalY%2Fs.GRID_SIZE)%3Bthis.state.draggedEmoji.x%3Di%2Cthis.state.draggedEmoji.y%3Do%2Cthis.audioService.playPlaceSound()%2Cconsole.log(%60Emoji%20moved%20to%20grid%20(%24%7Be%7D%2C%20%24%7Bt%7D)%60)%2Cthis.saveEmojis()%2Cthis.networkService%26%26(this.networkService.removeEmoji(n%2Cr)%2Cthis.networkService.placeEmoji(e%2Ct%2Ca))%7D%7Delse%20this.state.draggedEmoji.x%3Dthis.state.emojiOriginalX%2Cthis.state.draggedEmoji.y%3Dthis.state.emojiOriginalY%2Cthis.audioService.playCollisionSound()%3Bthis.state.draggedEmoji.alpha%3D1%2Cthis.state.draggedEmoji.scale.set(1)%7Delse%20this.state.draggedEmoji.alpha%3D1%2Cthis.state.draggedEmoji.scale.set(1)%3Bthis.state.draggedEmoji%3Dnull%2Cthis.state.emojiReadyToDrag%3D!1%7DplaceEmoji(e%2Ci%2Co)%7Bconst%20a%3DMath.floor(e%2Fs.GRID_SIZE)%2Cn%3DMath.floor(i%2Fs.GRID_SIZE)%3Bif(0%3Ea%7C%7Ca%3E%3Ds.GRID_WIDTH%7C%7C0%3En%7C%7Cn%3E%3Ds.GRID_HEIGHT)return%3Bconst%20r%3Da*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cl%3Dn*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%3Bthis.emojiContainer.children.filter(e%3D%3E%7Bconst%20t%3DMath.floor(e.x%2Fs.GRID_SIZE)%2Ci%3DMath.floor(e.y%2Fs.GRID_SIZE)%3Breturn%20t%3D%3D%3Da%26%26i%3D%3D%3Dn%7D).forEach(e%3D%3E%7Be.off%26%26e.off(%22pointerdown%22)%2Cthis.emojiContainer.removeChild(e)%2Ce.destroy(%7Bchildren%3A!0%2Ctexture%3A!1%2CbaseTexture%3A!1%7D)%7D)%3Bconst%20c%3Dnew%20t(o%2C%7BfontSize%3A48%2CfontFamily%3A%22Arial%22%7D)%3Bc.anchor.set(.5)%2Cc.position.set(r%2Cl)%2Cc.scale.set(0)%2Cthis.makeEmojiDraggable(c)%2Cthis.emojiContainer.addChild(c)%2Cthis.audioService.playPlaceSound()%3Bconst%20h%3DDate.now()%2Cd%3Ds.EMOJI_PLACE_DURATION%2Cm%3D()%3D%3E%7Bconst%20e%3DDate.now()-h%2Ct%3DMath.min(e%2Fd%2C1)%2Ci%3D1-Math.pow(1-t%2C4)%3Bc.scale.set(i)%2C1%3Et%26%26requestAnimationFrame(m)%7D%3Bm()%2Cconsole.log(%60Placed%20%24%7Bo%7D%20at%20grid%20(%24%7Ba%7D%2C%20%24%7Bn%7D)%60)%2Cthis.saveEmojis()%2Cthis.networkService%26%26this.networkService.placeEmoji(a%2Cn%2Co)%7DplaceEmojiFromNetwork(e%2Ci%2Co)%7Bconst%20a%3De*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cn%3Di*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%3Bthis.emojiContainer.children.filter(t%3D%3E%7Bconst%20o%3DMath.floor(t.x%2Fs.GRID_SIZE)%2Ca%3DMath.floor(t.y%2Fs.GRID_SIZE)%3Breturn%20o%3D%3D%3De%26%26a%3D%3D%3Di%7D).forEach(e%3D%3E%7Be.off%26%26e.off(%22pointerdown%22)%2Cthis.emojiContainer.removeChild(e)%2Ce.destroy(%7Bchildren%3A!0%2Ctexture%3A!1%2CbaseTexture%3A!1%7D)%7D)%3Bconst%20r%3Dnew%20t(o%2C%7BfontSize%3A48%2CfontFamily%3A%22Arial%22%7D)%3Br.anchor.set(.5)%2Cr.position.set(a%2Cn)%2Cthis.makeEmojiDraggable(r)%2Cthis.emojiContainer.addChild(r)%2Cconsole.log(%60%F0%9F%93%A1%20Received%20%24%7Bo%7D%20at%20grid%20(%24%7Be%7D%2C%20%24%7Bi%7D)%20from%20network%60)%7DremoveEmojiFromNetwork(e%2Ct)%7Bthis.emojiContainer.children.filter(i%3D%3E%7Bconst%20o%3DMath.floor(i.x%2Fs.GRID_SIZE)%2Ca%3DMath.floor(i.y%2Fs.GRID_SIZE)%3Breturn%20o%3D%3D%3De%26%26a%3D%3D%3Dt%7D).forEach(e%3D%3E%7Be.off%26%26e.off(%22pointerdown%22)%2Cthis.emojiContainer.removeChild(e)%2Ce.destroy(%7Bchildren%3A!0%2Ctexture%3A!1%2CbaseTexture%3A!1%7D)%7D)%2Cconsole.log(%60%F0%9F%93%A1%20Removed%20emoji%20at%20grid%20(%24%7Be%7D%2C%20%24%7Bt%7D)%20from%20network%60)%7DplaceStaticEmoji(e%2Ci%2Co)%7Bconst%20a%3De*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cn%3Di*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cr%3Dnew%20t(o%2C%7BfontSize%3A48%2CfontFamily%3A%22Arial%22%7D)%3Br.anchor.set(.5)%2Cr.position.set(a%2Cn)%2Cthis.emojiContainer.addChild(r)%7DgetAllEmojis()%7Bconst%20e%3D%5B%5D%3Breturn%20this.emojiContainer.children.forEach(i%3D%3E%7Bif(i%20instanceof%20t%26%26%22static%22%3D%3D%3Di.eventMode)%7Bconst%20t%3DMath.floor(i.x%2Fs.GRID_SIZE)%2Co%3DMath.floor(i.y%2Fs.GRID_SIZE)%3Be.push(%7BgridX%3At%2CgridY%3Ao%2Cemoji%3Ai.text%7D)%7D%7D)%2Ce%7D%7Dconst%20d%3Dwindow.devicePixelRatio%7C%7C1%3Bconsole.log(%22Device%20Pixel%20Ratio%3A%22%2Cd)%3Bconst%20m%3Dnew%20o(%7BbackgroundColor%3A0%2CresizeTo%3Awindow%2Cresolution%3Ad%2CautoDensity%3A!0%2Cantialias%3A!0%7D)%3Bdocument.getElementById(%22game-container%22).appendChild(m.view)%2Cconsole.log(%60%E2%9C%85%20PixiJS%20initialized%20with%20%24%7Bd%7Dx%20resolution%60)%3Bconst%20u%3Dnew%20i%2Cg%3Dnew%20i%2Cp%3Dnew%20i%2Cv%3Dnew%20i%2CV%3Dnew%20i%2Cy%3Dnew%20i%3Bu.addChild(g)%2Cu.addChild(p)%2Cu.addChild(v)%2Cu.addChild(V)%2Cm.stage.addChild(u)%2Cm.stage.addChild(y)%3Bconst%20E%3Dnew%20t(%22%F0%9F%98%8E%22%2C%7BfontSize%3A48%2CfontFamily%3A%22Arial%22%7D)%3BE.anchor.set(.5)%2CV.addChild(E)%3Bconst%20S%3Dnew%20class%7BplayerGridX%3Ds.PLAYER_START_X%3BplayerGridY%3Ds.PLAYER_START_Y%3BisMoving%3D!1%3BcurrentAnimationId%3Dnull%3BcameraX%3D0%3BcameraY%3D0%3BcameraZoom%3D1%3BselectedEmoji%3Dnull%3BisMultiplayerEnabled%3D!0%3BplayerId%3D%22%22%3BswipeStartX%3D0%3BswipeStartY%3D0%3BtouchStartTime%3D0%3BisHolding%3D!1%3BholdDirection%3D%7Bx%3A0%2Cy%3A0%7D%3BholdMoveInterval%3Dnull%3BdraggedEmoji%3Dnull%3BemojiDragStartX%3D0%3BemojiDragStartY%3D0%3BemojiDragStartTime%3D0%3BemojiOriginalX%3D0%3BemojiOriginalY%3D0%3BemojiHoldTimer%3Dnull%3BemojiReadyToDrag%3D!1%3BtwoFingerStart%3D%5B%5D%3BinitialPinchDistance%3D0%3BinitialZoom%3D1%3BlastTwoFingerMidX%3D0%3BlastTwoFingerMidY%3D0%3BisPinching%3D!1%3BtwoFingerPanning%3D!1%3Btouches%3D%5B%5D%3BlastGridDraw%3D0%3BlastCameraState%3D%7Bx%3A0%2Cy%3A0%2Czoom%3A1%7D%3BlastCameraUpdate%3D%7Bx%3A0%2Cy%3A0%2Czoom%3A1%7D%3Bconstructor()%7Bconsole.log(%22GameState%20initialized%22)%7DcancelAnimation()%7Bnull!%3D%3Dthis.currentAnimationId%26%26(cancelAnimationFrame(this.currentAnimationId)%2Cthis.currentAnimationId%3Dnull)%2Cthis.isMoving%3D!1%7DstopHoldMovement()%7Bthis.isHolding%3D!1%2Cthis.holdMoveInterval%26%26(clearInterval(this.holdMoveInterval)%2Cthis.holdMoveInterval%3Dnull)%7DclearEmojiHoldTimer()%7Bthis.emojiHoldTimer%26%26(clearTimeout(this.emojiHoldTimer)%2Cthis.emojiHoldTimer%3Dnull)%7DresetEmojiDrag()%7Bthis.clearEmojiHoldTimer()%2Cthis.draggedEmoji%26%26(this.draggedEmoji.alpha%3D1%2Cthis.draggedEmoji.scale.set(1))%2Cthis.draggedEmoji%3Dnull%2Cthis.emojiReadyToDrag%3D!1%7Dcleanup()%7Bthis.cancelAnimation()%2Cthis.stopHoldMovement()%2Cthis.resetEmojiDrag()%7D%7D%2CI%3Dnew%20class%7BaudioContext%3Dnull%3BaudioUnlocked%3D!1%3BsilentAudio%3Dnull%3Bconstructor()%7Bthis.setupVisibilityListener()%7DisUnlocked()%7Breturn%20this.audioUnlocked%7Dasync%20unlockAudio()%7Bif(!this.audioUnlocked)%7Bconsole.log(%22%F0%9F%94%8A%20unlockAudio%20called%2C%20audioUnlocked%3A%22%2Cthis.audioUnlocked)%3Btry%7Bif(this.silentAudio%7C%7C(this.silentAudio%3Dnew%20Audio(%22data%3Aaudio%2Fmpeg%3Bbase64%2CSUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMKpIE5DSCBTb2Z0d2FyZQBUSVQyAAAABgAAAzIyMzUAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAAAAD%2F80DEAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf%2FzQsRbAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf%2FzQMSkAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV%22)%2Cthis.silentAudio.setAttribute(%22x-webkit-airplay%22%2C%22deny%22)%2Cthis.silentAudio.preload%3D%22auto%22%2Cthis.silentAudio.loop%3D!1%2Cconsole.log(%22%F0%9F%93%B1%20Created%20HTML5%20silent%20audio%20element%22))%2Cawait%20this.silentAudio.play().catch(e%3D%3Econsole.warn(%22Silent%20audio%20play%20failed%3A%22%2Ce))%2Cconsole.log(%22%E2%9C%85%20Silent%20HTML5%20audio%20played%22)%2C!this.audioContext)%7Bconst%20e%3Dwindow.AudioContext%7C%7Cwindow.webkitAudioContext%3Be%26%26(this.audioContext%3Dnew%20e%2Cconsole.log(%22%E2%9C%85%20Audio%20context%20created%2C%20state%3A%22%2Cthis.audioContext.state))%7Dif(!this.audioContext)return%20console.error(%22%E2%9D%8C%20Failed%20to%20create%20audio%20context%22)%2Cvoid%200%3B%22suspended%22%3D%3D%3Dthis.audioContext.state%26%26(await%20this.audioContext.resume()%2Cconsole.log(%22%E2%9C%85%20Audio%20context%20resumed%2C%20state%3A%22%2Cthis.audioContext.state))%3Bconst%20e%3Dthis.audioContext.createBuffer(1%2C1%2C22050)%2Ct%3Dthis.audioContext.createBufferSource()%3Bt.buffer%3De%2Ct.connect(this.audioContext.destination)%2Ct.start(0)%2Cawait%20new%20Promise(e%3D%3EsetTimeout(e%2C100))%2C%22running%22%3D%3D%3Dthis.audioContext.state%3F(this.audioUnlocked%3D!0%2Cconsole.log(%22%E2%9C%85%20Audio%20FULLY%20unlocked!%20State%3A%22%2Cthis.audioContext.state)%2Cthis.audioContext.onstatechange%3D()%3D%3E%7Bconsole.log(%22%F0%9F%94%84%20Audio%20state%20changed%20to%3A%22%2Cthis.audioContext%3F.state)%2C!this.audioContext%7C%7C%22interrupted%22!%3D%3Dthis.audioContext.state%26%26%22suspended%22!%3D%3Dthis.audioContext.state%7C%7C(console.log(%22%E2%9A%A0%EF%B8%8F%20Audio%20interrupted%2C%20attempting%20to%20resume...%22)%2Cthis.audioContext.resume().catch(e%3D%3Econsole.error(%22Resume%20failed%3A%22%2Ce)))%7D)%3Aconsole.warn(%22%E2%9A%A0%EF%B8%8F%20Audio%20context%20not%20running%3A%22%2Cthis.audioContext.state)%7Dcatch(e)%7Bconsole.error(%22%E2%9D%8C%20Error%20unlocking%20audio%3A%22%2Ce)%7D%7D%7DsetupVisibilityListener()%7Bdocument.addEventListener(%22visibilitychange%22%2C()%3D%3E%7B%22visible%22%3D%3D%3Ddocument.visibilityState%26%26this.audioContext%26%26(console.log(%22%F0%9F%91%81%EF%B8%8F%20Page%20visible%2C%20audio%20state%3A%22%2Cthis.audioContext.state)%2C%22suspended%22!%3D%3Dthis.audioContext.state%26%26%22interrupted%22!%3D%3Dthis.audioContext.state%7C%7Cthis.audioContext.resume().then(()%3D%3E%7Bconsole.log(%22%E2%9C%85%20Audio%20resumed%20after%20visibility%20change%22)%7D).catch(e%3D%3Econsole.error(%22Failed%20to%20resume%3A%22%2Ce)))%7D)%7Dasync%20resumeIfNeeded()%7Bif(!this.audioContext%7C%7C!this.audioUnlocked)return!1%3Btry%7Breturn%22suspended%22%3D%3D%3Dthis.audioContext.state%26%26(console.log(%22Resuming%20suspended%20audio%20context%22)%2Cawait%20this.audioContext.resume())%2C%22running%22%3D%3D%3Dthis.audioContext.state%7C%7C(console.warn(%22Audio%20context%20not%20running%2C%20state%3A%22%2Cthis.audioContext.state)%2C!1)%7Dcatch(e)%7Breturn%20console.error(%22Error%20resuming%20audio%3A%22%2Ce)%2C!1%7D%7Dasync%20playHopSound()%7Bif(await%20this.resumeIfNeeded())try%7Bconst%20e%3Ds.HOP_SOUND%2Ct%3Dthis.audioContext.createOscillator()%2Ci%3Dthis.audioContext.createGain()%3Bt.connect(i)%2Ci.connect(this.audioContext.destination)%2Ct.type%3De.type%2Ct.frequency.setValueAtTime(e.startFreq%2Cthis.audioContext.currentTime)%2Ct.frequency.exponentialRampToValueAtTime(e.endFreq%2Cthis.audioContext.currentTime%2B.08)%2Ci.gain.setValueAtTime(e.volume%2Cthis.audioContext.currentTime)%2Ci.gain.exponentialRampToValueAtTime(.01%2Cthis.audioContext.currentTime%2Be.duration)%2Ct.start(this.audioContext.currentTime)%2Ct.stop(this.audioContext.currentTime%2Be.duration)%7Dcatch(e)%7Bconsole.error(%22Error%20playing%20hop%20sound%3A%22%2Ce)%7D%7Dasync%20playPlaceSound()%7Bif(await%20this.resumeIfNeeded())try%7Bconst%20e%3Ds.PLACE_SOUND%2Ct%3Dthis.audioContext.createOscillator()%2Ci%3Dthis.audioContext.createGain()%3Bt.connect(i)%2Ci.connect(this.audioContext.destination)%2Ct.type%3De.type%2Ct.frequency.setValueAtTime(e.startFreq%2Cthis.audioContext.currentTime)%2Ct.frequency.exponentialRampToValueAtTime(e.endFreq%2Cthis.audioContext.currentTime%2B.1)%2Ci.gain.setValueAtTime(e.volume%2Cthis.audioContext.currentTime)%2Ci.gain.exponentialRampToValueAtTime(.6*e.volume%2Cthis.audioContext.currentTime%2B.06)%2Ci.gain.exponentialRampToValueAtTime(.01%2Cthis.audioContext.currentTime%2Be.duration)%2Ct.start(this.audioContext.currentTime)%2Ct.stop(this.audioContext.currentTime%2Be.duration)%7Dcatch(e)%7Bconsole.error(%22Error%20playing%20place%20sound%3A%22%2Ce)%7D%7Dasync%20playCollisionSound()%7Bif(await%20this.resumeIfNeeded())try%7Bconst%20e%3Ds.COLLISION_SOUND%2Ct%3Dthis.audioContext.createOscillator()%2Ci%3Dthis.audioContext.createGain()%3Bt.connect(i)%2Ci.connect(this.audioContext.destination)%2Ct.type%3De.type%2Ct.frequency.setValueAtTime(e.startFreq%2Cthis.audioContext.currentTime)%2Ct.frequency.exponentialRampToValueAtTime(e.endFreq%2Cthis.audioContext.currentTime%2B.05)%2Ci.gain.setValueAtTime(e.volume%2Cthis.audioContext.currentTime)%2Ci.gain.exponentialRampToValueAtTime(.01%2Cthis.audioContext.currentTime%2Be.duration)%2Ct.start(this.audioContext.currentTime)%2Ct.stop(this.audioContext.currentTime%2Be.duration)%7Dcatch(e)%7Bconsole.error(%22Error%20playing%20collision%20sound%3A%22%2Ce)%7D%7Dasync%20playRemoveSound()%7Bif(await%20this.resumeIfNeeded())try%7Bconst%20e%3Ds.REMOVE_SOUND%2Ct%3Dthis.audioContext.createOscillator()%2Ci%3Dthis.audioContext.createGain()%3Bt.connect(i)%2Ci.connect(this.audioContext.destination)%2Ct.type%3De.type%2Ct.frequency.setValueAtTime(e.startFreq%2Cthis.audioContext.currentTime)%2Ct.frequency.exponentialRampToValueAtTime(150%2Cthis.audioContext.currentTime%2B.05)%2Ct.frequency.exponentialRampToValueAtTime(e.endFreq%2Cthis.audioContext.currentTime%2Be.duration)%2Ci.gain.setValueAtTime(e.volume%2Cthis.audioContext.currentTime)%2Ci.gain.exponentialRampToValueAtTime(.4*e.volume%2Cthis.audioContext.currentTime%2B.05)%2Ci.gain.exponentialRampToValueAtTime(.01%2Cthis.audioContext.currentTime%2Be.duration)%2Ct.start(this.audioContext.currentTime)%2Ct.stop(this.audioContext.currentTime%2Be.duration)%7Dcatch(e)%7Bconsole.error(%22Error%20playing%20remove%20sound%3A%22%2Ce)%7D%7Dasync%20playTestBeep()%7Bif(!this.audioContext%7C%7C%22running%22!%3D%3Dthis.audioContext.state)return%20console.error(%22%E2%9D%8C%20Audio%20context%20not%20running%3A%22%2Cthis.audioContext%3F.state)%2Cvoid%200%3Btry%7Bconsole.log(%22Playing%20test%20beep...%22)%3Bconst%20e%3Dthis.audioContext.createOscillator()%2Ct%3Dthis.audioContext.createGain()%3Be.connect(t)%2Ct.connect(this.audioContext.destination)%2Ce.type%3D%22sine%22%2Ce.frequency.value%3D880%2Ct.gain.value%3D.3%2Ce.start(this.audioContext.currentTime)%2Ce.stop(this.audioContext.currentTime%2B.2)%2Cconsole.log(%22%E2%9C%85%20Test%20beep%20triggered%22)%7Dcatch(e)%7Bconsole.error(%22%E2%9D%8C%20Error%20playing%20test%20sound%3A%22%2Ce)%7D%7D%7D%2CC%3Dnew%20class%7Bapp%3Bstate%3BworldContainer%3Bconstructor(e%2Ct%2Ci)%7Bthis.app%3De%2Cthis.state%3Dt%2Cthis.worldContainer%3Di%7DupdateCamera()%7Bthis.worldContainer.scale.set(this.state.cameraZoom)%3Bconst%20e%3Dthis.app.renderer.screen.width%2F2%2Ct%3Dthis.app.renderer.screen.height%2F2%3Bthis.worldContainer.position.set(e-this.state.cameraX*this.state.cameraZoom%2Ct-this.state.cameraY*this.state.cameraZoom)%7DcenterCameraOn(e%2Ct)%7Bconst%20i%3Dthis.state.cameraX%2Co%3Dthis.state.cameraY%2Ca%3Ds.CAMERA_CENTER_DURATION%2Cn%3DDate.now()%2Cr%3D()%3D%3E%7Bconst%20s%3DDate.now()-n%2Cl%3DMath.min(s%2Fa%2C1)%2Cc%3D1-Math.pow(1-l%2C2)%3Bthis.state.cameraX%3Di%2B(e-i)*c%2Cthis.state.cameraY%3Do%2B(t-o)*c%2C1%3El%26%26requestAnimationFrame(r)%7D%3Br()%7DshakeCamera()%7Bconst%20e%3Dthis.state.cameraX%2Ct%3Dthis.state.cameraY%3Bfor(let%20i%3D0%3B3%3Ei%3Bi%2B%2B)setTimeout(()%3D%3E%7Bthis.state.cameraX%3De%2B5*(Math.random()-.5)%2Cthis.state.cameraY%3Dt%2B5*(Math.random()-.5)%7D%2C30*i)%3BsetTimeout(()%3D%3E%7Bthis.state.cameraX%3De%2Cthis.state.cameraY%3Dt%7D%2C100)%7DsetZoom(e)%7Bthis.state.cameraZoom%3DMath.max(s.MIN_ZOOM%2CMath.min(s.MAX_ZOOM%2Ce))%7DpanCamera(e%2Ct)%7Bthis.state.cameraX-%3De%2Cthis.state.cameraY-%3Dt%7DscreenToWorld(e%2Ct)%7Breturn%7Bx%3A(e-this.worldContainer.position.x)%2Fthis.state.cameraZoom%2Cy%3A(t-this.worldContainer.position.y)%2Fthis.state.cameraZoom%7D%7DworldToScreen(e%2Ct)%7Bconst%20i%3Dthis.app.renderer.screen.width%2F2%2Co%3Dthis.app.renderer.screen.height%2F2%3Breturn%7Bx%3Ai%2B(e-this.state.cameraX)*this.state.cameraZoom%2Cy%3Ao%2B(t-this.state.cameraY)*this.state.cameraZoom%7D%7D%7D(m%2CS%2Cu)%2CD%3Dnew%20class%7Bstate%3BcameraService%3BaudioService%3BplayerEmoji%3BemojiContainer%3BnetworkService%3Dnull%3Bconstructor(e%2Ct%2Ci%2Co%2Ca)%7Bthis.state%3De%2Cthis.cameraService%3Dt%2Cthis.audioService%3Di%2Cthis.playerEmoji%3Do%2Cthis.emojiContainer%3Da%2Cthis.setPlayerPosition()%7DsetNetworkService(e)%7Bthis.networkService%3De%7DgetPosition()%7Breturn%7Bx%3Athis.playerEmoji.x%2Cy%3Athis.playerEmoji.y%7D%7DsetPlayerPosition()%7Bconst%20e%3Dthis.state.playerGridX*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Ct%3Dthis.state.playerGridY*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%3Bthis.playerEmoji.position.set(e%2Ct)%7DhasEmojiAt(e%2Ct)%7Breturn%20this.emojiContainer.children.some(i%3D%3E%7Bconst%20o%3DMath.floor(i.x%2Fs.GRID_SIZE)%2Ca%3DMath.floor(i.y%2Fs.GRID_SIZE)%3Breturn%20o%3D%3D%3De%26%26a%3D%3D%3Dt%7D)%7DmovePlayer(e%2Ct%2Ci%3D!1)%7Bif(!this.state.isMoving)try%7Bconst%20o%3Dthis.state.playerGridX%2Be%2Ca%3Dthis.state.playerGridY%2Bt%3Bif(0%3Eo%7C%7Co%3E%3Ds.GRID_WIDTH%7C%7C0%3Ea%7C%7Ca%3E%3Ds.GRID_HEIGHT)return%20this.cameraService.shakeCamera()%2Cthis.audioService.playCollisionSound()%2Cvoid%200%3Bif(this.hasEmojiAt(o%2Ca))return%20this.cameraService.shakeCamera()%2Cthis.audioService.playCollisionSound()%2Cvoid%200%3Bthis.state.cancelAnimation()%2Cthis.state.isMoving%3D!0%2Cthis.state.playerGridX%3Do%2Cthis.state.playerGridY%3Da%3Bconst%20n%3Dthis.state.playerGridX*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cr%3Dthis.state.playerGridY*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cl%3Dthis.playerEmoji.x%2Cc%3Dthis.playerEmoji.y%2Ch%3Dthis.state.cameraX%2Cd%3Dthis.state.cameraY%2Cm%3Di%3Fs.FAST_MOVE_DURATION%3As.MOVE_DURATION%2Cu%3Di%3Fs.FAST_BOUNCE_SCALE%3As.BOUNCE_SCALE%2Cg%3DDate.now()%3Bthis.audioService.playHopSound()%3Bconst%20p%3D()%3D%3E%7Btry%7Bconst%20e%3DDate.now()-g%2Ct%3DMath.min(e%2Fm%2C1)%3Bif(!this.state.isMoving)return%20this.state.cancelAnimation()%2Cvoid%200%3Bconst%20i%3D1-Math.pow(1-t%2C3)%3Bif(this.playerEmoji.x%3Dl%2B(n-l)*i%2Cthis.playerEmoji.y%3Dc%2B(r-c)*i%2Cthis.state.cameraX%3Dh%2B(n-h)*i%2Cthis.state.cameraY%3Dd%2B(r-d)*i%2C1%3Et)%7Bconst%20e%3DMath.sin(t*Math.PI)%3Bthis.playerEmoji.scale.set(1%2Be*(u-1)*.5)%2Cthis.state.currentAnimationId%3DrequestAnimationFrame(p)%7Delse%20this.state.isMoving%3D!1%2Cthis.state.currentAnimationId%3Dnull%2Cthis.playerEmoji.scale.set(1)%2Cthis.networkService%26%26this.networkService.updatePlayerPosition(this.state.playerGridX%2Cthis.state.playerGridY)%7Dcatch(e)%7Bconsole.error(%22Error%20in%20animation%3A%22%2Ce)%2Cthis.state.cancelAnimation()%7D%7D%3Bp()%7Dcatch(o)%7Bconsole.error(%22Error%20in%20movePlayer%3A%22%2Co)%2Cthis.state.cancelAnimation()%7D%7DstartHoldMovement(e%2Ct)%7Bthis.state.isHolding%7C%7C(this.state.stopHoldMovement()%2Cthis.state.isHolding%3D!0%2Cthis.state.holdDirection%3D%7Bx%3Ae%2Cy%3At%7D%2Cthis.movePlayer(e%2Ct%2C!0)%2Cthis.state.holdMoveInterval%3DsetInterval(()%3D%3E%7Btry%7Bif(!this.state.isHolding)return%20this.state.stopHoldMovement()%2Cvoid%200%3Bthis.state.isMoving%7C%7Cthis.movePlayer(this.state.holdDirection.x%2Cthis.state.holdDirection.y%2C!0)%7Dcatch(e)%7Bconsole.error(%22Error%20in%20hold%20movement%3A%22%2Ce)%2Cthis.state.stopHoldMovement()%7D%7D%2C150))%7D%7D(S%2CC%2CI%2CE%2Cv)%2Cf%3Dnew%20h(S%2CI%2Cv)%2Cw%3Dnew%20class%7Bapp%3Bstate%3BgridGraphics%3BgridContainer%3Bconstructor(t%2Ci%2Co)%7Bthis.app%3Dt%2Cthis.state%3Di%2Cthis.gridContainer%3Do%2Cthis.gridGraphics%3Dnew%20e%2Cthis.gridContainer.addChild(this.gridGraphics)%7DdrawGrid()%7Bconst%20e%3DDate.now()%3Bif(Math.abs(this.state.cameraX-this.state.lastCameraState.x)%3Es.GRID_SIZE%2F2%7C%7CMath.abs(this.state.cameraY-this.state.lastCameraState.y)%3Es.GRID_SIZE%2F2%7C%7CMath.abs(this.state.cameraZoom-this.state.lastCameraState.zoom)%3E.1%7C%7Ce-this.state.lastGridDraw%3E%3Ds.GRID_DRAW_THROTTLE)%7Bthis.state.lastGridDraw%3De%2Cthis.state.lastCameraState%3D%7Bx%3Athis.state.cameraX%2Cy%3Athis.state.cameraY%2Czoom%3Athis.state.cameraZoom%7D%3Btry%7Bthis.gridGraphics.clear()%3Bconst%20e%3D5%2Ct%3Dthis.app.renderer.screen.width%2Fthis.state.cameraZoom%2Ci%3Dthis.app.renderer.screen.height%2Fthis.state.cameraZoom%2Co%3DMath.max(0%2CMath.floor((this.state.cameraX-t%2F2-e*s.GRID_SIZE)%2Fs.GRID_SIZE))%2Ca%3DMath.min(s.GRID_WIDTH%2CMath.ceil((this.state.cameraX%2Bt%2F2%2Be*s.GRID_SIZE)%2Fs.GRID_SIZE))%2Cn%3DMath.max(0%2CMath.floor((this.state.cameraY-i%2F2-e*s.GRID_SIZE)%2Fs.GRID_SIZE))%2Cr%3DMath.min(s.GRID_HEIGHT%2CMath.ceil((this.state.cameraY%2Bi%2F2%2Be*s.GRID_SIZE)%2Fs.GRID_SIZE))%3Bif((a-o)*(r-n)%3Es.MAX_GRID_CELLS)return%3Bconst%20l%3DMath.max(.5%2Cs.GRID_DOT_RADIUS%2Fthis.state.cameraZoom)%2Cc%3DMath.max(.3%2CMath.min(.7%2C.4%2B.2*this.state.cameraZoom))%3Bthis.gridGraphics.beginFill(16777215%2Cc)%3Bfor(let%20h%3Do%3Ba%3Eh%3Bh%2B%2B)for(let%20e%3Dn%3Br%3Ee%3Be%2B%2B)%7Bconst%20t%3Dh*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Ci%3De*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%3Bthis.gridGraphics.drawCircle(t%2Ci%2Cl)%7Dthis.gridGraphics.endFill()%7Dcatch(t)%7Bconsole.error(%22Error%20drawing%20grid%3A%22%2Ct)%7D%7D%7D%7D(m%2CS%2Cg)%2CT%3Dnew%20class%7BborderContainer%3Bconstructor(e)%7Bthis.borderContainer%3De%7DcreateForestBorder()%7Bconst%20e%3Ds.BORDER_WIDTH%3Bfor(let%20t%3D-e%3Bt%3Cs.GRID_WIDTH%2Be%3Bt%2B%2B)for(let%20i%3D-e%3B0%3Ei%3Bi%2B%2B)this.placeBorderTree(t%2Ci%2Cr)%3Bfor(let%20t%3D-e%3Bt%3Cs.GRID_WIDTH%2Be%3Bt%2B%2B)for(let%20i%3Ds.GRID_HEIGHT%3Bi%3Cs.GRID_HEIGHT%2Be%3Bi%2B%2B)this.placeBorderTree(t%2Ci%2Cr)%3Bfor(let%20t%3D-e%3B0%3Et%3Bt%2B%2B)for(let%20e%3D0%3Be%3Cs.GRID_HEIGHT%3Be%2B%2B)this.placeBorderTree(t%2Ce%2Cr)%3Bfor(let%20t%3Ds.GRID_WIDTH%3Bt%3Cs.GRID_WIDTH%2Be%3Bt%2B%2B)for(let%20e%3D0%3Be%3Cs.GRID_HEIGHT%3Be%2B%2B)this.placeBorderTree(t%2Ce%2Cr)%3Bconsole.log(%22%F0%9F%8C%B2%20Forest%20border%20created!%22)%7DplaceBorderTree(e%2Ci%2Co)%7Bconst%20a%3De*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cn%3Di*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Cr%3Do%5BMath.floor(Math.random()*o.length)%5D%2Cl%3Dnew%20t(r%2C%7BfontSize%3A48%2CfontFamily%3A%22Arial%22%7D)%3Bl.anchor.set(.5)%2Cl.position.set(a%2Cn)%2Cthis.borderContainer.addChild(l)%7D%7D(p)%2Cj%3Dnew%20class%7Bapp%3Bstate%3BaudioService%3BuiContainer%3BemojiButton%3BemojiPicker%3BemojiGrid%3BaudioUnlockButton%3BplayerIndicatorContainer%3BindicatorArrow%3BonEmojiSelect%3Bconstructor(o%2Ca%2Cs%2Cn)%7Bthis.app%3Do%2Cthis.state%3Da%2Cthis.audioService%3Ds%2Cthis.uiContainer%3Dn%2Cthis.emojiButton%3Ddocument.getElementById(%22emoji-button%22)%2Cthis.emojiPicker%3Ddocument.getElementById(%22emoji-picker%22)%2Cthis.emojiGrid%3Ddocument.getElementById(%22emoji-grid%22)%2Cthis.audioUnlockButton%3Ddocument.getElementById(%22audio-unlock-button%22)%2Cthis.playerIndicatorContainer%3Dnew%20i%3Bconst%20r%3Dnew%20e%3Br.beginFill(0%2C.6)%2Cr.drawCircle(0%2C0%2C24)%2Cr.endFill()%2Cthis.indicatorArrow%3Dnew%20t(%22%E2%86%92%22%2C%7BfontSize%3A32%2CfontFamily%3A%22Arial%22%7D)%2Cthis.indicatorArrow.anchor.set(.5)%2Cthis.playerIndicatorContainer.addChild(r)%2Cthis.playerIndicatorContainer.addChild(this.indicatorArrow)%2Cthis.playerIndicatorContainer.visible%3D!1%2Cthis.uiContainer.addChild(this.playerIndicatorContainer)%2Cthis.setupUI()%2Cthis.updateStatus()%7DsetupUI()%7Bn.forEach(e%3D%3E%7Bconst%20t%3Ddocument.createElement(%22div%22)%3Bt.className%3D%22emoji-item%22%2Ct.textContent%3De%2Ct.addEventListener(%22click%22%2C()%3D%3E%7Bthis.audioService.isUnlocked()%7C%7Cthis.audioService.unlockAudio()%2Cthis.state.selectedEmoji%3De%2Cthis.emojiButton.textContent%3De%2Cthis.emojiButton.classList.add(%22pulsing%22)%2Cthis.emojiPicker.classList.remove(%22visible%22)%2Cthis.updateStatus()%2Cthis.onEmojiSelect%26%26this.onEmojiSelect(e)%7D)%2Cthis.emojiGrid.appendChild(t)%7D)%2Cthis.emojiButton.addEventListener(%22click%22%2C()%3D%3E%7Bthis.audioService.isUnlocked()%7C%7Cthis.audioService.unlockAudio()%2Cthis.state.selectedEmoji%3F(this.state.selectedEmoji%3Dnull%2Cthis.emojiButton.textContent%3D%22%F0%9F%8E%A8%22%2Cthis.emojiButton.classList.remove(%22pulsing%22)%2Cthis.updateStatus())%3Athis.emojiPicker.classList.toggle(%22visible%22)%7D)%3Bconst%20e%3De%3D%3E%7Bconsole.log(%22%F0%9F%94%B4%20Audio%20unlock%20triggered%22)%2Ce.preventDefault()%2Ce.stopPropagation()%2Cthis.audioService.unlockAudio().then(()%3D%3E%7Bconsole.log(%22After%20unlock%2C%20audioUnlocked%3A%22%2Cthis.audioService.isUnlocked())%2Cthis.audioService.playTestBeep()%2Cthis.updateStatus()%7D).catch(e%3D%3E%7Bconsole.error(%22%E2%9D%8C%20Error%20in%20unlockAudio%3A%22%2Ce)%7D)%7D%3Bthis.audioUnlockButton.addEventListener(%22touchstart%22%2Ce%2C%7Bpassive%3A!1%7D)%2Cthis.audioUnlockButton.addEventListener(%22click%22%2Ce%2C%7Bpassive%3A!1%7D)%7DupdateStatus()%7Bthis.audioService.isUnlocked()%3F(this.audioUnlockButton.textContent%3D%22%F0%9F%94%8A%22%2Cthis.audioUnlockButton.classList.add(%22unlocked%22)%2Cthis.audioUnlockButton.title%3D%22Audio%20enabled%20%E2%9C%93%22)%3A(this.audioUnlockButton.textContent%3D%22%F0%9F%94%87%22%2Cthis.audioUnlockButton.classList.remove(%22unlocked%22)%2Cthis.audioUnlockButton.title%3D%22TAP%20ME%20to%20enable%20audio!%22)%7DupdatePlayerIndicator(e%2Ct)%7Bconst%20i%3Dthis.app.renderer.screen.width%2F2%2Co%3Dthis.app.renderer.screen.height%2F2%2Ca%3Di%2B(e-this.state.cameraX)*this.state.cameraZoom%2Cs%3Do%2B(t-this.state.cameraY)*this.state.cameraZoom%2Cn%3D50%2Cr%3Dn%3Ea%7C%7Ca%3Ethis.app.renderer.screen.width-n%7C%7Cn%3Es%7C%7Cs%3Ethis.app.renderer.screen.height-n%3Bif(this.playerIndicatorContainer.visible%3Dr%2Cr)%7Bconst%20e%3DMath.max(n%2CMath.min(this.app.renderer.screen.width-n%2Ca))%2Ct%3DMath.max(n%2CMath.min(this.app.renderer.screen.height-n%2Cs))%3Bthis.playerIndicatorContainer.position.set(e%2Ct)%3Bconst%20i%3DMath.atan2(s-t%2Ca-e)%3Bthis.indicatorArrow.rotation%3Di%7D%7DonEmojiSelected(e)%7Bthis.onEmojiSelect%3De%7D%7D(m%2CS%2CI%2Cy)%2CA%3Dnew%20class%7Bplayers%3Dnew%20Map%3BplayerContainer%3Bconstructor(e)%7Bthis.playerContainer%3De%2Cconsole.log(%22%E2%9C%85%20OtherPlayersManager%20initialized%22)%7DupdatePlayer(e%2Ct)%7Bconst%20i%3Dthis.players.get(e)%3Bi%3F(i.targetX%3Dt.x*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Ci.targetY%3Dt.y*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Ci.lastUpdate%3DDate.now()%2Ci.emoji.text!%3D%3Dt.emoji%26%26(i.emoji.text%3Dt.emoji))%3Athis.createPlayer(e%2Ct)%7DcreatePlayer(e%2Co)%7Bconst%20a%3Dnew%20i%2Cn%3Dnew%20t(o.emoji%2C%7BfontSize%3A48%2CfontFamily%3A%22Arial%22%7D)%3Bn.anchor.set(.5)%3Bconst%20r%3De.split(%22-%22).pop()%3F.substring(0%2C6)%7C%7C%22player%22%2Cl%3Dnew%20t(r%2C%7BfontSize%3A12%2CfontFamily%3A%22Arial%22%2Cfill%3A11184810%7D)%3Bl.anchor.set(.5)%2Cl.y%3D-40%2Ca.addChild(n)%2Ca.addChild(l)%3Bconst%20c%3Do.x*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%2Ch%3Do.y*s.GRID_SIZE%2Bs.GRID_SIZE%2F2%3Ba.position.set(c%2Ch)%2Cthis.playerContainer.addChild(a)%2Cthis.players.set(e%2C%7Bcontainer%3Aa%2Cemoji%3An%2Clabel%3Al%2CtargetX%3Ac%2CtargetY%3Ah%2CcurrentX%3Ac%2CcurrentY%3Ah%2ClastUpdate%3ADate.now()%7D)%2Cconsole.log(%22%F0%9F%91%A4%20Created%20player%3A%20%22%2Br)%7DremovePlayer(e)%7Bconst%20t%3Dthis.players.get(e)%3Bif(t)%7Bthis.playerContainer.removeChild(t.container)%2Cthis.players.delete(e)%3Bconst%20i%3De.split(%22-%22).pop()%3F.substring(0%2C6)%7C%7C%22player%22%3Bconsole.log(%22%F0%9F%91%8B%20Removed%20player%3A%20%22%2Bi)%7D%7Dupdate(e%3D1)%7Bconst%20t%3DDate.now()%3Bthis.players.forEach((e%2Ci)%3D%3E%7Bif(t-e.lastUpdate%3E1e4)return%20this.removePlayer(i)%2Cvoid%200%3Be.currentX%2B%3D.2*(e.targetX-e.currentX)%2Ce.currentY%2B%3D.2*(e.targetY-e.currentY)%2Ce.container.position.set(e.currentX%2Ce.currentY)%3Bconst%20o%3Dt-e.lastUpdate%3Be.container.alpha%3Do%3E5e3%3FMath.max(.3%2C1-(o-5e3)%2F5e3)%3A1%7D)%7DgetPlayerCount()%7Breturn%20this.players.size%7Dcleanup()%7Bthis.players.forEach((e%2Ct)%3D%3E%7Bthis.removePlayer(t)%7D)%2Cthis.players.clear()%2Cconsole.log(%22%F0%9F%A7%B9%20Cleaned%20up%20all%20other%20players%22)%7D%7D(V)%2CM%3Dnew%20URLSearchParams(window.location.search).get(%22room%22)%7C%7C%22default-room%22%3Bconsole.log(%22%F0%9F%8E%AE%20Joining%20room%3A%20%22%2BM)%3Bconst%20R%3Dnew%20class%7Bpeer%3BplayerId%3BroomId%3Bconnections%3Dnew%20Map%3BonPlayerUpdate%3BonPlayerLeave%3BonEmojiPlaced%3BonEmojiRemoved%3BplayerTimeouts%3Dnew%20Map%3BdiscoveryInterval%3BvoiceChatService%3Dnull%3BonGetEmojis%3Dnull%3Bconstructor(e%3D%22default-room%22%2Ct%2Ci%2Co%2Cs)%7Bthis.roomId%3De%2Cthis.onPlayerUpdate%3Dt%2Cthis.onPlayerLeave%3Di%2Cthis.onEmojiPlaced%3Do%2Cthis.onEmojiRemoved%3Ds%2Cconsole.log(%22%F0%9F%94%97%20Initializing%20WebRTC%20P2P...%22)%2Cconsole.log(%22%F0%9F%8C%90%20Room%3A%20%22%2Be)%3Bconst%20n%3De%2B%22-host%22%3Bthis.playerId%3Dn%2Cthis.peer%3Dnew%20a(n%2C%7Bdebug%3A1%7D)%2Cthis.setupPeerEvents()%7DsetupPeerEvents()%7Bthis.peer.on(%22open%22%2Ce%3D%3E%7Bthis.playerId%3De%2Cconsole.log(%22%E2%9C%85%20Connected%20to%20PeerJS%20signaling%20server%22)%2Cconsole.log(%22%F0%9F%93%A1%20My%20Peer%20ID%3A%20%22%2Be)%3Bconst%20t%3Dthis.roomId%2B%22-host%22%3Be%3D%3D%3Dt%3F(console.log(%22%F0%9F%8E%AF%20You%20are%20the%20ROOM%20HOST!%20Other%20players%20will%20connect%20to%20you.%22)%2Cconsole.log(%22%F0%9F%94%97%20Room%3A%20%22%2Bthis.roomId))%3A(console.log(%22%F0%9F%93%9E%20Connecting%20to%20room%20host%3A%20%22%2Bt)%2Cconsole.log(%22%F0%9F%94%97%20Room%3A%20%22%2Bthis.roomId)%2CsetTimeout(()%3D%3E%7Bthis.connectToPeer(t)%7D%2C500))%7D)%2Cthis.peer.on(%22connection%22%2Ce%3D%3E%7Bthis.handleIncomingConnection(e)%7D)%2Cthis.peer.on(%22call%22%2Ce%3D%3E%7Bthis.handleIncomingCall(e)%7D)%2Cthis.peer.on(%22error%22%2Ce%3D%3E%7Bconst%20t%3De.message%7C%7Ce.toString()%3Bt.includes(%22ID%22)%26%26t.includes(%22taken%22)%3F(console.log(%22%F0%9F%92%A1%20Host%20ID%20taken%2C%20joining%20as%20regular%20player...%22)%2Cthis.peer%26%26this.peer.destroy()%2Cthis.peer%3Dnew%20a(%7Bdebug%3A1%7D)%2Cthis.setupPeerEventsForClient())%3At.includes(%22Could%20not%20connect%22)%7C%7Cconsole.error(%22%E2%9D%8C%20Peer%20error%3A%22%2Ce)%7D)%2Cthis.peer.on(%22disconnected%22%2C()%3D%3E%7Bconsole.log(%22%E2%9A%A0%EF%B8%8F%20Disconnected%20from%20signaling%20server%2C%20reconnecting...%22)%2Cthis.peer.reconnect()%7D)%2Cwindow.addEventListener(%22beforeunload%22%2C()%3D%3E%7Bthis.disconnect()%7D)%7DsetupPeerEventsForClient()%7Bthis.peer.on(%22open%22%2Ce%3D%3E%7Bthis.playerId%3De%2Cconsole.log(%22%E2%9C%85%20Connected%20as%20regular%20player%22)%2Cconsole.log(%22%F0%9F%93%A1%20My%20Peer%20ID%3A%20%22%2Be)%2Cconsole.log(%60%F0%9F%93%9E%20Connecting%20to%20room%20host%3A%20%24%7Bthis.roomId%7D-host%60)%3Bconst%20t%3Dthis.roomId%2B%22-host%22%3BsetTimeout(()%3D%3E%7Bthis.connectToPeer(t)%7D%2C500)%7D)%2Cthis.peer.on(%22connection%22%2Ce%3D%3E%7Bthis.handleIncomingConnection(e)%7D)%2Cthis.peer.on(%22call%22%2Ce%3D%3E%7Bthis.handleIncomingCall(e)%7D)%2Cthis.peer.on(%22error%22%2Ce%3D%3E%7B(e.message%7C%7Ce.toString()).includes(%22Could%20not%20connect%22)%7C%7Cconsole.error(%22%E2%9D%8C%20Client%20peer%20error%3A%22%2Ce)%7D)%2Cthis.peer.on(%22disconnected%22%2C()%3D%3E%7Bconsole.log(%22%E2%9A%A0%EF%B8%8F%20Disconnected%2C%20reconnecting...%22)%2Cthis.peer.reconnect()%7D)%7DsetVoiceChatService(e)%7Bthis.voiceChatService%3De%7DsetGetEmojisCallback(e)%7Bthis.onGetEmojis%3De%7DhandleIncomingCall(e)%7Bconsole.log(%22%F0%9F%93%9E%20Incoming%20voice%20call%20from%3A%20%22%2Be.peer)%2Cthis.voiceChatService%26%26this.voiceChatService.isEnabled()%3Fthis.voiceChatService.answerCall(e)%3A(console.log(%22%E2%9A%A0%EF%B8%8F%20Voice%20chat%20not%20enabled%2C%20rejecting%20call%22)%2Ce.close())%7DhandleIncomingConnection(e)%7Bconsole.log(%22%F0%9F%93%9E%20Incoming%20connection%20from%3A%20%22%2Be.peer)%2Cthis.handleConnection(e)%3Bconst%20t%3Dthis.roomId%2B%22-host%22%3Bthis.playerId%3D%3D%3Dt%26%26(this.connections.forEach((t%2Ci)%3D%3E%7Bi!%3D%3De.peer%26%26t.open%26%26t.send(%7Btype%3A%22peer-discovered%22%2CpeerId%3Ae.peer%7D)%7D)%2Ce.open%26%26this.connections.forEach((t%2Ci)%3D%3E%7Bi!%3D%3De.peer%26%26e.send(%7Btype%3A%22peer-discovered%22%2CpeerId%3Ai%7D)%7D))%7DconnectToPeer(e)%7Bconsole.log(%22%F0%9F%93%9E%20Connecting%20to%20peer%3A%20%22%2Be)%3Bconst%20t%3Dthis.peer.connect(e%2C%7Breliable%3A!0%7D)%3Bthis.handleConnection(t)%7DhandleConnection(e)%7Be.on(%22open%22%2C()%3D%3E%7Bif(console.log(%22%E2%9C%85%20Connected%20to%3A%20%22%2Be.peer)%2Cthis.connections.set(e.peer%2Ce)%2Ce.send(%7Btype%3A%22hello%22%2Cfrom%3Athis.playerId%7D)%2Cthis.onGetEmojis)%7Bconst%20t%3Dthis.onGetEmojis()%3Bt.length%3E0%26%26(console.log(%60%F0%9F%93%A4%20Sending%20%24%7Bt.length%7D%20emojis%20to%20new%20peer%3A%20%24%7Be.peer%7D%60)%2Ce.send(%7Btype%3A%22emoji-state%22%2Cemojis%3At%7D))%7Dthis.voiceChatService%26%26this.voiceChatService.isEnabled()%26%26setTimeout(()%3D%3E%7Bthis.voiceChatService.callPeer(e.peer)%7D%2C500)%7D)%2Ce.on(%22data%22%2Ct%3D%3E%7Bthis.handleMessage(e.peer%2Ct)%7D)%2Ce.on(%22close%22%2C()%3D%3E%7Bconsole.log(%22%F0%9F%91%8B%20Disconnected%20from%3A%20%22%2Be.peer)%2Cthis.connections.delete(e.peer)%2Cthis.onPlayerLeave(e.peer)%3Bconst%20t%3Dthis.playerTimeouts.get(e.peer)%3Bt%26%26(clearTimeout(t)%2Cthis.playerTimeouts.delete(e.peer))%7D)%2Ce.on(%22error%22%2Ct%3D%3E%7Bconsole.error(%60%E2%9D%8C%20Connection%20error%20with%20%24%7Be.peer%7D%3A%60%2Ct)%7D)%7DhandleMessage(e%2Ct)%7Btry%7Bif(%22peer-discovered%22%3D%3D%3Dt.type)%7Bconst%20e%3Dt.peerId%3Be%3D%3D%3Dthis.playerId%7C%7Cthis.connections.has(e)%7C%7C(console.log(%22%F0%9F%94%8D%20Host%20told%20us%20about%20peer%3A%20%22%2Be)%2CsetTimeout(()%3D%3E%7Bthis.connectToPeer(e)%7D%2C500))%7Delse%20if(%22player-position%22%3D%3D%3Dt.type)%7Bthis.onPlayerUpdate(e%2C%7Bid%3Ae%2Cx%3At.x%2Cy%3At.y%2Cemoji%3At.emoji%7C%7C%22%F0%9F%98%8E%22%2ClastUpdate%3ADate.now()%7D)%3Bconst%20i%3Dthis.playerTimeouts.get(e)%3Bi%26%26clearTimeout(i)%3Bconst%20o%3DsetTimeout(()%3D%3E%7Bthis.onPlayerLeave(e)%2Cthis.playerTimeouts.delete(e)%7D%2C1e4)%3Bthis.playerTimeouts.set(e%2Co)%7Delse%22emoji-place%22%3D%3D%3Dt.type%3Fthis.onEmojiPlaced(t.x%2Ct.y%2Ct.emoji)%3A%22emoji-remove%22%3D%3D%3Dt.type%3Fthis.onEmojiRemoved(t.x%2Ct.y)%3A%22emoji-state%22%3D%3D%3Dt.type%3F(console.log(%60%F0%9F%93%A5%20Received%20%24%7Bt.emojis.length%7D%20emojis%20from%20peer%3A%20%24%7Be%7D%60)%2Ct.emojis.forEach(e%3D%3E%7Bthis.onEmojiPlaced(e.gridX%2Ce.gridY%2Ce.emoji)%7D))%3A%22hello%22%3D%3D%3Dt.type%26%26console.log(%22%F0%9F%91%8B%20Hello%20from%3A%20%22%2Be)%7Dcatch(i)%7Bconsole.error(%22Error%20handling%20message%3A%22%2Ci)%7D%7Dbroadcast(e)%7Bthis.connections.forEach(t%3D%3E%7Bt.open%26%26t.send(e)%7D)%7DupdatePlayerPosition(e%2Ct)%7Bthis.broadcast(%7Btype%3A%22player-position%22%2Cx%3Ae%2Cy%3At%2Cemoji%3A%22%F0%9F%98%8E%22%7D)%7DplaceEmoji(e%2Ct%2Ci)%7Bthis.broadcast(%7Btype%3A%22emoji-place%22%2Cx%3Ae%2Cy%3At%2Cemoji%3Ai%7D)%7DremoveEmoji(e%2Ct)%7Bthis.broadcast(%7Btype%3A%22emoji-remove%22%2Cx%3Ae%2Cy%3At%7D)%7DloadExistingEmojis(e)%7Bconsole.log(%22%E2%84%B9%EF%B8%8F%20WebRTC%20P2P%20-%20no%20persistent%20storage%22)%7Ddisconnect()%7Bthis.connections.forEach(e%3D%3E%7Be.close()%7D)%2Cthis.connections.clear()%2Cthis.discoveryInterval%26%26clearInterval(this.discoveryInterval)%2Cthis.peer%26%26this.peer.destroy()%2Cconsole.log(%22%F0%9F%91%8B%20Disconnected%20from%20WebRTC%20P2P%22)%7DgetPlayerId()%7Breturn%20this.playerId%7DgetPeer()%7Breturn%20this.peer%7DgetConnectedPeers()%7Breturn%20Array.from(this.connections.keys())%7DinitiateVoiceCalls()%7Bthis.voiceChatService%26%26this.voiceChatService.isEnabled()%26%26(console.log(%22%F0%9F%93%9E%20Initiating%20voice%20calls%20to%20all%20connected%20peers...%22)%2Cthis.connections.forEach((e%2Ct)%3D%3E%7Be.open%26%26this.voiceChatService.callPeer(t)%7D))%7D%7D(M%2C(e%2Ct)%3D%3E%7BA.updatePlayer(e%2Ct)%7D%2Ce%3D%3E%7BA.removePlayer(e)%2C_%26%26_.onPeerDisconnected(e)%7D%2C(e%2Ct%2Ci)%3D%3E%7Bf.placeEmojiFromNetwork(e%2Ct%2Ci)%7D%2C(e%2Ct)%3D%3E%7Bf.removeEmojiFromNetwork(e%2Ct)%7D)%3BD.setNetworkService(R)%2Cf.setNetworkService(R)%2CR.setGetEmojisCallback(()%3D%3Ef.getAllEmojis())%2CS.playerId%3DR.getPlayerId()%3Bconst%20x%3Dnew%20class%7Bpeer%3Dnull%3BlocalStream%3Dnull%3BmediaConnections%3Dnew%20Map%3BremoteStreams%3Dnew%20Map%3BaudioElements%3Dnew%20Map%3Benabled%3D!1%3Bmuted%3D!1%3BonSpeakingChange%3Dnull%3BspeakingDetection%3Dnew%20Map%3Bconstructor()%7Bconst%20e%3Dc.getItem(%22voicechat-config%22)%3Bif(e)try%7Bconst%20t%3DJSON.parse(e)%3Bthis.enabled%3Dt.enabled%7C%7C!1%2Cthis.muted%3Dt.muted%7C%7C!1%7Dcatch(t)%7Bconsole.warn(%22Failed%20to%20parse%20voice%20chat%20config%3A%22%2Ct)%7D%7DisEnabled()%7Breturn%20this.enabled%7DisMuted()%7Breturn%20this.muted%7Dasync%20enable(e)%7Bif(this.enabled)return!0%3Bthis.peer%3De%3Btry%7Breturn%20console.log(%22%F0%9F%8E%A4%20Requesting%20microphone%20access...%22)%2Cthis.localStream%3Dawait%20navigator.mediaDevices.getUserMedia(%7Baudio%3A%7BechoCancellation%3A!0%2CnoiseSuppression%3A!0%2CautoGainControl%3A!0%7D%2Cvideo%3A!1%7D)%2Cconsole.log(%22%E2%9C%85%20Microphone%20access%20granted%22)%2Cthis.localStream.getAudioTracks().forEach(e%3D%3E%7Be.enabled%3D!this.muted%7D)%2Cthis.enabled%3D!0%2Cthis.saveConfig()%2C!0%7Dcatch(t)%7Breturn%20console.warn(%22%E2%9A%A0%EF%B8%8F%20Microphone%20access%20denied%2C%20enabling%20listen-only%20mode%3A%22%2Ct)%2Cthis.localStream%3Dnull%2Cthis.muted%3D!0%2Cthis.enabled%3D!0%2Cthis.saveConfig()%2C!0%7D%7Ddisable()%7Bconsole.log(%22%F0%9F%94%87%20Disabling%20voice%20chat...%22)%2Cthis.mediaConnections.forEach(e%3D%3E%7Be.close()%7D)%2Cthis.mediaConnections.clear()%2Cthis.audioElements.forEach(e%3D%3E%7Be.pause()%2Ce.srcObject%3Dnull%7D)%2Cthis.audioElements.clear()%2Cthis.remoteStreams.clear()%2Cthis.localStream%26%26(this.localStream.getTracks().forEach(e%3D%3Ee.stop())%2Cthis.localStream%3Dnull)%2Cthis.speakingDetection.forEach((%7Binterval%3Ae%7D)%3D%3E%7BclearInterval(e)%7D)%2Cthis.speakingDetection.clear()%2Cthis.enabled%3D!1%2Cthis.saveConfig()%2Cconsole.log(%22%E2%9C%85%20Voice%20chat%20disabled%22)%7DtoggleMute()%7Breturn%20this.localStream%3F(this.muted%3D!this.muted%2Cthis.localStream.getAudioTracks().forEach(e%3D%3E%7Be.enabled%3D!this.muted%7D)%2Cthis.saveConfig()%2Cconsole.log(this.muted%3F%22%F0%9F%94%87%20Microphone%20muted%22%3A%22%F0%9F%8E%A4%20Microphone%20unmuted%22)%2Cthis.muted)%3A(console.log(%22%E2%9A%A0%EF%B8%8F%20No%20microphone%20available%20(listen-only%20mode)%22)%2Cthis.muted)%7DisListenOnly()%7Breturn%20this.enabled%26%26!this.localStream%7DcallPeer(e)%7Bif(this.enabled%26%26this.peer)%7Bif(this.mediaConnections.has(e))return%20console.log(%22%F0%9F%94%8A%20Already%20in%20voice%20call%20with%20%22%2Be)%2Cvoid%200%3Bconsole.log(%22%F0%9F%93%9E%20Calling%20peer%20for%20voice%20chat%3A%20%22%2Be)%3Btry%7Blet%20t%3Bthis.localStream%3Ft%3Dthis.localStream%3A(t%3Dthis.createSilentStream()%2Cconsole.log(%22%F0%9F%91%82%20Calling%20in%20listen-only%20mode%20(sending%20silent%20audio)%22))%3Bconst%20i%3Dthis.peer.call(e%2Ct)%3Bthis.handleMediaConnection(i)%7Dcatch(t)%7Bconsole.error(%60%E2%9D%8C%20Failed%20to%20call%20peer%20%24%7Be%7D%3A%60%2Ct)%7D%7D%7DanswerCall(e)%7Bif(!this.enabled)return%20console.log(%22%E2%9A%A0%EF%B8%8F%20Voice%20chat%20not%20enabled%2C%20rejecting%20call%22)%2Ce.close()%2Cvoid%200%3Bif(console.log(%22%F0%9F%93%9E%20Answering%20voice%20call%20from%3A%20%22%2Be.peer)%2Cthis.localStream)e.answer(this.localStream)%3Belse%7Bconst%20t%3Dthis.createSilentStream()%3Be.answer(t)%2Cconsole.log(%22%F0%9F%91%82%20Answered%20in%20listen-only%20mode%20(sending%20silent%20audio)%22)%7Dthis.handleMediaConnection(e)%7DcreateSilentStream()%7Bconst%20e%3Dnew(window.AudioContext%7C%7Cwindow.webkitAudioContext)%2Ct%3De.createMediaStreamDestination()%2Ci%3De.createOscillator()%2Co%3De.createGain()%3Breturn%20o.gain.value%3D0%2Ci.connect(o)%2Co.connect(t)%2Ci.start()%2Ct.stream%7DhandleMediaConnection(e)%7Bconst%20t%3De.peer%3Bthis.mediaConnections.set(t%2Ce)%2Ce.on(%22stream%22%2Ce%3D%3E%7Bconsole.log(%22%F0%9F%94%8A%20Receiving%20audio%20stream%20from%3A%20%22%2Bt)%2Cthis.remoteStreams.set(t%2Ce)%3Blet%20i%3Dthis.audioElements.get(t)%3Bi%7C%7C(i%3Dnew%20Audio%2Ci.autoplay%3D!0%2Cthis.audioElements.set(t%2Ci))%2Ci.srcObject%3De%2Ci.play().catch(e%3D%3Econsole.error(%22Failed%20to%20play%20audio%3A%22%2Ce))%2Cthis.setupSpeakingDetection(t%2Ce)%7D)%2Ce.on(%22close%22%2C()%3D%3E%7Bconsole.log(%22%F0%9F%91%8B%20Voice%20call%20ended%20with%3A%20%22%2Bt)%2Cthis.cleanupPeerAudio(t)%7D)%2Ce.on(%22error%22%2Ce%3D%3E%7Bconsole.error(%60%E2%9D%8C%20Media%20connection%20error%20with%20%24%7Bt%7D%3A%60%2Ce)%2Cthis.cleanupPeerAudio(t)%7D)%7DsetupSpeakingDetection(e%2Ct)%7Btry%7Bconst%20i%3Dnew(window.AudioContext%7C%7Cwindow.webkitAudioContext)%2Co%3Di.createMediaStreamSource(t)%2Ca%3Di.createAnalyser()%3Ba.fftSize%3D512%2Ca.smoothingTimeConstant%3D.8%2Co.connect(a)%3Bconst%20s%3Dnew%20Uint8Array(a.frequencyBinCount)%3Blet%20n%3D!1%3Bconst%20r%3D30%2Cl%3Dwindow.setInterval(()%3D%3E%7Ba.getByteFrequencyData(s)%3Blet%20t%3D0%3Bfor(let%20e%3D0%3Be%3Cs.length%3Be%2B%2B)t%2B%3Ds%5Be%5D%3Bconst%20i%3Dt%2Fs.length%3Er%3Bi!%3D%3Dn%26%26(n%3Di%2Cthis.onSpeakingChange%26%26this.onSpeakingChange(e%2Cn))%7D%2C100)%3Bthis.speakingDetection.set(e%2C%7Banalyser%3Aa%2Cinterval%3Al%7D)%7Dcatch(i)%7Bconsole.error(%22Failed%20to%20setup%20speaking%20detection%3A%22%2Ci)%7D%7DcleanupPeerAudio(e)%7Bthis.mediaConnections.delete(e)%3Bconst%20t%3Dthis.audioElements.get(e)%3Bt%26%26(t.pause()%2Ct.srcObject%3Dnull%2Cthis.audioElements.delete(e))%2Cthis.remoteStreams.delete(e)%3Bconst%20i%3Dthis.speakingDetection.get(e)%3Bi%26%26(clearInterval(i.interval)%2Cthis.speakingDetection.delete(e))%2Cthis.onSpeakingChange%26%26this.onSpeakingChange(e%2C!1)%7DonSpeaking(e)%7Bthis.onSpeakingChange%3De%7DgetConnectedPeers()%7Breturn%20Array.from(this.mediaConnections.keys())%7DisConnectedTo(e)%7Breturn%20this.mediaConnections.has(e)%7DsaveConfig()%7Bconst%20e%3D%7Benabled%3Athis.enabled%2Cmuted%3Athis.muted%7D%3Bc.setItem(%22voicechat-config%22%2CJSON.stringify(e))%7C%7Cconsole.log(%22%F0%9F%92%BE%20Skipped%20saving%20voice%20chat%20config%20(localStorage%20unavailable)%22)%7Ddestroy()%7Bthis.disable()%7D%7D%2C_%3Dnew%20class%7BvoiceChatService%3BnetworkService%3BvoiceToggleButton%3BvoiceMuteButton%3BvoiceChatStatus%3BvoicePeersList%3BspeakingPeers%3Dnew%20Set%3Bconstructor(e%2Ct)%7Bthis.voiceChatService%3De%2Cthis.networkService%3Dt%2Cthis.voiceToggleButton%3Ddocument.getElementById(%22voice-toggle-button%22)%2Cthis.voiceMuteButton%3Ddocument.getElementById(%22voice-mute-button%22)%2Cthis.voiceChatStatus%3Ddocument.getElementById(%22voice-chat-status%22)%2Cthis.voicePeersList%3Ddocument.getElementById(%22voice-peers-list%22)%2Cthis.setupUI()%2Cthis.updateUI()%2Cthis.voiceChatService.onSpeaking((e%2Ct)%3D%3E%7Bt%3Fthis.speakingPeers.add(e)%3Athis.speakingPeers.delete(e)%2Cthis.updatePeersList()%7D)%7DsetupUI()%7Bthis.voiceToggleButton.addEventListener(%22click%22%2Casync()%3D%3E%7Bif(this.voiceChatService.isEnabled())this.voiceChatService.disable()%2Cthis.updateUI()%2Cthis.updatePeersList()%3Belse%7Bconst%20e%3Dthis.networkService.getPeer()%3Bawait%20this.voiceChatService.enable(e)%3F(console.log(%22%E2%9C%85%20Voice%20chat%20enabled%22)%2Cthis.networkService.setVoiceChatService(this.voiceChatService)%2Cthis.networkService.initiateVoiceCalls()%2Cthis.updateUI()%2Cthis.updatePeersList()%2Cthis.voiceChatService.isListenOnly()%26%26console.log(%22%F0%9F%91%82%20Voice%20chat%20enabled%20in%20LISTEN-ONLY%20mode%20(microphone%20access%20denied)%22))%3Aconsole.error(%22%E2%9D%8C%20Failed%20to%20enable%20voice%20chat%22)%7D%7D)%2Cthis.voiceMuteButton.addEventListener(%22click%22%2C()%3D%3E%7Bthis.voiceChatService.isEnabled()%26%26(this.voiceChatService.toggleMute()%2Cthis.updateUI())%7D)%7DupdateUI()%7Bconst%20e%3Dthis.voiceChatService.isEnabled()%2Ct%3Dthis.voiceChatService.isMuted()%2Ci%3Dthis.voiceChatService.isListenOnly()%3Be%3F(this.voiceToggleButton.classList.add(%22active%22)%2Cthis.voiceToggleButton.title%3Di%3F%22Voice%20Chat%20(Listen-Only%20Mode)%20-%20Click%20to%20Disable%22%3A%22Disable%20Voice%20Chat%22)%3A(this.voiceToggleButton.classList.remove(%22active%22)%2Cthis.voiceToggleButton.title%3D%22Enable%20Voice%20Chat%22)%2Ce%26%26!i%3F(this.voiceMuteButton.classList.remove(%22disabled%22)%2Ct%3F(this.voiceMuteButton.classList.add(%22muted%22)%2Cthis.voiceMuteButton.textContent%3D%22%F0%9F%94%87%22%2Cthis.voiceMuteButton.title%3D%22Unmute%20Microphone%22)%3A(this.voiceMuteButton.classList.remove(%22muted%22)%2Cthis.voiceMuteButton.textContent%3D%22%F0%9F%8E%A4%22%2Cthis.voiceMuteButton.title%3D%22Mute%20Microphone%22))%3Ae%26%26i%3F(this.voiceMuteButton.classList.add(%22disabled%22)%2Cthis.voiceMuteButton.classList.remove(%22muted%22)%2Cthis.voiceMuteButton.textContent%3D%22%F0%9F%91%82%22%2Cthis.voiceMuteButton.title%3D%22Listen-Only%20Mode%20(No%20Microphone)%22)%3A(this.voiceMuteButton.classList.add(%22disabled%22)%2Cthis.voiceMuteButton.classList.remove(%22muted%22)%2Cthis.voiceMuteButton.textContent%3D%22%F0%9F%94%87%22%2Cthis.voiceMuteButton.title%3D%22Enable%20Voice%20Chat%20First%22)%2Ce%3Fthis.voiceChatStatus.classList.add(%22visible%22)%3Athis.voiceChatStatus.classList.remove(%22visible%22)%7DupdatePeersList()%7Bif(!this.voiceChatService.isEnabled())return%20this.voicePeersList.innerHTML%3D'%3Cdiv%20style%3D%22color%3A%20%23888%3B%22%3EVoice%20chat%20disabled%3C%2Fdiv%3E'%2Cvoid%200%3Bconst%20e%3Dthis.voiceChatService.isListenOnly()%3Blet%20t%3D%22%22%3Be%26%26(t%2B%3D'%3Cdiv%20style%3D%22color%3A%20%23FF9500%3B%20margin-bottom%3A%208px%3B%22%3E%F0%9F%91%82%20Listen-Only%20Mode%3C%2Fdiv%3E')%3Bconst%20i%3Dthis.voiceChatService.getConnectedPeers()%3Bif(0%3D%3D%3Di.length)return%20t%2B%3D'%3Cdiv%20style%3D%22color%3A%20%23888%3B%22%3ENo%20peers%20connected%3C%2Fdiv%3E'%2Cthis.voicePeersList.innerHTML%3Dt%2Cvoid%200%3Bi.forEach((e%2Ci)%3D%3E%7Bconst%20o%3De.substring(0%2C8)%2Ca%3Dthis.speakingPeers.has(e)%3Bt%2B%3D%60%5Cn%3Cdiv%20class%3D%22peer-speaking%22%3E%5Cn%20%24%7Ba%3F'%3Cdiv%20class%3D%22speaking-indicator%22%3E%3C%2Fdiv%3E'%3A'%3Cdiv%20style%3D%22width%3A%208px%3B%22%3E%3C%2Fdiv%3E'%7D%5Cn%3Cspan%3EPeer%20%24%7Bi%2B1%7D%3A%20%24%7Bo%7D%3C%2Fspan%3E%5Cn%3C%2Fdiv%3E%5Cn%20%60%7D)%2Cthis.voicePeersList.innerHTML%3Dt%7DonPeerConnected()%7Bthis.voiceChatService.isEnabled()%26%26this.updatePeersList()%7DonPeerDisconnected(e)%7Bthis.speakingPeers.delete(e)%2Cthis.voiceChatService.isEnabled()%26%26this.updatePeersList()%7D%7D(x%2CR)%3Bconsole.log(%22%F0%9F%8E%99%EF%B8%8F%20Voice%20chat%20initialized%20(disabled%20by%20default%20-%20click%20button%20to%20enable)%22)%2Cnew%20class%7Bapp%3Bstate%3BplayerController%3BcameraService%3BemojiManager%3BaudioService%3Bconstructor(e%2Ct%2Ci%2Co%2Ca%2Cs)%7Bthis.app%3De%2Cthis.state%3Dt%2Cthis.playerController%3Di%2Cthis.cameraService%3Do%2Cthis.emojiManager%3Da%2Cthis.audioService%3Ds%2Cthis.setupTouchHandlers()%2Cthis.setupKeyboardHandlers()%7DsetupTouchHandlers()%7Bthis.app.stage.eventMode%3D%22static%22%2Cthis.app.stage.hitArea%3Dthis.app.renderer.screen%2Cthis.app.stage.on(%22pointerdown%22%2Cthis.handlePointerDown.bind(this))%2Cthis.app.stage.on(%22pointermove%22%2Cthis.handlePointerMove.bind(this))%2Cthis.app.stage.on(%22pointerup%22%2Cthis.handlePointerUp.bind(this))%3Bconst%20e%3Dthis.app.view%3Be.addEventListener(%22touchstart%22%2Ce%3D%3E%7Be.touches.length%3E1%26%26e.preventDefault()%7D%2C%7Bpassive%3A!1%7D)%2Ce.addEventListener(%22touchmove%22%2Ce%3D%3E%7Be.touches.length%3E1%26%26e.preventDefault()%7D%2C%7Bpassive%3A!1%7D)%2Ce.addEventListener(%22gesturestart%22%2Ce%3D%3Ee.preventDefault())%2Ce.addEventListener(%22gesturechange%22%2Ce%3D%3Ee.preventDefault())%2Ce.addEventListener(%22gestureend%22%2Ce%3D%3Ee.preventDefault())%7DsetupKeyboardHandlers()%7Bwindow.addEventListener(%22keydown%22%2Ce%3D%3E%7Btry%7Bif(this.audioService.isUnlocked()%7C%7Cthis.audioService.unlockAudio()%2Cthis.state.isMoving)return%3Bswitch(e.key)%7Bcase%22ArrowUp%22%3Acase%22w%22%3Athis.playerController.movePlayer(0%2C-1)%2Ce.preventDefault()%3Bbreak%3Bcase%22ArrowDown%22%3Acase%22s%22%3Athis.playerController.movePlayer(0%2C1)%2Ce.preventDefault()%3Bbreak%3Bcase%22ArrowLeft%22%3Acase%22a%22%3Athis.playerController.movePlayer(-1%2C0)%2Ce.preventDefault()%3Bbreak%3Bcase%22ArrowRight%22%3Acase%22d%22%3Athis.playerController.movePlayer(1%2C0)%2Ce.preventDefault()%3Bbreak%3Bcase%22%20%22%3Aconst%20t%3Dthis.playerController.getPosition()%3Bthis.cameraService.centerCameraOn(t.x%2Ct.y)%2Ce.preventDefault()%7D%7Dcatch(t)%7Bconsole.error(%22Error%20in%20keyboard%20handler%3A%22%2Ct)%7D%7D)%7DhandlePointerDown(e)%7Bconst%20t%3De.data.originalEvent%3Bif(this.state.touches.push(%7BpointerId%3At.pointerId%2CclientX%3At.clientX%2CclientY%3At.clientY%7D)%2Cthis.audioService.isUnlocked()%7C%7Cthis.audioService.unlockAudio()%2C1%3D%3D%3Dthis.state.touches.length)this.state.swipeStartX%3De.data.global.x%2Cthis.state.swipeStartY%3De.data.global.y%2Cthis.state.touchStartTime%3DDate.now()%2Cthis.state.isPinching%3D!1%2Cthis.state.twoFingerPanning%3D!1%3Belse%20if(2%3D%3D%3Dthis.state.touches.length)%7Bthis.state.stopHoldMovement()%3Bconst%20e%3Dthis.state.touches%5B0%5D%2Ct%3Dthis.state.touches%5B1%5D%3Bthis.state.twoFingerStart%3D%5B%7Bx%3Ae.clientX%2Cy%3Ae.clientY%7D%2C%7Bx%3At.clientX%2Cy%3At.clientY%7D%5D%3Bconst%20i%3Dt.clientX-e.clientX%2Co%3Dt.clientY-e.clientY%3Bthis.state.initialPinchDistance%3DMath.sqrt(i*i%2Bo*o)%2Cthis.state.initialZoom%3Dthis.state.cameraZoom%2Cthis.state.lastTwoFingerMidX%3D(e.clientX%2Bt.clientX)%2F2%2Cthis.state.lastTwoFingerMidY%3D(e.clientY%2Bt.clientY)%2F2%7D%7DhandlePointerMove(e)%7Bconst%20t%3De.data.originalEvent%2Ci%3Dthis.state.touches.findIndex(e%3D%3Ee.pointerId%3D%3D%3Dt.pointerId)%3Bif(-1!%3D%3Di%26%26(this.state.touches%5Bi%5D%3D%7BpointerId%3At.pointerId%2CclientX%3At.clientX%2CclientY%3At.clientY%7D)%2Cthis.state.draggedEmoji%26%26this.state.emojiReadyToDrag)return%20this.emojiManager.handleEmojiDragMove(e.data.global.x%2Ce.data.global.y%2Cthis.state.cameraZoom)%2Cvoid%200%3Bif(this.state.draggedEmoji%26%26!this.state.emojiReadyToDrag)%7Bconst%20t%3De.data.global.x-this.state.emojiDragStartX%2Ci%3De.data.global.y-this.state.emojiDragStartY%3BMath.sqrt(t*t%2Bi*i)%3Es.EMOJI_DRAG_THRESHOLD%26%26this.state.resetEmojiDrag()%7Dif(1!%3D%3Dthis.state.touches.length%7C%7Cthis.state.isPinching%7C%7Cthis.state.twoFingerPanning)%7Bif(2%3D%3D%3Dthis.state.touches.length)%7Bconst%20e%3Dthis.state.touches%5B0%5D%2Ct%3Dthis.state.touches%5B1%5D%2Ci%3Dt.clientX-e.clientX%2Co%3Dt.clientY-e.clientY%2Ca%3DMath.sqrt(i*i%2Bo*o)%2Cs%3D(e.clientX%2Bt.clientX)%2F2%2Cn%3D(e.clientY%2Bt.clientY)%2F2%3Bif(Math.abs(a-this.state.initialPinchDistance)%3E10)%7Bthis.state.isPinching%3D!0%3Bconst%20e%3Da%2Fthis.state.initialPinchDistance%2Ct%3Dthis.state.initialZoom*e%3Bthis.cameraService.setZoom(t)%7Dif(void%200!%3D%3Dthis.state.lastTwoFingerMidX%26%26void%200!%3D%3Dthis.state.lastTwoFingerMidY)%7Bthis.state.twoFingerPanning%3D!0%3Bconst%20e%3D(s-this.state.lastTwoFingerMidX)%2Fthis.state.cameraZoom%2Ct%3D(n-this.state.lastTwoFingerMidY)%2Fthis.state.cameraZoom%3Bthis.cameraService.panCamera(e%2Ct)%7Dthis.state.lastTwoFingerMidX%3Ds%2Cthis.state.lastTwoFingerMidY%3Dn%7D%7Delse%20if(this.state.touches%5B0%5D%26%26!this.state.isHolding%26%26!this.state.isMoving%26%26!this.state.draggedEmoji)%7Bconst%20t%3De.data.global.x-th
load full (70,685 bytes) →
1-50 of 79