From e9bc11c7def380a2d03131389cc11412ed59cbe7 Mon Sep 17 00:00:00 2001 From: limbofeather <71227790+limbofeather@users.noreply.github.com> Date: Mon, 18 Dec 2023 13:44:09 -0500 Subject: [PATCH] Revert "Update default url" --- README.md | 2 +- cryptovoxels/integration.js | 2 +- tests/utils/networking.test.mjs | 2 +- tests/wonderland/deploy/wonderland-test-bundle.js | 2 +- tests/wonderland/deploy/wonderland-test-bundle.js.map | 2 +- unity/Assets/ZestySDK/Scripts/Internal/API.cs | 2 +- unity/Assets/ZestySDK/Scripts/Internal/Banner.cs | 2 +- utils/networking.js | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index da97736..9d8fdfe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # zesty-billboard -The Zesty Billboard SDK allows developers to integrate their app into the Zesty Network. More docs: https://zestyxyz.notion.site/Zesty-Market-Documentation-346d6f9aa8544cf9a5484c3ccf61523a +The Zesty Billboard SDK allows developers to integrate their app into the Zesty Network. More docs: https://docs.zesty.market Currently, we support the following platforms: diff --git a/cryptovoxels/integration.js b/cryptovoxels/integration.js index ae74cf1..6b5d8c9 100644 --- a/cryptovoxels/integration.js +++ b/cryptovoxels/integration.js @@ -101,7 +101,7 @@ const DEFAULT_URI_CONTENT = { "name": "Default banner", "description": "This is the default banner that would be displayed ipsum", "image": "https://ipfs.zesty.market/ipfs/QmWBNfP8roDrwz3XQo4qpu9fMxvUSTn8LB7d4JK7ybrfZ2/assets/zesty-ad-square.png", - "url": "https://www.zesty.xyz" + "url": "https://www.zesty.market" } /** diff --git a/tests/utils/networking.test.mjs b/tests/utils/networking.test.mjs index 95a72f2..be8c9a1 100644 --- a/tests/utils/networking.test.mjs +++ b/tests/utils/networking.test.mjs @@ -21,7 +21,7 @@ const MOCK_IFRAME_SETUP2 = { test.describe('fetchCampaignAd', () => { test('fetchCampaignAd should return a default banner if no URI is given', () => { return expect(fetchCampaignAd()).resolves.toMatchObject( - { Ads: [{ asset_url: DEFAULT_BANNER, cta_url: 'https://www.zesty.xyz' }], CampaignId: 'TestCampaign'} + { Ads: [{ asset_url: DEFAULT_BANNER, cta_url: 'https://www.zesty.market' }], CampaignId: 'TestCampaign'} ) }); diff --git a/tests/wonderland/deploy/wonderland-test-bundle.js b/tests/wonderland/deploy/wonderland-test-bundle.js index c0f86e6..641414a 100644 --- a/tests/wonderland/deploy/wonderland-test-bundle.js +++ b/tests/wonderland/deploy/wonderland-test-bundle.js @@ -15277,7 +15277,7 @@ var Wt = async (t, e = "tall", r = "standard") => { let i = encodeURI(window.top.location.href).replace(/\/$/, ""); return (await W.default.get(`${un}/ad?ad_unit_id=${t}&url=${i}`)).data; } catch { - return console.warn("No active campaign banner could be located. Displaying default banner."), { Ads: [{ asset_url: B[e].style[r], cta_url: "https://www.zesty.xyz" }], CampaignId: "TestCampaign" }; + return console.warn("No active campaign banner could be located. Displaying default banner."), { Ads: [{ asset_url: B[e].style[r], cta_url: "https://www.zesty.market" }], CampaignId: "TestCampaign" }; } }; var Jt = async (t, e = null) => { diff --git a/tests/wonderland/deploy/wonderland-test-bundle.js.map b/tests/wonderland/deploy/wonderland-test-bundle.js.map index f84b73b..87354ec 100644 --- a/tests/wonderland/deploy/wonderland-test-bundle.js.map +++ b/tests/wonderland/deploy/wonderland-test-bundle.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../node_modules/howler/dist/howler.js", "../node_modules/earcut/src/earcut.js", "../node_modules/@wonderlandengine/api/dist/index.js", "../node_modules/wasm-feature-detect/dist/esm/index.js", "../node_modules/@wonderlandengine/api/dist/property.js", "../node_modules/@wonderlandengine/api/dist/decorators.js", "../node_modules/@wonderlandengine/api/dist/utils/object.js", "../node_modules/@wonderlandengine/api/dist/utils/event.js", "../node_modules/@wonderlandengine/api/dist/wonderland.js", "../node_modules/@wonderlandengine/api/dist/utils/fetch.js", "../node_modules/@wonderlandengine/api/dist/scene.js", "../node_modules/@wonderlandengine/api/dist/texture-manager.js", "../node_modules/@wonderlandengine/api/dist/engine.js", "../node_modules/@wonderlandengine/api/dist/wasm.js", "../node_modules/@wonderlandengine/api/dist/version.js", "../node_modules/@wonderlandengine/components/dist/8thwall-camera.js", "../node_modules/@wonderlandengine/components/dist/utils/webxr.js", "../node_modules/@wonderlandengine/components/dist/anchor.js", "../node_modules/@wonderlandengine/components/dist/cursor-target.js", "../node_modules/gl-matrix/esm/common.js", "../node_modules/gl-matrix/esm/mat3.js", "../node_modules/gl-matrix/esm/mat4.js", "../node_modules/gl-matrix/esm/quat.js", "../node_modules/gl-matrix/esm/vec3.js", "../node_modules/gl-matrix/esm/vec4.js", "../node_modules/gl-matrix/esm/quat2.js", "../node_modules/@wonderlandengine/components/dist/hit-test-location.js", "../node_modules/@wonderlandengine/components/dist/cursor.js", "../node_modules/@wonderlandengine/components/dist/debug-object.js", "../node_modules/@wonderlandengine/components/dist/fixed-foveation.js", "../node_modules/@wonderlandengine/components/dist/hand-tracking.js", "../node_modules/@wonderlandengine/components/dist/howler-audio-listener.js", "../node_modules/@wonderlandengine/components/dist/howler-audio-source.js", "../node_modules/@wonderlandengine/components/dist/utils/utils.js", "../node_modules/@wonderlandengine/components/dist/image-texture.js", "../node_modules/@wonderlandengine/components/dist/mouse-look.js", "../node_modules/@wonderlandengine/components/dist/player-height.js", "../node_modules/@wonderlandengine/components/dist/target-framerate.js", "../node_modules/@wonderlandengine/components/dist/teleport.js", "../node_modules/@wonderlandengine/components/dist/trail.js", "../node_modules/@wonderlandengine/components/dist/two-joint-ik-solver.js", "../node_modules/@wonderlandengine/components/dist/video-texture.js", "../node_modules/@wonderlandengine/components/dist/vr-mode-active-switch.js", "../node_modules/@wonderlandengine/components/dist/plane-detection.js", "../node_modules/@wonderlandengine/components/dist/vrm.js", "../node_modules/@wonderlandengine/components/dist/wasd-controls.js", "../js/expose-banners.js", "../js/zesty-wonderland-sdk.js", "../js/index.js"], - "sourcesContent": ["/*!\n * howler.js v2.2.3\n * howlerjs.com\n *\n * (c) 2013-2020, James Simpson of GoldFire Studios\n * goldfirestudios.com\n *\n * MIT License\n */\n\n(function() {\n\n 'use strict';\n\n /** Global Methods **/\n /***************************************************************************/\n\n /**\n * Create the global controller. All contained methods and properties apply\n * to all sounds that are currently playing or will be in the future.\n */\n var HowlerGlobal = function() {\n this.init();\n };\n HowlerGlobal.prototype = {\n /**\n * Initialize the global Howler object.\n * @return {Howler}\n */\n init: function() {\n var self = this || Howler;\n\n // Create a global ID counter.\n self._counter = 1000;\n\n // Pool of unlocked HTML5 Audio objects.\n self._html5AudioPool = [];\n self.html5PoolSize = 10;\n\n // Internal properties.\n self._codecs = {};\n self._howls = [];\n self._muted = false;\n self._volume = 1;\n self._canPlayEvent = 'canplaythrough';\n self._navigator = (typeof window !== 'undefined' && window.navigator) ? window.navigator : null;\n\n // Public properties.\n self.masterGain = null;\n self.noAudio = false;\n self.usingWebAudio = true;\n self.autoSuspend = true;\n self.ctx = null;\n\n // Set to false to disable the auto audio unlocker.\n self.autoUnlock = true;\n\n // Setup the various state values for global tracking.\n self._setup();\n\n return self;\n },\n\n /**\n * Get/set the global volume for all sounds.\n * @param {Float} vol Volume from 0.0 to 1.0.\n * @return {Howler/Float} Returns self or current volume.\n */\n volume: function(vol) {\n var self = this || Howler;\n vol = parseFloat(vol);\n\n // If we don't have an AudioContext created yet, run the setup.\n if (!self.ctx) {\n setupAudioContext();\n }\n\n if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {\n self._volume = vol;\n\n // Don't update any of the nodes if we are muted.\n if (self._muted) {\n return self;\n }\n\n // When using Web Audio, we just need to adjust the master gain.\n if (self.usingWebAudio) {\n self.masterGain.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n }\n\n // Loop through and change volume for all HTML5 audio nodes.\n for (var i=0; i=0; i--) {\n self._howls[i].unload();\n }\n\n // Create a new AudioContext to make sure it is fully reset.\n if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== 'undefined') {\n self.ctx.close();\n self.ctx = null;\n setupAudioContext();\n }\n\n return self;\n },\n\n /**\n * Check for codec support of specific extension.\n * @param {String} ext Audio file extention.\n * @return {Boolean}\n */\n codecs: function(ext) {\n return (this || Howler)._codecs[ext.replace(/^x-/, '')];\n },\n\n /**\n * Setup various state values for global tracking.\n * @return {Howler}\n */\n _setup: function() {\n var self = this || Howler;\n\n // Keeps track of the suspend/resume state of the AudioContext.\n self.state = self.ctx ? self.ctx.state || 'suspended' : 'suspended';\n\n // Automatically begin the 30-second suspend process\n self._autoSuspend();\n\n // Check if audio is available.\n if (!self.usingWebAudio) {\n // No audio is available on this system if noAudio is set to true.\n if (typeof Audio !== 'undefined') {\n try {\n var test = new Audio();\n\n // Check if the canplaythrough event is available.\n if (typeof test.oncanplaythrough === 'undefined') {\n self._canPlayEvent = 'canplay';\n }\n } catch(e) {\n self.noAudio = true;\n }\n } else {\n self.noAudio = true;\n }\n }\n\n // Test to make sure audio isn't disabled in Internet Explorer.\n try {\n var test = new Audio();\n if (test.muted) {\n self.noAudio = true;\n }\n } catch (e) {}\n\n // Check for supported codecs.\n if (!self.noAudio) {\n self._setupCodecs();\n }\n\n return self;\n },\n\n /**\n * Check for browser support for various codecs and cache the results.\n * @return {Howler}\n */\n _setupCodecs: function() {\n var self = this || Howler;\n var audioTest = null;\n\n // Must wrap in a try/catch because IE11 in server mode throws an error.\n try {\n audioTest = (typeof Audio !== 'undefined') ? new Audio() : null;\n } catch (err) {\n return self;\n }\n\n if (!audioTest || typeof audioTest.canPlayType !== 'function') {\n return self;\n }\n\n var mpegTest = audioTest.canPlayType('audio/mpeg;').replace(/^no$/, '');\n\n // Opera version <33 has mixed MP3 support, so we need to check for and block it.\n var ua = self._navigator ? self._navigator.userAgent : '';\n var checkOpera = ua.match(/OPR\\/([0-6].)/g);\n var isOldOpera = (checkOpera && parseInt(checkOpera[0].split('/')[1], 10) < 33);\n var checkSafari = ua.indexOf('Safari') !== -1 && ua.indexOf('Chrome') === -1;\n var safariVersion = ua.match(/Version\\/(.*?) /);\n var isOldSafari = (checkSafari && safariVersion && parseInt(safariVersion[1], 10) < 15);\n\n self._codecs = {\n mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType('audio/mp3;').replace(/^no$/, ''))),\n mpeg: !!mpegTest,\n opus: !!audioTest.canPlayType('audio/ogg; codecs=\"opus\"').replace(/^no$/, ''),\n ogg: !!audioTest.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, ''),\n oga: !!audioTest.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/, ''),\n wav: !!(audioTest.canPlayType('audio/wav; codecs=\"1\"') || audioTest.canPlayType('audio/wav')).replace(/^no$/, ''),\n aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''),\n caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''),\n m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''),\n weba: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs=\"vorbis\"').replace(/^no$/, '')),\n webm: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs=\"vorbis\"').replace(/^no$/, '')),\n dolby: !!audioTest.canPlayType('audio/mp4; codecs=\"ec-3\"').replace(/^no$/, ''),\n flac: !!(audioTest.canPlayType('audio/x-flac;') || audioTest.canPlayType('audio/flac;')).replace(/^no$/, '')\n };\n\n return self;\n },\n\n /**\n * Some browsers/devices will only allow audio to be played after a user interaction.\n * Attempt to automatically unlock audio on the first user interaction.\n * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/\n * @return {Howler}\n */\n _unlockAudio: function() {\n var self = this || Howler;\n\n // Only run this if Web Audio is supported and it hasn't already been unlocked.\n if (self._audioUnlocked || !self.ctx) {\n return;\n }\n\n self._audioUnlocked = false;\n self.autoUnlock = false;\n\n // Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views.\n // Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000.\n // By calling Howler.unload(), we create a new AudioContext with the correct sampleRate.\n if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {\n self._mobileUnloaded = true;\n self.unload();\n }\n\n // Scratch buffer for enabling iOS to dispose of web audio buffers correctly, as per:\n // http://stackoverflow.com/questions/24119684\n self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);\n\n // Call this method on touch start to create and play a buffer,\n // then check if the audio actually played to determine if\n // audio has now been unlocked on iOS, Android, etc.\n var unlock = function(e) {\n // Create a pool of unlocked HTML5 Audio objects that can\n // be used for playing sounds without user interaction. HTML5\n // Audio objects must be individually unlocked, as opposed\n // to the WebAudio API which only needs a single activation.\n // This must occur before WebAudio setup or the source.onended\n // event will not fire.\n while (self._html5AudioPool.length < self.html5PoolSize) {\n try {\n var audioNode = new Audio();\n\n // Mark this Audio object as unlocked to ensure it can get returned\n // to the unlocked pool when released.\n audioNode._unlocked = true;\n\n // Add the audio node to the pool.\n self._releaseHtml5Audio(audioNode);\n } catch (e) {\n self.noAudio = true;\n break;\n }\n }\n\n // Loop through any assigned audio nodes and unlock them.\n for (var i=0; i= 55.\n if (typeof self.ctx.resume === 'function') {\n self.ctx.resume();\n }\n\n // Setup a timeout to check that we are unlocked on the next event loop.\n source.onended = function() {\n source.disconnect(0);\n\n // Update the unlocked state and prevent this check from happening again.\n self._audioUnlocked = true;\n\n // Remove the touch start listener.\n document.removeEventListener('touchstart', unlock, true);\n document.removeEventListener('touchend', unlock, true);\n document.removeEventListener('click', unlock, true);\n document.removeEventListener('keydown', unlock, true);\n\n // Let all sounds know that audio has been unlocked.\n for (var i=0; i 0 ? sound._seek : self._sprite[sprite][0] / 1000);\n var duration = Math.max(0, ((self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000) - seek);\n var timeout = (duration * 1000) / Math.abs(sound._rate);\n var start = self._sprite[sprite][0] / 1000;\n var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000;\n sound._sprite = sprite;\n\n // Mark the sound as ended instantly so that this async playback\n // doesn't get grabbed by another call to play while this one waits to start.\n sound._ended = false;\n\n // Update the parameters of the sound.\n var setParams = function() {\n sound._paused = false;\n sound._seek = seek;\n sound._start = start;\n sound._stop = stop;\n sound._loop = !!(sound._loop || self._sprite[sprite][2]);\n };\n\n // End the sound instantly if seek is at the end.\n if (seek >= stop) {\n self._ended(sound);\n return;\n }\n\n // Begin the actual playback.\n var node = sound._node;\n if (self._webAudio) {\n // Fire this when the sound is ready to play to begin Web Audio playback.\n var playWebAudio = function() {\n self._playLock = false;\n setParams();\n self._refreshBuffer(sound);\n\n // Setup the playback params.\n var vol = (sound._muted || self._muted) ? 0 : sound._volume;\n node.gain.setValueAtTime(vol, Howler.ctx.currentTime);\n sound._playStart = Howler.ctx.currentTime;\n\n // Play the sound using the supported method.\n if (typeof node.bufferSource.start === 'undefined') {\n sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration);\n } else {\n sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration);\n }\n\n // Start a new timer if none is present.\n if (timeout !== Infinity) {\n self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n }\n\n if (!internal) {\n setTimeout(function() {\n self._emit('play', sound._id);\n self._loadQueue();\n }, 0);\n }\n };\n\n if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') {\n playWebAudio();\n } else {\n self._playLock = true;\n\n // Wait for the audio context to resume before playing.\n self.once('resume', playWebAudio);\n\n // Cancel the end timer.\n self._clearTimer(sound._id);\n }\n } else {\n // Fire this when the sound is ready to play to begin HTML5 Audio playback.\n var playHtml5 = function() {\n node.currentTime = seek;\n node.muted = sound._muted || self._muted || Howler._muted || node.muted;\n node.volume = sound._volume * Howler.volume();\n node.playbackRate = sound._rate;\n\n // Some browsers will throw an error if this is called without user interaction.\n try {\n var play = node.play();\n\n // Support older browsers that don't support promises, and thus don't have this issue.\n if (play && typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')) {\n // Implements a lock to prevent DOMException: The play() request was interrupted by a call to pause().\n self._playLock = true;\n\n // Set param values immediately.\n setParams();\n\n // Releases the lock and executes queued actions.\n play\n .then(function() {\n self._playLock = false;\n node._unlocked = true;\n if (!internal) {\n self._emit('play', sound._id);\n } else {\n self._loadQueue();\n }\n })\n .catch(function() {\n self._playLock = false;\n self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +\n 'on mobile devices and Chrome where playback was not within a user interaction.');\n\n // Reset the ended and paused values.\n sound._ended = true;\n sound._paused = true;\n });\n } else if (!internal) {\n self._playLock = false;\n setParams();\n self._emit('play', sound._id);\n }\n\n // Setting rate before playing won't work in IE, so we set it again here.\n node.playbackRate = sound._rate;\n\n // If the node is still paused, then we can assume there was a playback issue.\n if (node.paused) {\n self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' +\n 'on mobile devices and Chrome where playback was not within a user interaction.');\n return;\n }\n\n // Setup the end timer on sprites or listen for the ended event.\n if (sprite !== '__default' || sound._loop) {\n self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n } else {\n self._endTimers[sound._id] = function() {\n // Fire ended on this audio node.\n self._ended(sound);\n\n // Clear this listener.\n node.removeEventListener('ended', self._endTimers[sound._id], false);\n };\n node.addEventListener('ended', self._endTimers[sound._id], false);\n }\n } catch (err) {\n self._emit('playerror', sound._id, err);\n }\n };\n\n // If this is streaming audio, make sure the src is set and load again.\n if (node.src === 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA') {\n node.src = self._src;\n node.load();\n }\n\n // Play immediately if ready, or wait for the 'canplaythrough'e vent.\n var loadedNoReadyState = (window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS);\n if (node.readyState >= 3 || loadedNoReadyState) {\n playHtml5();\n } else {\n self._playLock = true;\n self._state = 'loading';\n\n var listener = function() {\n self._state = 'loaded';\n \n // Begin playback.\n playHtml5();\n\n // Clear this listener.\n node.removeEventListener(Howler._canPlayEvent, listener, false);\n };\n node.addEventListener(Howler._canPlayEvent, listener, false);\n\n // Cancel the end timer.\n self._clearTimer(sound._id);\n }\n }\n\n return sound._id;\n },\n\n /**\n * Pause playback and save current position.\n * @param {Number} id The sound ID (empty to pause all in group).\n * @return {Howl}\n */\n pause: function(id) {\n var self = this;\n\n // If the sound hasn't loaded or a play() promise is pending, add it to the load queue to pause when capable.\n if (self._state !== 'loaded' || self._playLock) {\n self._queue.push({\n event: 'pause',\n action: function() {\n self.pause(id);\n }\n });\n\n return self;\n }\n\n // If no id is passed, get all ID's to be paused.\n var ids = self._getSoundIds(id);\n\n for (var i=0; i Returns the group's volume value.\n * volume(id) -> Returns the sound id's current volume.\n * volume(vol) -> Sets the volume of all sounds in this Howl group.\n * volume(vol, id) -> Sets the volume of passed sound id.\n * @return {Howl/Number} Returns self or current volume.\n */\n volume: function() {\n var self = this;\n var args = arguments;\n var vol, id;\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // Return the value of the groups' volume.\n return self._volume;\n } else if (args.length === 1 || args.length === 2 && typeof args[1] === 'undefined') {\n // First check if this is an ID, and if not, assume it is a new volume.\n var ids = self._getSoundIds();\n var index = ids.indexOf(args[0]);\n if (index >= 0) {\n id = parseInt(args[0], 10);\n } else {\n vol = parseFloat(args[0]);\n }\n } else if (args.length >= 2) {\n vol = parseFloat(args[0]);\n id = parseInt(args[1], 10);\n }\n\n // Update the volume or return the current volume.\n var sound;\n if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) {\n // If the sound hasn't loaded, add it to the load queue to change volume when capable.\n if (self._state !== 'loaded'|| self._playLock) {\n self._queue.push({\n event: 'volume',\n action: function() {\n self.volume.apply(self, args);\n }\n });\n\n return self;\n }\n\n // Set the group volume.\n if (typeof id === 'undefined') {\n self._volume = vol;\n }\n\n // Update one or all volumes.\n id = self._getSoundIds(id);\n for (var i=0; i 0) ? len / steps : len);\n var lastTick = Date.now();\n\n // Store the value being faded to.\n sound._fadeTo = to;\n\n // Update the volume value on each interval tick.\n sound._interval = setInterval(function() {\n // Update the volume based on the time since the last tick.\n var tick = (Date.now() - lastTick) / len;\n lastTick = Date.now();\n vol += diff * tick;\n\n // Round to within 2 decimal points.\n vol = Math.round(vol * 100) / 100;\n\n // Make sure the volume is in the right bounds.\n if (diff < 0) {\n vol = Math.max(to, vol);\n } else {\n vol = Math.min(to, vol);\n }\n\n // Change the volume.\n if (self._webAudio) {\n sound._volume = vol;\n } else {\n self.volume(vol, sound._id, true);\n }\n\n // Set the group's volume.\n if (isGroup) {\n self._volume = vol;\n }\n\n // When the fade is complete, stop it and fire event.\n if ((to < from && vol <= to) || (to > from && vol >= to)) {\n clearInterval(sound._interval);\n sound._interval = null;\n sound._fadeTo = null;\n self.volume(to, sound._id);\n self._emit('fade', sound._id);\n }\n }, stepLen);\n },\n\n /**\n * Internal method that stops the currently playing fade when\n * a new fade starts, volume is changed or the sound is stopped.\n * @param {Number} id The sound id.\n * @return {Howl}\n */\n _stopFade: function(id) {\n var self = this;\n var sound = self._soundById(id);\n\n if (sound && sound._interval) {\n if (self._webAudio) {\n sound._node.gain.cancelScheduledValues(Howler.ctx.currentTime);\n }\n\n clearInterval(sound._interval);\n sound._interval = null;\n self.volume(sound._fadeTo, id);\n sound._fadeTo = null;\n self._emit('fade', id);\n }\n\n return self;\n },\n\n /**\n * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.\n * loop() -> Returns the group's loop value.\n * loop(id) -> Returns the sound id's loop value.\n * loop(loop) -> Sets the loop value for all sounds in this Howl group.\n * loop(loop, id) -> Sets the loop value of passed sound id.\n * @return {Howl/Boolean} Returns self or current loop value.\n */\n loop: function() {\n var self = this;\n var args = arguments;\n var loop, id, sound;\n\n // Determine the values for loop and id.\n if (args.length === 0) {\n // Return the grou's loop value.\n return self._loop;\n } else if (args.length === 1) {\n if (typeof args[0] === 'boolean') {\n loop = args[0];\n self._loop = loop;\n } else {\n // Return this sound's loop value.\n sound = self._soundById(parseInt(args[0], 10));\n return sound ? sound._loop : false;\n }\n } else if (args.length === 2) {\n loop = args[0];\n id = parseInt(args[1], 10);\n }\n\n // If no id is passed, get all ID's to be looped.\n var ids = self._getSoundIds(id);\n for (var i=0; i Returns the first sound node's current playback rate.\n * rate(id) -> Returns the sound id's current playback rate.\n * rate(rate) -> Sets the playback rate of all sounds in this Howl group.\n * rate(rate, id) -> Sets the playback rate of passed sound id.\n * @return {Howl/Number} Returns self or the current playback rate.\n */\n rate: function() {\n var self = this;\n var args = arguments;\n var rate, id;\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // We will simply return the current rate of the first node.\n id = self._sounds[0]._id;\n } else if (args.length === 1) {\n // First check if this is an ID, and if not, assume it is a new rate value.\n var ids = self._getSoundIds();\n var index = ids.indexOf(args[0]);\n if (index >= 0) {\n id = parseInt(args[0], 10);\n } else {\n rate = parseFloat(args[0]);\n }\n } else if (args.length === 2) {\n rate = parseFloat(args[0]);\n id = parseInt(args[1], 10);\n }\n\n // Update the playback rate or return the current value.\n var sound;\n if (typeof rate === 'number') {\n // If the sound hasn't loaded, add it to the load queue to change playback rate when capable.\n if (self._state !== 'loaded' || self._playLock) {\n self._queue.push({\n event: 'rate',\n action: function() {\n self.rate.apply(self, args);\n }\n });\n\n return self;\n }\n\n // Set the group rate.\n if (typeof id === 'undefined') {\n self._rate = rate;\n }\n\n // Update one or all volumes.\n id = self._getSoundIds(id);\n for (var i=0; i Returns the first sound node's current seek position.\n * seek(id) -> Returns the sound id's current seek position.\n * seek(seek) -> Sets the seek position of the first sound node.\n * seek(seek, id) -> Sets the seek position of passed sound id.\n * @return {Howl/Number} Returns self or the current seek position.\n */\n seek: function() {\n var self = this;\n var args = arguments;\n var seek, id;\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // We will simply return the current position of the first node.\n if (self._sounds.length) {\n id = self._sounds[0]._id;\n }\n } else if (args.length === 1) {\n // First check if this is an ID, and if not, assume it is a new seek position.\n var ids = self._getSoundIds();\n var index = ids.indexOf(args[0]);\n if (index >= 0) {\n id = parseInt(args[0], 10);\n } else if (self._sounds.length) {\n id = self._sounds[0]._id;\n seek = parseFloat(args[0]);\n }\n } else if (args.length === 2) {\n seek = parseFloat(args[0]);\n id = parseInt(args[1], 10);\n }\n\n // If there is no ID, bail out.\n if (typeof id === 'undefined') {\n return 0;\n }\n\n // If the sound hasn't loaded, add it to the load queue to seek when capable.\n if (typeof seek === 'number' && (self._state !== 'loaded' || self._playLock)) {\n self._queue.push({\n event: 'seek',\n action: function() {\n self.seek.apply(self, args);\n }\n });\n\n return self;\n }\n\n // Get the sound.\n var sound = self._soundById(id);\n\n if (sound) {\n if (typeof seek === 'number' && seek >= 0) {\n // Pause the sound and update position for restarting playback.\n var playing = self.playing(id);\n if (playing) {\n self.pause(id, true);\n }\n\n // Move the position of the track and cancel timer.\n sound._seek = seek;\n sound._ended = false;\n self._clearTimer(id);\n\n // Update the seek position for HTML5 Audio.\n if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) {\n sound._node.currentTime = seek;\n }\n\n // Seek and emit when ready.\n var seekAndEmit = function() {\n // Restart the playback if the sound was playing.\n if (playing) {\n self.play(id, true);\n }\n\n self._emit('seek', id);\n };\n\n // Wait for the play lock to be unset before emitting (HTML5 Audio).\n if (playing && !self._webAudio) {\n var emitSeek = function() {\n if (!self._playLock) {\n seekAndEmit();\n } else {\n setTimeout(emitSeek, 0);\n }\n };\n setTimeout(emitSeek, 0);\n } else {\n seekAndEmit();\n }\n } else {\n if (self._webAudio) {\n var realTime = self.playing(id) ? Howler.ctx.currentTime - sound._playStart : 0;\n var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;\n return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));\n } else {\n return sound._node.currentTime;\n }\n }\n }\n\n return self;\n },\n\n /**\n * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.\n * @param {Number} id The sound id to check. If none is passed, the whole sound group is checked.\n * @return {Boolean} True if playing and false if not.\n */\n playing: function(id) {\n var self = this;\n\n // Check the passed sound ID (if any).\n if (typeof id === 'number') {\n var sound = self._soundById(id);\n return sound ? !sound._paused : false;\n }\n\n // Otherwise, loop through all sounds and check if any are playing.\n for (var i=0; i= 0) {\n Howler._howls.splice(index, 1);\n }\n\n // Delete this sound from the cache (if no other Howl is using it).\n var remCache = true;\n for (i=0; i= 0) {\n remCache = false;\n break;\n }\n }\n\n if (cache && remCache) {\n delete cache[self._src];\n }\n\n // Clear global errors.\n Howler.noAudio = false;\n\n // Clear out `self`.\n self._state = 'unloaded';\n self._sounds = [];\n self = null;\n\n return null;\n },\n\n /**\n * Listen to a custom event.\n * @param {String} event Event name.\n * @param {Function} fn Listener to call.\n * @param {Number} id (optional) Only listen to events for this sound.\n * @param {Number} once (INTERNAL) Marks event to fire only once.\n * @return {Howl}\n */\n on: function(event, fn, id, once) {\n var self = this;\n var events = self['_on' + event];\n\n if (typeof fn === 'function') {\n events.push(once ? {id: id, fn: fn, once: once} : {id: id, fn: fn});\n }\n\n return self;\n },\n\n /**\n * Remove a custom event. Call without parameters to remove all events.\n * @param {String} event Event name.\n * @param {Function} fn Listener to remove. Leave empty to remove all.\n * @param {Number} id (optional) Only remove events for this sound.\n * @return {Howl}\n */\n off: function(event, fn, id) {\n var self = this;\n var events = self['_on' + event];\n var i = 0;\n\n // Allow passing just an event and ID.\n if (typeof fn === 'number') {\n id = fn;\n fn = null;\n }\n\n if (fn || id) {\n // Loop through event store and remove the passed function.\n for (i=0; i=0; i--) {\n // Only fire the listener if the correct ID is used.\n if (!events[i].id || events[i].id === id || event === 'load') {\n setTimeout(function(fn) {\n fn.call(this, id, msg);\n }.bind(self, events[i].fn), 0);\n\n // If this event was setup with `once`, remove it.\n if (events[i].once) {\n self.off(event, events[i].fn, events[i].id);\n }\n }\n }\n\n // Pass the event type into load queue so that it can continue stepping.\n self._loadQueue(event);\n\n return self;\n },\n\n /**\n * Queue of actions initiated before the sound has loaded.\n * These will be called in sequence, with the next only firing\n * after the previous has finished executing (even if async like play).\n * @return {Howl}\n */\n _loadQueue: function(event) {\n var self = this;\n\n if (self._queue.length > 0) {\n var task = self._queue[0];\n\n // Remove this task if a matching event was passed.\n if (task.event === event) {\n self._queue.shift();\n self._loadQueue();\n }\n\n // Run the task if no event type is passed.\n if (!event) {\n task.action();\n }\n }\n\n return self;\n },\n\n /**\n * Fired when playback ends at the end of the duration.\n * @param {Sound} sound The sound object to work with.\n * @return {Howl}\n */\n _ended: function(sound) {\n var self = this;\n var sprite = sound._sprite;\n\n // If we are using IE and there was network latency we may be clipping\n // audio before it completes playing. Lets check the node to make sure it\n // believes it has completed, before ending the playback.\n if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {\n setTimeout(self._ended.bind(self, sound), 100);\n return self;\n }\n\n // Should this sound loop?\n var loop = !!(sound._loop || self._sprite[sprite][2]);\n\n // Fire the ended event.\n self._emit('end', sound._id);\n\n // Restart the playback for HTML5 Audio loop.\n if (!self._webAudio && loop) {\n self.stop(sound._id, true).play(sound._id);\n }\n\n // Restart this timer if on a Web Audio loop.\n if (self._webAudio && loop) {\n self._emit('play', sound._id);\n sound._seek = sound._start || 0;\n sound._rateSeek = 0;\n sound._playStart = Howler.ctx.currentTime;\n\n var timeout = ((sound._stop - sound._start) * 1000) / Math.abs(sound._rate);\n self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);\n }\n\n // Mark the node as paused.\n if (self._webAudio && !loop) {\n sound._paused = true;\n sound._ended = true;\n sound._seek = sound._start || 0;\n sound._rateSeek = 0;\n self._clearTimer(sound._id);\n\n // Clean up the buffer source.\n self._cleanBuffer(sound._node);\n\n // Attempt to auto-suspend AudioContext if no sounds are still playing.\n Howler._autoSuspend();\n }\n\n // When using a sprite, end the track.\n if (!self._webAudio && !loop) {\n self.stop(sound._id, true);\n }\n\n return self;\n },\n\n /**\n * Clear the end timer for a sound playback.\n * @param {Number} id The sound ID.\n * @return {Howl}\n */\n _clearTimer: function(id) {\n var self = this;\n\n if (self._endTimers[id]) {\n // Clear the timeout or remove the ended listener.\n if (typeof self._endTimers[id] !== 'function') {\n clearTimeout(self._endTimers[id]);\n } else {\n var sound = self._soundById(id);\n if (sound && sound._node) {\n sound._node.removeEventListener('ended', self._endTimers[id], false);\n }\n }\n\n delete self._endTimers[id];\n }\n\n return self;\n },\n\n /**\n * Return the sound identified by this ID, or return null.\n * @param {Number} id Sound ID\n * @return {Object} Sound object or null.\n */\n _soundById: function(id) {\n var self = this;\n\n // Loop through all sounds and find the one with this ID.\n for (var i=0; i=0; i--) {\n if (cnt <= limit) {\n return;\n }\n\n if (self._sounds[i]._ended) {\n // Disconnect the audio source when using Web Audio.\n if (self._webAudio && self._sounds[i]._node) {\n self._sounds[i]._node.disconnect(0);\n }\n\n // Remove sounds until we have the pool size.\n self._sounds.splice(i, 1);\n cnt--;\n }\n }\n },\n\n /**\n * Get all ID's from the sounds pool.\n * @param {Number} id Only return one ID if one is passed.\n * @return {Array} Array of IDs.\n */\n _getSoundIds: function(id) {\n var self = this;\n\n if (typeof id === 'undefined') {\n var ids = [];\n for (var i=0; i= 0;\n\n if (Howler._scratchBuffer && node.bufferSource) {\n node.bufferSource.onended = null;\n node.bufferSource.disconnect(0);\n if (isIOS) {\n try { node.bufferSource.buffer = Howler._scratchBuffer; } catch(e) {}\n }\n }\n node.bufferSource = null;\n\n return self;\n },\n\n /**\n * Set the source to a 0-second silence to stop any downloading (except in IE).\n * @param {Object} node Audio node to clear.\n */\n _clearSound: function(node) {\n var checkIE = /MSIE |Trident\\//.test(Howler._navigator && Howler._navigator.userAgent);\n if (!checkIE) {\n node.src = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA';\n }\n }\n };\n\n /** Single Sound Methods **/\n /***************************************************************************/\n\n /**\n * Setup the sound object, which each node attached to a Howl group is contained in.\n * @param {Object} howl The Howl parent group.\n */\n var Sound = function(howl) {\n this._parent = howl;\n this.init();\n };\n Sound.prototype = {\n /**\n * Initialize a new Sound object.\n * @return {Sound}\n */\n init: function() {\n var self = this;\n var parent = self._parent;\n\n // Setup the default parameters.\n self._muted = parent._muted;\n self._loop = parent._loop;\n self._volume = parent._volume;\n self._rate = parent._rate;\n self._seek = 0;\n self._paused = true;\n self._ended = true;\n self._sprite = '__default';\n\n // Generate a unique ID for this sound.\n self._id = ++Howler._counter;\n\n // Add itself to the parent's pool.\n parent._sounds.push(self);\n\n // Create the new node.\n self.create();\n\n return self;\n },\n\n /**\n * Create and setup a new sound object, whether HTML5 Audio or Web Audio.\n * @return {Sound}\n */\n create: function() {\n var self = this;\n var parent = self._parent;\n var volume = (Howler._muted || self._muted || self._parent._muted) ? 0 : self._volume;\n\n if (parent._webAudio) {\n // Create the gain node for controlling volume (the source will connect to this).\n self._node = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();\n self._node.gain.setValueAtTime(volume, Howler.ctx.currentTime);\n self._node.paused = true;\n self._node.connect(Howler.masterGain);\n } else if (!Howler.noAudio) {\n // Get an unlocked Audio object from the pool.\n self._node = Howler._obtainHtml5Audio();\n\n // Listen for errors (http://dev.w3.org/html5/spec-author-view/spec.html#mediaerror).\n self._errorFn = self._errorListener.bind(self);\n self._node.addEventListener('error', self._errorFn, false);\n\n // Listen for 'canplaythrough' event to let us know the sound is ready.\n self._loadFn = self._loadListener.bind(self);\n self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false);\n\n // Listen for the 'ended' event on the sound to account for edge-case where\n // a finite sound has a duration of Infinity.\n self._endFn = self._endListener.bind(self);\n self._node.addEventListener('ended', self._endFn, false);\n\n // Setup the new audio node.\n self._node.src = parent._src;\n self._node.preload = parent._preload === true ? 'auto' : parent._preload;\n self._node.volume = volume * Howler.volume();\n\n // Begin loading the source.\n self._node.load();\n }\n\n return self;\n },\n\n /**\n * Reset the parameters of this sound to the original state (for recycle).\n * @return {Sound}\n */\n reset: function() {\n var self = this;\n var parent = self._parent;\n\n // Reset all of the parameters of this sound.\n self._muted = parent._muted;\n self._loop = parent._loop;\n self._volume = parent._volume;\n self._rate = parent._rate;\n self._seek = 0;\n self._rateSeek = 0;\n self._paused = true;\n self._ended = true;\n self._sprite = '__default';\n\n // Generate a new ID so that it isn't confused with the previous sound.\n self._id = ++Howler._counter;\n\n return self;\n },\n\n /**\n * HTML5 Audio error listener callback.\n */\n _errorListener: function() {\n var self = this;\n\n // Fire an error event and pass back the code.\n self._parent._emit('loaderror', self._id, self._node.error ? self._node.error.code : 0);\n\n // Clear the event listener.\n self._node.removeEventListener('error', self._errorFn, false);\n },\n\n /**\n * HTML5 Audio canplaythrough listener callback.\n */\n _loadListener: function() {\n var self = this;\n var parent = self._parent;\n\n // Round up the duration to account for the lower precision in HTML5 Audio.\n parent._duration = Math.ceil(self._node.duration * 10) / 10;\n\n // Setup a sprite if none is defined.\n if (Object.keys(parent._sprite).length === 0) {\n parent._sprite = {__default: [0, parent._duration * 1000]};\n }\n\n if (parent._state !== 'loaded') {\n parent._state = 'loaded';\n parent._emit('load');\n parent._loadQueue();\n }\n\n // Clear the event listener.\n self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false);\n },\n\n /**\n * HTML5 Audio ended listener callback.\n */\n _endListener: function() {\n var self = this;\n var parent = self._parent;\n\n // Only handle the `ended`` event if the duration is Infinity.\n if (parent._duration === Infinity) {\n // Update the parent duration to match the real audio duration.\n // Round up the duration to account for the lower precision in HTML5 Audio.\n parent._duration = Math.ceil(self._node.duration * 10) / 10;\n\n // Update the sprite that corresponds to the real duration.\n if (parent._sprite.__default[1] === Infinity) {\n parent._sprite.__default[1] = parent._duration * 1000;\n }\n\n // Run the regular ended method.\n parent._ended(self);\n }\n\n // Clear the event listener since the duration is now correct.\n self._node.removeEventListener('ended', self._endFn, false);\n }\n };\n\n /** Helper Methods **/\n /***************************************************************************/\n\n var cache = {};\n\n /**\n * Buffer a sound from URL, Data URI or cache and decode to audio source (Web Audio API).\n * @param {Howl} self\n */\n var loadBuffer = function(self) {\n var url = self._src;\n\n // Check if the buffer has already been cached and use it instead.\n if (cache[url]) {\n // Set the duration from the cache.\n self._duration = cache[url].duration;\n\n // Load the sound into this Howl.\n loadSound(self);\n\n return;\n }\n\n if (/^data:[^;]+;base64,/.test(url)) {\n // Decode the base64 data URI without XHR, since some browsers don't support it.\n var data = atob(url.split(',')[1]);\n var dataView = new Uint8Array(data.length);\n for (var i=0; i 0) {\n cache[self._src] = buffer;\n loadSound(self, buffer);\n } else {\n error();\n }\n };\n\n // Decode the buffer into an audio source.\n if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1) {\n Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error);\n } else {\n Howler.ctx.decodeAudioData(arraybuffer, success, error);\n }\n }\n\n /**\n * Sound is now loaded, so finish setting everything up and fire the loaded event.\n * @param {Howl} self\n * @param {Object} buffer The decoded buffer sound source.\n */\n var loadSound = function(self, buffer) {\n // Set the duration.\n if (buffer && !self._duration) {\n self._duration = buffer.duration;\n }\n\n // Setup a sprite if none is defined.\n if (Object.keys(self._sprite).length === 0) {\n self._sprite = {__default: [0, self._duration * 1000]};\n }\n\n // Fire the loaded event.\n if (self._state !== 'loaded') {\n self._state = 'loaded';\n self._emit('load');\n self._loadQueue();\n }\n };\n\n /**\n * Setup the audio context when available, or switch to HTML5 Audio mode.\n */\n var setupAudioContext = function() {\n // If we have already detected that Web Audio isn't supported, don't run this step again.\n if (!Howler.usingWebAudio) {\n return;\n }\n\n // Check if we are using Web Audio and setup the AudioContext if we are.\n try {\n if (typeof AudioContext !== 'undefined') {\n Howler.ctx = new AudioContext();\n } else if (typeof webkitAudioContext !== 'undefined') {\n Howler.ctx = new webkitAudioContext();\n } else {\n Howler.usingWebAudio = false;\n }\n } catch(e) {\n Howler.usingWebAudio = false;\n }\n\n // If the audio context creation still failed, set using web audio to false.\n if (!Howler.ctx) {\n Howler.usingWebAudio = false;\n }\n\n // Check if a webview is being used on iOS8 or earlier (rather than the browser).\n // If it is, disable Web Audio as it causes crashing.\n var iOS = (/iP(hone|od|ad)/.test(Howler._navigator && Howler._navigator.platform));\n var appVersion = Howler._navigator && Howler._navigator.appVersion.match(/OS (\\d+)_(\\d+)_?(\\d+)?/);\n var version = appVersion ? parseInt(appVersion[1], 10) : null;\n if (iOS && version && version < 9) {\n var safari = /safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase());\n if (Howler._navigator && !safari) {\n Howler.usingWebAudio = false;\n }\n }\n\n // Create and expose the master GainNode when using Web Audio (useful for plugins or advanced usage).\n if (Howler.usingWebAudio) {\n Howler.masterGain = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain();\n Howler.masterGain.gain.setValueAtTime(Howler._muted ? 0 : Howler._volume, Howler.ctx.currentTime);\n Howler.masterGain.connect(Howler.ctx.destination);\n }\n\n // Re-run the setup on Howler.\n Howler._setup();\n };\n\n // Add support for AMD (Asynchronous Module Definition) libraries such as require.js.\n if (typeof define === 'function' && define.amd) {\n define([], function() {\n return {\n Howler: Howler,\n Howl: Howl\n };\n });\n }\n\n // Add support for CommonJS libraries such as browserify.\n if (typeof exports !== 'undefined') {\n exports.Howler = Howler;\n exports.Howl = Howl;\n }\n\n // Add to global in Node.js (for testing, etc).\n if (typeof global !== 'undefined') {\n global.HowlerGlobal = HowlerGlobal;\n global.Howler = Howler;\n global.Howl = Howl;\n global.Sound = Sound;\n } else if (typeof window !== 'undefined') { // Define globally in case AMD is not available or unused.\n window.HowlerGlobal = HowlerGlobal;\n window.Howler = Howler;\n window.Howl = Howl;\n window.Sound = Sound;\n }\n})();\n\n\n/*!\n * Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.\n * \n * howler.js v2.2.3\n * howlerjs.com\n *\n * (c) 2013-2020, James Simpson of GoldFire Studios\n * goldfirestudios.com\n *\n * MIT License\n */\n\n(function() {\n\n 'use strict';\n\n // Setup default properties.\n HowlerGlobal.prototype._pos = [0, 0, 0];\n HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0];\n\n /** Global Methods **/\n /***************************************************************************/\n\n /**\n * Helper method to update the stereo panning position of all current Howls.\n * Future Howls will not use this value unless explicitly set.\n * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.\n * @return {Howler/Number} Self or current stereo panning value.\n */\n HowlerGlobal.prototype.stereo = function(pan) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self.ctx || !self.ctx.listener) {\n return self;\n }\n\n // Loop through all Howls and update their stereo panning.\n for (var i=self._howls.length-1; i>=0; i--) {\n self._howls[i].stereo(pan);\n }\n\n return self;\n };\n\n /**\n * Get/set the position of the listener in 3D cartesian space. Sounds using\n * 3D position will be relative to the listener's position.\n * @param {Number} x The x-position of the listener.\n * @param {Number} y The y-position of the listener.\n * @param {Number} z The z-position of the listener.\n * @return {Howler/Array} Self or current listener position.\n */\n HowlerGlobal.prototype.pos = function(x, y, z) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self.ctx || !self.ctx.listener) {\n return self;\n }\n\n // Set the defaults for optional 'y' & 'z'.\n y = (typeof y !== 'number') ? self._pos[1] : y;\n z = (typeof z !== 'number') ? self._pos[2] : z;\n\n if (typeof x === 'number') {\n self._pos = [x, y, z];\n\n if (typeof self.ctx.listener.positionX !== 'undefined') {\n self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1);\n self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1);\n self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1);\n } else {\n self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]);\n }\n } else {\n return self._pos;\n }\n\n return self;\n };\n\n /**\n * Get/set the direction the listener is pointing in the 3D cartesian space.\n * A front and up vector must be provided. The front is the direction the\n * face of the listener is pointing, and up is the direction the top of the\n * listener is pointing. Thus, these values are expected to be at right angles\n * from each other.\n * @param {Number} x The x-orientation of the listener.\n * @param {Number} y The y-orientation of the listener.\n * @param {Number} z The z-orientation of the listener.\n * @param {Number} xUp The x-orientation of the top of the listener.\n * @param {Number} yUp The y-orientation of the top of the listener.\n * @param {Number} zUp The z-orientation of the top of the listener.\n * @return {Howler/Array} Returns self or the current orientation vectors.\n */\n HowlerGlobal.prototype.orientation = function(x, y, z, xUp, yUp, zUp) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self.ctx || !self.ctx.listener) {\n return self;\n }\n\n // Set the defaults for optional 'y' & 'z'.\n var or = self._orientation;\n y = (typeof y !== 'number') ? or[1] : y;\n z = (typeof z !== 'number') ? or[2] : z;\n xUp = (typeof xUp !== 'number') ? or[3] : xUp;\n yUp = (typeof yUp !== 'number') ? or[4] : yUp;\n zUp = (typeof zUp !== 'number') ? or[5] : zUp;\n\n if (typeof x === 'number') {\n self._orientation = [x, y, z, xUp, yUp, zUp];\n\n if (typeof self.ctx.listener.forwardX !== 'undefined') {\n self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1);\n self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1);\n } else {\n self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp);\n }\n } else {\n return or;\n }\n\n return self;\n };\n\n /** Group Methods **/\n /***************************************************************************/\n\n /**\n * Add new properties to the core init.\n * @param {Function} _super Core init method.\n * @return {Howl}\n */\n Howl.prototype.init = (function(_super) {\n return function(o) {\n var self = this;\n\n // Setup user-defined default properties.\n self._orientation = o.orientation || [1, 0, 0];\n self._stereo = o.stereo || null;\n self._pos = o.pos || null;\n self._pannerAttr = {\n coneInnerAngle: typeof o.coneInnerAngle !== 'undefined' ? o.coneInnerAngle : 360,\n coneOuterAngle: typeof o.coneOuterAngle !== 'undefined' ? o.coneOuterAngle : 360,\n coneOuterGain: typeof o.coneOuterGain !== 'undefined' ? o.coneOuterGain : 0,\n distanceModel: typeof o.distanceModel !== 'undefined' ? o.distanceModel : 'inverse',\n maxDistance: typeof o.maxDistance !== 'undefined' ? o.maxDistance : 10000,\n panningModel: typeof o.panningModel !== 'undefined' ? o.panningModel : 'HRTF',\n refDistance: typeof o.refDistance !== 'undefined' ? o.refDistance : 1,\n rolloffFactor: typeof o.rolloffFactor !== 'undefined' ? o.rolloffFactor : 1\n };\n\n // Setup event listeners.\n self._onstereo = o.onstereo ? [{fn: o.onstereo}] : [];\n self._onpos = o.onpos ? [{fn: o.onpos}] : [];\n self._onorientation = o.onorientation ? [{fn: o.onorientation}] : [];\n\n // Complete initilization with howler.js core's init function.\n return _super.call(this, o);\n };\n })(Howl.prototype.init);\n\n /**\n * Get/set the stereo panning of the audio source for this sound or all in the group.\n * @param {Number} pan A value of -1.0 is all the way left and 1.0 is all the way right.\n * @param {Number} id (optional) The sound ID. If none is passed, all in group will be updated.\n * @return {Howl/Number} Returns self or the current stereo panning value.\n */\n Howl.prototype.stereo = function(pan, id) {\n var self = this;\n\n // Stop right here if not using Web Audio.\n if (!self._webAudio) {\n return self;\n }\n\n // If the sound hasn't loaded, add it to the load queue to change stereo pan when capable.\n if (self._state !== 'loaded') {\n self._queue.push({\n event: 'stereo',\n action: function() {\n self.stereo(pan, id);\n }\n });\n\n return self;\n }\n\n // Check for PannerStereoNode support and fallback to PannerNode if it doesn't exist.\n var pannerType = (typeof Howler.ctx.createStereoPanner === 'undefined') ? 'spatial' : 'stereo';\n\n // Setup the group's stereo panning if no ID is passed.\n if (typeof id === 'undefined') {\n // Return the group's stereo panning if no parameters are passed.\n if (typeof pan === 'number') {\n self._stereo = pan;\n self._pos = [pan, 0, 0];\n } else {\n return self._stereo;\n }\n }\n\n // Change the streo panning of one or all sounds in group.\n var ids = self._getSoundIds(id);\n for (var i=0; i Returns the group's values.\n * pannerAttr(id) -> Returns the sound id's values.\n * pannerAttr(o) -> Set's the values of all sounds in this Howl group.\n * pannerAttr(o, id) -> Set's the values of passed sound id.\n *\n * Attributes:\n * coneInnerAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,\n * inside of which there will be no volume reduction.\n * coneOuterAngle - (360 by default) A parameter for directional audio sources, this is an angle, in degrees,\n * outside of which the volume will be reduced to a constant value of `coneOuterGain`.\n * coneOuterGain - (0 by default) A parameter for directional audio sources, this is the gain outside of the\n * `coneOuterAngle`. It is a linear value in the range `[0, 1]`.\n * distanceModel - ('inverse' by default) Determines algorithm used to reduce volume as audio moves away from\n * listener. Can be `linear`, `inverse` or `exponential.\n * maxDistance - (10000 by default) The maximum distance between source and listener, after which the volume\n * will not be reduced any further.\n * refDistance - (1 by default) A reference distance for reducing volume as source moves further from the listener.\n * This is simply a variable of the distance model and has a different effect depending on which model\n * is used and the scale of your coordinates. Generally, volume will be equal to 1 at this distance.\n * rolloffFactor - (1 by default) How quickly the volume reduces as source moves from listener. This is simply a\n * variable of the distance model and can be in the range of `[0, 1]` with `linear` and `[0, \u221E]`\n * with `inverse` and `exponential`.\n * panningModel - ('HRTF' by default) Determines which spatialization algorithm is used to position audio.\n * Can be `HRTF` or `equalpower`.\n *\n * @return {Howl/Object} Returns self or current panner attributes.\n */\n Howl.prototype.pannerAttr = function() {\n var self = this;\n var args = arguments;\n var o, id, sound;\n\n // Stop right here if not using Web Audio.\n if (!self._webAudio) {\n return self;\n }\n\n // Determine the values based on arguments.\n if (args.length === 0) {\n // Return the group's panner attribute values.\n return self._pannerAttr;\n } else if (args.length === 1) {\n if (typeof args[0] === 'object') {\n o = args[0];\n\n // Set the grou's panner attribute values.\n if (typeof id === 'undefined') {\n if (!o.pannerAttr) {\n o.pannerAttr = {\n coneInnerAngle: o.coneInnerAngle,\n coneOuterAngle: o.coneOuterAngle,\n coneOuterGain: o.coneOuterGain,\n distanceModel: o.distanceModel,\n maxDistance: o.maxDistance,\n refDistance: o.refDistance,\n rolloffFactor: o.rolloffFactor,\n panningModel: o.panningModel\n };\n }\n\n self._pannerAttr = {\n coneInnerAngle: typeof o.pannerAttr.coneInnerAngle !== 'undefined' ? o.pannerAttr.coneInnerAngle : self._coneInnerAngle,\n coneOuterAngle: typeof o.pannerAttr.coneOuterAngle !== 'undefined' ? o.pannerAttr.coneOuterAngle : self._coneOuterAngle,\n coneOuterGain: typeof o.pannerAttr.coneOuterGain !== 'undefined' ? o.pannerAttr.coneOuterGain : self._coneOuterGain,\n distanceModel: typeof o.pannerAttr.distanceModel !== 'undefined' ? o.pannerAttr.distanceModel : self._distanceModel,\n maxDistance: typeof o.pannerAttr.maxDistance !== 'undefined' ? o.pannerAttr.maxDistance : self._maxDistance,\n refDistance: typeof o.pannerAttr.refDistance !== 'undefined' ? o.pannerAttr.refDistance : self._refDistance,\n rolloffFactor: typeof o.pannerAttr.rolloffFactor !== 'undefined' ? o.pannerAttr.rolloffFactor : self._rolloffFactor,\n panningModel: typeof o.pannerAttr.panningModel !== 'undefined' ? o.pannerAttr.panningModel : self._panningModel\n };\n }\n } else {\n // Return this sound's panner attribute values.\n sound = self._soundById(parseInt(args[0], 10));\n return sound ? sound._pannerAttr : self._pannerAttr;\n }\n } else if (args.length === 2) {\n o = args[0];\n id = parseInt(args[1], 10);\n }\n\n // Update the values of the specified sounds.\n var ids = self._getSoundIds(id);\n for (var i=0; i 80 * dim) {\n minX = maxX = data[0];\n minY = maxY = data[1];\n\n for (var i = dim; i < outerLen; i += dim) {\n x = data[i];\n y = data[i + 1];\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n }\n\n // minX, minY and invSize are later used to transform coords into integers for z-order calculation\n invSize = Math.max(maxX - minX, maxY - minY);\n invSize = invSize !== 0 ? 32767 / invSize : 0;\n }\n\n earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);\n\n return triangles;\n}\n\n// create a circular doubly linked list from polygon points in the specified winding order\nfunction linkedList(data, start, end, dim, clockwise) {\n var i, last;\n\n if (clockwise === (signedArea(data, start, end, dim) > 0)) {\n for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);\n } else {\n for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);\n }\n\n if (last && equals(last, last.next)) {\n removeNode(last);\n last = last.next;\n }\n\n return last;\n}\n\n// eliminate colinear or duplicate points\nfunction filterPoints(start, end) {\n if (!start) return start;\n if (!end) end = start;\n\n var p = start,\n again;\n do {\n again = false;\n\n if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {\n removeNode(p);\n p = end = p.prev;\n if (p === p.next) break;\n again = true;\n\n } else {\n p = p.next;\n }\n } while (again || p !== end);\n\n return end;\n}\n\n// main ear slicing loop which triangulates a polygon (given as a linked list)\nfunction earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {\n if (!ear) return;\n\n // interlink polygon nodes in z-order\n if (!pass && invSize) indexCurve(ear, minX, minY, invSize);\n\n var stop = ear,\n prev, next;\n\n // iterate through ears, slicing them one by one\n while (ear.prev !== ear.next) {\n prev = ear.prev;\n next = ear.next;\n\n if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {\n // cut off the triangle\n triangles.push(prev.i / dim | 0);\n triangles.push(ear.i / dim | 0);\n triangles.push(next.i / dim | 0);\n\n removeNode(ear);\n\n // skipping the next vertex leads to less sliver triangles\n ear = next.next;\n stop = next.next;\n\n continue;\n }\n\n ear = next;\n\n // if we looped through the whole remaining polygon and can't find any more ears\n if (ear === stop) {\n // try filtering points and slicing again\n if (!pass) {\n earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);\n\n // if this didn't work, try curing all small self-intersections locally\n } else if (pass === 1) {\n ear = cureLocalIntersections(filterPoints(ear), triangles, dim);\n earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);\n\n // as a last resort, try splitting the remaining polygon into two\n } else if (pass === 2) {\n splitEarcut(ear, triangles, dim, minX, minY, invSize);\n }\n\n break;\n }\n }\n}\n\n// check whether a polygon node forms a valid ear with adjacent nodes\nfunction isEar(ear) {\n var a = ear.prev,\n b = ear,\n c = ear.next;\n\n if (area(a, b, c) >= 0) return false; // reflex, can't be an ear\n\n // now make sure we don't have other points inside the potential ear\n var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n // triangle bbox; min & max are calculated like this for speed\n var x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),\n y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),\n x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),\n y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);\n\n var p = c.next;\n while (p !== a) {\n if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&\n pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) &&\n area(p.prev, p, p.next) >= 0) return false;\n p = p.next;\n }\n\n return true;\n}\n\nfunction isEarHashed(ear, minX, minY, invSize) {\n var a = ear.prev,\n b = ear,\n c = ear.next;\n\n if (area(a, b, c) >= 0) return false; // reflex, can't be an ear\n\n var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n // triangle bbox; min & max are calculated like this for speed\n var x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx),\n y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy),\n x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx),\n y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy);\n\n // z-order range for the current triangle bbox;\n var minZ = zOrder(x0, y0, minX, minY, invSize),\n maxZ = zOrder(x1, y1, minX, minY, invSize);\n\n var p = ear.prevZ,\n n = ear.nextZ;\n\n // look for points inside the triangle in both directions\n while (p && p.z >= minZ && n && n.z <= maxZ) {\n if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;\n p = p.prevZ;\n\n if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;\n n = n.nextZ;\n }\n\n // look for remaining points in decreasing z-order\n while (p && p.z >= minZ) {\n if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;\n p = p.prevZ;\n }\n\n // look for remaining points in increasing z-order\n while (n && n.z <= maxZ) {\n if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;\n n = n.nextZ;\n }\n\n return true;\n}\n\n// go through all polygon nodes and cure small local self-intersections\nfunction cureLocalIntersections(start, triangles, dim) {\n var p = start;\n do {\n var a = p.prev,\n b = p.next.next;\n\n if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {\n\n triangles.push(a.i / dim | 0);\n triangles.push(p.i / dim | 0);\n triangles.push(b.i / dim | 0);\n\n // remove two nodes involved\n removeNode(p);\n removeNode(p.next);\n\n p = start = b;\n }\n p = p.next;\n } while (p !== start);\n\n return filterPoints(p);\n}\n\n// try splitting polygon into two and triangulate them independently\nfunction splitEarcut(start, triangles, dim, minX, minY, invSize) {\n // look for a valid diagonal that divides the polygon into two\n var a = start;\n do {\n var b = a.next.next;\n while (b !== a.prev) {\n if (a.i !== b.i && isValidDiagonal(a, b)) {\n // split the polygon in two by the diagonal\n var c = splitPolygon(a, b);\n\n // filter colinear points around the cuts\n a = filterPoints(a, a.next);\n c = filterPoints(c, c.next);\n\n // run earcut on each half\n earcutLinked(a, triangles, dim, minX, minY, invSize, 0);\n earcutLinked(c, triangles, dim, minX, minY, invSize, 0);\n return;\n }\n b = b.next;\n }\n a = a.next;\n } while (a !== start);\n}\n\n// link every hole into the outer loop, producing a single-ring polygon without holes\nfunction eliminateHoles(data, holeIndices, outerNode, dim) {\n var queue = [],\n i, len, start, end, list;\n\n for (i = 0, len = holeIndices.length; i < len; i++) {\n start = holeIndices[i] * dim;\n end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;\n list = linkedList(data, start, end, dim, false);\n if (list === list.next) list.steiner = true;\n queue.push(getLeftmost(list));\n }\n\n queue.sort(compareX);\n\n // process holes from left to right\n for (i = 0; i < queue.length; i++) {\n outerNode = eliminateHole(queue[i], outerNode);\n }\n\n return outerNode;\n}\n\nfunction compareX(a, b) {\n return a.x - b.x;\n}\n\n// find a bridge between vertices that connects hole with an outer ring and and link it\nfunction eliminateHole(hole, outerNode) {\n var bridge = findHoleBridge(hole, outerNode);\n if (!bridge) {\n return outerNode;\n }\n\n var bridgeReverse = splitPolygon(bridge, hole);\n\n // filter collinear points around the cuts\n filterPoints(bridgeReverse, bridgeReverse.next);\n return filterPoints(bridge, bridge.next);\n}\n\n// David Eberly's algorithm for finding a bridge between hole and outer polygon\nfunction findHoleBridge(hole, outerNode) {\n var p = outerNode,\n hx = hole.x,\n hy = hole.y,\n qx = -Infinity,\n m;\n\n // find a segment intersected by a ray from the hole's leftmost point to the left;\n // segment's endpoint with lesser x will be potential connection point\n do {\n if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {\n var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);\n if (x <= hx && x > qx) {\n qx = x;\n m = p.x < p.next.x ? p : p.next;\n if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint\n }\n }\n p = p.next;\n } while (p !== outerNode);\n\n if (!m) return null;\n\n // look for points inside the triangle of hole point, segment intersection and endpoint;\n // if there are no points found, we have a valid connection;\n // otherwise choose the point of the minimum angle with the ray as connection point\n\n var stop = m,\n mx = m.x,\n my = m.y,\n tanMin = Infinity,\n tan;\n\n p = m;\n\n do {\n if (hx >= p.x && p.x >= mx && hx !== p.x &&\n pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {\n\n tan = Math.abs(hy - p.y) / (hx - p.x); // tangential\n\n if (locallyInside(p, hole) &&\n (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) {\n m = p;\n tanMin = tan;\n }\n }\n\n p = p.next;\n } while (p !== stop);\n\n return m;\n}\n\n// whether sector in vertex m contains sector in vertex p in the same coordinates\nfunction sectorContainsSector(m, p) {\n return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;\n}\n\n// interlink polygon nodes in z-order\nfunction indexCurve(start, minX, minY, invSize) {\n var p = start;\n do {\n if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize);\n p.prevZ = p.prev;\n p.nextZ = p.next;\n p = p.next;\n } while (p !== start);\n\n p.prevZ.nextZ = null;\n p.prevZ = null;\n\n sortLinked(p);\n}\n\n// Simon Tatham's linked list merge sort algorithm\n// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html\nfunction sortLinked(list) {\n var i, p, q, e, tail, numMerges, pSize, qSize,\n inSize = 1;\n\n do {\n p = list;\n list = null;\n tail = null;\n numMerges = 0;\n\n while (p) {\n numMerges++;\n q = p;\n pSize = 0;\n for (i = 0; i < inSize; i++) {\n pSize++;\n q = q.nextZ;\n if (!q) break;\n }\n qSize = inSize;\n\n while (pSize > 0 || (qSize > 0 && q)) {\n\n if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {\n e = p;\n p = p.nextZ;\n pSize--;\n } else {\n e = q;\n q = q.nextZ;\n qSize--;\n }\n\n if (tail) tail.nextZ = e;\n else list = e;\n\n e.prevZ = tail;\n tail = e;\n }\n\n p = q;\n }\n\n tail.nextZ = null;\n inSize *= 2;\n\n } while (numMerges > 1);\n\n return list;\n}\n\n// z-order of a point given coords and inverse of the longer side of data bbox\nfunction zOrder(x, y, minX, minY, invSize) {\n // coords are transformed into non-negative 15-bit integer range\n x = (x - minX) * invSize | 0;\n y = (y - minY) * invSize | 0;\n\n x = (x | (x << 8)) & 0x00FF00FF;\n x = (x | (x << 4)) & 0x0F0F0F0F;\n x = (x | (x << 2)) & 0x33333333;\n x = (x | (x << 1)) & 0x55555555;\n\n y = (y | (y << 8)) & 0x00FF00FF;\n y = (y | (y << 4)) & 0x0F0F0F0F;\n y = (y | (y << 2)) & 0x33333333;\n y = (y | (y << 1)) & 0x55555555;\n\n return x | (y << 1);\n}\n\n// find the leftmost node of a polygon ring\nfunction getLeftmost(start) {\n var p = start,\n leftmost = start;\n do {\n if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p;\n p = p.next;\n } while (p !== start);\n\n return leftmost;\n}\n\n// check if a point lies within a convex triangle\nfunction pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {\n return (cx - px) * (ay - py) >= (ax - px) * (cy - py) &&\n (ax - px) * (by - py) >= (bx - px) * (ay - py) &&\n (bx - px) * (cy - py) >= (cx - px) * (by - py);\n}\n\n// check if a diagonal between two polygon nodes is valid (lies in polygon interior)\nfunction isValidDiagonal(a, b) {\n return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges\n (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible\n (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors\n equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case\n}\n\n// signed area of a triangle\nfunction area(p, q, r) {\n return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);\n}\n\n// check if two points are equal\nfunction equals(p1, p2) {\n return p1.x === p2.x && p1.y === p2.y;\n}\n\n// check if two segments intersect\nfunction intersects(p1, q1, p2, q2) {\n var o1 = sign(area(p1, q1, p2));\n var o2 = sign(area(p1, q1, q2));\n var o3 = sign(area(p2, q2, p1));\n var o4 = sign(area(p2, q2, q1));\n\n if (o1 !== o2 && o3 !== o4) return true; // general case\n\n if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1\n if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1\n if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2\n if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2\n\n return false;\n}\n\n// for collinear points p, q, r, check if point q lies on segment pr\nfunction onSegment(p, q, r) {\n return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);\n}\n\nfunction sign(num) {\n return num > 0 ? 1 : num < 0 ? -1 : 0;\n}\n\n// check if a polygon diagonal intersects any polygon segments\nfunction intersectsPolygon(a, b) {\n var p = a;\n do {\n if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&\n intersects(p, p.next, a, b)) return true;\n p = p.next;\n } while (p !== a);\n\n return false;\n}\n\n// check if a polygon diagonal is locally inside the polygon\nfunction locallyInside(a, b) {\n return area(a.prev, a, a.next) < 0 ?\n area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 :\n area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;\n}\n\n// check if the middle point of a polygon diagonal is inside the polygon\nfunction middleInside(a, b) {\n var p = a,\n inside = false,\n px = (a.x + b.x) / 2,\n py = (a.y + b.y) / 2;\n do {\n if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&\n (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))\n inside = !inside;\n p = p.next;\n } while (p !== a);\n\n return inside;\n}\n\n// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;\n// if one belongs to the outer ring and another to a hole, it merges it into a single ring\nfunction splitPolygon(a, b) {\n var a2 = new Node(a.i, a.x, a.y),\n b2 = new Node(b.i, b.x, b.y),\n an = a.next,\n bp = b.prev;\n\n a.next = b;\n b.prev = a;\n\n a2.next = an;\n an.prev = a2;\n\n b2.next = a2;\n a2.prev = b2;\n\n bp.next = b2;\n b2.prev = bp;\n\n return b2;\n}\n\n// create a node and optionally link it with previous one (in a circular doubly linked list)\nfunction insertNode(i, x, y, last) {\n var p = new Node(i, x, y);\n\n if (!last) {\n p.prev = p;\n p.next = p;\n\n } else {\n p.next = last.next;\n p.prev = last;\n last.next.prev = p;\n last.next = p;\n }\n return p;\n}\n\nfunction removeNode(p) {\n p.next.prev = p.prev;\n p.prev.next = p.next;\n\n if (p.prevZ) p.prevZ.nextZ = p.nextZ;\n if (p.nextZ) p.nextZ.prevZ = p.prevZ;\n}\n\nfunction Node(i, x, y) {\n // vertex index in coordinates array\n this.i = i;\n\n // vertex coordinates\n this.x = x;\n this.y = y;\n\n // previous and next vertex nodes in a polygon ring\n this.prev = null;\n this.next = null;\n\n // z-order curve value\n this.z = 0;\n\n // previous and next nodes in z-order\n this.prevZ = null;\n this.nextZ = null;\n\n // indicates whether this is a steiner point\n this.steiner = false;\n}\n\n// return a percentage difference between the polygon area and its triangulation area;\n// used to verify correctness of triangulation\nearcut.deviation = function (data, holeIndices, dim, triangles) {\n var hasHoles = holeIndices && holeIndices.length;\n var outerLen = hasHoles ? holeIndices[0] * dim : data.length;\n\n var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));\n if (hasHoles) {\n for (var i = 0, len = holeIndices.length; i < len; i++) {\n var start = holeIndices[i] * dim;\n var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;\n polygonArea -= Math.abs(signedArea(data, start, end, dim));\n }\n }\n\n var trianglesArea = 0;\n for (i = 0; i < triangles.length; i += 3) {\n var a = triangles[i] * dim;\n var b = triangles[i + 1] * dim;\n var c = triangles[i + 2] * dim;\n trianglesArea += Math.abs(\n (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -\n (data[a] - data[b]) * (data[c + 1] - data[a + 1]));\n }\n\n return polygonArea === 0 && trianglesArea === 0 ? 0 :\n Math.abs((trianglesArea - polygonArea) / polygonArea);\n};\n\nfunction signedArea(data, start, end, dim) {\n var sum = 0;\n for (var i = start, j = end - dim; i < end; i += dim) {\n sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);\n j = i;\n }\n return sum;\n}\n\n// turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts\nearcut.flatten = function (data) {\n var dim = data[0][0].length,\n result = {vertices: [], holes: [], dimensions: dim},\n holeIndex = 0;\n\n for (var i = 0; i < data.length; i++) {\n for (var j = 0; j < data[i].length; j++) {\n for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]);\n }\n if (i > 0) {\n holeIndex += data[i - 1].length;\n result.holes.push(holeIndex);\n }\n }\n return result;\n};\n", "import { simd, threads } from 'wasm-feature-detect';\nimport { WonderlandEngine } from './engine.js';\nimport { WASM } from './wasm.js';\nimport { APIVersion } from './version.js';\nexport * from './utils/event.js';\nexport * from './wonderland.js';\nexport * from './engine.js';\nexport * from './scene.js';\nexport * from './property.js';\nexport * from './texture-manager.js';\nexport * from './version.js';\nexport * from './wasm.js';\nfunction loadScript(scriptURL) {\n return new Promise((res, rej) => {\n const s = document.createElement('script');\n const node = document.body.appendChild(s);\n s.onload = () => {\n document.body.removeChild(node);\n res();\n };\n s.onerror = (e) => {\n document.body.removeChild(node);\n rej(e);\n };\n s.src = scriptURL;\n });\n}\n/**\n * Finds whether simd & threading are supported or not.\n *\n * @returns An object containing boolean for simd and thread.\n */\nasync function detectFeatures() {\n let [simdSupported, threadsSupported] = await Promise.all([simd(), threads()]);\n if (simdSupported) {\n console.log('WASM SIMD is supported');\n }\n else {\n console.warn('WASM SIMD is not supported');\n }\n if (threadsSupported) {\n if (self.crossOriginIsolated) {\n console.log('WASM Threads is supported');\n }\n else {\n console.warn('WASM Threads is supported, but the page is not crossOriginIsolated, therefore thread support is disabled.');\n }\n }\n else {\n console.warn('WASM Threads is not supported');\n }\n threadsSupported = threadsSupported && self.crossOriginIsolated;\n return {\n simdSupported,\n threadsSupported,\n };\n}\n/* Global boolean to check if AR/VR is supported. */\nconst xrSupported = {\n ar: null,\n vr: null,\n};\n/**\n * Check whether XR is supported and store the result in the global space.\n */\nfunction checkXRSupport() {\n if (typeof navigator === 'undefined' || !navigator.xr) {\n xrSupported.vr = false;\n xrSupported.ar = false;\n return Promise.resolve(xrSupported);\n }\n const vrPromise = xrSupported.vr !== null\n ? Promise.resolve()\n : navigator.xr\n .isSessionSupported('immersive-vr')\n .then((supported) => (xrSupported.vr = supported));\n const arPromise = xrSupported.ar !== null\n ? Promise.resolve()\n : navigator.xr\n .isSessionSupported('immersive-ar')\n .then((supported) => (xrSupported.ar = supported));\n return Promise.all([vrPromise, arPromise]).then(() => xrSupported);\n}\n/**\n * Ensures that this API is compatible with the given\n * runtime version.\n *\n * We only enforce compatibility for major and minor components, i.e.,\n * the runtime and the API must both be of the form `x.y.*`.\n *\n * @throws If the major or the minor components are different.\n *\n * @param version The target version\n */\nexport function checkRuntimeCompatibility(version) {\n const { major, minor } = version;\n let majorDiff = major - APIVersion.major;\n let minorDiff = minor - APIVersion.minor;\n /* Same version, so perfectly compatible. */\n if (!majorDiff && !minorDiff)\n return;\n const error = 'checkRuntimeCompatibility(): Version compatibility mismatch:\\n' +\n '\\t\u2192 API and runtime compatibility is enforced on a patch level (versions x.y.*)\\n';\n const isRuntimeOlder = majorDiff < 0 || (!majorDiff && minorDiff < 0);\n if (isRuntimeOlder) {\n /* Runtime is out of date. */\n throw new Error(`${error}\\t\u2192 Please use a Wonderland Engine editor version >= ${APIVersion.major}.${APIVersion.minor}.*`);\n }\n /* API is out of date. */\n throw new Error(`${error}\\t\u2192 Please use a new API version >= ${version.major}.${version.minor}.*`);\n}\n/**\n * Load the runtime using the WASM and JS files.\n *\n * @param runtime The runtime base string, e.g,: `WonderlandRuntime-loader-physx`.\n * @param options Options to modify the loading behaviour.\n *\n * @returns A promise that resolves when the engine is ready to be used.\n */\nexport async function loadRuntime(runtime, options = {}) {\n const xrPromise = checkXRSupport();\n const { simdSupported, threadsSupported } = await detectFeatures();\n const { simd = simdSupported, threads = threadsSupported, physx = false, loader = false, xrFramebufferScaleFactor = 1.0, loadingScreen = 'WonderlandRuntime-LoadingScreen.bin', canvas = 'canvas', } = options;\n const variant = [];\n if (loader)\n variant.push('loader');\n if (physx)\n variant.push('physx');\n if (simd)\n variant.push('simd');\n if (threads)\n variant.push('threads');\n const variantStr = variant.join('-');\n let filename = runtime;\n if (variantStr)\n filename = `${filename}-${variantStr}`;\n const download = function (filename, errorMessage) {\n return fetch(filename)\n .then((r) => {\n if (!r.ok)\n return Promise.reject(errorMessage);\n return r.arrayBuffer();\n })\n .catch((_) => Promise.reject(errorMessage));\n };\n const [wasmData, loadingScreenData] = await Promise.all([\n download(`${filename}.wasm`, 'Failed to fetch runtime .wasm file'),\n download(loadingScreen, 'Failed to fetch loading screen file').catch((_) => null),\n ]);\n const glCanvas = document.getElementById(canvas);\n if (!glCanvas) {\n throw new Error(`loadRuntime(): Failed to find canvas with id '${canvas}'`);\n }\n if (!(glCanvas instanceof HTMLCanvasElement)) {\n throw new Error(`loadRuntime(): HTML element '${canvas}' must be a canvas`);\n }\n const wasm = new WASM(threads);\n wasm.worker = `${filename}.worker.js`;\n wasm.wasm = wasmData;\n wasm.canvas = glCanvas;\n const engine = new WonderlandEngine(wasm, loadingScreenData);\n if (!window._WL) {\n window._WL = { runtimes: {} };\n }\n const runtimes = window._WL.runtimes;\n /* Global identifier of this runtime in `window`. */\n const runtimeGlobalId = variantStr ? variantStr : 'default';\n /* Only load the runtime if not previously loaded in the page */\n if (!runtimes[runtimeGlobalId]) {\n await loadScript(`${filename}.js`);\n runtimes[runtimeGlobalId] = window.instantiateWonderlandRuntime;\n window.instantiateWonderlandRuntime = undefined;\n }\n await runtimes[runtimeGlobalId](wasm);\n /* Throws if the runtime isn't compatible with the API. */\n checkRuntimeCompatibility(engine.runtimeVersion);\n engine._init();\n const xr = await xrPromise;\n engine.arSupported = xr.ar;\n engine.vrSupported = xr.vr;\n engine.xrFramebufferScaleFactor = xrFramebufferScaleFactor;\n engine.autoResizeCanvas = true;\n engine.start();\n return engine;\n}\n", "export const bigInt=()=>(async e=>{try{return(await WebAssembly.instantiate(e)).instance.exports.b(BigInt(0))===BigInt(0)}catch(e){return!1}})(new Uint8Array([0,97,115,109,1,0,0,0,1,6,1,96,1,126,1,126,3,2,1,0,7,5,1,1,98,0,0,10,6,1,4,0,32,0,11])),bulkMemory=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,5,3,1,0,1,10,14,1,12,0,65,0,65,0,65,0,252,10,0,0,11])),exceptions=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,8,1,6,0,6,64,25,11,11])),extendedConst=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,5,3,1,0,1,11,9,1,0,65,1,65,2,106,11,0])),gc=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,10,2,95,1,125,0,96,0,1,107,0,3,2,1,1,10,12,1,10,0,67,0,0,0,0,251,7,0,11])),memory64=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,5,3,1,4,1])),multiValue=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,6,1,96,0,2,127,127,3,2,1,0,10,8,1,6,0,65,0,65,0,11])),mutableGlobals=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,2,8,1,1,97,1,98,3,127,1,6,6,1,127,1,65,0,11,7,5,1,1,97,3,1])),referenceTypes=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,7,1,5,0,208,112,26,11])),relaxedSimd=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,15,1,13,0,65,1,253,15,65,2,253,15,253,128,2,11])),saturatedFloatToInt=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,12,1,10,0,67,0,0,0,0,252,0,26,11])),signExtensions=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,8,1,6,0,65,0,192,26,11])),simd=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,5,1,96,0,1,123,3,2,1,0,10,10,1,8,0,65,0,253,15,253,98,11])),streamingCompilation=()=>(async()=>\"compileStreaming\"in WebAssembly)(),tailCall=async()=>WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,10,6,1,4,0,18,0,11])),threads=()=>(async e=>{try{return\"undefined\"!=typeof MessageChannel&&(new MessageChannel).port1.postMessage(new SharedArrayBuffer(1)),WebAssembly.validate(e)}catch(e){return!1}})(new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,2,1,0,5,4,1,3,1,1,10,11,1,9,0,65,0,254,16,2,0,26,11]));\n", "/**\n * Component property type.\n */\nexport var Type;\n(function (Type) {\n /**\n * **Native**\n *\n * Property of a native component. Must not be used in custom components.\n *\n * @hidden\n */\n Type[Type[\"Native\"] = 1] = \"Native\";\n /**\n * **Bool**:\n *\n * Appears in the editor as a checkbox.\n *\n * Initial value is `false`, unless overridden by the `default` property.\n */\n Type[Type[\"Bool\"] = 2] = \"Bool\";\n /**\n * **Int**:\n *\n * Appears in the editor as an integer input field.\n *\n * Initial value is `0`, unless overridden by the `default` property.\n */\n Type[Type[\"Int\"] = 4] = \"Int\";\n /**\n * **Float**:\n *\n * Appears in the editor as a floating point input field.\n *\n * Initial value is `0.0`, unless overridden by the `default` property.\n */\n Type[Type[\"Float\"] = 8] = \"Float\";\n /**\n * **String / Text**:\n *\n * Appears in the editor as a single-line text input field.\n *\n * Initial value is an empty string, unless overridden by the `default`\n * property.\n */\n Type[Type[\"String\"] = 16] = \"String\";\n /**\n * **Enumeration**:\n *\n * Appears in the editor as a dropdown with given values. The additional\n * `values` parameter with selection options is mandatory.\n *\n * The property value is resolved to an **index** into the `values` array.\n *\n * Initial value is the first element in `values`, unless overridden by\n * the `default` property. The `default` value can be a string or an index\n * into `values`.\n *\n * @example\n *\n * ```js\n * camera: {type: Type.Enum, values: ['auto', 'back', 'front'], default: 'auto'},\n * ```\n */\n Type[Type[\"Enum\"] = 32] = \"Enum\";\n /**\n * **Object reference**:\n *\n * Appears in the editor as an object resource selection dropdown\n * with object picker.\n *\n * Initial value is `null`.\n */\n Type[Type[\"Object\"] = 64] = \"Object\";\n /**\n * **Mesh reference**:\n *\n * Appears in the editor as a mesh resource selection dropdown.\n *\n * Initial value is `null`.\n */\n Type[Type[\"Mesh\"] = 128] = \"Mesh\";\n /**\n * **Texture reference**:\n *\n * Appears in the editor as a texture resource selection dropdown.\n *\n * Initial value is `null`.\n */\n Type[Type[\"Texture\"] = 256] = \"Texture\";\n /**\n * **Material reference**:\n *\n * Appears in the editor as a material resource selection dropdown.\n *\n * Initial value is `null`.\n */\n Type[Type[\"Material\"] = 512] = \"Material\";\n /**\n * **Animation reference**:\n *\n * Appears in the editor as an animation resource selection dropdown.\n *\n * Initial value is `null`.\n */\n Type[Type[\"Animation\"] = 1024] = \"Animation\";\n /**\n * **Skin reference**:\n *\n * Appears in the editor as a skin resource selection dropdown.\n *\n * Initial value is `null`.\n */\n Type[Type[\"Skin\"] = 2048] = \"Skin\";\n /**\n * **Color**:\n *\n * Appears in the editor as a color widget.\n *\n * Initial value is `[0.0, 0.0, 0.0, 1.0]`, unless overridden by the\n * `default` property.\n */\n Type[Type[\"Color\"] = 4096] = \"Color\";\n})(Type || (Type = {}));\n/**\n * Component property namespace.\n *\n * Usage:\n *\n * ```js\n * import {Component, Property} from '@wonderlandengine/api';\n *\n * class MyComponent extends Component {\n * static Properties = {\n * myBool: Property.bool(true),\n * myInt: Property.int(42),\n * myString: Property.string('Hello World!'),\n * myMesh: Property.mesh(),\n * }\n * }\n * ```\n *\n * For TypeScript users, you can use the decorators instead.\n */\nexport const Property = {\n /**\n * Create an boolean property.\n *\n * @param defaultValue The default value. If not provided, defaults to `false`.\n */\n bool(defaultValue = false) {\n return { type: Type.Bool, default: defaultValue };\n },\n /**\n * Create an integer property.\n *\n * @param defaultValue The default value. If not provided, defaults to `0`.\n */\n int(defaultValue = 0) {\n return { type: Type.Int, default: defaultValue };\n },\n /**\n * Create an float property.\n *\n * @param defaultValue The default value. If not provided, defaults to `0.0`.\n */\n float(defaultValue = 0.0) {\n return { type: Type.Float, default: defaultValue };\n },\n /**\n * Create an string property.\n *\n * @param defaultValue The default value. If not provided, defaults to `''`.\n */\n string(defaultValue = '') {\n return { type: Type.String, default: defaultValue };\n },\n /**\n * Create an enumeration property.\n *\n * @param values The list of values.\n * @param defaultValue The default value. Can be a string or an index into\n * `values`. If not provided, defaults to the first element.\n */\n enum(values, defaultValue) {\n return { type: Type.Enum, values, default: defaultValue };\n },\n /** Create an {@link Object3D} reference property. */\n object() {\n return { type: Type.Object, default: null };\n },\n /** Create a {@link Mesh} reference property. */\n mesh() {\n return { type: Type.Mesh, default: null };\n },\n /** Create a {@link Texture} reference property. */\n texture() {\n return { type: Type.Texture, default: null };\n },\n /** Create a {@link Material} reference property. */\n material() {\n return { type: Type.Material, default: null };\n },\n /** Create an {@link Animation} reference property. */\n animation() {\n return { type: Type.Animation, default: null };\n },\n /** Create a {@link Skin} reference property. */\n skin() {\n return { type: Type.Skin, default: null };\n },\n /**\n * Create a color property.\n *\n * @param r The red component, in the range [0; 1].\n * @param g The green component, in the range [0; 1].\n * @param b The blue component, in the range [0; 1].\n * @param a The alpha component, in the range [0; 1].\n */\n color(r = 0.0, g = 0.0, b = 0.0, a = 1.0) {\n return { type: Type.Color, default: [r, g, b, a] };\n },\n};\n", "import { Property, Type } from './property.js';\n/**\n * Decorator for JS component properties.\n *\n * @param data The property description as an object literal\n * @returns A decorator function modifying the `Properties` static\n * attribute\n */\nfunction propertyDecorator(data) {\n return function (target, propertyKey) {\n const ctor = target.constructor;\n ctor.Properties = ctor.Properties ?? {};\n ctor.Properties[propertyKey] = data;\n };\n}\n/**\n * Decorator for making a getter enumerable.\n *\n * Usage:\n *\n * ```ts\n * class MyClass {\n * @enumerable()\n * get projectionMatrix(): Float32Array { ... }\n * }\n * ```\n */\nexport function enumerable() {\n return function (_, __, descriptor) {\n descriptor.enumerable = true;\n };\n}\n/**\n * Decorator for native properties.\n *\n * Usage:\n *\n * ```ts\n * class MyClass {\n * @nativeProperty()\n * get projectionMatrix(): Float32Array { ... }\n * }\n * ```\n */\nexport function nativeProperty() {\n return function (target, propertyKey, descriptor) {\n enumerable()(target, propertyKey, descriptor);\n propertyDecorator({ type: Type.Native })(target, propertyKey);\n };\n}\n/**\n * Property decorators namespace.\n *\n * You can use the decorators to mark a class attribute as\n * a Wonderland Engine property.\n *\n * Usage:\n *\n * ```ts\n * import {Mesh} from '@wonderlandengine/api';\n * import {property} from '@wonderlandengine/api/decorators.js';\n *\n * class MyComponent extends Component {\n * @property.bool(true)\n * myBool!: boolean;\n *\n * @property.int(42)\n * myInt!: number;\n *\n * @property.string('Hello World!')\n * myString!: string;\n *\n * @property.mesh()\n * myMesh!: Mesh;\n * }\n * ```\n *\n * For JavaScript users, please declare the properties statically.\n */\nexport const property = {};\nfor (const name in Property) {\n /* Assign each property functor to a TypeScript decorator.\n * This code extracts parameters and return type to provide proper\n * typings to the user. */\n property[name] = (...args) => {\n const functor = Property[name];\n return propertyDecorator(functor(...args));\n };\n}\n", "/**\n * Check if a given value is a native string or a `String` instance.\n *\n * @param value The value to check.\n * @returns `true` if the `value` has type string literal or `String`, `false` otherwise.\n */\nexport function isString(value) {\n if (value === '')\n return true;\n return value && (typeof value === 'string' || value.constructor === String);\n}\n/**\n * Check if a given value is a native number or a `Number` instance.\n *\n * @param value The value to check.\n * @returns `true` if the `value` has type number literal or `Number`, `false` otherwise.\n */\nexport function isNumber(value) {\n if (value === null || value === undefined)\n return false;\n return typeof value === 'number' || value.constructor === Number;\n}\n", "/**\n * Event emitter.\n *\n * This class allows to register listeners that will get notified by the emitter.\n *\n * Usage example\n *\n * ```js\n * // `onPreRender` is an `Emitter` instance.\n * scene.onPreRender.add(() => console.log('before rendering'));\n * // `onPostRender` is an `Emitter` instance.\n * scene.onPostRender.add(() => console.log('after rendering'));\n * ```\n *\n * You can create your own emitters:\n *\n * ```js\n * import {Emitter} from '@wonderlandengine/api';\n *\n * const emitter = new Emitter();\n * ```\n *\n * You can notify listeners in to your emitter using {@link Emitter.notify}:\n *\n * ```js\n * // Notifies all the listeners.\n * emitter.notify();\n * // Notifies all the listeners with some data.\n * emitter.notify({ myInt: 42, myStr: 'Hello World!' });\n * ```\n *\n * @category event\n */\nexport class Emitter {\n /**\n * List of listeners to trigger when `notify` is called.\n *\n * @hidden\n */\n _listeners = [];\n /**\n * Register a new listener to be triggered on {@link Emitter.notify}.\n *\n * Basic usage:\n *\n * ```js\n * emitter.add((data) => {\n * console.log('event received!');\n * console.log(data);\n * });\n * ```\n *\n * Automatically remove the listener when an event is received:\n *\n * ```js\n * emitter.add((data) => {\n * console.log('event received!');\n * console.log(data);\n * }, {once: true});\n * ```\n *\n * @param listener The callback to register.\n * @param opts The listener options. For more information, please have a look\n * at the {@link ListenerOptions} interface.\n *\n * @returns Reference to self (for method chaining)\n */\n add(listener, opts = {}) {\n const { once = false, id = undefined } = opts;\n this._listeners.push({ id, once, callback: listener });\n return this;\n }\n /**\n * Equivalent to {@link Emitter.add}.\n *\n * @param listeners The callback(s) to register.\n * @returns Reference to self (for method chaining).\n *\n * @deprecated Please use {@link Emitter.add} instead.\n */\n push(...listeners) {\n for (const cb of listeners)\n this.add(cb);\n return this;\n }\n /**\n * Register a new listener to be triggered on {@link Emitter.notify}.\n *\n * Once notified, the listener will be automatically removed.\n *\n * The method is equivalent to calling {@link Emitter.add} with:\n *\n * ```js\n * emitter.add(listener, {once: true});\n * ```\n *\n * @param listener The callback to register.\n *\n * @returns Reference to self (for method chaining).\n */\n once(listener) {\n return this.add(listener, { once: true });\n }\n /**\n * Remove a registered listener.\n *\n * Usage with a callback:\n *\n * ```js\n * const listener = (data) => console.log(data);\n * emitter.add(listener);\n *\n * // Remove using the callback reference:\n * emitter.remove(listener);\n * ```\n *\n * Usage with an id:\n *\n * ```js\n * emitter.add((data) => console.log(data), {id: 'my-callback'});\n *\n * // Remove using the id:\n * emitter.remove('my-callback');\n * ```\n *\n * Using identifiers, you will need to ensure your value is unique to avoid\n * removing listeners from other libraries, e.g.,:\n *\n * ```js\n * emitter.add((data) => console.log(data), {id: 'non-unique'});\n * // This second listener could be added by a third-party library.\n * emitter.add((data) => console.log('Hello From Library!'), {id: 'non-unique'});\n *\n * // Ho Snap! This also removed the library listener!\n * emitter.remove('non-unique');\n * ```\n *\n * The identifier can be any type. However, remember that the comparison will be\n * by-value for primitive types (string, number), but by reference for objects.\n *\n * Example:\n *\n * ```js\n * emitter.add(() => console.log('Hello'), {id: {value: 42}});\n * emitter.add(() => console.log('World!'), {id: {value: 42}});\n * emitter.remove({value: 42}); // None of the above listeners match!\n * emitter.notify(); // Prints 'Hello' and 'World!'.\n * ```\n *\n * Here, both emitters have id `{value: 42}`, but the comparison is made by reference. Thus,\n * the `remove()` call has no effect. We can make it work by doing:\n *\n * ```js\n * const id = {value: 42};\n * emitter.add(() => console.log('Hello'), {id});\n * emitter.add(() => console.log('World!'), {id});\n * emitter.remove(id); // Same reference, it works!\n * emitter.notify(); // Doesn't print.\n * ```\n *\n * @param listener The registered callback or a value representing the `id`.\n *\n * @returns Reference to self (for method chaining)\n */\n remove(listener) {\n const listeners = this._listeners;\n for (let i = 0; i < listeners.length; ++i) {\n const target = listeners[i];\n if (target.callback === listener || target.id === listener) {\n listeners.splice(i--, 1);\n }\n }\n return this;\n }\n /**\n * Check whether the listener is registered.\n *\n * @note This method performs a linear search.\n *\n * @param listener The registered callback or a value representing the `id`.\n * @returns `true` if the handle is found, `false` otherwise.\n */\n has(listener) {\n const listeners = this._listeners;\n for (let i = 0; i < listeners.length; ++i) {\n const target = listeners[i];\n if (target.callback === listener || target.id === listener)\n return true;\n }\n return false;\n }\n /**\n * Notify listeners with the given data object.\n *\n * @note This method ensures all listeners are called even if\n * an exception is thrown. For (possibly) faster notification,\n * please use {@link Emitter.notifyUnsafe}.\n *\n * @param data The data to pass to listener when invoked.\n */\n notify(...data) {\n const listeners = this._listeners;\n for (let i = 0; i < listeners.length; ++i) {\n const listener = listeners[i];\n if (listener.once)\n listeners.splice(i--, 1);\n try {\n listener.callback(...data);\n }\n catch (e) {\n console.error(e);\n }\n }\n }\n /**\n * Notify listeners with the given data object.\n *\n * @note Because this method doesn't catch exceptions, some listeners\n * will be skipped on a throw. Please use {@link Emitter.notify} for safe\n * notification.\n *\n * @param data The data to pass to listener when invoked.\n */\n notifyUnsafe(...data) {\n const listeners = this._listeners;\n for (let i = 0; i < listeners.length; ++i) {\n const listener = listeners[i];\n if (listener.once)\n listeners.splice(i--, 1);\n listener.callback(...data);\n }\n }\n /**\n * Return a promise that will resolve on the next event.\n *\n * @note The promise might never resolve if no event is sent.\n *\n * @returns A promise that resolves with the data passed to\n * {@link Emitter.notify}.\n */\n promise() {\n return new Promise((res, _) => {\n this.once((...args) => {\n if (args.length > 1) {\n res(args);\n }\n else {\n res(args[0]);\n }\n });\n });\n }\n /** Number of listeners. */\n get listenerCount() {\n return this._listeners.length;\n }\n /** `true` if it has no listeners, `false` otherwise. */\n get isEmpty() {\n return this.listenerCount === 0;\n }\n}\n/* Dummy value used with RetainEmitter. */\nconst RetainEmitterUndefined = {};\n/**\n * Event emitter that retains event data when notified.\n *\n * After a notification happens, subsequent calls to {@link RetainEmitter.add} will get\n * automatically notified.\n *\n * You can use another emitter in order to cancel the last retained event:\n *\n * ```js\n * import {Emitter, RetainedEmitter} from '@wonderlandengine/api';\n *\n * const onStart = new RetainedEmitter();\n *\n * onStart.notify(42);\n * onStart.add((data) => console.log(data)) // Prints '42'.\n * ```\n *\n * You can reset the state of the emitter, i.e., making it forget about the\n * last event using:\n *\n * ```js\n * import {Emitter, RetainedEmitter} from '@wonderlandengine/api';\n *\n * const onStart = new RetainedEmitter();\n * onStart.notify(42);\n * onStart.add((data) => console.log(data)) // Prints '42'.\n *\n * // Reset the state of the emitter.\n * onStart.reset();\n * onStart.add((data) => console.log(data)) // Doesn't print anything.\n * ```\n *\n * For more information about emitters, please have a look at the base {@link Emitter} class.\n *\n * @category event\n */\nexport class RetainEmitter extends Emitter {\n /** Pre-resolved data. @hidden */\n _event = RetainEmitterUndefined;\n /**\n * Emitter target used to reset the state of this emitter.\n *\n * @hidden\n */\n _reset;\n /** @override */\n add(listener, opts) {\n const immediate = opts?.immediate ?? true;\n if (this._event !== RetainEmitterUndefined && immediate) {\n listener(...this._event);\n }\n super.add(listener, opts);\n return this;\n }\n /**\n * @override\n *\n * @param listener The callback to register.\n * @param immediate If `true`, directly resolves if the emitter retains a value.\n *\n * @returns Reference to self (for method chaining).\n */\n once(listener, immediate) {\n return this.add(listener, { once: true, immediate });\n }\n /** @override */\n notify(...data) {\n this._event = data;\n super.notify(...data);\n }\n /** @override */\n notifyUnsafe(...data) {\n this._event = data;\n super.notifyUnsafe(...data);\n }\n /**\n * Reset the state of the emitter.\n *\n * Further call to {@link Emitter.add} will not automatically resolve,\n * until a new call to {@link Emitter.notify} is performed.\n *\n * @returns Reference to self (for method chaining)\n */\n reset() {\n this._event = RetainEmitterUndefined;\n return this;\n }\n /** Returns the retained data, or `undefined` if no data was retained. */\n get data() {\n return this.isDataRetained ? this._event : undefined;\n }\n /** `true` if data is retained from the last event, `false` otherwise. */\n get isDataRetained() {\n return this._event !== RetainEmitterUndefined;\n }\n}\n", "/**\n * Types\n */\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nimport { nativeProperty, enumerable } from './decorators.js';\nimport { isNumber, isString } from './utils/object.js';\nimport { Emitter } from './utils/event.js';\n/**\n * Wonderland Engine API\n * @namespace WL\n */\n/**\n * Collider type enum for {@link CollisionComponent}.\n */\nexport var Collider;\n(function (Collider) {\n /**\n * **Sphere Collider**:\n *\n * Simplest and most performant collision shape. If this type is set on a\n * {@link CollisionComponent}, only the first component of\n * {@link CollisionComponent#extents} will be used to determine the radius.\n */\n Collider[Collider[\"Sphere\"] = 0] = \"Sphere\";\n /**\n * **Axis Aligned Bounding Box Collider**:\n *\n * Box that is always aligned to XYZ axis. It cannot be rotated but is more\n * efficient than {@link Collider.Box}.\n */\n Collider[Collider[\"AxisAlignedBox\"] = 1] = \"AxisAlignedBox\";\n /**\n * **Aligned Bounding Box Collider**:\n *\n * Box that matches the object's rotation and translation correctly. This\n * is the least efficient collider and should only be chosen over\n * {@link Collider.Sphere} and {@link Collider.AxisAlignedBox} if really\n * necessary.\n */\n Collider[Collider[\"Box\"] = 2] = \"Box\";\n})(Collider || (Collider = {}));\n/**\n * Alignment type enum for {@link TextComponent}.\n */\nexport var Alignment;\n(function (Alignment) {\n /** Text start is at object origin */\n Alignment[Alignment[\"Left\"] = 0] = \"Left\";\n /** Text center is at object origin */\n Alignment[Alignment[\"Center\"] = 1] = \"Center\";\n /** Text end is at object origin */\n Alignment[Alignment[\"Right\"] = 2] = \"Right\";\n})(Alignment || (Alignment = {}));\n/**\n * Justification type enum for {@link TextComponent}.\n */\nexport var Justification;\n(function (Justification) {\n /** Text line is at object origin */\n Justification[Justification[\"Line\"] = 0] = \"Line\";\n /** Text middle is at object origin */\n Justification[Justification[\"Middle\"] = 1] = \"Middle\";\n /** Text top is at object origin */\n Justification[Justification[\"Top\"] = 2] = \"Top\";\n /** Text bottom is at object origin */\n Justification[Justification[\"Bottom\"] = 3] = \"Bottom\";\n})(Justification || (Justification = {}));\n/**\n * Effect type enum for {@link TextComponent}.\n */\nexport var TextEffect;\n(function (TextEffect) {\n /** Text is rendered normally */\n TextEffect[TextEffect[\"None\"] = 0] = \"None\";\n /** Text is rendered with an outline */\n TextEffect[TextEffect[\"Outline\"] = 1] = \"Outline\";\n})(TextEffect || (TextEffect = {}));\n/**\n * Input type enum for {@link InputComponent}.\n */\nexport var InputType;\n(function (InputType) {\n /** Head input */\n InputType[InputType[\"Head\"] = 0] = \"Head\";\n /** Left eye input */\n InputType[InputType[\"EyeLeft\"] = 1] = \"EyeLeft\";\n /** Right eye input */\n InputType[InputType[\"EyeRight\"] = 2] = \"EyeRight\";\n /** Left controller input */\n InputType[InputType[\"ControllerLeft\"] = 3] = \"ControllerLeft\";\n /** Right controller input */\n InputType[InputType[\"ControllerRight\"] = 4] = \"ControllerRight\";\n /** Left ray input */\n InputType[InputType[\"RayLeft\"] = 5] = \"RayLeft\";\n /** Right ray input */\n InputType[InputType[\"RayRight\"] = 6] = \"RayRight\";\n})(InputType || (InputType = {}));\n/**\n * Light type enum for {@link LightComponent}.\n */\nexport var LightType;\n(function (LightType) {\n /** Point light */\n LightType[LightType[\"Point\"] = 0] = \"Point\";\n /** Spot light */\n LightType[LightType[\"Spot\"] = 1] = \"Spot\";\n /** Sun light / Directional light */\n LightType[LightType[\"Sun\"] = 2] = \"Sun\";\n})(LightType || (LightType = {}));\n/**\n * Animation state of {@link AnimationComponent}.\n */\nexport var AnimationState;\n(function (AnimationState) {\n /** Animation is currently playing */\n AnimationState[AnimationState[\"Playing\"] = 0] = \"Playing\";\n /** Animation is paused and will continue at current playback\n * time on {@link AnimationComponent#play} */\n AnimationState[AnimationState[\"Paused\"] = 1] = \"Paused\";\n /** Animation is stopped */\n AnimationState[AnimationState[\"Stopped\"] = 2] = \"Stopped\";\n})(AnimationState || (AnimationState = {}));\n/**\n * Rigid body force mode for {@link PhysXComponent#addForce} and {@link PhysXComponent#addTorque}.\n *\n * [PhysX API Reference](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxapi/files/structPxForceMode.html)\n */\nexport var ForceMode;\n(function (ForceMode) {\n /** Apply as force */\n ForceMode[ForceMode[\"Force\"] = 0] = \"Force\";\n /** Apply as impulse */\n ForceMode[ForceMode[\"Impulse\"] = 1] = \"Impulse\";\n /** Apply as velocity change, mass dependent */\n ForceMode[ForceMode[\"VelocityChange\"] = 2] = \"VelocityChange\";\n /** Apply as mass dependent force */\n ForceMode[ForceMode[\"Acceleration\"] = 3] = \"Acceleration\";\n})(ForceMode || (ForceMode = {}));\n/**\n * Collision callback event type.\n */\nexport var CollisionEventType;\n(function (CollisionEventType) {\n /** Touch/contact detected, collision */\n CollisionEventType[CollisionEventType[\"Touch\"] = 0] = \"Touch\";\n /** Touch/contact lost, uncollide */\n CollisionEventType[CollisionEventType[\"TouchLost\"] = 1] = \"TouchLost\";\n /** Touch/contact with trigger detected */\n CollisionEventType[CollisionEventType[\"TriggerTouch\"] = 2] = \"TriggerTouch\";\n /** Touch/contact with trigger lost */\n CollisionEventType[CollisionEventType[\"TriggerTouchLost\"] = 3] = \"TriggerTouchLost\";\n})(CollisionEventType || (CollisionEventType = {}));\n/**\n * Rigid body {@link PhysXComponent#shape}.\n *\n * [PhysX SDK Guide](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/Geometry.html#geometry-types).\n */\nexport var Shape;\n(function (Shape) {\n /** No shape. */\n Shape[Shape[\"None\"] = 0] = \"None\";\n /** Sphere shape. */\n Shape[Shape[\"Sphere\"] = 1] = \"Sphere\";\n /** Capsule shape. */\n Shape[Shape[\"Capsule\"] = 2] = \"Capsule\";\n /** Box shape. */\n Shape[Shape[\"Box\"] = 3] = \"Box\";\n /** Plane shape. */\n Shape[Shape[\"Plane\"] = 4] = \"Plane\";\n /** Convex mesh shape. */\n Shape[Shape[\"ConvexMesh\"] = 5] = \"ConvexMesh\";\n /** Triangle mesh shape. */\n Shape[Shape[\"TriangleMesh\"] = 6] = \"TriangleMesh\";\n})(Shape || (Shape = {}));\n/**\n * Mesh attribute enum.\n * @since 0.9.0\n */\nexport var MeshAttribute;\n(function (MeshAttribute) {\n /** Position attribute, 3 floats */\n MeshAttribute[MeshAttribute[\"Position\"] = 0] = \"Position\";\n /** Tangent attribute, 4 floats */\n MeshAttribute[MeshAttribute[\"Tangent\"] = 1] = \"Tangent\";\n /** Normal attribute, 3 floats */\n MeshAttribute[MeshAttribute[\"Normal\"] = 2] = \"Normal\";\n /** Texture coordinate attribute, 2 floats */\n MeshAttribute[MeshAttribute[\"TextureCoordinate\"] = 3] = \"TextureCoordinate\";\n /** Color attribute, 4 floats, RGBA, range `0` to `1` */\n MeshAttribute[MeshAttribute[\"Color\"] = 4] = \"Color\";\n /** Joint id attribute, 8 unsigned ints */\n MeshAttribute[MeshAttribute[\"JointId\"] = 5] = \"JointId\";\n /** Joint weights attribute, 8 floats */\n MeshAttribute[MeshAttribute[\"JointWeight\"] = 6] = \"JointWeight\";\n})(MeshAttribute || (MeshAttribute = {}));\n/**\n * Material parameter type.\n */\nexport var MaterialParamType;\n(function (MaterialParamType) {\n /** Unsigned integer parameter type. */\n MaterialParamType[MaterialParamType[\"UnsignedInt\"] = 0] = \"UnsignedInt\";\n /** Integer parameter type. */\n MaterialParamType[MaterialParamType[\"Int\"] = 1] = \"Int\";\n /** Float parameter type. */\n MaterialParamType[MaterialParamType[\"Float\"] = 2] = \"Float\";\n /** Sampler resource parameter type, i.e., a {@link Texture}. */\n MaterialParamType[MaterialParamType[\"Sampler\"] = 3] = \"Sampler\";\n /**\n * Font resource parameter type.\n *\n * **Note**: Changing font isn't exposed yet and will raise an error.\n */\n MaterialParamType[MaterialParamType[\"Font\"] = 4] = \"Font\";\n})(MaterialParamType || (MaterialParamType = {}));\n/**\n * Check whether a given shape is a mesh or not.\n *\n * @param shape The shape to check.\n * @returns `true` if the shape is a mesh, `false` if it's a primitive.\n */\nfunction isMeshShape(shape) {\n return shape === Shape.ConvexMesh || shape === Shape.TriangleMesh;\n}\n/**\n * Constants.\n */\n/**\n * Default world up vector.\n */\nconst UP_VECTOR = [0, 1, 0];\n/**\n * Native component\n *\n * Provides access to a native component instance of a specified component type.\n *\n * Usage example:\n *\n * ```js\n * import { Component, Type } from '@wonderlandengine/api';\n *\n * export class MyComponent extends Component {\n * static TypeName = 'my-component';\n * static Properties = {\n * myBoolean: { type: Type.Boolean, default: false },\n * };\n * start() {}\n * onActivate() {}\n * onDeactivate() {}\n * update(dt) {}\n * }\n * ```\n */\nexport class Component {\n /**\n * Unique identifier for this component class.\n *\n * This is used to register, add, and retrieve components of a given type.\n */\n static TypeName;\n /**\n * Properties of this component class.\n *\n * Properties are public attributes that can be configured via the\n * Wonderland Editor.\n *\n * Example:\n *\n * ```js\n * import { Component, Type } from '@wonderlandengine/api';\n * class MyComponent extends Component {\n * static TypeName = 'my-component';\n * static Properties = {\n * myBoolean: { type: Type.Boolean, default: false },\n * myFloat: { type: Type.Float, default: false },\n * myTexture: { type: Type.Texture, default: null },\n * };\n * }\n * ```\n *\n * Properties are automatically added to each component instance, and are\n * accessible like any JS attribute:\n *\n * ```js\n * // Creates a new component and set each properties value:\n * const myComponent = object.addComponent(MyComponent, {\n * myBoolean: true,\n * myFloat: 42.0,\n * myTexture: null\n * });\n *\n * // You can also override the properties on the instance:\n * myComponent.myBoolean = false;\n * myComponent.myFloat = -42.0;\n * ```\n */\n static Properties;\n /**\n * This was never released in an official version, we are keeping it\n * to easy transition to the new API.\n *\n * @deprecated Use {@link Component.onRegister} instead.\n * @hidden\n */\n static Dependencies;\n /**\n * Called when this component class is registered.\n *\n * @example\n *\n * This callback can be used to register dependencies of a component,\n * e.g., component classes that need to be registered in order to add\n * them at runtime with {@link Object3D.addComponent}, independent of whether\n * they are used in the editor.\n *\n * ```js\n * class Spawner extends Component {\n * static TypeName = 'spawner';\n *\n * static onRegister(engine) {\n * engine.registerComponent(SpawnedComponent);\n * }\n *\n * // You can now use addComponent with SpawnedComponent\n * }\n * ```\n *\n * @example\n *\n * This callback can be used to register different implementations of a\n * component depending on client features or API versions.\n *\n * ```js\n * // Properties need to be the same for all implementations!\n * const SharedProperties = {};\n *\n * class Anchor extends Component {\n * static TypeName = 'spawner';\n * static Properties = SharedProperties;\n *\n * static onRegister(engine) {\n * if(navigator.xr === undefined) {\n * /* WebXR unsupported, keep this dummy component *\\/\n * return;\n * }\n * /* WebXR supported! Override already registered dummy implementation\n * * with one depending on hit-test API support *\\/\n * engine.registerComponent(window.HitTestSource === undefined ?\n * AnchorWithoutHitTest : AnchorWithHitTest);\n * }\n *\n * // This one implements no functions\n * }\n * ```\n */\n static onRegister;\n /** Manager index. @hidden */\n _manager;\n /** Instance index. @hidden */\n _id;\n /**\n * Object containing this object.\n *\n * **Note**: This is cached for faster retrieval.\n *\n * @hidden\n */\n _object;\n /** Wonderland Engine instance. @hidden */\n _engine;\n /**\n * Create a new instance\n *\n * @param engine The engine instance.\n * @param manager Index of the manager.\n * @param id WASM component instance index.\n *\n * @hidden\n */\n constructor(engine, manager = -1, id = -1) {\n this._engine = engine;\n this._manager = manager;\n this._id = id;\n this._object = null;\n }\n /** Hosting engine instance. */\n get engine() {\n return this._engine;\n }\n /** The name of this component's type */\n get type() {\n const ctor = this.constructor;\n return ctor.TypeName ?? this._engine.wasm._typeNameFor(this._manager);\n }\n /** The object this component is attached to. */\n get object() {\n if (!this._object) {\n const objectId = this._engine.wasm._wl_component_get_object(this._manager, this._id);\n this._object = this._engine.wrapObject(objectId);\n }\n return this._object;\n }\n /**\n * Set whether this component is active.\n *\n * Activating/deactivating a component comes at a small cost of reordering\n * components in the respective component manager. This function therefore\n * is not a trivial assignment.\n *\n * Does nothing if the component is already activated/deactivated.\n *\n * @param active New active state.\n */\n set active(active) {\n this._engine.wasm._wl_component_setActive(this._manager, this._id, active);\n }\n /**\n * Whether this component is active\n */\n get active() {\n return this._engine.wasm._wl_component_isActive(this._manager, this._id) != 0;\n }\n /**\n * Remove this component from its objects and destroy it.\n *\n * It is best practice to set the component to `null` after,\n * to ensure it does not get used later.\n *\n * ```js\n * c.destroy();\n * c = null;\n * ```\n * @since 0.9.0\n */\n destroy() {\n this._engine.wasm._wl_component_remove(this._manager, this._id);\n this._manager = -1;\n this._id = -1;\n }\n /**\n * Checks equality by comparing whether the wrapped native component ids\n * and component manager types are equal.\n *\n * @param otherComponent Component to check equality with.\n * @returns Whether this component equals the given component.\n */\n equals(otherComponent) {\n if (!otherComponent)\n return false;\n return this._manager == otherComponent._manager && this._id == otherComponent._id;\n }\n /**\n * Reset the component properties to default.\n *\n * @returns Reference to self (for method chaining).\n */\n reset() {\n const ctor = this.constructor;\n const properties = ctor.Properties;\n for (const name in properties) {\n this[name] = properties[name].default;\n }\n return this;\n }\n /**\n * Trigger the component {@link Component.init} method.\n *\n * @note Use this method instead of directly calling {@link Component.init},\n * because this method creates an handler for the {@link Component.start}.\n *\n * @note This api is meant to be used internally.\n *\n * @hidden\n */\n _triggerInit() {\n if (this.init) {\n try {\n this.init();\n }\n catch (e) {\n console.error(`Exception during ${this.type} init() on object ${this.object.name}`);\n console.error(e);\n }\n }\n if (!this.start)\n return;\n /* Arm onActivate() with the initial start() call */\n const oldActivate = this.onActivate;\n this.onActivate = function () {\n /* As \"component\" is the component index, which may change\n * through calls to init() and start(), we call it on the\n * calling object, which will be the component, instead of\n * wljs_component_start() etc */\n try {\n this.start?.();\n }\n catch (e) {\n console.error(`Exception during ${this.type} start() on object ${this.object.name}`);\n console.error(e);\n }\n this.onActivate = oldActivate;\n if (!this.onActivate)\n return;\n try {\n this.onActivate();\n }\n catch (e) {\n console.error(`Exception during ${this.type} onActivate() on object ${this.object.name}`);\n console.error(e);\n }\n };\n }\n /**\n * Trigger the component {@link Component.update} method.\n *\n * @note This api is meant to be used internally.\n *\n * @hidden\n */\n _triggerUpdate(dt) {\n if (!this.update)\n return;\n try {\n this.update(dt);\n }\n catch (e) {\n console.error(`Exception during ${this.type} update() on object ${this.object.name}`);\n console.error(e);\n if (this._engine.wasm._deactivate_component_on_error) {\n this.active = false;\n }\n }\n }\n /**\n * Trigger the component {@link Component.onActivate} method.\n *\n * @note This api is meant to be used internally.\n *\n * @hidden\n */\n _triggerOnActivate() {\n if (!this.onActivate)\n return;\n try {\n this.onActivate();\n }\n catch (e) {\n console.error(`Exception during ${this.type} onActivate() on object ${this.object.name}`);\n console.error(e);\n }\n }\n /**\n * Trigger the component {@link Component.onDeactivate} method.\n *\n * @note This api is meant to be used internally.\n *\n * @hidden\n */\n _triggerOnDeactivate() {\n if (!this.onDeactivate)\n return;\n try {\n this.onDeactivate();\n }\n catch (e) {\n console.error(`Exception during ${this.type} onDeactivate() on object ${this.object.name}`);\n console.error(e);\n }\n }\n /**\n * Trigger the component {@link Component.onDestroy} method.\n *\n * @note This api is meant to be used internally.\n *\n * @hidden\n */\n _triggerOnDestroy() {\n if (!this.onDestroy)\n return;\n try {\n this.onDestroy();\n }\n catch (e) {\n console.error(`Exception during ${this.type} onDestroy() on object ${this.object.name}`);\n console.error(e);\n }\n }\n}\n/**\n * Native collision component.\n *\n * Provides access to a native collision component instance.\n */\nexport class CollisionComponent extends Component {\n /** @override */\n static TypeName = 'collision';\n /** Collision component collider */\n get collider() {\n return this._engine.wasm._wl_collision_component_get_collider(this._id);\n }\n /**\n * Set collision component collider.\n *\n * @param collider Collider of the collision component.\n */\n set collider(collider) {\n this._engine.wasm._wl_collision_component_set_collider(this._id, collider);\n }\n /**\n * Collision component extents.\n *\n * If {@link collider} returns {@link Collider.Sphere}, only the first\n * component of the returned vector is used.\n */\n get extents() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_collision_component_get_extents(this._id), 3);\n }\n /**\n * Set collision component extents.\n *\n * If {@link collider} returns {@link Collider.Sphere}, only the first\n * component of the passed vector is used.\n *\n * Example:\n *\n * ```js\n * // Spans 1 unit on the x-axis, 2 on the y-axis, 3 on the z-axis.\n * collision.extent = [1, 2, 3];\n * ```\n *\n * @param extents Extents of the collision component, expects a\n * 3 component array.\n */\n set extents(extents) {\n this.extents.set(extents);\n }\n /**\n * Collision component group.\n *\n * The groups is a bitmask that is compared to other components in {@link CollisionComponent#queryOverlaps}\n * or the group in {@link Scene#rayCast}.\n *\n * Colliders that have no common groups will not overlap with each other. If a collider\n * has none of the groups set for {@link Scene#rayCast}, the ray will not hit it.\n *\n * Each bit represents belonging to a group, see example.\n *\n * ```js\n * // c belongs to group 2\n * c.group = (1 << 2);\n *\n * // c belongs to group 0\n * c.group = (1 << 0);\n *\n * // c belongs to group 0 *and* 2\n * c.group = (1 << 0) | (1 << 2);\n *\n * (c.group & (1 << 2)) != 0; // true\n * (c.group & (1 << 7)) != 0; // false\n * ```\n */\n get group() {\n return this._engine.wasm._wl_collision_component_get_group(this._id);\n }\n /**\n * Set collision component group.\n *\n * @param group Group mask of the collision component.\n */\n set group(group) {\n this._engine.wasm._wl_collision_component_set_group(this._id, group);\n }\n /**\n * Query overlapping objects.\n *\n * Usage:\n *\n * ```js\n * const collision = object.getComponent('collision');\n * const overlaps = collision.queryOverlaps();\n * for(const otherCollision of overlaps) {\n * const otherObject = otherCollision.object;\n * console.log(`Collision with object ${otherObject.objectId}`);\n * }\n * ```\n *\n * @returns Collision components overlapping this collider.\n */\n queryOverlaps() {\n const count = this._engine.wasm._wl_collision_component_query_overlaps(this._id, this._engine.wasm._tempMem, this._engine.wasm._tempMemSize >> 1);\n const overlaps = new Array(count);\n for (let i = 0; i < count; ++i) {\n overlaps[i] = new CollisionComponent(this._engine, this._manager, this._engine.wasm._tempMemUint16[i]);\n }\n return overlaps;\n }\n}\n__decorate([\n nativeProperty()\n], CollisionComponent.prototype, \"collider\", null);\n__decorate([\n nativeProperty()\n], CollisionComponent.prototype, \"extents\", null);\n__decorate([\n nativeProperty()\n], CollisionComponent.prototype, \"group\", null);\n/**\n * Native text component\n *\n * Provides access to a native text component instance\n */\nexport class TextComponent extends Component {\n /** @override */\n static TypeName = 'text';\n /** Text component alignment. */\n get alignment() {\n return this._engine.wasm._wl_text_component_get_horizontal_alignment(this._id);\n }\n /**\n * Set text component alignment.\n *\n * @param alignment Alignment for the text component.\n */\n set alignment(alignment) {\n this._engine.wasm._wl_text_component_set_horizontal_alignment(this._id, alignment);\n }\n /** Text component justification. */\n get justification() {\n return this._engine.wasm._wl_text_component_get_vertical_alignment(this._id);\n }\n /**\n * Set text component justification.\n *\n * @param justification Justification for the text component.\n */\n set justification(justification) {\n this._engine.wasm._wl_text_component_set_vertical_alignment(this._id, justification);\n }\n /** Text component character spacing. */\n get characterSpacing() {\n return this._engine.wasm._wl_text_component_get_character_spacing(this._id);\n }\n /**\n * Set text component character spacing.\n *\n * @param spacing Character spacing for the text component.\n */\n set characterSpacing(spacing) {\n this._engine.wasm._wl_text_component_set_character_spacing(this._id, spacing);\n }\n /** Text component line spacing. */\n get lineSpacing() {\n return this._engine.wasm._wl_text_component_get_line_spacing(this._id);\n }\n /**\n * Set text component line spacing\n *\n * @param spacing Line spacing for the text component\n */\n set lineSpacing(spacing) {\n this._engine.wasm._wl_text_component_set_line_spacing(this._id, spacing);\n }\n /** Text component effect. */\n get effect() {\n return this._engine.wasm._wl_text_component_get_effect(this._id);\n }\n /**\n * Set text component effect\n *\n * @param effect Effect for the text component\n */\n set effect(effect) {\n this._engine.wasm._wl_text_component_set_effect(this._id, effect);\n }\n /** Text component text. */\n get text() {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_text_component_get_text(this._id);\n return wasm.UTF8ToString(ptr);\n }\n /**\n * Set text component text.\n *\n * @param text Text of the text component.\n */\n set text(text) {\n const wasm = this._engine.wasm;\n wasm._wl_text_component_set_text(this._id, wasm.tempUTF8(text.toString()));\n }\n /**\n * Set material to render the text with.\n *\n * @param material New material.\n */\n set material(material) {\n const matIndex = material ? material._index : 0;\n this._engine.wasm._wl_text_component_set_material(this._id, matIndex);\n }\n /** Material used to render the text. */\n get material() {\n const id = this._engine.wasm._wl_text_component_get_material(this._id);\n return id > 0 ? new Material(this._engine, id) : null;\n }\n}\n__decorate([\n nativeProperty()\n], TextComponent.prototype, \"alignment\", null);\n__decorate([\n nativeProperty()\n], TextComponent.prototype, \"justification\", null);\n__decorate([\n nativeProperty()\n], TextComponent.prototype, \"characterSpacing\", null);\n__decorate([\n nativeProperty()\n], TextComponent.prototype, \"lineSpacing\", null);\n__decorate([\n nativeProperty()\n], TextComponent.prototype, \"effect\", null);\n__decorate([\n nativeProperty()\n], TextComponent.prototype, \"text\", null);\n__decorate([\n nativeProperty()\n], TextComponent.prototype, \"material\", null);\n/**\n * Native view component.\n *\n * Provides access to a native view component instance.\n */\nexport class ViewComponent extends Component {\n /** @override */\n static TypeName = 'view';\n /** Projection matrix. */\n get projectionMatrix() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_view_component_get_projection_matrix(this._id), 16);\n }\n /** ViewComponent near clipping plane value. */\n get near() {\n return this._engine.wasm._wl_view_component_get_near(this._id);\n }\n /**\n * Set near clipping plane distance for the view.\n *\n * If an XR session is active, the change will apply in the\n * following frame, otherwise the change is immediate.\n *\n * @param near Near depth value.\n */\n set near(near) {\n this._engine.wasm._wl_view_component_set_near(this._id, near);\n }\n /** Far clipping plane value. */\n get far() {\n return this._engine.wasm._wl_view_component_get_far(this._id);\n }\n /**\n * Set far clipping plane distance for the view.\n *\n * If an XR session is active, the change will apply in the\n * following frame, otherwise the change is immediate.\n *\n * @param far Near depth value.\n */\n set far(far) {\n this._engine.wasm._wl_view_component_set_far(this._id, far);\n }\n /**\n * Get the horizontal field of view for the view, **in degrees**.\n *\n * If an XR session is active, this returns the field of view reported by\n * the device, regardless of the fov that was set.\n */\n get fov() {\n return this._engine.wasm._wl_view_component_get_fov(this._id);\n }\n /**\n * Set the horizontal field of view for the view, **in degrees**.\n *\n * If an XR session is active, the field of view reported by the device is\n * used and this value is ignored. After the XR session ends, the new value\n * is applied.\n *\n * @param fov Horizontal field of view, **in degrees**.\n */\n set fov(fov) {\n this._engine.wasm._wl_view_component_set_fov(this._id, fov);\n }\n}\n__decorate([\n enumerable()\n], ViewComponent.prototype, \"projectionMatrix\", null);\n__decorate([\n nativeProperty()\n], ViewComponent.prototype, \"near\", null);\n__decorate([\n nativeProperty()\n], ViewComponent.prototype, \"far\", null);\n__decorate([\n nativeProperty()\n], ViewComponent.prototype, \"fov\", null);\n/**\n * Native input component.\n *\n * Provides access to a native input component instance.\n */\nexport class InputComponent extends Component {\n /** @override */\n static TypeName = 'input';\n /** Input component type */\n get inputType() {\n return this._engine.wasm._wl_input_component_get_type(this._id);\n }\n /**\n * Set input component type.\n *\n * @params New input component type.\n */\n set inputType(type) {\n this._engine.wasm._wl_input_component_set_type(this._id, type);\n }\n /**\n * WebXR Device API input source associated with this input component,\n * if type {@link InputType.ControllerLeft} or {@link InputType.ControllerRight}.\n */\n get xrInputSource() {\n const xrSession = this._engine.xrSession;\n if (xrSession) {\n for (let inputSource of xrSession.inputSources) {\n if (inputSource.handedness == this.handedness) {\n return inputSource;\n }\n }\n }\n return null;\n }\n /**\n * 'left', 'right' or `null` depending on the {@link InputComponent#inputType}.\n */\n get handedness() {\n const inputType = this.inputType;\n if (inputType == InputType.ControllerRight ||\n inputType == InputType.RayRight ||\n inputType == InputType.EyeRight)\n return 'right';\n if (inputType == InputType.ControllerLeft ||\n inputType == InputType.RayLeft ||\n inputType == InputType.EyeLeft)\n return 'left';\n return null;\n }\n}\n__decorate([\n nativeProperty()\n], InputComponent.prototype, \"inputType\", null);\n__decorate([\n enumerable()\n], InputComponent.prototype, \"xrInputSource\", null);\n__decorate([\n enumerable()\n], InputComponent.prototype, \"handedness\", null);\n/**\n * Native light component.\n *\n * Provides access to a native light component instance.\n */\nexport class LightComponent extends Component {\n /** @override */\n static TypeName = 'light';\n getColor(out = new Float32Array(3)) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_light_component_get_color(this._id) / 4; /* Align F32 */\n out[0] = wasm.HEAPF32[ptr];\n out[1] = wasm.HEAPF32[ptr + 1];\n out[2] = wasm.HEAPF32[ptr + 2];\n return out;\n }\n /**\n * Set light color.\n *\n * @param c New color array/vector, expected to have at least 3 elements.\n * @since 1.0.0\n */\n setColor(c) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_light_component_get_color(this._id) / 4; /* Align F32 */\n wasm.HEAPF32[ptr] = c[0];\n wasm.HEAPF32[ptr + 1] = c[1];\n wasm.HEAPF32[ptr + 2] = c[2];\n }\n /**\n * View on the light color.\n *\n * @note Prefer to use {@link getColor} in performance-critical code.\n */\n get color() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_light_component_get_color(this._id), 3);\n }\n /**\n * Set light color.\n *\n * @param c Color of the light component.\n *\n * @note Prefer to use {@link setColor} in performance-critical code.\n */\n set color(c) {\n this.color.set(c);\n }\n /** Light type. */\n get lightType() {\n return this._engine.wasm._wl_light_component_get_type(this._id);\n }\n /**\n * Set light type.\n *\n * @param lightType Type of the light component.\n */\n set lightType(t) {\n this._engine.wasm._wl_light_component_set_type(this._id, t);\n }\n /**\n * Light intensity.\n * @since 1.0.0\n */\n get intensity() {\n return this._engine.wasm._wl_light_component_get_intensity(this._id);\n }\n /**\n * Set light intensity.\n *\n * @param intensity Intensity of the light component.\n * @since 1.0.0\n */\n set intensity(intensity) {\n this._engine.wasm._wl_light_component_set_intensity(this._id, intensity);\n }\n /**\n * Outer angle for spot lights, in degrees.\n * @since 1.0.0\n */\n get outerAngle() {\n return this._engine.wasm._wl_light_component_get_outerAngle(this._id);\n }\n /**\n * Set outer angle for spot lights.\n *\n * @param angle Outer angle, in degrees.\n * @since 1.0.0\n */\n set outerAngle(angle) {\n this._engine.wasm._wl_light_component_set_outerAngle(this._id, angle);\n }\n /**\n * Inner angle for spot lights, in degrees.\n * @since 1.0.0\n */\n get innerAngle() {\n return this._engine.wasm._wl_light_component_get_innerAngle(this._id);\n }\n /**\n * Set inner angle for spot lights.\n *\n * @param angle Inner angle, in degrees.\n * @since 1.0.0\n */\n set innerAngle(angle) {\n this._engine.wasm._wl_light_component_set_innerAngle(this._id, angle);\n }\n /**\n * Whether the light casts shadows.\n * @since 1.0.0\n */\n get shadows() {\n return !!this._engine.wasm._wl_light_component_get_shadows(this._id);\n }\n /**\n * Set whether the light casts shadows.\n *\n * @param b Whether the light casts shadows.\n * @since 1.0.0\n */\n set shadows(b) {\n this._engine.wasm._wl_light_component_set_shadows(this._id, b);\n }\n /**\n * Range for shadows.\n * @since 1.0.0\n */\n get shadowRange() {\n return this._engine.wasm._wl_light_component_get_shadowRange(this._id);\n }\n /**\n * Set range for shadows.\n *\n * @param range Range for shadows.\n * @since 1.0.0\n */\n set shadowRange(range) {\n this._engine.wasm._wl_light_component_set_shadowRange(this._id, range);\n }\n /**\n * Bias value for shadows.\n * @since 1.0.0\n */\n get shadowBias() {\n return this._engine.wasm._wl_light_component_get_shadowBias(this._id);\n }\n /**\n * Set bias value for shadows.\n *\n * @param bias Bias for shadows.\n * @since 1.0.0\n */\n set shadowBias(bias) {\n this._engine.wasm._wl_light_component_set_shadowBias(this._id, bias);\n }\n /**\n * Normal bias value for shadows.\n * @since 1.0.0\n */\n get shadowNormalBias() {\n return this._engine.wasm._wl_light_component_get_shadowNormalBias(this._id);\n }\n /**\n * Set normal bias value for shadows.\n *\n * @param bias Normal bias for shadows.\n * @since 1.0.0\n */\n set shadowNormalBias(bias) {\n this._engine.wasm._wl_light_component_set_shadowNormalBias(this._id, bias);\n }\n /**\n * Texel size for shadows.\n * @since 1.0.0\n */\n get shadowTexelSize() {\n return this._engine.wasm._wl_light_component_get_shadowTexelSize(this._id);\n }\n /**\n * Set texel size for shadows.\n *\n * @param size Texel size for shadows.\n * @since 1.0.0\n */\n set shadowTexelSize(size) {\n this._engine.wasm._wl_light_component_set_shadowTexelSize(this._id, size);\n }\n /**\n * Cascade count for {@link LightType.Sun} shadows.\n * @since 1.0.0\n */\n get cascadeCount() {\n return this._engine.wasm._wl_light_component_get_cascadeCount(this._id);\n }\n /**\n * Set cascade count for {@link LightType.Sun} shadows.\n *\n * @param count Cascade count.\n * @since 1.0.0\n */\n set cascadeCount(count) {\n this._engine.wasm._wl_light_component_set_cascadeCount(this._id, count);\n }\n}\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"color\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"lightType\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"intensity\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"outerAngle\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"innerAngle\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"shadows\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"shadowRange\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"shadowBias\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"shadowNormalBias\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"shadowTexelSize\", null);\n__decorate([\n nativeProperty()\n], LightComponent.prototype, \"cascadeCount\", null);\n/**\n * Native animation component.\n *\n * Provides access to a native animation component instance.\n */\nexport class AnimationComponent extends Component {\n /** @override */\n static TypeName = 'animation';\n /**\n * Set animation to play.\n *\n * Make sure to {@link Animation#retarget} the animation to affect the\n * right objects.\n *\n * @param anim Animation to play.\n */\n set animation(anim) {\n this._engine.wasm._wl_animation_component_set_animation(this._id, anim ? anim._index : 0);\n }\n /** Animation set for this component */\n get animation() {\n const id = this._engine.wasm._wl_animation_component_get_animation(this._id);\n return id > 0 ? new Animation(this._engine, id) : null;\n }\n /**\n * Set play count. Set to `0` to loop indefinitely.\n *\n * @param playCount Number of times to repeat the animation.\n */\n set playCount(playCount) {\n this._engine.wasm._wl_animation_component_set_playCount(this._id, playCount);\n }\n /** Number of times the animation is played. */\n get playCount() {\n return this._engine.wasm._wl_animation_component_get_playCount(this._id);\n }\n /**\n * Set speed. Set to negative values to run the animation backwards.\n *\n * Setting speed has an immediate effect for the current frame's update\n * and will continue with the speed from the current point in the animation.\n *\n * @param speed New speed at which to play the animation.\n * @since 0.8.10\n */\n set speed(speed) {\n this._engine.wasm._wl_animation_component_set_speed(this._id, speed);\n }\n /**\n * Speed factor at which the animation is played.\n *\n * @since 0.8.10\n */\n get speed() {\n return this._engine.wasm._wl_animation_component_get_speed(this._id);\n }\n /** Current playing state of the animation */\n get state() {\n return this._engine.wasm._wl_animation_component_state(this._id);\n }\n /**\n * Play animation.\n *\n * If the animation is currently paused, resumes from that position. If the\n * animation is already playing, does nothing.\n *\n * To restart the animation, {@link AnimationComponent#stop} it first.\n */\n play() {\n this._engine.wasm._wl_animation_component_play(this._id);\n }\n /** Stop animation. */\n stop() {\n this._engine.wasm._wl_animation_component_stop(this._id);\n }\n /** Pause animation. */\n pause() {\n this._engine.wasm._wl_animation_component_pause(this._id);\n }\n}\n__decorate([\n nativeProperty()\n], AnimationComponent.prototype, \"animation\", null);\n__decorate([\n nativeProperty()\n], AnimationComponent.prototype, \"playCount\", null);\n__decorate([\n nativeProperty()\n], AnimationComponent.prototype, \"speed\", null);\n__decorate([\n enumerable()\n], AnimationComponent.prototype, \"state\", null);\n/**\n * Native mesh component.\n *\n * Provides access to a native mesh component instance.\n */\nexport class MeshComponent extends Component {\n /** @override */\n static TypeName = 'mesh';\n /**\n * Set material to render the mesh with.\n *\n * @param material Material to render the mesh with.\n */\n set material(material) {\n this._engine.wasm._wl_mesh_component_set_material(this._id, material ? material._index : 0);\n }\n /** Material used to render the mesh. */\n get material() {\n const id = this._engine.wasm._wl_mesh_component_get_material(this._id);\n return id > 0 ? new Material(this._engine, id) : null;\n }\n /** Mesh rendered by this component. */\n get mesh() {\n const id = this._engine.wasm._wl_mesh_component_get_mesh(this._id);\n return id > 0 ? new Mesh(this._engine, id) : null;\n }\n /**\n * Set mesh to rendered with this component.\n *\n * @param mesh Mesh rendered by this component.\n */\n set mesh(mesh) {\n this._engine.wasm._wl_mesh_component_set_mesh(this._id, mesh ? mesh._index : 0);\n }\n /** Skin for this mesh component. */\n get skin() {\n const id = this._engine.wasm._wl_mesh_component_get_skin(this._id);\n return id > 0 ? new Skin(this._engine, id) : null;\n }\n /**\n * Set skin to transform this mesh component.\n *\n * @param skin Skin to use for rendering skinned meshes.\n */\n set skin(skin) {\n this._engine.wasm._wl_mesh_component_set_skin(this._id, skin ? skin._index : 0);\n }\n}\n__decorate([\n nativeProperty()\n], MeshComponent.prototype, \"material\", null);\n__decorate([\n nativeProperty()\n], MeshComponent.prototype, \"mesh\", null);\n__decorate([\n nativeProperty()\n], MeshComponent.prototype, \"skin\", null);\n/**\n * Enum for Physics axes locking\n *\n * See {@link PhysXComponent.angularLockAxis} and {@link PhysXComponent.linearLockAxis}.\n */\nexport var LockAxis;\n(function (LockAxis) {\n /**\n * No axis selected.\n */\n LockAxis[LockAxis[\"None\"] = 0] = \"None\";\n /**\n * **X axis**:\n */\n LockAxis[LockAxis[\"X\"] = 1] = \"X\";\n /**\n * **Y axis**:\n */\n LockAxis[LockAxis[\"Y\"] = 2] = \"Y\";\n /**\n * **Z axis**:\n */\n LockAxis[LockAxis[\"Z\"] = 4] = \"Z\";\n})(LockAxis || (LockAxis = {}));\n/**\n * Native physx rigid body component.\n *\n * Provides access to a native mesh component instance.\n * Only available when using physx enabled runtime, see \"Project Settings > Runtime\".\n */\nexport class PhysXComponent extends Component {\n /** @override */\n static TypeName = 'physx';\n /**\n * Set whether this rigid body is static.\n *\n * Setting this property only takes effect once the component\n * switches from inactive to active.\n *\n * @param b Whether the rigid body should be static.\n */\n set static(b) {\n this._engine.wasm._wl_physx_component_set_static(this._id, b);\n }\n /**\n * Whether this rigid body is static.\n *\n * This property returns whether the rigid body is *effectively*\n * static. If static property was set while the rigid body was\n * active, it will not take effect until the rigid body is set\n * inactive and active again. Until the component is set inactive,\n * this getter will return whether the rigid body is actually\n * static.\n */\n get static() {\n return !!this._engine.wasm._wl_physx_component_get_static(this._id);\n }\n /**\n * Set whether this rigid body is kinematic.\n *\n * @param b Whether the rigid body should be kinematic.\n */\n set kinematic(b) {\n this._engine.wasm._wl_physx_component_set_kinematic(this._id, b);\n }\n /**\n * Whether this rigid body is kinematic.\n */\n get kinematic() {\n return !!this._engine.wasm._wl_physx_component_get_kinematic(this._id);\n }\n /**\n * Set whether this rigid body's gravity is enabled.\n *\n * @param b Whether the rigid body's gravity should be enabled.\n */\n set gravity(b) {\n this._engine.wasm._wl_physx_component_set_gravity(this._id, b);\n }\n /**\n * Whether this rigid body's gravity flag is enabled.\n */\n get gravity() {\n return !!this._engine.wasm._wl_physx_component_get_gravity(this._id);\n }\n /**\n * Set whether this rigid body's simulate flag is enabled.\n *\n * @param b Whether the rigid body's simulate flag should be enabled.\n */\n set simulate(b) {\n this._engine.wasm._wl_physx_component_set_simulate(this._id, b);\n }\n /**\n * Whether this rigid body's simulate flag is enabled.\n */\n get simulate() {\n return !!this._engine.wasm._wl_physx_component_get_simulate(this._id);\n }\n /**\n * Set whether to allow simulation of this rigid body.\n *\n * {@link allowSimulation} and {@link trigger} can not be enabled at the\n * same time. Enabling {@link allowSimulation} while {@link trigger} is enabled\n * will disable {@link trigger}.\n *\n * @param b Whether to allow simulation of this rigid body.\n */\n set allowSimulation(b) {\n this._engine.wasm._wl_physx_component_set_allowSimulation(this._id, b);\n }\n /**\n * Whether to allow simulation of this rigid body.\n */\n get allowSimulation() {\n return !!this._engine.wasm._wl_physx_component_get_allowSimulation(this._id);\n }\n /**\n * Set whether this rigid body may be queried in ray casts.\n *\n * @param b Whether this rigid body may be queried in ray casts.\n */\n set allowQuery(b) {\n this._engine.wasm._wl_physx_component_set_allowQuery(this._id, b);\n }\n /**\n * Whether this rigid body may be queried in ray casts.\n */\n get allowQuery() {\n return !!this._engine.wasm._wl_physx_component_get_allowQuery(this._id);\n }\n /**\n * Set whether this physics body is a trigger.\n *\n * {@link allowSimulation} and {@link trigger} can not be enabled at the\n * same time. Enabling trigger while {@link allowSimulation} is enabled,\n * will disable {@link allowSimulation}.\n *\n * @param b Whether this physics body is a trigger.\n */\n set trigger(b) {\n this._engine.wasm._wl_physx_component_set_trigger(this._id, b);\n }\n /**\n * Whether this physics body is a trigger.\n */\n get trigger() {\n return !!this._engine.wasm._wl_physx_component_get_trigger(this._id);\n }\n /**\n * Set the shape for collision detection.\n *\n * @param s New shape.\n * @since 0.8.5\n */\n set shape(s) {\n this._engine.wasm._wl_physx_component_set_shape(this._id, s);\n }\n /** The shape for collision detection. */\n get shape() {\n return this._engine.wasm._wl_physx_component_get_shape(this._id);\n }\n /**\n * Set additional data for the shape.\n *\n * Retrieved only from {@link PhysXComponent#shapeData}.\n * @since 0.8.10\n */\n set shapeData(d) {\n if (d == null || !isMeshShape(this.shape))\n return;\n this._engine.wasm._wl_physx_component_set_shape_data(this._id, d.index);\n }\n /**\n * Additional data for the shape.\n *\n * `null` for {@link Shape} values: `None`, `Sphere`, `Capsule`, `Box`, `Plane`.\n * `{index: n}` for `TriangleMesh` and `ConvexHull`.\n *\n * This data is currently only for passing onto or creating other {@link PhysXComponent}.\n * @since 0.8.10\n */\n get shapeData() {\n if (!isMeshShape(this.shape))\n return null;\n return { index: this._engine.wasm._wl_physx_component_get_shape_data(this._id) };\n }\n /**\n * Set the shape extents for collision detection.\n *\n * @param e New extents for the shape.\n * @since 0.8.5\n */\n set extents(e) {\n this.extents.set(e);\n }\n /**\n * The shape extents for collision detection.\n */\n get extents() {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_physx_component_get_extents(this._id);\n return new Float32Array(wasm.HEAPF32.buffer, ptr, 3);\n }\n /**\n * Get staticFriction.\n */\n get staticFriction() {\n return this._engine.wasm._wl_physx_component_get_staticFriction(this._id);\n }\n /**\n * Set staticFriction.\n * @param v New staticFriction.\n */\n set staticFriction(v) {\n this._engine.wasm._wl_physx_component_set_staticFriction(this._id, v);\n }\n /**\n * Get dynamicFriction.\n */\n get dynamicFriction() {\n return this._engine.wasm._wl_physx_component_get_dynamicFriction(this._id);\n }\n /**\n * Set dynamicFriction\n * @param v New dynamicDamping.\n */\n set dynamicFriction(v) {\n this._engine.wasm._wl_physx_component_set_dynamicFriction(this._id, v);\n }\n /**\n * Get bounciness.\n * @since 0.9.0\n */\n get bounciness() {\n return this._engine.wasm._wl_physx_component_get_bounciness(this._id);\n }\n /**\n * Set bounciness.\n * @param v New bounciness.\n * @since 0.9.0\n */\n set bounciness(v) {\n this._engine.wasm._wl_physx_component_set_bounciness(this._id, v);\n }\n /**\n * Get linearDamping/\n */\n get linearDamping() {\n return this._engine.wasm._wl_physx_component_get_linearDamping(this._id);\n }\n /**\n * Set linearDamping.\n * @param v New linearDamping.\n */\n set linearDamping(v) {\n this._engine.wasm._wl_physx_component_set_linearDamping(this._id, v);\n }\n /** Get angularDamping. */\n get angularDamping() {\n return this._engine.wasm._wl_physx_component_get_angularDamping(this._id);\n }\n /**\n * Set angularDamping.\n * @param v New angularDamping.\n */\n set angularDamping(v) {\n this._engine.wasm._wl_physx_component_set_angularDamping(this._id, v);\n }\n /**\n * Set linear velocity.\n *\n * [PhysX Manual - \"Velocity\"](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/RigidBodyDynamics.html#velocity)\n *\n * Has no effect, if the component is not active.\n *\n * @param v New linear velocity.\n */\n set linearVelocity(v) {\n this._engine.wasm._wl_physx_component_set_linearVelocity(this._id, v[0], v[1], v[2]);\n }\n /** Linear velocity or `[0, 0, 0]` if the component is not active. */\n get linearVelocity() {\n const wasm = this._engine.wasm;\n wasm._wl_physx_component_get_linearVelocity(this._id, wasm._tempMem);\n return new Float32Array(wasm.HEAPF32.buffer, wasm._tempMem, 3);\n }\n /**\n * Set angular velocity\n *\n * [PhysX Manual - \"Velocity\"](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/RigidBodyDynamics.html#velocity)\n *\n * Has no effect, if the component is not active.\n *\n * @param v New angular velocity\n */\n set angularVelocity(v) {\n this._engine.wasm._wl_physx_component_set_angularVelocity(this._id, v[0], v[1], v[2]);\n }\n /** Angular velocity or `[0, 0, 0]` if the component is not active. */\n get angularVelocity() {\n const wasm = this._engine.wasm;\n wasm._wl_physx_component_get_angularVelocity(this._id, wasm._tempMem);\n return new Float32Array(wasm.HEAPF32.buffer, wasm._tempMem, 3);\n }\n /**\n * Set the components groups mask.\n *\n * @param flags New flags that need to be set.\n */\n set groupsMask(flags) {\n this._engine.wasm._wl_physx_component_set_groupsMask(this._id, flags);\n }\n /**\n * Get the components groups mask flags.\n *\n * Each bit represents membership to group, see example.\n *\n * ```js\n * // Assign c to group 2\n * c.groupsMask = (1 << 2);\n *\n * // Assign c to group 0\n * c.groupsMask = (1 << 0);\n *\n * // Assign c to group 0 and 2\n * c.groupsMask = (1 << 0) | (1 << 2);\n *\n * (c.groupsMask & (1 << 2)) != 0; // true\n * (c.groupsMask & (1 << 7)) != 0; // false\n * ```\n */\n get groupsMask() {\n return this._engine.wasm._wl_physx_component_get_groupsMask(this._id);\n }\n /**\n * Set the components blocks mask.\n *\n * @param flags New flags that need to be set.\n */\n set blocksMask(flags) {\n this._engine.wasm._wl_physx_component_set_blocksMask(this._id, flags);\n }\n /**\n * Get the components blocks mask flags.\n *\n * Each bit represents membership to the block, see example.\n *\n * ```js\n * // Block overlap with any objects in group 2\n * c.blocksMask = (1 << 2);\n *\n * // Block overlap with any objects in group 0\n * c.blocksMask = (1 << 0)\n *\n * // Block overlap with any objects in group 0 and 2\n * c.blocksMask = (1 << 0) | (1 << 2);\n *\n * (c.blocksMask & (1 << 2)) != 0; // true\n * (c.blocksMask & (1 << 7)) != 0; // false\n * ```\n */\n get blocksMask() {\n return this._engine.wasm._wl_physx_component_get_blocksMask(this._id);\n }\n /**\n * Set axes to lock for linear velocity.\n *\n * @param lock The Axis that needs to be set.\n *\n * Combine flags with Bitwise OR.\n * ```js\n * body.linearLockAxis = LockAxis.X | LockAxis.Y; // x and y set\n * body.linearLockAxis = LockAxis.X; // y unset\n * ```\n *\n * @note This has no effect if the component is static.\n */\n set linearLockAxis(lock) {\n this._engine.wasm._wl_physx_component_set_linearLockAxis(this._id, lock);\n }\n /**\n * Get the linear lock axes flags.\n *\n * To get the state of a specific flag, Bitwise AND with the LockAxis needed.\n *\n * ```js\n * if(body.linearLockAxis & LockAxis.Y) {\n * console.log(\"The Y flag was set!\");\n * }\n * ```\n *\n * @return axes that are currently locked for linear movement.\n */\n get linearLockAxis() {\n return this._engine.wasm._wl_physx_component_get_linearLockAxis(this._id);\n }\n /**\n * Set axes to lock for angular velocity.\n *\n * @param lock The Axis that needs to be set.\n *\n * ```js\n * body.angularLockAxis = LockAxis.X | LockAxis.Y; // x and y set\n * body.angularLockAxis = LockAxis.X; // y unset\n * ```\n *\n * @note This has no effect if the component is static.\n */\n set angularLockAxis(lock) {\n this._engine.wasm._wl_physx_component_set_angularLockAxis(this._id, lock);\n }\n /**\n * Get the angular lock axes flags.\n *\n * To get the state of a specific flag, Bitwise AND with the LockAxis needed.\n *\n * ```js\n * if(body.angularLockAxis & LockAxis.Y) {\n * console.log(\"The Y flag was set!\");\n * }\n * ```\n *\n * @return axes that are currently locked for angular movement.\n */\n get angularLockAxis() {\n return this._engine.wasm._wl_physx_component_get_angularLockAxis(this._id);\n }\n /**\n * Set mass.\n *\n * [PhysX Manual - \"Mass Properties\"](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/RigidBodyDynamics.html#mass-properties)\n *\n * @param m New mass.\n */\n set mass(m) {\n this._engine.wasm._wl_physx_component_set_mass(this._id, m);\n }\n /** Mass */\n get mass() {\n return this._engine.wasm._wl_physx_component_get_mass(this._id);\n }\n /**\n * Set mass space interia tensor.\n *\n * [PhysX Manual - \"Mass Properties\"](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/RigidBodyDynamics.html#mass-properties)\n *\n * Has no effect, if the component is not active.\n *\n * @param v New mass space interatia tensor.\n */\n set massSpaceInteriaTensor(v) {\n this._engine.wasm._wl_physx_component_set_massSpaceInertiaTensor(this._id, v[0], v[1], v[2]);\n }\n /**\n * Apply a force.\n *\n * [PhysX Manual - \"Applying Forces and Torques\"](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/RigidBodyDynamics.html#applying-forces-and-torques)\n *\n * Has no effect, if the component is not active.\n *\n * @param f Force vector.\n * @param m Force mode, see {@link ForceMode}, default `Force`.\n * @param localForce Whether the force vector is in local space, default `false`.\n * @param p Position to apply force at, default is center of mass.\n * @param local Whether position is in local space, default `false`.\n */\n addForce(f, m = ForceMode.Force, localForce = false, p, local = false) {\n const wasm = this._engine.wasm;\n if (!p) {\n wasm._wl_physx_component_addForce(this._id, f[0], f[1], f[2], m, localForce);\n return;\n }\n wasm._wl_physx_component_addForceAt(this._id, f[0], f[1], f[2], m, localForce, p[0], p[1], p[2], local);\n }\n /**\n * Apply torque.\n *\n * [PhysX Manual - \"Applying Forces and Torques\"](https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/RigidBodyDynamics.html#applying-forces-and-torques)\n *\n * Has no effect, if the component is not active.\n *\n * @param f Force vector.\n * @param m Force mode, see {@link ForceMode}, default `Force`.\n */\n addTorque(f, m = ForceMode.Force) {\n this._engine.wasm._wl_physx_component_addTorque(this._id, f[0], f[1], f[2], m);\n }\n /**\n * Add on collision callback.\n *\n * @param callback Function to call when this rigid body (un)collides with any other.\n *\n * ```js\n * let rigidBody = this.object.getComponent('physx');\n * rigidBody.onCollision(function(type, other) {\n * // Ignore uncollides\n * if(type == CollisionEventType.TouchLost) return;\n *\n * // Take damage on collision with enemies\n * if(other.object.name.startsWith('enemy-')) {\n * this.applyDamage(10);\n * }\n * }.bind(this));\n * ```\n *\n * @returns Id of the new callback for use with {@link PhysXComponent#removeCollisionCallback}.\n */\n onCollision(callback) {\n return this.onCollisionWith(this, callback);\n }\n /**\n * Add filtered on collision callback.\n *\n * @param otherComp Component for which callbacks will\n * be triggered. If you pass this component, the method is equivalent to.\n * {@link PhysXComponent#onCollision}.\n * @param callback Function to call when this rigid body\n * (un)collides with `otherComp`.\n * @returns Id of the new callback for use with {@link PhysXComponent#removeCollisionCallback}.\n */\n onCollisionWith(otherComp, callback) {\n const physics = this._engine.physics;\n physics._callbacks[this._id] = physics._callbacks[this._id] || [];\n physics._callbacks[this._id].push(callback);\n return this._engine.wasm._wl_physx_component_addCallback(this._id, otherComp._id || this._id);\n }\n /**\n * Remove a collision callback added with {@link PhysXComponent#onCollision} or {@link PhysXComponent#onCollisionWith}.\n *\n * @param callbackId Callback id as returned by {@link PhysXComponent#onCollision} or {@link PhysXComponent#onCollisionWith}.\n * @throws When the callback does not belong to the component.\n * @throws When the callback does not exist.\n */\n removeCollisionCallback(callbackId) {\n const physics = this._engine.physics;\n const r = this._engine.wasm._wl_physx_component_removeCallback(this._id, callbackId);\n /* r is the amount of object to remove from the end of the\n * callbacks array for this object */\n if (r)\n physics._callbacks[this._id].splice(-r);\n }\n}\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"static\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"kinematic\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"gravity\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"simulate\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"allowSimulation\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"allowQuery\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"trigger\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"shape\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"shapeData\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"extents\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"staticFriction\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"dynamicFriction\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"bounciness\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"linearDamping\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"angularDamping\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"linearVelocity\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"angularVelocity\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"groupsMask\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"blocksMask\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"linearLockAxis\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"angularLockAxis\", null);\n__decorate([\n nativeProperty()\n], PhysXComponent.prototype, \"mass\", null);\n/**\n * Access to the physics scene\n */\nexport class Physics {\n /**\n * @hidden\n *\n * **Note**: This is public to emulate a `friend` accessor.\n */\n _callbacks;\n /** Wonderland Engine instance */\n _engine;\n /** Ray Hit */\n _rayHit;\n /** Hit. */\n _hit;\n constructor(engine) {\n this._engine = engine;\n this._rayHit = engine.wasm._malloc(4 * (3 * 4 + 3 * 4 + 4 + 2) + 4);\n this._hit = new RayHit(this._engine, this._rayHit);\n this._callbacks = {};\n }\n /**\n * Cast a ray through the physics scene and find intersecting objects.\n *\n * The resulting ray hit will contain **up to 4** closest ray hits,\n * sorted by increasing distance.\n *\n * @param o Ray origin.\n * @param d Ray direction.\n * @param group Collision group to filter by: only objects that are\n * part of given group are considered for raycast.\n * @param maxDistance Maximum ray distance, default `100.0`.\n *\n * @returns The RayHit instance, belonging to this class.\n *\n * @note The returned {@link RayHit} object is owned by the Physics instance and\n * will be reused with the next {@link Physics#rayCast} call.\n */\n rayCast(o, d, group, maxDistance = 100.0) {\n this._engine.wasm._wl_physx_ray_cast(o[0], o[1], o[2], d[0], d[1], d[2], group, maxDistance, this._rayHit);\n return this._hit;\n }\n}\n/**\n * Mesh index type.\n */\nexport var MeshIndexType;\n(function (MeshIndexType) {\n /** Single byte mesh index, range 0-255 */\n MeshIndexType[MeshIndexType[\"UnsignedByte\"] = 1] = \"UnsignedByte\";\n /** Two byte mesh index, range 0-65535 */\n MeshIndexType[MeshIndexType[\"UnsignedShort\"] = 2] = \"UnsignedShort\";\n /** Four byte mesh index, range 0-4294967295 */\n MeshIndexType[MeshIndexType[\"UnsignedInt\"] = 4] = \"UnsignedInt\";\n})(MeshIndexType || (MeshIndexType = {}));\n/**\n * Mesh skinning type.\n */\nexport var MeshSkinningType;\n(function (MeshSkinningType) {\n /** Not skinned */\n MeshSkinningType[MeshSkinningType[\"None\"] = 0] = \"None\";\n /** Skinned, 4 joints/weight per vertex */\n MeshSkinningType[MeshSkinningType[\"FourJoints\"] = 1] = \"FourJoints\";\n /** Skinned, 8 joints/weight per vertex */\n MeshSkinningType[MeshSkinningType[\"EightJoints\"] = 2] = \"EightJoints\";\n})(MeshSkinningType || (MeshSkinningType = {}));\n/**\n * Wrapper around a native mesh data.\n *\n * To modify a mesh, you get access to a {@link MeshAttributeAccessor} that allows you to modify\n * the content of the buffers:\n *\n * Usage:\n *\n * ```js\n * const mesh = new Mesh(engine, {vertexCount: 3, indexData: [0, 1, 2] });\n * const positions = mesh.attribute(MeshAttribute.Position);\n * ...\n * ```\n */\nexport class Mesh {\n /**\n * Index of the mesh in the manager.\n *\n * @hidden\n */\n _index = -1;\n /** Wonderland Engine instance. @hidden */\n _engine;\n /**\n * Create a new instance.\n *\n * @param params Either a mesh index to wrap or set of parameters to create a new mesh.\n * For more information, please have a look at the {@link MeshParameters} interface.\n */\n constructor(engine, params) {\n this._engine = engine ?? WL;\n this._index = -1;\n if (isNumber(params)) {\n this._index = params;\n return;\n }\n if (!params.vertexCount)\n throw new Error(\"Missing parameter 'vertexCount'\");\n const wasm = this._engine.wasm;\n let indexData = 0;\n let indexType = 0;\n let indexDataSize = 0;\n if (params.indexData) {\n indexType = params.indexType || MeshIndexType.UnsignedShort;\n indexDataSize = params.indexData.length * indexType;\n indexData = wasm._malloc(indexDataSize);\n /* Copy the index data into wasm memory */\n switch (indexType) {\n case MeshIndexType.UnsignedByte:\n wasm.HEAPU8.set(params.indexData, indexData);\n break;\n case MeshIndexType.UnsignedShort:\n wasm.HEAPU16.set(params.indexData, indexData >> 1);\n break;\n case MeshIndexType.UnsignedInt:\n wasm.HEAPU32.set(params.indexData, indexData >> 2);\n break;\n }\n }\n const { skinningType = MeshSkinningType.None } = params;\n this._index = wasm._wl_mesh_create(indexData, indexDataSize, indexType, params.vertexCount, skinningType);\n }\n /** Number of vertices in this mesh. */\n get vertexCount() {\n return this._engine.wasm._wl_mesh_get_vertexCount(this._index);\n }\n /** Index data (read-only) or `null` if the mesh is not indexed. */\n get indexData() {\n const wasm = this._engine.wasm;\n const tempMem = wasm._tempMem;\n const ptr = wasm._wl_mesh_get_indexData(this._index, tempMem, tempMem + 4);\n if (ptr === null)\n return null;\n const indexCount = wasm.HEAPU32[tempMem / 4];\n const indexSize = wasm.HEAPU32[tempMem / 4 + 1];\n switch (indexSize) {\n case MeshIndexType.UnsignedByte:\n return new Uint8Array(wasm.HEAPU8.buffer, ptr, indexCount);\n case MeshIndexType.UnsignedShort:\n return new Uint16Array(wasm.HEAPU16.buffer, ptr, indexCount);\n case MeshIndexType.UnsignedInt:\n return new Uint32Array(wasm.HEAPU32.buffer, ptr, indexCount);\n }\n return null;\n }\n /** Hosting engine instance. */\n get engine() {\n return this._engine;\n }\n /**\n * Apply changes to {@link attribute | vertex attributes}.\n *\n * Uploads the updated vertex attributes to the GPU and updates the bounding\n * sphere to match the new vertex positions.\n *\n * Since this is an expensive operation, call it only once you have performed\n * all modifications on a mesh and avoid calling if you did not perform any\n * modifications at all.\n */\n update() {\n this._engine.wasm._wl_mesh_update(this._index);\n }\n getBoundingSphere(out = new Float32Array(4)) {\n const tempMemFloat = this._engine.wasm._tempMemFloat;\n this._engine.wasm._wl_mesh_get_boundingSphere(this._index, this._engine.wasm._tempMem);\n out[0] = tempMemFloat[0];\n out[1] = tempMemFloat[1];\n out[2] = tempMemFloat[2];\n out[3] = tempMemFloat[3];\n return out;\n }\n attribute(attr) {\n if (typeof attr != 'number')\n throw new TypeError('Expected number, but got ' + typeof attr);\n const tempMemUint32 = this._engine.wasm._tempMemUint32;\n this._engine.wasm._wl_mesh_get_attribute(this._index, attr, this._engine.wasm._tempMem);\n if (tempMemUint32[0] == 255)\n return null;\n const arraySize = tempMemUint32[5];\n return new MeshAttributeAccessor(this._engine, {\n attribute: tempMemUint32[0],\n offset: tempMemUint32[1],\n stride: tempMemUint32[2],\n formatSize: tempMemUint32[3],\n componentCount: tempMemUint32[4],\n /* The WASM API returns `0` for a scalar value. We clamp it to 1 as we strictly use it as a multiplier for get/set operations */\n arraySize: arraySize ? arraySize : 1,\n length: this.vertexCount,\n bufferType: (attr !== MeshAttribute.JointId\n ? Float32Array\n : Uint16Array),\n });\n }\n /**\n * Destroy and free the meshes memory.\n *\n * It is best practice to set the mesh variable to `null` after calling\n * destroy to prevent accidental use:\n *\n * ```js\n * mesh.destroy();\n * mesh = null;\n * ```\n *\n * Accessing the mesh after destruction behaves like accessing an empty\n * mesh.\n *\n * @since 0.9.0\n */\n destroy() {\n this._engine.wasm._wl_mesh_destroy(this._index);\n }\n /**\n * Checks equality by comparing whether the wrapped native mesh ids are\n * equal.\n *\n * @param otherMesh Mesh to check equality with.\n * @returns Whether this mesh equals the given mesh.\n *\n * @since 1.0.0\n */\n equals(otherMesh) {\n if (!otherMesh)\n return false;\n return this._index === otherMesh._index;\n }\n}\n/**\n * An iterator over a mesh vertex attribute.\n *\n * Usage:\n *\n * ```js\n * const mesh = this.object.getComponent('mesh').mesh;\n * const positions = mesh.attribute(WL.MeshAttribute.Position);\n *\n * const temp = new Float32Array(3);\n * for(int i = 0; i < positions.length; ++i) {\n * // pos will reference temp and thereby not allocate additional\n * // JavaScript garbage, which would cause a perf spike when collected.\n * const pos = positions.get(i, temp);\n * // scale position by 2 on X axis only\n * pos[0] *= 2.0f;\n * positions.set(i, pos);\n * }\n * // we're done modifying, tell the engine to move vertex data to the GPU\n * mesh.update();\n * ```\n */\nexport class MeshAttributeAccessor {\n /** Max number of elements. */\n length = 0;\n /** Wonderland Engine instance. @hidden */\n _engine;\n /** Attribute index. @hidden */\n _attribute = -1;\n /** Attribute offset. @hidden */\n _offset = 0;\n /** Attribute stride. @hidden */\n _stride = 0;\n /** Format size native enum. @hidden */\n _formatSize = 0;\n /** Number of components per vertex. @hidden */\n _componentCount = 0;\n /** Number of values per vertex. @hidden */\n _arraySize = 1;\n /**\n * Class to instantiate an ArrayBuffer to get/set values.\n */\n _bufferType;\n /**\n * Function to allocate temporary WASM memory. It is cached in the accessor to avoid\n * conditionals during get/set.\n */\n _tempBufferGetter;\n /**\n * Create a new instance.\n *\n * @note Please use {@link Mesh.attribute} to create a new instance.\n *\n * @param options Contains information about how to read the data.\n * @note Do not use this constructor. Instead, please use the {@link Mesh.attribute} method.\n *\n * @hidden\n */\n constructor(engine, options) {\n this._engine = engine;\n const wasm = this._engine.wasm;\n this._attribute = options.attribute;\n this._offset = options.offset;\n this._stride = options.stride;\n this._formatSize = options.formatSize;\n this._componentCount = options.componentCount;\n this._arraySize = options.arraySize;\n this._bufferType = options.bufferType;\n this.length = options.length;\n this._tempBufferGetter = (this._bufferType === Float32Array\n ? wasm.getTempBufferF32.bind(wasm)\n : wasm.getTempBufferU16.bind(wasm));\n }\n /**\n * Create a new TypedArray to hold this attribute's values.\n *\n * This method is useful to create a view to hold the data to\n * pass to {@link get} and {@link set}\n *\n * Example:\n *\n * ```js\n * const vertexCount = 4;\n * const positionAttribute = mesh.attribute(MeshAttributes.Position);\n *\n * // A position has 3 floats per vertex. Thus, positions has length 3 * 4.\n * const positions = positionAttribute.createArray(vertexCount);\n * ```\n *\n * @param count The number of **vertices** expected.\n * @returns A TypedArray with the appropriate format to access the data\n */\n createArray(count = 1) {\n count = count > this.length ? this.length : count;\n return new this._bufferType(count * this._componentCount * this._arraySize);\n }\n get(index, out = this.createArray()) {\n if (out.length % this._componentCount !== 0) {\n throw new Error(`out.length, ${out.length} is not a multiple of the attribute vector components, ${this._componentCount}`);\n }\n const dest = this._tempBufferGetter(out.length);\n const elementSize = this._bufferType.BYTES_PER_ELEMENT;\n const destSize = elementSize * out.length;\n const srcFormatSize = this._formatSize * this._arraySize;\n const destFormatSize = this._componentCount * elementSize * this._arraySize;\n this._engine.wasm._wl_mesh_get_attribute_values(this._attribute, srcFormatSize, this._offset + index * this._stride, this._stride, destFormatSize, dest.byteOffset, destSize);\n for (let i = 0; i < out.length; ++i)\n out[i] = dest[i];\n return out;\n }\n /**\n * Set attribute element.\n *\n * @param i Index\n * @param v Value to set the element to\n *\n * `v.length` needs to be a multiple of the attributes component count, see\n * {@link MeshAttribute}. If `v.length` is more than one multiple, it will be\n * filled with the next n attribute elements, which can reduce overhead\n * of this call.\n *\n * @returns Reference to self (for method chaining)\n */\n set(i, v) {\n if (v.length % this._componentCount !== 0)\n throw new Error(`out.length, ${v.length} is not a multiple of the attribute vector components, ${this._componentCount}`);\n const elementSize = this._bufferType.BYTES_PER_ELEMENT;\n const srcSize = elementSize * v.length;\n const srcFormatSize = this._componentCount * elementSize * this._arraySize;\n const destFormatSize = this._formatSize * this._arraySize;\n const wasm = this._engine.wasm;\n /* Unless we are already working with data from WASM heap, we\n * need to copy into temporary memory. */\n if (v.buffer != wasm.HEAPU8.buffer) {\n const dest = this._tempBufferGetter(v.length);\n dest.set(v);\n v = dest;\n }\n wasm._wl_mesh_set_attribute_values(this._attribute, srcFormatSize, v.byteOffset, srcSize, destFormatSize, this._offset + i * this._stride, this._stride);\n return this;\n }\n}\n/**\n * Wrapper around a native material.\n *\n * Each material instance will have properties associated to the pipeline it uses.\n * The material properties are automatically added to each material instance, example:\n *\n * ```js\n * const material = mesh.material; // Material with a `Phong Opaque Textured` pipeline\n * // You can access all the material properties from the editor using:\n * material.diffuseTexture = null;\n * material.diffuseColor = [1.0, 0.0, 0.0, 1.0];\n * ```\n */\nexport class Material {\n /**\n * Index of this material in the manager.\n *\n * @hidden\n */\n _index;\n /**\n * Material definition index in the scene.\n *\n * @hidden\n */\n _definition;\n /** Wonderland Engine instance. @hidden */\n _engine;\n /**\n * Create a new Material.\n *\n * @note Creating material is expensive. Please use {@link Material#clone} to clone a material.\n * @note Do not use this constructor directly with an index, this is reserved for internal purposes.\n */\n constructor(engine, params) {\n this._engine = engine;\n if (typeof params !== 'number') {\n if (!params?.pipeline)\n throw new Error(\"Missing parameter 'pipeline'\");\n const wasm = this._engine.wasm;\n const pipeline = params.pipeline;\n this._index = wasm._wl_material_create(wasm.tempUTF8(pipeline));\n if (this._index < 0)\n throw new Error(`No such pipeline '${pipeline}'`);\n }\n else {\n this._index = params;\n }\n this._definition = this._engine.wasm._wl_material_get_definition(this._index);\n if (!this._engine.wasm._materialDefinitions[this._definition])\n throw new Error(`Material Definition ${this._definition} not found for material with index ${this._index}`);\n return new Proxy(this, {\n get(target, prop) {\n const wasm = engine.wasm;\n const definition = wasm._materialDefinitions[target._definition];\n const param = definition.get(prop);\n if (!param)\n return target[prop];\n if (wasm._wl_material_get_param_value(target._index, param.index, wasm._tempMem)) {\n const type = param.type;\n switch (type.type) {\n case MaterialParamType.UnsignedInt:\n return type.componentCount == 1\n ? wasm._tempMemUint32[0]\n : new Uint32Array(wasm.HEAPU32.buffer, wasm._tempMem, type.componentCount);\n case MaterialParamType.Int:\n return type.componentCount == 1\n ? wasm._tempMemInt[0]\n : new Int32Array(wasm.HEAP32.buffer, wasm._tempMem, type.componentCount);\n case MaterialParamType.Float:\n return type.componentCount == 1\n ? wasm._tempMemFloat[0]\n : new Float32Array(wasm.HEAPF32.buffer, wasm._tempMem, type.componentCount);\n case MaterialParamType.Sampler:\n return engine.textures.wrap(wasm._tempMemInt[0]);\n default:\n throw new Error(`Invalid type ${type.type} on parameter ${param.index} for material ${target._index}`);\n }\n }\n },\n set(target, prop, value) {\n const wasm = engine.wasm;\n const definition = wasm._materialDefinitions[target._definition];\n const param = definition.get(prop);\n if (!param) {\n target[prop] = value;\n return true;\n }\n const type = param.type;\n switch (type.type) {\n case MaterialParamType.UnsignedInt:\n case MaterialParamType.Int:\n case MaterialParamType.Sampler:\n const v = value.id ?? value;\n wasm._wl_material_set_param_value_uint(target._index, param.index, v);\n break;\n case MaterialParamType.Float:\n let count = 1;\n if (typeof value === 'number') {\n wasm._tempMemFloat[0] = value;\n }\n else {\n count = value.length;\n for (let i = 0; i < count; ++i)\n wasm._tempMemFloat[i] = value[i];\n }\n wasm._wl_material_set_param_value_float(target._index, param.index, wasm._tempMem, count);\n break;\n case MaterialParamType.Font:\n throw new Error('Setting font properties is currently unsupported.');\n }\n return true;\n },\n });\n }\n /** @deprecated Use {@link #pipeline} instead. */\n get shader() {\n return this.pipeline;\n }\n /** Name of the pipeline used by this material. */\n get pipeline() {\n const wasm = this._engine.wasm;\n return wasm.UTF8ToString(wasm._wl_material_get_pipeline(this._index));\n }\n /** Hosting engine instance. */\n get engine() {\n return this._engine;\n }\n /**\n * Create a copy of the underlying native material.\n *\n * @returns Material clone.\n */\n clone() {\n const id = this._engine.wasm._wl_material_clone(this._index);\n return id > 0 ? new Material(this._engine, id) : null;\n }\n /**\n * Checks equality by comparing whether the wrapped native material ids are\n * equal.\n *\n * @param otherMaterial Material to check equality with.\n * @returns Whether this material equals the given material.\n *\n * @since 1.0.0\n */\n equals(otherMaterial) {\n if (!otherMaterial)\n return false;\n return this._index === otherMaterial._index;\n }\n /**\n * Wrap a native material index.\n *\n * @param engine Engine instance.\n * @param index The index.\n * @returns Material instance or `null` if index <= 0.\n *\n * @deprecated Please use `new Material()` instead.\n */\n static wrap(engine, index) {\n /** @todo: this propagate nullable in the entire codebase. Remove. */\n return index > 0 ? new Material(engine, index) : null;\n }\n}\n/** Temporary canvas */\nlet temp2d = null;\n/**\n * Wrapper around a native texture data.\n */\nexport class Texture {\n /** Wonderland Engine instance. @hidden */\n _engine;\n /** Index in the manager. @hidden */\n _id = 0;\n /** HTML image index. @hidden */\n _imageIndex = null;\n /**\n * @param engine The engine instance\n * @param param HTML media element to create texture from or texture id to wrap.\n */\n constructor(engine, param) {\n this._engine = engine ?? WL;\n const wasm = engine.wasm;\n if (param instanceof HTMLImageElement ||\n param instanceof HTMLVideoElement ||\n param instanceof HTMLCanvasElement) {\n const index = wasm._images.length;\n wasm._images.push(param);\n this._imageIndex = index;\n this._id = this._engine.wasm._wl_renderer_addImage(index);\n }\n else {\n this._id = param;\n }\n this._engine.textures._set(this);\n }\n /** Whether this texture is valid. */\n get valid() {\n return this._id >= 0;\n }\n /** Index in this manager. */\n get id() {\n return this._id;\n }\n /** Update the texture to match the HTML element (e.g. reflect the current frame of a video). */\n update() {\n if (!this.valid || this._imageIndex === null)\n return;\n this._engine.wasm._wl_renderer_updateImage(this._id, this._imageIndex);\n }\n /** Width of the texture. */\n get width() {\n return this._engine.wasm._wl_texture_width(this._id);\n }\n /** Height of the texture. */\n get height() {\n return this._engine.wasm._wl_texture_height(this._id);\n }\n /** Hosting engine instance. */\n get engine() {\n return this._engine;\n }\n /**\n * Update a subrange on the texture to match the HTML element (e.g. reflect the current frame of a video).\n *\n * Usage:\n *\n * ```js\n * // Copies rectangle of pixel starting from (10, 20)\n * texture.updateSubImage(10, 20, 600, 400);\n * ```\n *\n * @param x x offset\n * @param y y offset\n * @param w width\n * @param h height\n */\n updateSubImage(x, y, w, h) {\n if (!this.valid || this._imageIndex === null)\n return;\n /* Lazy initialize temp canvas */\n if (!temp2d) {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Texture.updateSubImage(): Failed to obtain CanvasRenderingContext2D.');\n }\n temp2d = { canvas, ctx };\n }\n const wasm = this._engine.wasm;\n const img = wasm._images[this._imageIndex];\n if (!img)\n return;\n temp2d.canvas.width = w;\n temp2d.canvas.height = h;\n temp2d.ctx.drawImage(img, x, y, w, h, 0, 0, w, h);\n const yOffset = (img.videoHeight ?? img.height) - y - h;\n wasm._images[this._imageIndex] = temp2d.canvas;\n wasm._wl_renderer_updateImage(this._id, this._imageIndex, x, yOffset);\n wasm._images[this._imageIndex] = img;\n }\n /**\n * Destroy and free the texture's texture altas space and memory.\n *\n * It is best practice to set the texture variable to `null` after calling\n * destroy to prevent accidental use of the invalid texture:\n *\n * ```js\n * texture.destroy();\n * texture = null;\n * ```\n *\n * @since 0.9.0\n */\n destroy() {\n this.engine.textures._destroy(this);\n this._id = -1;\n this._imageIndex = null;\n }\n /**\n * Checks equality by comparing whether the wrapped native texture ids are\n * equal.\n *\n * @param otherTexture Texture to check equality with.\n * @returns Whether this texture equals the given texture.\n *\n * @since 1.0.0\n */\n equals(otherTexture) {\n if (!otherTexture)\n return false;\n return this._id === otherTexture._id;\n }\n}\n/**\n * Wrapper around a native animation.\n */\nexport class Animation {\n /** Index of the mesh in the manager. @hidden */\n _index;\n /** Wonderland Engine instance. @hidden */\n _engine;\n /**\n * @param index Index in the manager\n */\n constructor(engine = WL, index) {\n this._engine = engine;\n this._index = index;\n }\n /** Duration of this animation. */\n get duration() {\n return this._engine.wasm._wl_animation_get_duration(this._index);\n }\n /** Number of tracks in this animation. */\n get trackCount() {\n return this._engine.wasm._wl_animation_get_trackCount(this._index);\n }\n /**\n * Clone this animation retargeted to a new set of objects.\n *\n * The clone shares most of the data with the original and is therefore\n * light-weight.\n *\n * **Experimental:** This API might change in upcoming versions.\n *\n * If retargeting to {@link Skin}, the join names will be used to determine a mapping\n * from the previous skin to the new skin. The source skin will be retrieved from\n * the first track in the animation that targets a joint.\n *\n * @param newTargets New targets per track. Expected to have\n * {@link Animation#trackCount} elements or to be a {@link Skin}.\n * @returns The retargeted clone of this animation.\n */\n retarget(newTargets) {\n const wasm = this._engine.wasm;\n if (newTargets instanceof Skin) {\n const animId = wasm._wl_animation_retargetToSkin(this._index, newTargets._index);\n return new Animation(this._engine, animId);\n }\n if (newTargets.length != this.trackCount) {\n throw Error('Expected ' +\n this.trackCount.toString() +\n ' targets, but got ' +\n newTargets.length.toString());\n }\n const ptr = wasm._malloc(2 * newTargets.length);\n for (let i = 0; i < newTargets.length; ++i) {\n wasm.HEAPU16[ptr >> (1 + i)] = newTargets[i].objectId;\n }\n const animId = wasm._wl_animation_retarget(this._index, ptr);\n wasm._free(ptr);\n return new Animation(this._engine, animId);\n }\n /**\n * Checks equality by comparing whether the wrapped native animation ids\n * are equal.\n *\n * @param otherAnimation Animation to check equality with.\n * @returns Whether this animation equals the given animation.\n *\n * @since 1.0.0\n */\n equals(otherAnimation) {\n if (!otherAnimation)\n return false;\n return this._index === otherAnimation._index;\n }\n}\n/**\n * Scene graph object.\n *\n * Node in the scene graph or \"entity\". Consists of transformation and a reference\n * to its parent object. Usually holds components and is accessible by components\n * through {@link Component#object}.\n *\n * Objects are stored in a data oriented manner inside WebAssembly memory. This class\n * is a JavaScript API wrapper around this memory for more convenient use in\n * components.\n *\n * Objects can be created and added to a scene through\n * {@link Scene#addObject} on the {@link WonderlandEngine.scene}.\n */\nexport class Object3D {\n /** Wonderland Engine instance. @hidden */\n _engine;\n /**\n * Object index in the manager.\n *\n * @hidden\n */\n _objectId = -1;\n /**\n * @param o Object id to wrap\n *\n * For performance reasons, please use {@link WonderlandEngine.wrapObject}\n */\n constructor(engine, o) {\n this._objectId = o;\n this._engine = engine;\n }\n /**\n * Name of the object.\n *\n * Useful for identifying objects during debugging.\n */\n get name() {\n const wasm = this._engine.wasm;\n return wasm.UTF8ToString(wasm._wl_object_name(this.objectId));\n }\n /**\n * Set the object's name.\n *\n * @param newName The new name to set.\n */\n set name(newName) {\n const wasm = this._engine.wasm;\n wasm._wl_object_set_name(this.objectId, wasm.tempUTF8(newName));\n }\n /**\n * Parent of this object or `null` if parented to root.\n */\n get parent() {\n const p = this._engine.wasm._wl_object_parent(this.objectId);\n return p === 0 ? null : this._engine.wrapObject(p);\n }\n /**\n * Children of this object.\n */\n get children() {\n const childrenCount = this._engine.wasm._wl_object_get_children_count(this.objectId);\n if (childrenCount === 0)\n return [];\n const wasm = this._engine.wasm;\n wasm.requireTempMem(childrenCount * 2);\n this._engine.wasm._wl_object_get_children(this.objectId, wasm._tempMem, wasm._tempMemSize >> 1);\n const children = new Array(childrenCount);\n for (let i = 0; i < childrenCount; ++i) {\n children[i] = this._engine.wrapObject(wasm._tempMemUint16[i]);\n }\n return children;\n }\n /**\n * Reparent object to given object.\n *\n * @note Reparenting is not trivial and might have a noticeable performance impact.\n *\n * @param newParent New parent or `null` to parent to root\n */\n set parent(newParent) {\n this._engine.wasm._wl_object_set_parent(this.objectId, newParent == null ? 0 : newParent.objectId);\n }\n /** Object index in the manager. */\n get objectId() {\n return this._objectId;\n }\n /** Hosting engine instance. */\n get engine() {\n return this._engine;\n }\n /**\n * Reset local transformation (translation, rotation and scaling) to identity.\n *\n * @returns Reference to self (for method chaining).\n */\n resetTransform() {\n this._engine.wasm._wl_object_reset_translation_rotation(this.objectId);\n this._engine.wasm._wl_object_reset_scaling(this.objectId);\n return this;\n }\n /**\n * Reset local position and rotation to identity.\n *\n * @returns Reference to self (for method chaining).\n */\n resetPositionRotation() {\n this._engine.wasm._wl_object_reset_translation_rotation(this.objectId);\n return this;\n }\n /** @deprecated Please use {@link Object3D.resetPositionRotation} instead. */\n resetTranslationRotation() {\n return this.resetPositionRotation();\n }\n /**\n * Reset local rotation, keep translation.\n *\n * @note To reset both rotation and translation, prefer\n * {@link resetTranslationRotation}.\n *\n * @returns Reference to self (for method chaining).\n */\n resetRotation() {\n this._engine.wasm._wl_object_reset_rotation(this.objectId);\n return this;\n }\n /**\n * Reset local translation, keep rotation.\n *\n * @note To reset both rotation and translation, prefer\n * {@link resetTranslationRotation}.\n *\n * @returns Reference to self (for method chaining).\n */\n resetPosition() {\n this._engine.wasm._wl_object_reset_translation(this.objectId);\n return this;\n }\n /** @deprecated Please use {@link Object3D.resetPosition} instead. */\n resetTranslation() {\n return this.resetPosition();\n }\n /**\n * Reset local scaling to identity (``[1.0, 1.0, 1.0]``).\n *\n * @returns Reference to self (for method chaining).\n */\n resetScaling() {\n this._engine.wasm._wl_object_reset_scaling(this.objectId);\n return this;\n }\n /** @deprecated Please use {@link Object3D.translateLocal} instead. */\n translate(v) {\n return this.translateLocal(v);\n }\n /**\n * Translate object by a vector in the parent's space.\n *\n * @param v Vector to translate by.\n *\n * @returns Reference to self (for method chaining).\n */\n translateLocal(v) {\n this._engine.wasm._wl_object_translate(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n /**\n * Translate object by a vector in object space.\n *\n * @param v Vector to translate by.\n *\n * @returns Reference to self (for method chaining).\n */\n translateObject(v) {\n this._engine.wasm._wl_object_translate_obj(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n /**\n * Translate object by a vector in world space.\n *\n * @param v Vector to translate by.\n *\n * @returns Reference to self (for method chaining).\n */\n translateWorld(v) {\n this._engine.wasm._wl_object_translate_world(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n /** @deprecated Please use {@link Object3D.rotateAxisAngleDegLocal} instead. */\n rotateAxisAngleDeg(a, d) {\n this.rotateAxisAngleDegLocal(a, d);\n return this;\n }\n /**\n * Rotate around given axis by given angle (degrees) in local space.\n *\n * @param a Vector representing the rotation axis.\n * @param d Angle in degrees.\n *\n * @note If the object is translated the rotation will be around\n * the parent. To rotate around the object origin, use\n * {@link rotateAxisAngleDegObject}\n *\n * @see {@link rotateAxisAngleRad}\n *\n * @returns Reference to self (for method chaining).\n */\n rotateAxisAngleDegLocal(a, d) {\n this._engine.wasm._wl_object_rotate_axis_angle(this.objectId, a[0], a[1], a[2], d);\n return this;\n }\n /** @deprecated Please use {@link Object3D.rotateAxisAngleRadLocal} instead. */\n rotateAxisAngleRad(a, d) {\n return this.rotateAxisAngleRadLocal(a, d);\n }\n /**\n * Rotate around given axis by given angle (radians) in local space.\n *\n * @param a Vector representing the rotation axis.\n * @param d Angle in radians.\n *\n * @note If the object is translated the rotation will be around\n * the parent. To rotate around the object origin, use\n * {@link rotateAxisAngleDegObject}\n *\n * @see {@link rotateAxisAngleDeg}\n *\n * @returns Reference to self (for method chaining).\n */\n rotateAxisAngleRadLocal(a, d) {\n this._engine.wasm._wl_object_rotate_axis_angle_rad(this.objectId, a[0], a[1], a[2], d);\n return this;\n }\n /**\n * Rotate around given axis by given angle (degrees) in object space.\n *\n * @param a Vector representing the rotation axis.\n * @param d Angle in degrees.\n *\n * Equivalent to prepending a rotation quaternion to the object's\n * local transformation.\n *\n * @see {@link rotateAxisAngleRadObject}\n *\n * @returns Reference to self (for method chaining).\n */\n rotateAxisAngleDegObject(a, d) {\n this._engine.wasm._wl_object_rotate_axis_angle_obj(this.objectId, a[0], a[1], a[2], d);\n return this;\n }\n /**\n * Rotate around given axis by given angle (radians) in object space\n * Equivalent to prepending a rotation quaternion to the object's\n * local transformation.\n *\n * @param a Vector representing the rotation axis\n * @param d Angle in degrees\n *\n * @see {@link rotateAxisAngleDegObject}\n *\n * @returns Reference to self (for method chaining).\n */\n rotateAxisAngleRadObject(a, d) {\n this._engine.wasm._wl_object_rotate_axis_angle_rad_obj(this.objectId, a[0], a[1], a[2], d);\n return this;\n }\n /** @deprecated Please use {@link Object3D.rotateLocal} instead. */\n rotate(q) {\n this.rotateLocal(q);\n return this;\n }\n /**\n * Rotate by a quaternion.\n *\n * @param q the Quaternion to rotate by.\n *\n * @returns Reference to self (for method chaining).\n */\n rotateLocal(q) {\n this._engine.wasm._wl_object_rotate_quat(this.objectId, q[0], q[1], q[2], q[3]);\n return this;\n }\n /**\n * Rotate by a quaternion in object space.\n *\n * Equivalent to prepending a rotation quaternion to the object's\n * local transformation.\n *\n * @param q the Quaternion to rotate by.\n *\n * @returns Reference to self (for method chaining).\n */\n rotateObject(q) {\n this._engine.wasm._wl_object_rotate_quat_obj(this.objectId, q[0], q[1], q[2], q[3]);\n return this;\n }\n /** @deprecated Please use {@link Object3D.scaleLocal} instead. */\n scale(v) {\n this.scaleLocal(v);\n return this;\n }\n /**\n * Scale object by a vector in object space.\n *\n * @param v Vector to scale by.\n *\n * @returns Reference to self (for method chaining).\n */\n scaleLocal(v) {\n this._engine.wasm._wl_object_scale(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n getPositionLocal(out = new Float32Array(3)) {\n const wasm = this._engine.wasm;\n /* Translation is different than rotation & scaling.\n * We can't simply read the memory. */\n wasm._wl_object_get_translation_local(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n getTranslationLocal(out = new Float32Array(3)) {\n return this.getPositionLocal(out);\n }\n getPositionWorld(out = new Float32Array(3)) {\n const wasm = this._engine.wasm;\n /* Translation is different than rotation & scaling.\n * We can't simply read the memory. */\n wasm._wl_object_get_translation_world(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n getTranslationWorld(out = new Float32Array(3)) {\n return this.getPositionWorld(out);\n }\n /**\n * Set local / object space position.\n *\n * Concatenates a new translation dual quaternion onto the existing rotation.\n *\n * @param v New local position array/vector, expected to have at least 3 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setPositionLocal(v) {\n this._engine.wasm._wl_object_set_translation_local(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n /** @deprecated Please use {@link Object3D.setPositionLocal} instead. */\n setTranslationLocal(v) {\n return this.setPositionLocal(v);\n }\n /**\n * Set world space position.\n *\n * Applies the inverse parent transform with a new translation dual quaternion\n * which is concatenated onto the existing rotation.\n *\n * @param v New world position array/vector, expected to have at least 3 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setPositionWorld(v) {\n this._engine.wasm._wl_object_set_translation_world(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n /** @deprecated Please use {@link Object3D.setPositionWorld} instead. */\n setTranslationWorld(v) {\n return this.setPositionWorld(v);\n }\n getScalingLocal(out = new Float32Array(3)) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_scaling_local(this.objectId) / 4; /* Align F32 */\n out[0] = wasm.HEAPF32[ptr];\n out[1] = wasm.HEAPF32[ptr + 1];\n out[2] = wasm.HEAPF32[ptr + 2];\n return out;\n }\n /**\n * Set local / object space scaling.\n *\n * @param v New local scaling array/vector, expected to have at least 3 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setScalingLocal(v) {\n this._engine.wasm._wl_object_set_scaling_local(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n getScalingWorld(out = new Float32Array(3)) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_scaling_world(this.objectId) / 4; /* Align F32 */\n out[0] = wasm.HEAPF32[ptr];\n out[1] = wasm.HEAPF32[ptr + 1];\n out[2] = wasm.HEAPF32[ptr + 2];\n return out;\n }\n /**\n * Set World space scaling.\n *\n * @param v New world scaling array/vector, expected to have at least 3 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setScalingWorld(v) {\n this._engine.wasm._wl_object_set_scaling_world(this.objectId, v[0], v[1], v[2]);\n return this;\n }\n getRotationLocal(out = new Float32Array(4)) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_trans_local(this.objectId) / 4; /* Align F32 */\n /* The first 4 floats represent the rotation quaternion. */\n out[0] = wasm.HEAPF32[ptr];\n out[1] = wasm.HEAPF32[ptr + 1];\n out[2] = wasm.HEAPF32[ptr + 2];\n out[3] = wasm.HEAPF32[ptr + 3];\n return out;\n }\n /**\n * Set local space rotation.\n *\n * @param v New world rotation array/vector, expected to have at least 4 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setRotationLocal(v) {\n this._engine.wasm._wl_object_set_rotation_local(this.objectId, v[0], v[1], v[2], v[3]);\n return this;\n }\n getRotationWorld(out = new Float32Array(4)) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_trans_world(this.objectId) / 4; /* Align F32 */\n /* The first 4 floats represent the rotation quaternion. */\n out[0] = wasm.HEAPF32[ptr];\n out[1] = wasm.HEAPF32[ptr + 1];\n out[2] = wasm.HEAPF32[ptr + 2];\n out[3] = wasm.HEAPF32[ptr + 3];\n return out;\n }\n /**\n * Set local space rotation.\n *\n * @param v New world rotation array/vector, expected to have at least 4 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setRotationWorld(v) {\n this._engine.wasm._wl_object_set_rotation_world(this.objectId, v[0], v[1], v[2], v[3]);\n return this;\n }\n getTransformLocal(out = new Float32Array(8)) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_trans_local(this.objectId) / 4; /* Align F32 */\n out[0] = wasm.HEAPF32[ptr];\n out[1] = wasm.HEAPF32[ptr + 1];\n out[2] = wasm.HEAPF32[ptr + 2];\n out[3] = wasm.HEAPF32[ptr + 3];\n out[4] = wasm.HEAPF32[ptr + 4];\n out[5] = wasm.HEAPF32[ptr + 5];\n out[6] = wasm.HEAPF32[ptr + 6];\n out[7] = wasm.HEAPF32[ptr + 7];\n return out;\n }\n /**\n * Set local space rotation.\n *\n * @param v New local transform array, expected to have at least 8 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setTransformLocal(v) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_trans_local(this.objectId) / 4; /* Align F32 */\n wasm.HEAPF32[ptr] = v[0];\n wasm.HEAPF32[ptr + 1] = v[1];\n wasm.HEAPF32[ptr + 2] = v[2];\n wasm.HEAPF32[ptr + 3] = v[3];\n wasm.HEAPF32[ptr + 4] = v[4];\n wasm.HEAPF32[ptr + 5] = v[5];\n wasm.HEAPF32[ptr + 6] = v[6];\n wasm.HEAPF32[ptr + 7] = v[7];\n this.setDirty();\n return this;\n }\n getTransformWorld(out = new Float32Array(8)) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_trans_world(this.objectId) / 4; /* Align F32 */\n out[0] = wasm.HEAPF32[ptr];\n out[1] = wasm.HEAPF32[ptr + 1];\n out[2] = wasm.HEAPF32[ptr + 2];\n out[3] = wasm.HEAPF32[ptr + 3];\n out[4] = wasm.HEAPF32[ptr + 4];\n out[5] = wasm.HEAPF32[ptr + 5];\n out[6] = wasm.HEAPF32[ptr + 6];\n out[7] = wasm.HEAPF32[ptr + 7];\n return out;\n }\n /**\n * Set world space rotation.\n *\n * @param v New world transform array, expected to have at least 8 elements.\n *\n * @returns Reference to self (for method chaining).\n */\n setTransformWorld(v) {\n const wasm = this._engine.wasm;\n const ptr = wasm._wl_object_trans_world(this.objectId) / 4; /* Align F32 */\n wasm.HEAPF32[ptr] = v[0];\n wasm.HEAPF32[ptr + 1] = v[1];\n wasm.HEAPF32[ptr + 2] = v[2];\n wasm.HEAPF32[ptr + 3] = v[3];\n wasm.HEAPF32[ptr + 4] = v[4];\n wasm.HEAPF32[ptr + 5] = v[5];\n wasm.HEAPF32[ptr + 6] = v[6];\n wasm.HEAPF32[ptr + 7] = v[7];\n this._engine.wasm._wl_object_trans_world_to_local(this.objectId);\n return this;\n }\n /**\n * Local space transformation.\n *\n * @deprecated Please use {@link Object3D.setTransformLocal} and\n * {@link Object3D.getTransformLocal} instead.\n */\n get transformLocal() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_object_trans_local(this.objectId), 8);\n }\n /**\n * Set local transform.\n *\n * @param t Local space transformation.\n *\n * @since 0.8.5\n *\n * @deprecated Please use {@link Object3D.setTransformLocal} and\n * {@link Object3D.getTransformLocal} instead.\n */\n set transformLocal(t) {\n this.transformLocal.set(t);\n this.setDirty();\n }\n /**\n * Global / world space transformation.\n *\n * May recompute transformations of the hierarchy of this object,\n * if they were changed by JavaScript components this frame.\n *\n * @deprecated Please use {@link Object3D.setTransformWorld} and\n * {@link Object3D.getTransformWorld} instead.\n */\n get transformWorld() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_object_trans_world(this.objectId), 8);\n }\n /**\n * Set world transform.\n *\n * @param t Global / world space transformation.\n *\n * @since 0.8.5\n *\n * @deprecated Please use {@link Object3D.setTransformWorld} and\n * {@link Object3D.getTransformWorld} instead.\n */\n set transformWorld(t) {\n this.transformWorld.set(t);\n this._engine.wasm._wl_object_trans_world_to_local(this.objectId);\n }\n /**\n * Local / object space scaling.\n *\n * @deprecated Please use {@link Object3D.setScalingLocal} and\n * {@link Object3D.getScalingLocal} instead.\n */\n get scalingLocal() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_object_scaling_local(this.objectId), 3);\n }\n /**\n * Set local space scaling.\n *\n * @param s Local space scaling.\n *\n * @since 0.8.7\n *\n * @deprecated Please use {@link Object3D.setScalingLocal} and\n * {@link Object3D.getScalingLocal} instead.\n */\n set scalingLocal(s) {\n this.scalingLocal.set(s);\n this.setDirty();\n }\n /**\n * Global / world space scaling.\n *\n * May recompute transformations of the hierarchy of this object,\n * if they were changed by JavaScript components this frame.\n *\n * @deprecated Please use {@link Object3D.setScalingWorld} and\n * {@link Object3D.getScalingWorld} instead.\n */\n get scalingWorld() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_object_scaling_world(this.objectId), 3);\n }\n /**\n * Set world space scaling.\n *\n * @param t World space scaling.\n *\n * @since 0.8.7\n *\n * @deprecated Please use {@link Object3D.setScalingWorld} and\n * {@link Object3D.getScalingWorld} instead.\n */\n set scalingWorld(s) {\n this.scalingWorld.set(s);\n this._engine.wasm._wl_object_scaling_world_to_local(this.objectId);\n }\n /**\n * Local space rotation.\n *\n * @since 0.8.7\n *\n * @deprecated Please use {@link Object3D.getRotationLocal} and\n * {@link Object3D.setRotationLocal} instead.\n */\n get rotationLocal() {\n return this.transformLocal.subarray(0, 4);\n }\n /**\n * Global / world space rotation\n *\n * @since 0.8.7\n *\n * @deprecated Please use {@link Object3D.getRotationWorld} and\n * {@link Object3D.setRotationWorld} instead.\n */\n get rotationWorld() {\n return this.transformWorld.subarray(0, 4);\n }\n /**\n * Set local space rotation.\n *\n * @param r Local space rotation\n *\n * @since 0.8.7\n *\n * @deprecated Please use {@link Object3D.getRotationLocal} and\n * {@link Object3D.setRotationLocal} instead.\n */\n set rotationLocal(r) {\n this._engine.wasm._wl_object_set_rotation_local(this.objectId, r[0], r[1], r[2], r[3]);\n }\n /**\n * Set world space rotation.\n *\n * @param r Global / world space rotation.\n *\n * @since 0.8.7\n *\n * @deprecated Please use {@link Object3D.getRotationWorld} and\n * {@link Object3D.setRotationWorld} instead.\n */\n set rotationWorld(r) {\n this._engine.wasm._wl_object_set_rotation_world(this.objectId, r[0], r[1], r[2], r[3]);\n }\n /** @deprecated Please use {@link Object3D.getForwardWorld} instead. */\n getForward(out) {\n return this.getForwardWorld(out);\n }\n /**\n * Compute the object's forward facing world space vector.\n *\n * The forward vector in object space is along the negative z-axis, i.e.,\n * `[0, 0, -1]`.\n *\n * @param out Destination array/vector, expected to have at least 3 elements.\n * @return The `out` parameter.\n */\n getForwardWorld(out) {\n out[0] = 0;\n out[1] = 0;\n out[2] = -1;\n this.transformVectorWorld(out);\n return out;\n }\n /** @deprecated Please use {@link Object3D.getUpWorld} instead. */\n getUp(out) {\n return this.getUpWorld(out);\n }\n /**\n * Compute the object's up facing world space vector.\n *\n * @param out Destination array/vector, expected to have at least 3 elements.\n * @return The `out` parameter.\n */\n getUpWorld(out) {\n out[0] = 0;\n out[1] = 1;\n out[2] = 0;\n this.transformVectorWorld(out);\n return out;\n }\n /** @deprecated Please use {@link Object3D.getRightWorld} instead. */\n getRight(out) {\n return this.getRightWorld(out);\n }\n /**\n * Compute the object's right facing world space vector.\n *\n * @param out Destination array/vector, expected to have at least 3 elements.\n * @return The `out` parameter.\n */\n getRightWorld(out) {\n out[0] = 1;\n out[1] = 0;\n out[2] = 0;\n this.transformVectorWorld(out);\n return out;\n }\n /**\n * Transform a vector by this object's world transform.\n *\n * @param out Out vector\n * @param v Vector to transform, default `out`\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformVectorWorld(out, v = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat[0] = v[0];\n wasm._tempMemFloat[1] = v[1];\n wasm._tempMemFloat[2] = v[2];\n wasm._wl_object_transformVectorWorld(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform a vector by this object's local transform.\n *\n * @param out Out vector\n * @param v Vector to transform, default `out`\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformVectorLocal(out, v = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat[0] = v[0];\n wasm._tempMemFloat[1] = v[1];\n wasm._tempMemFloat[2] = v[2];\n wasm._wl_object_transformVectorLocal(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform a point by this object's world transform.\n *\n * @param out Out point.\n * @param p Point to transform, default `out`.\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformPointWorld(out, p = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat[0] = p[0];\n wasm._tempMemFloat[1] = p[1];\n wasm._tempMemFloat[2] = p[2];\n wasm._wl_object_transformPointWorld(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform a point by this object's local transform.\n *\n * @param out Out point.\n * @param p Point to transform, default `out`.\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformPointLocal(out, p = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat[0] = p[0];\n wasm._tempMemFloat[1] = p[1];\n wasm._tempMemFloat[2] = p[2];\n wasm._wl_object_transformPointLocal(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform a vector by this object's inverse world transform.\n *\n * @param out Out vector.\n * @param v Vector to transform, default `out`.\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformVectorInverseWorld(out, v = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat[0] = v[0];\n wasm._tempMemFloat[1] = v[1];\n wasm._tempMemFloat[2] = v[2];\n wasm._wl_object_transformVectorInverseWorld(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform a vector by this object's inverse local transform.\n *\n * @param out Out vector\n * @param v Vector to transform, default `out`\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformVectorInverseLocal(out, v = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat[0] = v[0];\n wasm._tempMemFloat[1] = v[1];\n wasm._tempMemFloat[2] = v[2];\n wasm._wl_object_transformVectorInverseLocal(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform a point by this object's inverse world transform.\n *\n * @param out Out point.\n * @param p Point to transform, default `out`.\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformPointInverseWorld(out, p = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat[0] = p[0];\n wasm._tempMemFloat[1] = p[1];\n wasm._tempMemFloat[2] = p[2];\n wasm._wl_object_transformPointInverseWorld(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform a point by this object's inverse local transform.\n *\n * @param out Out point.\n * @param p Point to transform, default `out`.\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n transformPointInverseLocal(out, p = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat.set(p);\n wasm._wl_object_transformPointInverseLocal(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n return out;\n }\n /**\n * Transform an object space dual quaternion into world space.\n *\n * @param out Out transformation.\n * @param q Local space transformation, default `out`.\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n toWorldSpaceTransform(out, q = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat.set(q);\n wasm._wl_object_toWorldSpaceTransform(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n out[3] = wasm._tempMemFloat[3];\n out[4] = wasm._tempMemFloat[4];\n out[5] = wasm._tempMemFloat[5];\n out[6] = wasm._tempMemFloat[6];\n out[7] = wasm._tempMemFloat[7];\n return out;\n }\n /**\n * Transform a world space dual quaternion into local space.\n *\n * @param out Out transformation\n * @param q World space transformation, default `out`\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n toLocalSpaceTransform(out, q = out) {\n const p = this.parent;\n if (p) {\n p.toObjectSpaceTransform(out, q);\n return out;\n }\n if (out !== q) {\n out[0] = q[0];\n out[1] = q[1];\n out[2] = q[2];\n out[3] = q[3];\n out[4] = q[4];\n out[5] = q[5];\n out[6] = q[6];\n out[7] = q[7];\n }\n return out;\n }\n /**\n * Transform a world space dual quaternion into object space.\n *\n * @param out Out transformation.\n * @param q World space transformation, default `out`\n * @return The `out` parameter.\n *\n * @since 0.8.7\n */\n toObjectSpaceTransform(out, q = out) {\n const wasm = this._engine.wasm;\n wasm._tempMemFloat.set(q);\n wasm._wl_object_toObjectSpaceTransform(this.objectId, wasm._tempMem);\n out[0] = wasm._tempMemFloat[0];\n out[1] = wasm._tempMemFloat[1];\n out[2] = wasm._tempMemFloat[2];\n out[3] = wasm._tempMemFloat[3];\n out[4] = wasm._tempMemFloat[4];\n out[5] = wasm._tempMemFloat[5];\n out[6] = wasm._tempMemFloat[6];\n out[7] = wasm._tempMemFloat[7];\n return out;\n }\n /**\n * Turn towards / look at target.\n *\n * Rotates the object so that its forward vector faces towards the target\n * position. The `up` vector acts as a hint to uniquely orient the object's\n * up direction. When orienting a view component, the projected `up` vector\n * faces upwards on the viewing plane.\n *\n * @param p Target position to turn towards, in world space.\n * @param up Up vector to align object with, in world space. Default is `[0, 1, 0]`.\n *\n * @returns Reference to self (for method chaining).\n */\n lookAt(p, up = UP_VECTOR) {\n this._engine.wasm._wl_object_lookAt(this.objectId, p[0], p[1], p[2], up[0], up[1], up[2]);\n return this;\n }\n /** Destroy the object with all of its components and remove it from the scene */\n destroy() {\n this._engine.wasm._wl_scene_remove_object(this.objectId);\n this._objectId = -1;\n }\n /**\n * Mark transformation dirty.\n *\n * Causes an eventual recalculation of {@link transformWorld}, either\n * on next {@link getTranslationWorld}, {@link transformWorld} or\n * {@link scalingWorld} or the beginning of next frame, whichever\n * happens first.\n */\n setDirty() {\n this._engine.wasm._wl_object_set_dirty(this.objectId);\n }\n /**\n * Disable/enable all components of this object.\n *\n * @param b New state for the components.\n *\n * @since 0.8.5\n */\n set active(b) {\n const comps = this.getComponents();\n for (let c of comps) {\n c.active = b;\n }\n }\n getComponent(typeOrClass, index = 0) {\n const type = isString(typeOrClass) ? typeOrClass : typeOrClass.TypeName;\n const wasm = this._engine.wasm;\n const componentType = wasm._wl_get_component_manager_index(wasm.tempUTF8(type));\n if (componentType < 0) {\n /* Not a native component, try js: */\n const typeIndex = wasm._componentTypeIndices[type];\n if (typeIndex === undefined)\n return null;\n const jsIndex = wasm._wl_get_js_component_index(this.objectId, typeIndex, index);\n return jsIndex < 0 ? null : this._engine.wasm._components[jsIndex];\n }\n const componentId = this._engine.wasm._wl_get_component_id(this.objectId, componentType, index);\n return this._engine._wrapComponent(type, componentType, componentId);\n }\n /**\n * @param typeOrClass Type name, pass a falsey value (`undefined` or `null`) to retrieve all.\n * It's also possible to give a class definition. In this case, the method will use the `class.TypeName` field to\n * find the components.\n * @returns All components of given type attached to this object.\n *\n * @note As this function is non-trivial, avoid using it in `update()` repeatedly,\n * but rather store its result in `init()` or `start()`\n * @warning This method will currently return at most 341 components.\n */\n getComponents(typeOrClass) {\n const wasm = this._engine.wasm;\n let componentType = null;\n let type = null;\n if (typeOrClass) {\n type = isString(typeOrClass) ? typeOrClass : typeOrClass.TypeName;\n componentType = wasm._typeIndexFor(type);\n }\n const components = [];\n const maxComps = Math.floor((wasm._tempMemSize / 3) * 2);\n const componentsCount = wasm._wl_object_get_components(this.objectId, wasm._tempMem, maxComps);\n const offset = 2 * componentsCount;\n wasm._wl_object_get_component_types(this.objectId, wasm._tempMem + offset, maxComps);\n const jsManagerIndex = wasm._typeIndexFor('js');\n for (let i = 0; i < componentsCount; ++i) {\n const t = wasm._tempMemUint8[i + offset];\n const componentId = wasm._tempMemUint16[i];\n /* Handle JS types separately */\n if (t == jsManagerIndex) {\n const typeIndex = wasm._wl_get_js_component_index_for_id(componentId);\n const comp = wasm._components[typeIndex];\n if (componentType === null || comp.type == type)\n components.push(comp);\n continue;\n }\n if (componentType === null) {\n const managerName = wasm._typeNameFor(t);\n components.push(this._engine._wrapComponent(managerName, t, componentId));\n }\n else if (t == componentType) {\n /* Optimized manager name retrieval, already have type */\n components.push(this._engine._wrapComponent(type, componentType, componentId));\n }\n }\n return components;\n }\n addComponent(typeOrClass, params) {\n const wasm = this._engine.wasm;\n const type = isString(typeOrClass) ? typeOrClass : typeOrClass.TypeName;\n const componentType = wasm._typeIndexFor(type);\n let component = null;\n let componentIndex = null;\n if (componentType < 0) {\n /* JavaScript component */\n if (!(type in wasm._componentTypeIndices)) {\n throw new TypeError(\"Unknown component type '\" + type + \"'\");\n }\n const componentId = wasm._wl_object_add_js_component(this.objectId, wasm._componentTypeIndices[type]);\n componentIndex = wasm._wl_get_js_component_index_for_id(componentId);\n component = wasm._components[componentIndex];\n }\n else {\n /* native component */\n const componentId = wasm._wl_object_add_component(this.objectId, componentType);\n component = this._engine._wrapComponent(type, componentType, componentId);\n }\n if (params !== undefined) {\n const ctor = component.constructor;\n for (const key in params) {\n if (!(key in ctor.Properties))\n continue;\n component[key] = params[key];\n }\n }\n /* Explicitly initialize native components */\n if (componentType < 0) {\n /* @todo: `componentIndex` can be null here, that's an error */\n wasm._wljs_component_init(componentIndex);\n /* start() is called through onActivate() */\n }\n /* If it was not explicitly requested by the user to leave the component inactive,\n * we activate it as a final step. This invalidates componentIndex! */\n if (!params || !('active' in params && !params.active)) {\n component.active = true;\n }\n return component;\n }\n /**\n * Whether given object's transformation has changed.\n */\n get changed() {\n return !!this._engine.wasm._wl_object_is_changed(this.objectId);\n }\n /**\n * Checks equality by comparing whether the wrapped native object ids are\n * equal.\n *\n * @param otherObject Object to check equality with.\n * @returns Whether this object equals the given object.\n */\n equals(otherObject) {\n if (!otherObject)\n return false;\n return this.objectId == otherObject.objectId;\n }\n}\n/**\n * Wrapper around a native skin data.\n */\nexport class Skin {\n /**\n * Index of the skin in the manager.\n * @hidden\n */\n _index;\n /** Wonderland Engine instance. @hidden */\n _engine;\n constructor(engine, index) {\n this._engine = engine;\n this._index = index;\n }\n /** Amount of joints in this skin. */\n get jointCount() {\n return this._engine.wasm._wl_skin_get_joint_count(this._index);\n }\n /** Joints object ids for this skin */\n get jointIds() {\n const wasm = this._engine.wasm;\n return new Uint16Array(wasm.HEAPU16.buffer, wasm._wl_skin_joint_ids(this._index), this.jointCount);\n }\n /**\n * Dual quaternions in a flat array of size 8 times {@link jointCount}.\n *\n * Inverse bind transforms of the skin.\n */\n get inverseBindTransforms() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_skin_inverse_bind_transforms(this._index), 8 * this.jointCount);\n }\n /**\n * Vectors in a flat array of size 3 times {@link jointCount}.\n *\n * Inverse bind scalings of the skin.\n */\n get inverseBindScalings() {\n const wasm = this._engine.wasm;\n return new Float32Array(wasm.HEAPF32.buffer, wasm._wl_skin_inverse_bind_scalings(this._index), 3 * this.jointCount);\n }\n /**\n * Checks equality by comparing whether the wrapped native skin ids are\n * equal.\n *\n * @param otherSkin Skin to check equality with.\n * @returns Whether this skin equals the given skin.\n *\n * @since 1.0.0\n */\n equals(otherSkin) {\n if (!otherSkin)\n return false;\n return this._index === otherSkin._index;\n }\n}\n/* For backward compatibility with < 1.0.0. */\nexport { Object3D as Object };\n/**\n * Ray hit.\n *\n * Result of a {@link Scene.rayCast}.\n *\n * @note this class wraps internal engine data and should only be created internally.\n */\nexport class RayHit {\n /** Wonderland Engine instance. @hidden */\n _engine;\n /** Pointer to the memory heap. */\n _ptr;\n /**\n * @param ptr Pointer to the ray hits memory.\n */\n constructor(engine, ptr) {\n if ((ptr & 3) !== 0) {\n throw new Error('Misaligned pointer: please report a bug');\n }\n this._engine = engine;\n this._ptr = ptr;\n }\n /** Array of ray hit locations. */\n get locations() {\n let p = this._ptr;\n let l = [];\n for (let i = 0; i < this.hitCount; ++i) {\n l.push(new Float32Array(this._engine.wasm.HEAPF32.buffer, p + 12 * i, 3));\n }\n return l;\n }\n /** Array of ray hit normals (only when using {@link Physics#rayCast}. */\n get normals() {\n let p = this._ptr + 48;\n let l = [];\n for (let i = 0; i < this.hitCount; ++i) {\n l.push(new Float32Array(this._engine.wasm.HEAPF32.buffer, p + 12 * i, 3));\n }\n return l;\n }\n /**\n * Prefer these to recalculating the distance from locations.\n *\n * Distances of array hits to ray origin.\n */\n get distances() {\n const p = this._ptr + 48 * 2;\n return new Float32Array(this._engine.wasm.HEAPF32.buffer, p, this.hitCount);\n }\n /** Hit objects */\n get objects() {\n const HEAPU16 = this._engine.wasm.HEAPU16;\n const objects = [null, null, null, null];\n let p = (this._ptr + (48 * 2 + 16)) >> 1;\n for (let i = 0; i < this.hitCount; ++i) {\n objects[i] = this._engine.wrapObject(HEAPU16[p + i]);\n }\n return objects;\n }\n /** Number of hits (max 4) */\n get hitCount() {\n return Math.min(this._engine.wasm.HEAPU32[this._ptr / 4 + 30], 4);\n }\n}\nclass math {\n /** (Experimental!) Cubic Hermite spline interpolation for vector3 and quaternions.\n *\n * With `f == 0`, `out` will be `b`, if `f == 1`, `out` will be c.\n *\n * Whether a quaternion or vector3 interpolation is intended is determined by\n * length of `a`.\n *\n * @param out Array to write result to.\n * @param a First tangent/handle.\n * @param b First point or quaternion.\n * @param c Second point or quaternion.\n * @param d Second handle.\n * @param f Interpolation factor in [0; 1].\n * @returns The `out` parameter.\n *\n * @since 0.8.6\n */\n static cubicHermite(out, a, b, c, d, f, engine = WL) {\n const wasm = engine.wasm;\n wasm._tempMemFloat.subarray(0).set(a);\n wasm._tempMemFloat.subarray(4).set(b);\n wasm._tempMemFloat.subarray(8).set(c);\n wasm._tempMemFloat.subarray(12).set(d);\n const isQuat = a.length == 4;\n wasm._wl_math_cubicHermite(wasm._tempMem + 4 * 16, wasm._tempMem + 4 * 0, wasm._tempMem + 4 * 4, wasm._tempMem + 4 * 8, wasm._tempMem + 4 * 12, f, isQuat);\n out[0] = wasm._tempMemFloat[16];\n out[1] = wasm._tempMemFloat[17];\n out[2] = wasm._tempMemFloat[18];\n if (isQuat)\n out[3] = wasm._tempMemFloat[19];\n return out;\n }\n}\nexport { math };\n/**\n * Class for accessing internationalization (i18n) features.\n *\n * Allows {@link I18N.onLanguageChanged \"detecting language change\"},\n * {@link I18N.language \"setting the current language\"} or translating\n * {@link I18N.translate() \"individual terms\"}.\n *\n * Internationalization works with terms,\n * a string type keyword that is linked to a different text for each language.\n *\n * Internally, string parameters for text and js components are\n * automatically swapped during language change, given they are linked to a term.\n * If manual text swapping is desired, {@link I18N.translate()}\n * can be used to retrieve the current translation for any term.\n *\n * You can also use the {@link I18N.onLanguageChanged} to manually update text\n * when a language is changed to for example update a number in a string.\n *\n * @since 1.0.0\n */\nexport class I18N {\n /**\n * {@link Emitter} for language change events.\n *\n * First parameter to a listener is the old language index,\n * second parameter is the new language index.\n *\n * Usage from a within a component:\n * ```js\n * this.engine.i18n.onLanguageChanged.add((oldLanguageIndex, newLanguageIndex) => {\n * const oldLanguage = this.engine.i18n.languageName(oldLanguageIndex);\n * const newLanguage = this.engine.i18n.languageName(newLanguageIndex);\n * console.log(\"Switched from\", oldLanguage, \"to\", newLanguage);\n * });\n * ```\n */\n onLanguageChanged = new Emitter();\n /** Wonderland Engine instance. @hidden */\n _engine;\n /**\n * Constructor\n */\n constructor(engine) {\n this._engine = engine;\n }\n /**\n * Set current language and apply translations to linked text parameters.\n *\n * @param code Language code to switch to\n */\n set language(code) {\n if (code == null)\n return;\n const wasm = this._engine.wasm;\n wasm._wl_i18n_setLanguage(wasm.tempUTF8(code));\n }\n /**\n * Get current language code.\n *\n */\n get language() {\n const wasm = this._engine.wasm;\n const code = wasm._wl_i18n_currentLanguage();\n if (code === 0)\n return null;\n return wasm.UTF8ToString(code);\n }\n /**\n * Get translated string for a term for the currently loaded language.\n *\n * @param term Term to translate\n */\n translate(term) {\n const wasm = this._engine.wasm;\n const translation = wasm._wl_i18n_translate(wasm.tempUTF8(term));\n if (translation === 0)\n return null;\n return wasm.UTF8ToString(translation);\n }\n /**\n * Get the number of languages in the project.\n *\n */\n languageCount() {\n const wasm = this._engine.wasm;\n return wasm._wl_i18n_languageCount();\n }\n /**\n * Get a language code.\n *\n * @param index Index of the language to get the code from\n */\n languageIndex(code) {\n const wasm = this._engine.wasm;\n return wasm._wl_i18n_languageIndex(wasm.tempUTF8(code));\n }\n /**\n * Get a language code.\n *\n * @param index Index of the language to get the code from\n */\n languageCode(index) {\n const wasm = this._engine.wasm;\n const code = wasm._wl_i18n_languageCode(index);\n if (code === 0)\n return null;\n return wasm.UTF8ToString(code);\n }\n /**\n * Get a language name.\n *\n * @param index Index of the language to get the name from\n */\n languageName(index) {\n const wasm = this._engine.wasm;\n const name = wasm._wl_i18n_languageName(index);\n if (name === 0)\n return null;\n return wasm.UTF8ToString(name);\n }\n}\n/** Properties of a WebXR session */\nexport class XR {\n /** Wonderland WASM bridge. @hidden */\n #wasm;\n #mode;\n constructor(wasm, mode) {\n this.#wasm = wasm;\n this.#mode = mode;\n }\n /** Current WebXR session mode */\n get sessionMode() {\n return this.#mode;\n }\n /** Current WebXR session */\n get session() {\n return this.#wasm.webxr_session;\n }\n /** Current WebXR frame */\n get frame() {\n return this.#wasm.webxr_frame;\n }\n referenceSpaceForType(type) {\n return this.#wasm.webxr_refSpaces[type] ?? null;\n }\n /** Set current reference space type used for retrieving eye, head, hand and joint poses */\n set currentReferenceSpace(refSpace) {\n this.#wasm.webxr_refSpace = refSpace;\n this.#wasm.webxr_refSpaceType = null;\n for (const type of Object.keys(this.#wasm.webxr_refSpaces)) {\n if (this.#wasm.webxr_refSpaces[type] === refSpace) {\n /* Keep track of reference space type */\n this.#wasm.webxr_refSpaceType = type;\n }\n }\n }\n /** Current reference space type used for retrieving eye, head, hand and joint poses */\n get currentReferenceSpace() {\n return this.#wasm.webxr_refSpace;\n }\n /** Current WebXR reference space type or `null` if not a default reference space */\n get currentReferenceSpaceType() {\n return this.#wasm.webxr_refSpaceType;\n }\n /** Current WebXR base layer */\n get baseLayer() {\n return this.#wasm.webxr_baseLayer;\n }\n /** Current WebXR framebuffer */\n get framebuffers() {\n if (!Array.isArray(this.#wasm.webxr_fbo)) {\n return [this.#wasm.GL.framebuffers[this.#wasm.webxr_fbo]];\n }\n return this.#wasm.webxr_fbo.map((id) => this.#wasm.GL.framebuffers[id]);\n }\n}\n", "/**\n * Fetch a file as an `ArrayBuffer`, with fetch progress passed to a callback.\n *\n * @param path Path of the file to fetch\n * @param onProgress Callback receiving the current fetch progress and total\n * size, in bytes. Also called a final time on completion.\n * @returns Promise that resolves when the fetch successfully completes\n */\nexport function fetchWithProgress(path, onProgress) {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n xhr.open('GET', path);\n xhr.responseType = 'arraybuffer';\n xhr.onprogress = (progress) => {\n if (progress.lengthComputable) {\n onProgress?.(progress.loaded, progress.total);\n }\n };\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n const buffer = xhr.response;\n onProgress?.(buffer.byteLength, buffer.byteLength);\n resolve(buffer);\n }\n else {\n reject(xhr.statusText);\n }\n };\n xhr.onerror = () => reject(xhr.statusText);\n xhr.send();\n });\n}\n", "import { Emitter } from './utils/event.js';\nimport { fetchWithProgress } from './utils/fetch.js';\nimport { isString } from './utils/object.js';\nimport { RayHit, ViewComponent } from './wonderland.js';\n/**\n * Provides global scene functionality like raycasting.\n */\nexport class Scene {\n /** Called before rendering the scene */\n onPreRender = new Emitter();\n /** Called after the scene has been rendered */\n onPostRender = new Emitter();\n /** Wonderland Engine instance. @hidden */\n _engine;\n /** Ray hit pointer in WASM heap. @hidden */\n _rayHit;\n /** Ray hit. @hidden */\n _hit;\n constructor(engine) {\n this._engine = engine;\n this._rayHit = engine.wasm._malloc(4 * (3 * 4 + 3 * 4 + 4 + 2) + 4);\n this._hit = new RayHit(this._engine, this._rayHit);\n }\n /**\n * Currently active view components.\n */\n get activeViews() {\n const wasm = this._engine.wasm;\n const count = wasm._wl_scene_get_active_views(this._engine.wasm._tempMem, 16);\n const views = [];\n const viewTypeIndex = wasm._typeIndexFor('view');\n for (let i = 0; i < count; ++i) {\n views.push(new ViewComponent(this._engine, viewTypeIndex, this._engine.wasm._tempMemInt[i]));\n }\n return views;\n }\n /**\n * Cast a ray through the scene and find intersecting objects.\n *\n * The resulting ray hit will contain up to **4** closest ray hits,\n * sorted by increasing distance.\n *\n * @param o Ray origin.\n * @param d Ray direction.\n * @param group Collision group to filter by: only objects that are\n * part of given group are considered for raycast.\n *\n * @returns The scene cached {@link RayHit} instance.\n * @note The returned object is owned by the Scene instance\n * will be reused with the next {@link Scene#rayCast} call.\n */\n rayCast(o, d, group) {\n this._engine.wasm._wl_scene_ray_cast(o[0], o[1], o[2], d[0], d[1], d[2], group, this._rayHit);\n return this._hit;\n }\n /**\n * Add an object to the scene.\n *\n * @param parent Parent object or `null`.\n * @returns A newly created object.\n */\n addObject(parent = null) {\n const parentId = parent ? parent.objectId : 0;\n const objectId = this._engine.wasm._wl_scene_add_object(parentId);\n return this._engine.wrapObject(objectId);\n }\n /**\n * Batch-add objects to the scene.\n *\n * Will provide better performance for adding multiple objects (e.g. > 16)\n * than calling {@link Scene#addObject} repeatedly in a loop.\n *\n * By providing upfront information of how many objects will be required,\n * the engine is able to batch-allocate the required memory rather than\n * convervatively grow the memory in small steps.\n *\n * **Experimental:** This API might change in upcoming versions.\n *\n * @param count Number of objects to add.\n * @param parent Parent object or `null`, default `null`.\n * @param componentCountHint Hint for how many components in total will\n * be added to the created objects afterwards, default `0`.\n * @returns Newly created objects\n */\n addObjects(count, parent = null, componentCountHint = 0) {\n const parentId = parent ? parent.objectId : 0;\n this._engine.wasm.requireTempMem(count * 2);\n const actualCount = this._engine.wasm._wl_scene_add_objects(parentId, count, componentCountHint || 0, this._engine.wasm._tempMem, this._engine.wasm._tempMemSize >> 1);\n const ids = this._engine.wasm._tempMemUint16.subarray(0, actualCount);\n const wrapper = this._engine.wrapObject.bind(this._engine);\n const objects = Array.from(ids, wrapper);\n return objects;\n }\n /**\n * Pre-allocate memory for a given amount of objects and components.\n *\n * Will provide better performance for adding objects later with {@link Scene#addObject}\n * and {@link Scene#addObjects}.\n *\n * By providing upfront information of how many objects will be required,\n * the engine is able to batch-allocate the required memory rather than\n * conservatively grow the memory in small steps.\n *\n * **Experimental:** This API might change in upcoming versions.\n *\n * @param objectCount Number of objects to add.\n * @param componentCountPerType Amount of components to\n * allocate for {@link Object3D.addComponent}, e.g. `{mesh: 100, collision: 200, \"my-comp\": 100}`.\n * @since 0.8.10\n */\n reserveObjects(objectCount, componentCountPerType) {\n const wasm = this._engine.wasm;\n componentCountPerType = componentCountPerType || {};\n const jsManagerIndex = wasm._typeIndexFor('js');\n let countsPerTypeIndex = wasm._tempMemInt.subarray();\n countsPerTypeIndex.fill(0);\n for (const e of Object.entries(componentCountPerType)) {\n const typeIndex = wasm._typeIndexFor(e[0]);\n countsPerTypeIndex[typeIndex < 0 ? jsManagerIndex : typeIndex] += e[1];\n }\n wasm._wl_scene_reserve_objects(objectCount, wasm._tempMem);\n }\n /**\n * Set the background clear color.\n *\n * @param color new clear color (RGBA).\n * @since 0.8.5\n */\n set clearColor(color) {\n this._engine.wasm._wl_scene_set_clearColor(color[0], color[1], color[2], color[3]);\n }\n /**\n * Set whether to clear the color framebuffer before drawing.\n *\n * This function is useful if an external framework (e.g. an AR tracking\n * framework) is responsible for drawing a camera frame before Wonderland\n * Engine draws the scene on top of it.\n *\n * @param b Whether to enable color clear.\n * @since 0.9.4\n */\n set colorClearEnabled(b) {\n this._engine.wasm._wl_scene_enableColorClear(b);\n }\n /** Hosting engine instance. */\n get engine() {\n return this._engine;\n }\n /**\n * Load a scene file (.bin).\n *\n * Will replace the currently active scene with the one loaded\n * from given file. It is assumed that JavaScript components required by\n * the new scene were registered in advance.\n *\n * Once the scene is loaded successfully and initialized,\n * {@link WonderlandEngine.onSceneLoaded} is notified.\n *\n * @param filename Path to the .bin file.\n * @returns Promise that resolves when the scene was loaded.\n */\n async load(filename) {\n const wasm = this._engine.wasm;\n const buffer = await fetchWithProgress(filename, (bytes, size) => {\n console.log(`Scene downloading: ${bytes} / ${size}`);\n wasm._wl_set_loading_screen_progress(bytes / size);\n });\n const size = buffer.byteLength;\n console.log(`Scene download of ${size} bytes successful.`);\n const ptr = wasm._malloc(size);\n new Uint8Array(wasm.HEAPU8.buffer, ptr, size).set(new Uint8Array(buffer));\n try {\n wasm._wl_load_scene_bin(ptr, size, wasm.tempUTF8(filename));\n }\n finally {\n /* Catch calls to abort(), e.g. via asserts */\n wasm._free(ptr);\n }\n const binQueue = wasm._queuedBinFiles;\n if (binQueue.length > 0) {\n wasm._queuedBinFiles = [];\n await Promise.all(binQueue.map((path) => this.append(path)));\n }\n this._engine.onSceneLoaded.notify();\n }\n /**\n * Append a scene file.\n *\n * Loads and parses the file and its images and appends the result\n * to the currently active scene.\n *\n * Supported formats are streamable Wonderland scene files (.bin) and glTF\n * 3D scenes (.gltf, .glb).\n *\n * ```js\n * WL.scene.append(filename).then(root => {\n * // root contains the loaded scene\n * });\n * ```\n *\n * In case the `loadGltfExtensions` option is set to true, the response\n * will be an object containing both the root of the loaded scene and\n * any glTF extensions found on nodes, meshes and the root of the file.\n *\n * ```js\n * WL.scene.append(filename, { loadGltfExtensions: true }).then(({root, extensions}) => {\n * // root contains the loaded scene\n * // extensions.root contains any extensions at the root of glTF document\n * const rootExtensions = extensions.root;\n * // extensions.mesh and extensions.node contain extensions indexed by Object id\n * const childObject = root.children[0];\n * const meshExtensions = root.meshExtensions[childObject.objectId];\n * const nodeExtensions = root.nodeExtensions[childObject.objectId];\n * // extensions.idMapping contains a mapping from glTF node index to Object id\n * });\n * ```\n *\n * @param file The .bin, .gltf or .glb file to append. Should be a URL or\n * an `ArrayBuffer` with the file content.\n * @param options Additional options for loading.\n * @returns Promise that resolves when the scene was appended.\n */\n async append(file, options) {\n const buffer = isString(file) ? await fetchWithProgress(file) : file;\n const wasm = this._engine.wasm;\n let callback;\n const promise = new Promise((resolve, reject) => {\n callback = wasm.addFunction((objectId, extensionData, extensionDataSize) => {\n if (objectId < 0) {\n reject();\n return;\n }\n const root = objectId ? this._engine.wrapObject(objectId) : null;\n if (extensionData && extensionDataSize) {\n const marshalled = new Uint32Array(wasm.HEAPU32.buffer, extensionData, extensionDataSize / 4);\n const extensions = this._unmarshallGltfExtensions(marshalled);\n resolve({ root, extensions });\n }\n else {\n resolve(root);\n }\n }, 'viii');\n }).finally(() => wasm.removeFunction(callback));\n const size = buffer.byteLength;\n const ptr = wasm._malloc(size);\n const data = new Uint8Array(wasm.HEAPU8.buffer, ptr, size);\n data.set(new Uint8Array(buffer));\n const MAGIC = 'WLEV';\n const isBinFile = data.byteLength > MAGIC.length &&\n data\n .subarray(0, MAGIC.length)\n .every((value, i) => value === MAGIC.charCodeAt(i));\n try {\n if (isBinFile) {\n wasm._wl_append_scene_bin(ptr, size, callback);\n }\n else {\n const loadExtensions = options?.loadGltfExtensions ?? false;\n wasm._wl_append_scene_gltf(ptr, size, loadExtensions, callback);\n }\n }\n catch (e) {\n wasm.removeFunction(callback);\n throw e;\n }\n finally {\n wasm._free(ptr);\n }\n const result = await promise;\n const binQueue = wasm._queuedBinFiles;\n if (isBinFile && binQueue.length > 0) {\n wasm._queuedBinFiles = [];\n await Promise.all(binQueue.map((path) => this.append(path, options)));\n }\n return result;\n }\n /**\n * Unmarshalls the GltfExtensions from an Uint32Array.\n *\n * @param data Array containing the gltf extension data.\n * @returns The extensions stored in an object literal.\n *\n * @hidden\n */\n _unmarshallGltfExtensions(data) {\n /* @todo: This method should be moved in the internal Emscripten library. */\n const extensions = {\n root: {},\n mesh: {},\n node: {},\n idMapping: [],\n };\n let index = 0;\n const readString = () => {\n const strPtr = data[index++];\n const strLen = data[index++];\n return this._engine.wasm.UTF8ViewToString(strPtr, strPtr + strLen);\n };\n const idMappingSize = data[index++];\n const idMapping = new Array(idMappingSize);\n for (let i = 0; i < idMappingSize; ++i) {\n idMapping[i] = data[index++];\n }\n extensions.idMapping = idMapping;\n const meshExtensionsSize = data[index++];\n for (let i = 0; i < meshExtensionsSize; ++i) {\n const objectId = data[index++];\n extensions.mesh[idMapping[objectId]] = JSON.parse(readString());\n }\n const nodeExtensionsSize = data[index++];\n for (let i = 0; i < nodeExtensionsSize; ++i) {\n const objectId = data[index++];\n extensions.node[idMapping[objectId]] = JSON.parse(readString());\n }\n const rootExtensionsStr = readString();\n if (rootExtensionsStr) {\n extensions.root = JSON.parse(rootExtensionsStr);\n }\n return extensions;\n }\n /**\n * Reset the scene.\n *\n * This method deletes all used and allocated objects, and components.\n */\n reset() {\n this._engine.wasm._wl_scene_reset();\n }\n}\n", "import { Texture } from './wonderland.js';\n/**\n * Manage textures.\n *\n * This manager is accessible on the engine instance using {@link WonderlandEngine.textures}.\n *\n * Usage\n *\n * ```js\n * this.engine.load('path/to/texture.png').then((texture) => {\n * console.log('Loaded!');\n * console.log(texture);\n * })\n * ```\n */\nexport class TextureManager {\n /** Wonderland Engine instance. @hidden */\n _engine;\n /** Texture cache. @hidden */\n #cache = [];\n /** @hidden */\n constructor(engine) {\n this._engine = engine;\n }\n /**\n * Retrieve the texture with the given id.\n *\n * @param id The texture identifier.\n * @return The {@link Texture} if found, `null` otherwise.\n */\n get(id) {\n return this.#cache[id] ?? null;\n }\n /**\n * Load an image from URL as {@link Texture}.\n *\n * @param filename URL to load from.\n * @param crossOrigin Cross origin flag for the image object.\n * @returns Loaded texture.\n */\n load(filename, crossOrigin) {\n let image = new Image();\n image.crossOrigin = crossOrigin ?? image.crossOrigin;\n image.src = filename;\n return new Promise((resolve, reject) => {\n image.onload = () => {\n let texture = new Texture(this._engine, image);\n if (!texture.valid) {\n reject('Failed to add image ' +\n image.src +\n ' to texture atlas. Probably incompatible format.');\n }\n resolve(texture);\n };\n image.onerror = function () {\n reject('Failed to load image. Not found or no read access');\n };\n });\n }\n /**\n * Wrap a texture ID using {@link Texture}.\n *\n * @note This method performs caching and will return the same\n * instance on subsequent calls.\n *\n * @param id ID of the texture to create.\n *\n * @returns The texture.\n */\n wrap(id) {\n const texture = this.#cache[id] ?? (this.#cache[id] = new Texture(this._engine, id));\n texture['_id'] = id;\n return texture;\n }\n /** Number of textures allocated in the manager. */\n get allocatedCount() {\n return this.#cache.length;\n }\n /**\n * Number of textures in the manager.\n *\n * @note For performance reasons, avoid calling this method when possible.\n */\n get count() {\n let count = 0;\n for (const tex of this.#cache) {\n if (tex && tex.id >= 0)\n ++count;\n }\n return count;\n }\n /**\n * Set a new texture in the manager cache.\n *\n * @note This api is meant to be used internally.\n *\n * @param texture The texture to add.\n *\n * @hidden\n */\n _set(texture) {\n /* @todo: Destroy texture at previous id? */\n this.#cache[texture.id] = texture;\n }\n /**\n * Destroys the texture.\n *\n * @note This api is meant to be used internally.\n *\n * @param texture The texture to destroy.\n *\n * @hidden\n */\n _destroy(texture) {\n this._engine.wasm._wl_texture_destroy(texture.id);\n const img = texture['_imageIndex'];\n if (img !== null) {\n this._engine.wasm._images[img] = null;\n }\n }\n /**\n * Reset the manager.\n *\n * @note This api is meant to be used internally.\n *\n * @hidden\n */\n _reset() {\n this.#cache.length = 0;\n }\n}\n", "import { CollisionComponent, AnimationComponent, LightComponent, MeshComponent, PhysXComponent, InputComponent, ViewComponent, TextComponent, Object as Object3D, Physics, I18N, } from './wonderland.js';\nimport { Emitter, RetainEmitter } from './utils/event.js';\nimport { isString } from './utils/object.js';\nimport { Scene } from './scene.js';\nimport { TextureManager } from './texture-manager.js';\n/**\n * Main Wonderland Engine instance.\n *\n * Controls the canvas, rendering, and JS <-> WASM communication.\n */\nexport class WonderlandEngine {\n /**\n * {@link Emitter} for WebXR session end events.\n *\n * Usage from a within a component:\n * ```js\n * this.engine.onXRSessionEnd.add(() => console.log(\"XR session ended.\"));\n * ```\n */\n onXRSessionEnd = new Emitter();\n /**\n * {@link Emitter} for WebXR session start events.\n *\n * Usage from a within a component:\n * ```js\n * this.engine.onXRSessionStart.add((session, mode) => console.log(session, mode));\n * ```\n *\n * By default, this emitter is retained and will automatically call any callback added\n * while a session is already started:\n *\n * ```js\n * // XR session is already active.\n * this.engine.onXRSessionStart.add((session, mode) => {\n * console.log(session, mode); // Triggered immediately.\n * });\n * ```\n */\n onXRSessionStart = new RetainEmitter();\n /**\n * {@link Emitter} for canvas / main framebuffer resize events.\n *\n * Usage from a within a component:\n * ```js\n * this.engine.onResize.add(() => {\n * const canvas = this.engine.canvas;\n * console.log(`New Size: ${canvas.width}, ${canvas.height}`);\n * });\n * ```\n *\n * @note The size of the canvas is in physical pixels, and is set via {@link WonderlandEngine.resize}.\n */\n onResize = new Emitter();\n /** Whether AR is supported by the browser. */\n arSupported = false;\n /** Whether VR is supported by the browser. */\n vrSupported = false;\n /**\n * {@link Emitter} for scene loaded events.\n *\n * Listeners get notified when a call to {@link Scene#load()} finishes,\n * which also happens after the main scene has replaced the loading screen.\n *\n * Usage from a within a component:\n * ```js\n * this.engine.onSceneLoaded.add(() => console.log(\"Scene switched!\"));\n * ```\n */\n onSceneLoaded = new Emitter();\n /**\n * Current main scene.\n */\n scene = null;\n /**\n * Access to internationalization.\n */\n i18n = new I18N(this);\n /**\n * WebXR related state, `null` if no XR session is active.\n */\n xr = null;\n /* Component class instances per type to avoid GC */\n _componentCache = {};\n /* Object class instances per type to avoid GC */\n _objectCache = [];\n /**\n * WebAssembly bridge.\n *\n * @hidden\n */\n #wasm;\n /**\n * Physics manager, only available when physx is enabled in the runtime.\n *\n * @hidden\n */\n #physics = null;\n /** Texture manager. @hidden */\n #textures = new TextureManager(this);\n /**\n * Resize observer to track for canvas size changes.\n *\n * @hidden\n */\n #resizeObserver = null;\n /**\n * Create a new engine instance.\n *\n * @param wasm Wasm bridge instance\n * @param loadingScreen Loading screen .bin file data\n *\n * @hidden\n */\n constructor(wasm, loadingScreen) {\n this.#wasm = wasm;\n this.#wasm['_setEngine'](this); /* String lookup to bypass private. */\n this.#wasm._loadingScreen = loadingScreen;\n this._componentCache = {};\n this._objectCache.length = 0;\n this.canvas.addEventListener('webglcontextlost', function (e) {\n console.error('Context lost:');\n console.error(e);\n }, false);\n }\n /**\n * Start the engine if it's not already running.\n *\n * When using the {@link loadRuntime} function, this method is called\n * automatically.\n */\n start() {\n this.wasm._wl_application_start();\n }\n /**\n * Register a custom JavaScript component type.\n *\n * You can register a component directly using a class inheriting from {@link Component}:\n *\n * ```js\n * import { Component, Type } from '@wonderlandengine/api';\n *\n * export class MyComponent extends Component {\n * static TypeName = 'my-component';\n * static Properties = {\n * myParam: {type: Type.Float, default: 42.0},\n * };\n * init() {}\n * start() {}\n * update(dt) {}\n * onActivate() {}\n * onDeactivate() {}\n * onDestroy() {}\n * });\n *\n * // Here, we assume we have an engine already instantiated.\n * // In general, the registration occurs in the `index.js` file in your\n * // final application.\n * engine.registerComponent(MyComponent);\n * ```\n *\n * {@label CLASSES}\n * @param classes Custom component(s) extending {@link Component}.\n *\n * @since 1.0.0\n */\n registerComponent(...classes) {\n for (const arg of classes) {\n this.wasm._registerComponent(arg);\n }\n }\n /**\n * Checks whether the given component is registered or not.\n *\n * @param typeOrClass A string representing the component typename (e.g., `'cursor-component'`),\n * or a component class (e.g., `CursorComponent`).\n * @returns `true` if the component is registered, `false` otherwise.\n */\n isRegistered(typeOrClass) {\n return this.#wasm.isRegistered(isString(typeOrClass) ? typeOrClass : typeOrClass.TypeName);\n }\n /**\n * Resize the canvas and the rendering context.\n *\n * @note The `width` and `height` parameters will be scaled by the\n * `devicePixelRatio` value. By default, the pixel ratio used is\n * [window.devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio).\n *\n * @param width The width, in CSS pixels.\n * @param height The height, in CSS pixels.\n * @param devicePixelRatio The pixel ratio factor.\n */\n resize(width, height, devicePixelRatio = window.devicePixelRatio) {\n width = width * devicePixelRatio;\n height = height * devicePixelRatio;\n this.canvas.width = width;\n this.canvas.height = height;\n this.wasm._wl_application_resize(width, height);\n this.onResize.notify();\n }\n /**\n * Run the next frame.\n *\n * @param fixedDelta The elapsed time between this frame and the previous one.\n *\n * @note The engine automatically schedules next frames. You should only\n * use this method for testing.\n */\n nextFrame(fixedDelta = 0) {\n this.#wasm._wl_nextFrame(fixedDelta);\n }\n /**\n * Request a XR session.\n *\n * @note Please use this call instead of directly calling `navigator.xr.requestSession()`.\n * Wonderland Engine requires to be aware that a session is started, and this\n * is done through this call.\n *\n * @param mode The XR mode.\n * @param features An array of required features, e.g., `['local-floor', 'hit-test']`.\n * @param optionalFeatures An array of optional features, e.g., `['bounded-floor', 'depth-sensing']`.\n * @returns A promise resolving with the `XRSession`, a string error message otherwise.\n */\n requestXRSession(mode, features, optionalFeatures = []) {\n if (!navigator.xr) {\n const isLocalhost = location.hostname === 'localhost' || location.hostname === '127.0.0.1';\n const missingHTTPS = location.protocol !== 'https:' && !isLocalhost;\n return Promise.reject(missingHTTPS\n ? 'WebXR is only supported with HTTPS or on localhost!'\n : 'WebXR unsupported in this browser.');\n }\n return this.#wasm.webxr_requestSession(mode, features, optionalFeatures);\n }\n /**\n * Wrap an object ID using {@link Object}.\n *\n * @note This method performs caching and will return the same\n * instance on subsequent calls.\n *\n * @param objectId ID of the object to create.\n *\n * @returns The object\n */\n wrapObject(objectId) {\n const cache = this._objectCache;\n const o = cache[objectId] || (cache[objectId] = new Object3D(this, objectId));\n o['_objectId'] = objectId;\n return o;\n }\n /* Public Getters & Setter */\n /**\n * WebAssembly bridge.\n *\n * @note Use with care. This object is used to communicate\n * with the WebAssembly code throughout the api.\n *\n * @hidden\n */\n get wasm() {\n return this.#wasm;\n }\n /** Canvas element that Wonderland Engine renders to. */\n get canvas() {\n return this.#wasm.canvas;\n }\n /**\n * Current WebXR session or `null` if no session active.\n *\n * @deprecated Use {@link XR.session} on the {@link xr}\n * object instead.\n */\n get xrSession() {\n return this.xr?.session ?? null;\n }\n /**\n * Current WebXR frame or `null` if no session active.\n *\n * @deprecated Use {@link XR.frame} on the {@link xr}\n * object instead.\n */\n get xrFrame() {\n return this.xr?.frame ?? null;\n }\n /**\n * Current WebXR base layer or `null` if no session active.\n *\n * @deprecated Use {@link XR.baseLayer} on the {@link xr}\n * object instead.\n */\n get xrBaseLayer() {\n return this.xr?.baseLayer ?? null;\n }\n /**\n * Current WebXR framebuffer or `null` if no session active.\n *\n * @deprecated Use {@link XR.framebuffers} on the\n * {@link xr} object instead.\n */\n get xrFramebuffer() {\n return this.xr?.framebuffers[0] ?? null;\n }\n /** Framebuffer scale factor. */\n get xrFramebufferScaleFactor() {\n return this.#wasm.webxr_framebufferScaleFactor;\n }\n set xrFramebufferScaleFactor(value) {\n this.#wasm.webxr_framebufferScaleFactor = value;\n }\n /** Physics manager, only available when physx is enabled in the runtime. */\n get physics() {\n return this.#physics;\n }\n /**\n * Texture managger.\n *\n * Use this to load or programmatically create new textures at runtime.\n */\n get textures() {\n return this.#textures;\n }\n /*\n * Enable or disable the mechanism to automatically resize the canvas.\n *\n * Internally, the engine uses a [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n * Changing the canvas css will thus automatically be tracked by the engine.\n */\n set autoResizeCanvas(flag) {\n const state = !!this.#resizeObserver;\n if (state === flag)\n return;\n if (!flag) {\n this.#resizeObserver?.unobserve(this.canvas);\n this.#resizeObserver = null;\n return;\n }\n this.#resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === this.canvas) {\n this.resize(entry.contentRect.width, entry.contentRect.height);\n }\n }\n });\n this.#resizeObserver.observe(this.canvas);\n }\n /** `true` if the canvas is automatically resized by the engine. */\n get autoResizeCanvas() {\n return this.#resizeObserver !== null;\n }\n /** Retrieves the runtime version. */\n get runtimeVersion() {\n const wasm = this.#wasm;\n const v = wasm._wl_application_version(wasm._tempMem);\n return {\n major: wasm._tempMemUint16[0],\n minor: wasm._tempMemUint16[1],\n patch: wasm._tempMemUint16[2],\n rc: wasm._tempMemUint16[3],\n };\n }\n /* Internal-Only Methods */\n /**\n * Initialize the engine.\n *\n * @note Should be called after the WebAssembly is fully loaded.\n *\n * @hidden\n */\n _init() {\n this.scene = new Scene(this);\n /* Setup the error handler. This is used to to manage native errors. */\n this.#wasm._wl_set_error_callback(this.#wasm.addFunction((messagePtr) => {\n throw new Error(this.#wasm.UTF8ToString(messagePtr));\n }, 'vi'));\n this.#physics = null;\n if (this.#wasm.withPhysX) {\n /* Setup the physics callback. */\n const physics = new Physics(this);\n this.#wasm._wl_physx_set_collision_callback(this.#wasm.addFunction((a, index, type, b) => {\n const callback = physics._callbacks[a][index];\n const component = new PhysXComponent(this, this.wasm._typeIndexFor('physx'), b);\n callback(type, component);\n }, 'viiii'));\n this.#physics = physics;\n }\n this.resize(this.canvas.clientWidth, this.canvas.clientHeight);\n }\n /**\n * Reset the runtime state, including:\n * - Component cache\n * - Images\n * - Callbacks\n *\n * @note This api is meant to be used internally.\n *\n * @hidden\n */\n _reset() {\n this._componentCache = {};\n this._objectCache.length = 0;\n this.#textures._reset();\n this.scene.reset();\n this.wasm.reset();\n }\n /**\n * Retrieves a component instance if it exists, or create and cache\n * a new one.\n *\n * @note This api is meant to be used internally. Please have a look at\n * {@link Object3D.addComponent} instead.\n *\n * @param type component type name\n * @param componentType Component manager index\n * @param componentId Component id in the manager\n *\n * @returns JavaScript instance wrapping the native component\n *\n * @hidden\n */\n _wrapComponent(type, componentType, componentId) {\n if (componentId < 0)\n return null;\n /* @todo: extremely slow in JS to do that... Better to use a Map or allocate the array. */\n const c = this._componentCache[componentType] ||\n (this._componentCache[componentType] = []);\n if (c[componentId]) {\n return c[componentId];\n }\n let component;\n if (type == 'collision') {\n component = new CollisionComponent(this, componentType, componentId);\n }\n else if (type == 'text') {\n component = new TextComponent(this, componentType, componentId);\n }\n else if (type == 'view') {\n component = new ViewComponent(this, componentType, componentId);\n }\n else if (type == 'mesh') {\n component = new MeshComponent(this, componentType, componentId);\n }\n else if (type == 'input') {\n component = new InputComponent(this, componentType, componentId);\n }\n else if (type == 'light') {\n component = new LightComponent(this, componentType, componentId);\n }\n else if (type == 'animation') {\n component = new AnimationComponent(this, componentType, componentId);\n }\n else if (type == 'physx') {\n component = new PhysXComponent(this, componentType, componentId);\n }\n else {\n const typeIndex = this.wasm._componentTypeIndices[type];\n const constructor = this.wasm._componentTypes[typeIndex];\n component = new constructor(this);\n }\n /* Sets the manager and identifier from the outside, to\n * simplify the user's constructor. */\n /* @ts-ignore */\n component._engine = this;\n component._manager = componentType;\n component._id = componentId;\n c[componentId] = component;\n return component;\n }\n}\n", "import { RetainEmitter } from './index.js';\nimport { Type } from './property.js';\nimport { Animation, Component, Material, Mesh, Skin, XR, } from './wonderland.js';\n/**\n * Default component parameter value per type.\n */\nconst _componentDefaults = new Map([\n [Type.Bool, false],\n [Type.Int, 0],\n [Type.Float, 0.0],\n [Type.String, ''],\n [Type.Enum, undefined],\n [Type.Object, null],\n [Type.Mesh, null],\n [Type.Texture, null],\n [Type.Material, null],\n [Type.Animation, null],\n [Type.Skin, null],\n [Type.Color, [0.0, 0.0, 0.0, 1.0]],\n]);\n/**\n * Setup the defaults value of the properties on a given\n * component class.\n *\n * @param ctor The component class\n */\nfunction _setupDefaults(ctor) {\n for (const name in ctor.Properties) {\n const p = ctor.Properties[name];\n if (p.type === Type.Enum) {\n /* Enum default can be a string or an index. Convert to and/or\n * sanity-check the index. */\n if (p.values?.length) {\n /* Don't try to look up the default if the user specified a\n * number or we already converted to one. */\n if (typeof p.default !== 'number') {\n /* If undefined, missing element or wrong type this returns\n * -1 which becomes 0 below. This matches editor behavior. */\n p.default = p.values.indexOf(p.default);\n }\n if (p.default < 0 || p.default >= p.values.length) {\n p.default = 0;\n }\n }\n else {\n /* There's no index value that makes sense */\n p.default = undefined;\n }\n }\n else {\n p.default = p.default ?? _componentDefaults.get(p.type);\n }\n ctor.prototype[name] = p.default;\n }\n}\n/**\n * Low-level wrapper to interact with the WebAssembly code.\n *\n * @hidden\n */\nexport class WASM {\n /**\n * Emscripten worker field.\n *\n * @note This api is meant to be used internally.\n */\n worker = '';\n /**\n * Emscripten wasm field.\n *\n * @note This api is meant to be used internally.\n */\n wasm = null;\n /**\n * Emscripten canvas.\n *\n * @note This api is meant to be used internally.\n */\n canvas = null;\n /** Current WebXR */\n /**\n * Emscripten WebXR session.\n *\n * @note This api is meant to be used internally.\n */\n webxr_session = null;\n /**\n * Emscripten WebXR request session callback.\n *\n * @note This api is meant to be used internally.\n */\n webxr_requestSession = null;\n /**\n * Emscripten WebXR frame.\n *\n * @note This api is meant to be used internally.\n */\n webxr_frame = null;\n /**\n * Emscripten current WebXR reference space.\n *\n * @note This api is meant to be used internally.\n */\n webxr_refSpace = null;\n /**\n * Emscripten WebXR reference spaces.\n *\n * @note This api is meant to be used internally.\n */\n webxr_refSpaces = null;\n /**\n * Emscripten WebXR current reference space type.\n *\n * @note This api is meant to be used internally.\n */\n webxr_refSpaceType = null;\n /**\n * Emscripten WebXR GL projection layer.\n *\n * @note This api is meant to be used internally.\n */\n webxr_baseLayer = null;\n /**\n * Emscripten WebXR framebuffer scale factor.\n *\n * @note This api is meant to be used internally.\n */\n webxr_framebufferScaleFactor = 1.0;\n /**\n * Emscripten WebXR framebuffer(s).\n *\n * @note This api is meant to be used internally.\n */\n /* webxr_fbo will not get overwritten if we are rendering to the\n * default framebuffer, e.g., when using WebXR emulator. */\n webxr_fbo = 0;\n /**\n * Convert a WASM memory view to a JavaScript string.\n *\n * @param ptr Pointer start\n * @param ptrEnd Pointer end\n * @returns JavaScript string\n */\n UTF8ViewToString;\n /** If `true`, logs will not spam the console on error. */\n _deactivate_component_on_error = false;\n /** Temporary memory pointer. */\n _tempMem = null;\n /** Temporary memory size. */\n _tempMemSize = 0;\n /** Temporary float memory view. */\n _tempMemFloat = null;\n /** Temporary int memory view. */\n _tempMemInt = null;\n /** Temporary uint8 memory view. */\n _tempMemUint8 = null;\n /** Temporary uint32 memory view. */\n _tempMemUint32 = null;\n /** Temporary uint16 memory view. */\n _tempMemUint16 = null;\n /** Loading screen .bin file data */\n _loadingScreen = null;\n /** List of callbacks triggered when the scene is loaded. */\n _sceneLoadedCallback = [];\n /**\n * Material definition cache. Each pipeline has its own\n * associated material definition.\n */\n _materialDefinitions = [];\n /** Image cache. */\n _images = [];\n /** Component instances. */\n _components = [];\n /** Component Type info. */\n _componentTypes = [];\n /** Index per component type name. */\n _componentTypeIndices = {};\n /** Wonderland engine instance. */\n _engine = null;\n /**\n * `true` if this runtime is using physx.\n *\n * @note This api is meant to be used internally.\n */\n _withPhysX = false;\n /** Decoder for UTF8 `ArrayBuffer` to JavaScript string. */\n _utf8Decoder = new TextDecoder('utf8');\n /** List of .bin files to delay-load. */\n _queuedBinFiles = [];\n /**\n * Create a new instance of the WebAssembly <> API bridge.\n *\n * @param threads `true` if the runtime used has threads support\n */\n constructor(threads) {\n if (threads) {\n this.UTF8ViewToString = (s, e) => {\n if (!s)\n return '';\n return this._utf8Decoder.decode(this.HEAPU8.slice(s, e));\n };\n return;\n }\n this.UTF8ViewToString = (s, e) => {\n if (!s)\n return '';\n return this._utf8Decoder.decode(this.HEAPU8.subarray(s, e));\n };\n }\n /**\n * Reset the cache of the library\n *\n * @note Should only be called when tearing down the runtime.\n */\n reset() {\n this._materialDefinitions = [];\n this._images = [];\n this._components = [];\n this._componentTypes = [];\n this._componentTypeIndices = {};\n }\n /**\n * Checks whether the given component is registered or not.\n *\n * @param ctor A string representing the component typename (e.g., `'cursor-component'`).\n * @returns `true` if the component is registered, `false` otherwise.\n */\n isRegistered(type) {\n return type in this._componentTypeIndices;\n }\n /**\n * Register a legacy component in this Emscripten instance.\n *\n * @note This api is meant to be used internally.\n *\n * @param typeName The name of the component.\n * @param params An object containing the parameters (properties).\n * @param object The object's prototype.\n * @returns The registration index\n */\n _registerComponentLegacy(typeName, params, object) {\n const ctor = class CustomComponent extends Component {\n };\n ctor.TypeName = typeName;\n ctor.Properties = params;\n Object.assign(ctor.prototype, object);\n return this._registerComponent(ctor);\n }\n /**\n * Register a class component in this Emscripten instance.\n *\n * @note This api is meant to be used internally.\n *\n * @param ctor The class to register.\n * @returns The registration index.\n */\n _registerComponent(ctor) {\n if (!ctor.TypeName)\n throw new Error('no name provided for component.');\n if (!ctor.prototype._triggerInit) {\n throw new Error(`registerComponent(): Component ${ctor.TypeName} must extend Component`);\n }\n // TODO: 'Dependencies' is hard-deprecated, remove at 1.1\n const dependencies = ctor.Dependencies;\n if (dependencies) {\n for (const dependency of dependencies) {\n /* For dependencies, we skip potential over-registration. */\n if (!this.isRegistered(dependency.TypeName)) {\n this._registerComponent(dependency);\n }\n }\n }\n _setupDefaults(ctor);\n const typeIndex = ctor.TypeName in this._componentTypeIndices\n ? this._componentTypeIndices[ctor.TypeName]\n : this._componentTypes.length;\n this._componentTypes[typeIndex] = ctor;\n this._componentTypeIndices[ctor.TypeName] = typeIndex;\n console.log('Registered component', ctor.TypeName, `(class ${ctor.name})`, 'with index', typeIndex);\n if (ctor.onRegister)\n ctor.onRegister(this._engine);\n return typeIndex;\n }\n /**\n * Allocate the requested amount of temporary memory\n * in this WASM instance.\n *\n * @param size The number of bytes to allocate\n */\n allocateTempMemory(size) {\n console.log('Allocating temp mem:', size);\n this._tempMemSize = size;\n if (this._tempMem)\n this._free(this._tempMem);\n this._tempMem = this._malloc(this._tempMemSize);\n this.updateTempMemory();\n }\n /**\n * @todo: Delete this and only keep `allocateTempMemory`\n *\n * @param size Number of bytes to allocate\n */\n requireTempMem(size) {\n if (this._tempMemSize >= size)\n return;\n /* Grow in 1kb increments */\n this.allocateTempMemory(Math.ceil(size / 1024) * 1024);\n }\n /**\n * Update the temporary memory views. This must be called whenever the\n * temporary memory address changes.\n *\n * @note This api is meant to be used internally.\n */\n updateTempMemory() {\n this._tempMemFloat = new Float32Array(this.HEAP8.buffer, this._tempMem, this._tempMemSize >> 2);\n this._tempMemInt = new Int32Array(this.HEAP8.buffer, this._tempMem, this._tempMemSize >> 2);\n this._tempMemUint32 = new Uint32Array(this.HEAP8.buffer, this._tempMem, this._tempMemSize >> 2);\n this._tempMemUint16 = new Uint16Array(this.HEAP8.buffer, this._tempMem, this._tempMemSize >> 1);\n this._tempMemUint8 = new Uint8Array(this.HEAP8.buffer, this._tempMem, this._tempMemSize);\n }\n /**\n * Returns a uint8 buffer view on temporary WASM memory.\n *\n * **Note**: this method might allocate if the requested memory is bigger\n * than the current temporary memory allocated.\n *\n * @param count The number of **elements** required\n * @returns A {@link TypedArray} over the WASM memory\n */\n getTempBufferU8(count) {\n this.requireTempMem(count);\n return this._tempMemUint8;\n }\n /**\n * Returns a uint16 buffer view on temporary WASM memory.\n *\n * **Note**: this method might allocate if the requested memory is bigger\n * than the current temporary memory allocated.\n *\n * @param count The number of **elements** required\n * @returns A {@link TypedArray} over the WASM memory\n */\n getTempBufferU16(count) {\n this.requireTempMem(count * 2);\n return this._tempMemUint16;\n }\n /**\n * Returns a uint32 buffer view on temporary WASM memory.\n *\n * **Note**: this method might allocate if the requested memory is bigger\n * than the current temporary memory allocated.\n *\n * @param count The number of **elements** required.\n * @returns A {@link TypedArray} over the WASM memory.\n */\n getTempBufferU32(count) {\n this.requireTempMem(count * 4);\n return this._tempMemUint32;\n }\n /**\n * Returns a int32 buffer view on temporary WASM memory.\n *\n * **Note**: this method might allocate if the requested memory is bigger\n * than the current temporary memory allocated.\n *\n * @param count The number of **elements** required.\n * @returns A {@link TypedArray} over the WASM memory.\n */\n getTempBufferI32(count) {\n this.requireTempMem(count * 4);\n return this._tempMemInt;\n }\n /**\n * Returns a float32 buffer view on temporary WASM memory.\n *\n * **Note**: this method might allocate if the requested memory is bigger\n * than the current temporary memory allocated.\n *\n * @param count The number of **elements** required.\n * @returns A {@link TypedArray} over the WASM memory.\n */\n getTempBufferF32(count) {\n this.requireTempMem(count * 4);\n return this._tempMemFloat;\n }\n /**\n * Copy the string into temporary WASM memory and retrieve the pointer.\n *\n * @note This method will compute the strlen and append a `\\0`.\n *\n * @note The result should be used **directly** otherwise it might get\n * overridden by any next call modifying the temporary memory.\n *\n * @param str The string to write to temporary memory\n * @return The temporary pointer onto the WASM memory\n */\n tempUTF8(str) {\n const strLen = this.lengthBytesUTF8(str) + 1;\n this.requireTempMem(strLen);\n this.stringToUTF8(str, this._tempMem, strLen);\n return this._tempMem;\n }\n /**\n * Return the index of the component type.\n *\n * @note This method uses malloc and copies the string\n * to avoid overwriting caller's temporary data.\n *\n * @param type The type\n * @return The component type index\n */\n _typeIndexFor(type) {\n const lengthBytes = this.lengthBytesUTF8(type) + 1;\n const mem = this._malloc(lengthBytes);\n this.stringToUTF8(type, mem, lengthBytes);\n const componentType = this._wl_get_component_manager_index(mem);\n this._free(mem);\n return componentType;\n }\n /**\n * Return the name of component type stored at the given index.\n *\n * @param typeIndex The type index\n * @return The name as a string\n */\n _typeNameFor(typeIndex) {\n return this.UTF8ToString(this._wl_component_manager_name(typeIndex));\n }\n /**\n * Returns `true` if the runtime supports physx or not.\n */\n get withPhysX() {\n return this._withPhysX;\n }\n /**\n * Set the engine instance holding this bridge.\n *\n * @note This api is meant to be used internally.\n *\n * @param engine The engine instance.\n */\n _setEngine(engine) {\n this._engine = engine;\n }\n /* WebAssembly to JS call bridge. */\n _wljs_xr_session_start(mode) {\n if (this._engine.xr === null) {\n this._engine.xr = new XR(this, mode);\n this._engine.onXRSessionStart.notify(this.webxr_session, mode);\n }\n }\n _wljs_xr_session_end() {\n const startEmitter = this._engine.onXRSessionStart;\n if (startEmitter instanceof RetainEmitter)\n startEmitter.reset();\n this._engine.onXRSessionEnd.notify();\n this._engine.xr = null;\n }\n _wljs_xr_disable() {\n /* @todo This could directly be fully handled in JS. */\n this._engine.arSupported = false;\n this._engine.vrSupported = false;\n }\n _wljs_allocate(numComponents) {\n this._components = new Array(numComponents);\n }\n _wljs_init(withPhysX) {\n this._withPhysX = withPhysX;\n /* Target memory for JS API functions that return arrays */\n this.allocateTempMemory(1024);\n }\n _wljs_reallocate(numComponents) {\n if (numComponents > this._components.length) {\n this._components.length = numComponents;\n }\n }\n _wljs_scene_add_material_definition(definitionId) {\n const definition = new Map();\n /* Cache material definition for faster read/write */\n const nbParams = this._wl_material_definition_get_count(definitionId);\n for (let i = 0; i < nbParams; ++i) {\n const name = this.UTF8ToString(this._wl_material_definition_get_param_name(definitionId, i));\n const t = this._wl_material_definition_get_param_type(definitionId, i);\n definition.set(name, {\n index: i,\n type: {\n type: t & 0xff,\n componentCount: (t >> 8) & 0xff,\n metaType: (t >> 16) & 0xff,\n },\n });\n }\n this._materialDefinitions[definitionId] = definition;\n }\n _wljs_set_component_param_bool(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] = v !== 0;\n }\n _wljs_set_component_param_int(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] = v;\n }\n _wljs_set_component_param_float(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] = v;\n }\n _wljs_set_component_param_string(c, p, pe, v, ve) {\n const param = this.UTF8ViewToString(p, pe);\n const value = this.UTF8ViewToString(v, ve);\n this._components[c][param] = value;\n }\n _wljs_set_component_param_color(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] = new Float32Array([0, 8, 16, 24].map((s) => ((v >>> s) & 0xff) / 255.0));\n }\n _wljs_set_component_param_object(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] =\n v > 0 ? this._engine.wrapObject(v) : null;\n }\n _wljs_set_component_param_mesh(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] =\n v > 0 ? new Mesh(this._engine, v) : null;\n }\n _wljs_set_component_param_texture(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] =\n v > 0 ? this._engine.textures.wrap(v) : null;\n }\n _wljs_set_component_param_material(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] =\n v > 0 ? new Material(this._engine, v) : null;\n }\n _wljs_set_component_param_animation(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] =\n v > 0 ? new Animation(this._engine, v) : null;\n }\n _wljs_set_component_param_skin(c, p, pe, v) {\n const param = this.UTF8ViewToString(p, pe);\n this._components[c][param] =\n v > 0 ? new Skin(this._engine, v) : null;\n }\n _wljs_get_component_type_index(namePtr, nameEndPtr) {\n return this._componentTypeIndices[this.UTF8ViewToString(namePtr, nameEndPtr)];\n }\n _wljs_component_create(jsManagerIndex, index, id, type, object) {\n const ctor = this._componentTypes[type];\n const component = new ctor().reset();\n /* Sets the manager and identifier from the outside, to simplify the user's constructor. */\n /* @ts-ignore */\n component._engine = this._engine;\n component._manager = jsManagerIndex;\n component._id = id;\n component._object = this._engine.wrapObject(object);\n this._components[index] = component;\n return component;\n }\n _wljs_component_init(component) {\n const c = this._components[component];\n c._triggerInit();\n }\n _wljs_component_update(component, dt) {\n const c = this._components[component];\n if (!c) {\n console.warn('WL: component was undefined:', component);\n this._components[component] = new Component(this._engine);\n return;\n }\n c._triggerUpdate(dt);\n }\n _wljs_component_onActivate(component) {\n const c = this._components[component];\n if (c)\n c._triggerOnActivate();\n }\n _wljs_component_onDeactivate(component) {\n const c = this._components[component];\n c._triggerOnDeactivate();\n }\n _wljs_component_onDestroy(component) {\n const c = this._components[component];\n c._triggerOnDestroy();\n }\n _wljs_swap(a, b) {\n const componentA = this._components[a];\n this._components[a] = this._components[b];\n this._components[b] = componentA;\n }\n /* JS to WebAssembly bridge. */\n HEAP8 = null;\n HEAPU8 = null;\n HEAPU16 = null;\n HEAP16 = null;\n HEAPU32 = null;\n HEAP32 = null;\n HEAPF32 = null;\n HEAPF64 = null;\n GL = null;\n assert = null;\n _free = null;\n _malloc = null;\n lengthBytesUTF8 = null;\n stringToUTF8 = null;\n UTF8ToString = null;\n addFunction = null;\n removeFunction = null;\n _wl_set_error_callback = null;\n _wl_application_version = null;\n _wl_application_start = null;\n _wl_application_resize = null;\n _wl_nextUpdate = null;\n _wl_nextFrame = null;\n _wl_renderer_set_mesh_layout = null;\n _wl_scene_get_active_views = null;\n _wl_scene_ray_cast = null;\n _wl_scene_add_object = null;\n _wl_scene_add_objects = null;\n _wl_scene_reserve_objects = null;\n _wl_scene_set_clearColor = null;\n _wl_scene_enableColorClear = null;\n _wl_set_loading_screen_progress = null;\n _wl_load_scene_bin = null;\n _wl_append_scene_bin = null;\n _wl_append_scene_gltf = null;\n _wl_scene_reset = null;\n _wl_component_get_object = null;\n _wl_component_setActive = null;\n _wl_component_isActive = null;\n _wl_component_remove = null;\n _wl_collision_component_get_collider = null;\n _wl_collision_component_set_collider = null;\n _wl_collision_component_get_extents = null;\n _wl_collision_component_get_group = null;\n _wl_collision_component_set_group = null;\n _wl_collision_component_query_overlaps = null;\n _wl_text_component_get_horizontal_alignment = null;\n _wl_text_component_set_horizontal_alignment = null;\n _wl_text_component_get_vertical_alignment = null;\n _wl_text_component_set_vertical_alignment = null;\n _wl_text_component_get_character_spacing = null;\n _wl_text_component_set_character_spacing = null;\n _wl_text_component_get_line_spacing = null;\n _wl_text_component_set_line_spacing = null;\n _wl_text_component_get_effect = null;\n _wl_text_component_set_effect = null;\n _wl_text_component_get_text = null;\n _wl_text_component_set_text = null;\n _wl_text_component_set_material = null;\n _wl_text_component_get_material = null;\n _wl_view_component_get_projection_matrix = null;\n _wl_view_component_get_near = null;\n _wl_view_component_set_near = null;\n _wl_view_component_get_far = null;\n _wl_view_component_set_far = null;\n _wl_view_component_get_fov = null;\n _wl_view_component_set_fov = null;\n _wl_input_component_get_type = null;\n _wl_input_component_set_type = null;\n _wl_light_component_get_color = null;\n _wl_light_component_get_type = null;\n _wl_light_component_set_type = null;\n _wl_light_component_get_intensity = null;\n _wl_light_component_set_intensity = null;\n _wl_light_component_get_outerAngle = null;\n _wl_light_component_set_outerAngle = null;\n _wl_light_component_get_innerAngle = null;\n _wl_light_component_set_innerAngle = null;\n _wl_light_component_get_shadows = null;\n _wl_light_component_set_shadows = null;\n _wl_light_component_get_shadowRange = null;\n _wl_light_component_set_shadowRange = null;\n _wl_light_component_get_shadowBias = null;\n _wl_light_component_set_shadowBias = null;\n _wl_light_component_get_shadowNormalBias = null;\n _wl_light_component_set_shadowNormalBias = null;\n _wl_light_component_get_shadowTexelSize = null;\n _wl_light_component_set_shadowTexelSize = null;\n _wl_light_component_get_cascadeCount = null;\n _wl_light_component_set_cascadeCount = null;\n _wl_animation_component_get_animation = null;\n _wl_animation_component_set_animation = null;\n _wl_animation_component_get_playCount = null;\n _wl_animation_component_set_playCount = null;\n _wl_animation_component_get_speed = null;\n _wl_animation_component_set_speed = null;\n _wl_animation_component_play = null;\n _wl_animation_component_stop = null;\n _wl_animation_component_pause = null;\n _wl_animation_component_state = null;\n _wl_mesh_component_get_material = null;\n _wl_mesh_component_set_material = null;\n _wl_mesh_component_get_mesh = null;\n _wl_mesh_component_set_mesh = null;\n _wl_mesh_component_get_skin = null;\n _wl_mesh_component_set_skin = null;\n _wl_physx_component_get_static = null;\n _wl_physx_component_set_static = null;\n _wl_physx_component_get_kinematic = null;\n _wl_physx_component_set_kinematic = null;\n _wl_physx_component_get_gravity = null;\n _wl_physx_component_set_gravity = null;\n _wl_physx_component_get_simulate = null;\n _wl_physx_component_set_simulate = null;\n _wl_physx_component_get_allowSimulation = null;\n _wl_physx_component_set_allowSimulation = null;\n _wl_physx_component_get_allowQuery = null;\n _wl_physx_component_set_allowQuery = null;\n _wl_physx_component_get_trigger = null;\n _wl_physx_component_set_trigger = null;\n _wl_physx_component_get_shape = null;\n _wl_physx_component_set_shape = null;\n _wl_physx_component_get_shape_data = null;\n _wl_physx_component_set_shape_data = null;\n _wl_physx_component_get_extents = null;\n _wl_physx_component_get_staticFriction = null;\n _wl_physx_component_set_staticFriction = null;\n _wl_physx_component_get_dynamicFriction = null;\n _wl_physx_component_set_dynamicFriction = null;\n _wl_physx_component_get_bounciness = null;\n _wl_physx_component_set_bounciness = null;\n _wl_physx_component_get_linearDamping = null;\n _wl_physx_component_set_linearDamping = null;\n _wl_physx_component_get_angularDamping = null;\n _wl_physx_component_set_angularDamping = null;\n _wl_physx_component_get_linearVelocity = null;\n _wl_physx_component_set_linearVelocity = null;\n _wl_physx_component_get_angularVelocity = null;\n _wl_physx_component_set_angularVelocity = null;\n _wl_physx_component_get_groupsMask = null;\n _wl_physx_component_set_groupsMask = null;\n _wl_physx_component_get_blocksMask = null;\n _wl_physx_component_set_blocksMask = null;\n _wl_physx_component_get_linearLockAxis = null;\n _wl_physx_component_set_linearLockAxis = null;\n _wl_physx_component_get_angularLockAxis = null;\n _wl_physx_component_set_angularLockAxis = null;\n _wl_physx_component_get_mass = null;\n _wl_physx_component_set_mass = null;\n _wl_physx_component_set_massSpaceInertiaTensor = null;\n _wl_physx_component_addForce = null;\n _wl_physx_component_addForceAt = null;\n _wl_physx_component_addTorque = null;\n _wl_physx_component_addCallback = null;\n _wl_physx_component_removeCallback = null;\n _wl_physx_update_global_pose = null;\n _wl_physx_ray_cast = null;\n _wl_physx_set_collision_callback = null;\n _wl_mesh_create = null;\n _wl_mesh_get_vertexData = null;\n _wl_mesh_get_vertexCount = null;\n _wl_mesh_get_indexData = null;\n _wl_mesh_update = null;\n _wl_mesh_get_boundingSphere = null;\n _wl_mesh_get_attribute = null;\n _wl_mesh_destroy = null;\n _wl_mesh_get_attribute_values = null;\n _wl_mesh_set_attribute_values = null;\n _wl_material_create = null;\n _wl_material_get_definition = null;\n _wl_material_definition_get_count = null;\n _wl_material_definition_get_param_name = null;\n _wl_material_definition_get_param_type = null;\n _wl_material_get_pipeline = null;\n _wl_material_clone = null;\n _wl_material_get_param_index = null;\n _wl_material_get_param_type = null;\n _wl_material_get_param_value = null;\n _wl_material_set_param_value_uint = null;\n _wl_material_set_param_value_float = null;\n _wl_renderer_addImage = null;\n _wl_texture_width = null;\n _wl_texture_height = null;\n _wl_renderer_updateImage = null;\n _wl_texture_destroy = null;\n _wl_animation_get_duration = null;\n _wl_animation_get_trackCount = null;\n _wl_animation_retargetToSkin = null;\n _wl_animation_retarget = null;\n _wl_object_name = null;\n _wl_object_set_name = null;\n _wl_object_parent = null;\n _wl_object_get_children_count = null;\n _wl_object_get_children = null;\n _wl_object_set_parent = null;\n _wl_object_reset_scaling = null;\n _wl_object_reset_translation_rotation = null;\n _wl_object_reset_rotation = null;\n _wl_object_reset_translation = null;\n _wl_object_translate = null;\n _wl_object_translate_obj = null;\n _wl_object_translate_world = null;\n _wl_object_rotate_axis_angle = null;\n _wl_object_rotate_axis_angle_rad = null;\n _wl_object_rotate_axis_angle_obj = null;\n _wl_object_rotate_axis_angle_rad_obj = null;\n _wl_object_rotate_quat = null;\n _wl_object_rotate_quat_obj = null;\n _wl_object_scale = null;\n _wl_object_trans_local = null;\n _wl_object_get_translation_local = null;\n _wl_object_set_translation_local = null;\n _wl_object_get_translation_world = null;\n _wl_object_set_translation_world = null;\n _wl_object_trans_world = null;\n _wl_object_trans_world_to_local = null;\n _wl_object_scaling_local = null;\n _wl_object_scaling_world = null;\n _wl_object_set_scaling_local = null;\n _wl_object_set_scaling_world = null;\n _wl_object_scaling_world_to_local = null;\n _wl_object_set_rotation_local = null;\n _wl_object_set_rotation_world = null;\n _wl_object_transformVectorWorld = null;\n _wl_object_transformVectorLocal = null;\n _wl_object_transformPointWorld = null;\n _wl_object_transformPointLocal = null;\n _wl_object_transformVectorInverseWorld = null;\n _wl_object_transformVectorInverseLocal = null;\n _wl_object_transformPointInverseWorld = null;\n _wl_object_transformPointInverseLocal = null;\n _wl_object_toWorldSpaceTransform = null;\n _wl_object_toObjectSpaceTransform = null;\n _wl_object_lookAt = null;\n _wl_scene_remove_object = null;\n _wl_object_set_dirty = null;\n _wl_get_component_manager_index = null;\n _wl_get_js_component_index = null;\n _wl_get_js_component_index_for_id = null;\n _wl_get_component_id = null;\n _wl_object_get_components = null;\n _wl_object_get_component_types = null;\n _wl_object_add_js_component = null;\n _wl_object_add_component = null;\n _wl_object_is_changed = null;\n _wl_component_manager_name = null;\n _wl_skin_get_joint_count = null;\n _wl_skin_joint_ids = null;\n _wl_skin_inverse_bind_transforms = null;\n _wl_skin_inverse_bind_scalings = null;\n _wl_math_cubicHermite = null;\n _wl_i18n_setLanguage = null;\n _wl_i18n_currentLanguage = null;\n _wl_i18n_translate = null;\n _wl_i18n_languageCount = null;\n _wl_i18n_languageIndex = null;\n _wl_i18n_languageCode = null;\n _wl_i18n_languageName = null;\n}\n", "/**\n * This file is automatically generated.\n *\n * **Do not** modify this file directly, but instead update\n * the 'write-version.mjs' script.\n */\n/** Version of this API. */\nexport const APIVersion = {\n major: 1,\n minor: 0,\n patch: 1,\n rc: 0\n};\n", "import { Component, Type } from '@wonderlandengine/api';\n/**\n * 8thwall camera component.\n *\n * Sets up the 8thwall pipeline and retrieves tracking events to place an\n * object at the location of the tracked AR camera / mobile device.\n *\n * Use this for SLAM tracking based on 8thwall.\n *\n * Make sure to enable 8thwall in \"Project Settings\" > \"AR\". See also the\n * [AR Getting Started Guide](/getting-started/quick-start-ar)\n *\n *\n * Currently only supports world-tracking (SLAM) using BACK camera.\n *\n * - remove any occurrences of the old 8thwall-camera component in the editor\n * - Add this component to NonVrCamera\n *\n * IMPORTANT!\n * - until it get's fixed, select 'customIndexHtml' in the project settings\n * - open a generated index.html and crossorigin=\"anonymous\" attribute to the