kiwiengine 0.5.16 → 0.5.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,7 +55,7 @@ function readBool(key, defaultValue) {
55
55
  function writeBool(key, value) {
56
56
  safeStorage.setItem(key, value ? '1' : '0');
57
57
  }
58
- class Audio {
58
+ export class Audio {
59
59
  src;
60
60
  #volume;
61
61
  #loop;
@@ -1 +1 @@
1
- {"version":3,"file":"audio.js","sourceRoot":"","sources":["../../src/asset/audio.ts"],"names":[],"mappings":"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","sourcesContent":["import { isMobile } from '../utils/device'\nimport { audioLoader } from './loaders/audio'\n\nexport const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()\nwindow.addEventListener('mousedown', () => audioContext.resume())\nwindow.addEventListener('touchend', () => audioContext.resume())\n\nasync function getAvailableContext(): Promise<AudioContext> {\n if (audioContext.state === 'suspended') await audioContext.resume()\n return audioContext\n}\n\nlet isPageVisible = !document.hidden\nwindow.addEventListener('visibilitychange', () => {\n isPageVisible = !document.hidden\n})\n\ntype BasicStorage = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>\n\ntype SafeStorage = BasicStorage & {\n persistent: boolean\n}\n\nfunction createSafeStorage(): SafeStorage {\n const memory = (() => {\n const m = new Map<string, string>()\n const api: SafeStorage = {\n persistent: false,\n getItem: (k) => (m.has(k) ? m.get(k)! : null),\n setItem: (k, v) => { m.set(k, String(v)) },\n removeItem: (k) => { m.delete(k) },\n }\n return api\n })()\n\n if (typeof window === 'undefined') return memory\n\n try {\n const ls = window.localStorage\n const probeKey = '__safe_ls_probe__' + Math.random().toString(36).slice(2)\n ls.setItem(probeKey, '1')\n ls.removeItem(probeKey)\n\n const safe: SafeStorage = {\n persistent: true,\n getItem: (k) => ls.getItem(k),\n setItem: (k, v) => ls.setItem(k, v),\n removeItem: (k) => ls.removeItem(k),\n }\n return safe\n } catch {\n return memory\n }\n}\n\nconst safeStorage = createSafeStorage()\n\nfunction clamp01(n: number) {\n return Math.max(0, Math.min(1, n))\n}\n\nfunction readBool(key: string, defaultValue: boolean) {\n const v = safeStorage.getItem(key)\n if (v == null) return defaultValue\n return v === '1' || v === 'true'\n}\n\nfunction writeBool(key: string, value: boolean) {\n safeStorage.setItem(key, value ? '1' : '0')\n}\n\nclass Audio {\n src: string\n #volume: number\n #loop: boolean\n\n #audioBuffer?: AudioBuffer\n #audioContext?: AudioContext\n #gainNode?: GainNode\n #source?: AudioBufferSourceNode\n\n #isPlaying = false\n #isPaused = false\n #startTime = 0\n #pauseTime = 0\n #offset = 0\n\n constructor(src: string, volume: number, loop: boolean) {\n this.src = src\n this.#volume = clamp01(volume)\n this.#loop = loop\n this.play()\n }\n\n get volume() { return this.#volume }\n set volume(volume: number) {\n this.#volume = clamp01(volume)\n if (this.#gainNode) this.#gainNode.gain.value = this.#volume\n }\n\n async play() {\n // On mobile, avoid starting audio while the page is hidden (often blocked / unreliable)\n if (isMobile && !isPageVisible) return\n\n if (!this.#audioBuffer) {\n if (audioLoader.checkCached(this.src)) {\n this.#audioBuffer = audioLoader.getCached(this.src)\n } else {\n console.info(`Audio not preloaded. Loading now: ${this.src}`)\n this.#audioBuffer = await audioLoader.load(this.src)\n }\n }\n if (!this.#audioBuffer) return\n\n // If already playing, restart cleanly\n if (this.#isPlaying) this.stop()\n\n // If this is not a resume, reset offset to the beginning\n if (!this.#isPaused) this.#offset = 0\n\n this.#isPlaying = true\n this.#isPaused = false\n\n if (!this.#audioContext) this.#audioContext = await getAvailableContext()\n\n // If state changed while awaiting, bail out\n if (!this.#isPlaying) return\n\n if (!this.#gainNode) {\n this.#gainNode = this.#audioContext.createGain()\n this.#gainNode.gain.value = this.#volume\n this.#gainNode.connect(this.#audioContext.destination)\n } else {\n this.#gainNode.gain.value = this.#volume\n }\n\n this.#source = this.#audioContext.createBufferSource()\n this.#source.buffer = this.#audioBuffer\n this.#source.loop = this.#loop\n this.#source.connect(this.#gainNode)\n this.#source.start(0, this.#offset)\n this.#startTime = this.#audioContext.currentTime\n\n this.#source.onended = () => {\n // Only auto-stop for one-shot sounds that were not paused and are not looping\n if (!this.#isPaused && !this.#loop) this.stop()\n }\n }\n\n #clear(): void {\n if (this.#source) {\n // stop() can throw if already stopped; ignore safely\n try { this.#source.stop() } catch { /* noop */ }\n try { this.#source.disconnect() } catch { /* noop */ }\n this.#source = undefined\n }\n }\n\n pause() {\n if (this.#isPlaying && !this.#isPaused) {\n if (this.#audioContext) {\n // Track elapsed time so we can resume from the correct offset\n this.#pauseTime = this.#audioContext.currentTime\n this.#offset += this.#pauseTime - this.#startTime\n }\n this.#isPaused = true\n this.#isPlaying = false\n this.#clear()\n }\n }\n\n stop() {\n // Full stop resets the offset; next play starts from the beginning\n this.#isPlaying = false\n this.#isPaused = false\n this.#offset = 0\n this.#clear()\n }\n}\n\nclass MusicPlayer {\n #volume = 0.7\n #enabled = true\n #currentAudio?: Audio\n #pendingSrc?: string\n\n constructor() {\n const storedVol = parseFloat(safeStorage.getItem('musicVolume') || '')\n this.#volume = Number.isNaN(storedVol) ? this.#volume : clamp01(storedVol)\n\n // Separate from volume: true/false music enable state\n this.#enabled = readBool('musicEnabled', true)\n\n if (isMobile) {\n document.addEventListener('visibilitychange', () => {\n if (document.hidden) {\n // When hidden, pause to avoid mobile audio issues\n this.pause()\n } else {\n isPageVisible = true\n // Only resume if enabled\n if (this.#enabled) this.#currentAudio?.play()\n }\n })\n }\n }\n\n get enabled() { return this.#enabled }\n set enabled(v: boolean) {\n this.#enabled = v\n writeBool('musicEnabled', v)\n\n if (!v) {\n // \"Off\" means: do not output music. Keep the state by pausing (resume later).\n this.pause()\n return\n }\n\n // When turning on, play the last requested track if any; otherwise just resume\n if (this.#pendingSrc) {\n const src = this.#pendingSrc\n this.#pendingSrc = undefined\n this.play(src)\n } else {\n this.#currentAudio?.play()\n }\n }\n\n enable() { this.enabled = true }\n disable() { this.enabled = false }\n toggle() { this.enabled = !this.enabled }\n\n get volume() { return this.#volume }\n set volume(volume: number) {\n this.#volume = clamp01(volume)\n safeStorage.setItem('musicVolume', this.#volume.toString())\n if (this.#currentAudio) this.#currentAudio.volume = this.#volume\n }\n\n play(src: string) {\n // Remember the user's intent even if music is currently disabled\n this.#pendingSrc = src\n if (!this.#enabled) return\n\n // If it's the same track, resume instead of recreating the Audio\n if (this.#currentAudio?.src === src) {\n this.#currentAudio.play()\n return\n }\n\n this.#currentAudio?.stop()\n this.#currentAudio = new Audio(src, this.#volume, true)\n }\n\n pause() {\n this.#currentAudio?.pause()\n }\n\n stop() {\n // stop() is a hard reset (unlike pause)\n this.#currentAudio?.stop()\n this.#currentAudio = undefined\n this.#pendingSrc = undefined\n }\n}\n\nclass SfxPlayer {\n #volume = 1\n #enabled = true\n\n constructor() {\n const storedVol = parseFloat(safeStorage.getItem('sfxVolume') || '')\n this.#volume = Number.isNaN(storedVol) ? this.#volume : clamp01(storedVol)\n\n // Separate from volume: true/false SFX enable state\n this.#enabled = readBool('sfxEnabled', true)\n }\n\n get enabled() { return this.#enabled }\n set enabled(v: boolean) {\n this.#enabled = v\n writeBool('sfxEnabled', v)\n }\n\n enable() { this.enabled = true }\n disable() { this.enabled = false }\n toggle() { this.enabled = !this.enabled }\n\n get volume() { return this.#volume }\n set volume(volume: number) {\n this.#volume = clamp01(volume)\n safeStorage.setItem('sfxVolume', this.#volume.toString())\n }\n\n play(src: string) {\n // If disabled, do not play any one-shot sounds\n if (!this.#enabled) return\n new Audio(src, this.#volume, false)\n }\n\n playRandom(...srcs: string[]) {\n if (!this.#enabled) return\n this.play(srcs[Math.floor(Math.random() * srcs.length)])\n }\n}\n\nexport const musicPlayer = new MusicPlayer()\nexport const sfxPlayer = new SfxPlayer()\n"]}
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../../src/asset/audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,IAAK,MAAc,CAAC,kBAAkB,CAAC,EAAE,CAAA;AAC7F,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAA;AACjE,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAA;AAEhE,KAAK,UAAU,mBAAmB;IAChC,IAAI,YAAY,CAAC,KAAK,KAAK,WAAW;QAAE,MAAM,YAAY,CAAC,MAAM,EAAE,CAAA;IACnE,OAAO,YAAY,CAAA;AACrB,CAAC;AAED,IAAI,aAAa,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAA;AACpC,MAAM,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAC/C,aAAa,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAA;AAClC,CAAC,CAAC,CAAA;AAQF,SAAS,iBAAiB;IACxB,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE;QACnB,MAAM,CAAC,GAAG,IAAI,GAAG,EAAkB,CAAA;QACnC,MAAM,GAAG,GAAgB;YACvB,UAAU,EAAE,KAAK;YACjB,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7C,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA,CAAC,CAAC;YAC1C,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA,CAAC,CAAC;SACnC,CAAA;QACD,OAAO,GAAG,CAAA;IACZ,CAAC,CAAC,EAAE,CAAA;IAEJ,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,MAAM,CAAA;IAEhD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,YAAY,CAAA;QAC9B,MAAM,QAAQ,GAAG,mBAAmB,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAC1E,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QACzB,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;QAEvB,MAAM,IAAI,GAAgB;YACxB,UAAU,EAAE,IAAI;YAChB,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YAC7B,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;YACnC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;SACpC,CAAA;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAA;IACf,CAAC;AACH,CAAC;AAED,MAAM,WAAW,GAAG,iBAAiB,EAAE,CAAA;AAEvC,SAAS,OAAO,CAAC,CAAS;IACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;AACpC,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,YAAqB;IAClD,MAAM,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAClC,IAAI,CAAC,IAAI,IAAI;QAAE,OAAO,YAAY,CAAA;IAClC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,MAAM,CAAA;AAClC,CAAC;AAED,SAAS,SAAS,CAAC,GAAW,EAAE,KAAc;IAC5C,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,OAAO,KAAK;IAChB,GAAG,CAAQ;IACX,OAAO,CAAQ;IACf,KAAK,CAAS;IAEd,YAAY,CAAc;IAC1B,aAAa,CAAe;IAC5B,SAAS,CAAW;IACpB,OAAO,CAAwB;IAE/B,UAAU,GAAG,KAAK,CAAA;IAClB,SAAS,GAAG,KAAK,CAAA;IACjB,UAAU,GAAG,CAAC,CAAA;IACd,UAAU,GAAG,CAAC,CAAA;IACd,OAAO,GAAG,CAAC,CAAA;IAEX,YAAY,GAAW,EAAE,MAAc,EAAE,IAAa;QACpD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAc;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAA;IAC9D,CAAC;IAED,KAAK,CAAC,IAAI;QACR,wFAAwF;QACxF,IAAI,QAAQ,IAAI,CAAC,aAAa;YAAE,OAAM;QAEtC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtC,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACrD,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,qCAAqC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;gBAC7D,IAAI,CAAC,YAAY,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACtD,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAM;QAE9B,sCAAsC;QACtC,IAAI,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAEhC,yDAAyD;QACzD,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAA;QAErC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAA;QACtB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAA;QAEtB,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,IAAI,CAAC,aAAa,GAAG,MAAM,mBAAmB,EAAE,CAAA;QAEzE,4CAA4C;QAC5C,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAM;QAE5B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAA;YAChD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAA;YACxC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAA;QACxD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAA;QAC1C,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,kBAAkB,EAAE,CAAA;QACtD,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAA;QACvC,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAA;QAC9B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACpC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QACnC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,CAAA;QAEhD,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE;YAC1B,8EAA8E;YAC9E,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,KAAK;gBAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QACjD,CAAC,CAAA;IACH,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,qDAAqD;YACrD,IAAI,CAAC;gBAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YAChD,IAAI,CAAC;gBAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;YACtD,IAAI,CAAC,OAAO,GAAG,SAAS,CAAA;QAC1B,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;gBACvB,8DAA8D;gBAC9D,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,WAAW,CAAA;gBAChD,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAA;YACnD,CAAC;YACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;YACrB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAA;YACvB,IAAI,CAAC,MAAM,EAAE,CAAA;QACf,CAAC;IACH,CAAC;IAED,IAAI;QACF,mEAAmE;QACnE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAA;QACvB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAA;QAChB,IAAI,CAAC,MAAM,EAAE,CAAA;IACf,CAAC;CACF;AAED,MAAM,WAAW;IACf,OAAO,GAAG,GAAG,CAAA;IACb,QAAQ,GAAG,IAAI,CAAA;IACf,aAAa,CAAQ;IACrB,WAAW,CAAS;IAEpB;QACE,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAA;QACtE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAE1E,sDAAsD;QACtD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;QAE9C,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;gBACjD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;oBACpB,kDAAkD;oBAClD,IAAI,CAAC,KAAK,EAAE,CAAA;gBACd,CAAC;qBAAM,CAAC;oBACN,aAAa,GAAG,IAAI,CAAA;oBACpB,yBAAyB;oBACzB,IAAI,IAAI,CAAC,QAAQ;wBAAE,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAA;gBAC/C,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,IAAI,OAAO,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAA,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,CAAU;QACpB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;QACjB,SAAS,CAAC,cAAc,EAAE,CAAC,CAAC,CAAA;QAE5B,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,8EAA8E;YAC9E,IAAI,CAAC,KAAK,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,+EAA+E;QAC/E,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAA;YAC5B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAA;YAC5B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAChB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAA;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,KAAK,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC;IAChC,OAAO,KAAK,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA,CAAC,CAAC;IAClC,MAAM,KAAK,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IAEzC,IAAI,MAAM,KAAK,OAAO,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAc;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC9B,WAAW,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC3D,IAAI,IAAI,CAAC,aAAa;YAAE,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAA;IAClE,CAAC;IAED,IAAI,CAAC,GAAW;QACd,iEAAiE;QACjE,IAAI,CAAC,WAAW,GAAG,GAAG,CAAA;QACtB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAM;QAE1B,iEAAiE;QACjE,IAAI,IAAI,CAAC,aAAa,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;YACpC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAA;YACzB,OAAM;QACR,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAA;QAC1B,IAAI,CAAC,aAAa,GAAG,IAAI,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACzD,CAAC;IAED,KAAK;QACH,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,CAAA;IAC7B,CAAC;IAED,IAAI;QACF,wCAAwC;QACxC,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAA;QAC1B,IAAI,CAAC,aAAa,GAAG,SAAS,CAAA;QAC9B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAA;IAC9B,CAAC;CACF;AAED,MAAM,SAAS;IACb,OAAO,GAAG,CAAC,CAAA;IACX,QAAQ,GAAG,IAAI,CAAA;IAEf;QACE,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAA;QACpE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAE1E,oDAAoD;QACpD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;IAC9C,CAAC;IAED,IAAI,OAAO,KAAK,OAAO,IAAI,CAAC,QAAQ,CAAA,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,CAAU;QACpB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;QACjB,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;IAC5B,CAAC;IAED,MAAM,KAAK,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC;IAChC,OAAO,KAAK,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA,CAAC,CAAC;IAClC,MAAM,KAAK,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IAEzC,IAAI,MAAM,KAAK,OAAO,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAc;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC9B,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC3D,CAAC;IAED,IAAI,CAAC,GAAW;QACd,+CAA+C;QAC/C,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAM;QAC1B,IAAI,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IACrC,CAAC;IAED,UAAU,CAAC,GAAG,IAAc;QAC1B,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAM;QAC1B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IAC1D,CAAC;CACF;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;AAC5C,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAA","sourcesContent":["import { isMobile } from '../utils/device'\nimport { audioLoader } from './loaders/audio'\n\nexport const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()\nwindow.addEventListener('mousedown', () => audioContext.resume())\nwindow.addEventListener('touchend', () => audioContext.resume())\n\nasync function getAvailableContext(): Promise<AudioContext> {\n if (audioContext.state === 'suspended') await audioContext.resume()\n return audioContext\n}\n\nlet isPageVisible = !document.hidden\nwindow.addEventListener('visibilitychange', () => {\n isPageVisible = !document.hidden\n})\n\ntype BasicStorage = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>\n\ntype SafeStorage = BasicStorage & {\n persistent: boolean\n}\n\nfunction createSafeStorage(): SafeStorage {\n const memory = (() => {\n const m = new Map<string, string>()\n const api: SafeStorage = {\n persistent: false,\n getItem: (k) => (m.has(k) ? m.get(k)! : null),\n setItem: (k, v) => { m.set(k, String(v)) },\n removeItem: (k) => { m.delete(k) },\n }\n return api\n })()\n\n if (typeof window === 'undefined') return memory\n\n try {\n const ls = window.localStorage\n const probeKey = '__safe_ls_probe__' + Math.random().toString(36).slice(2)\n ls.setItem(probeKey, '1')\n ls.removeItem(probeKey)\n\n const safe: SafeStorage = {\n persistent: true,\n getItem: (k) => ls.getItem(k),\n setItem: (k, v) => ls.setItem(k, v),\n removeItem: (k) => ls.removeItem(k),\n }\n return safe\n } catch {\n return memory\n }\n}\n\nconst safeStorage = createSafeStorage()\n\nfunction clamp01(n: number) {\n return Math.max(0, Math.min(1, n))\n}\n\nfunction readBool(key: string, defaultValue: boolean) {\n const v = safeStorage.getItem(key)\n if (v == null) return defaultValue\n return v === '1' || v === 'true'\n}\n\nfunction writeBool(key: string, value: boolean) {\n safeStorage.setItem(key, value ? '1' : '0')\n}\n\nexport class Audio {\n src: string\n #volume: number\n #loop: boolean\n\n #audioBuffer?: AudioBuffer\n #audioContext?: AudioContext\n #gainNode?: GainNode\n #source?: AudioBufferSourceNode\n\n #isPlaying = false\n #isPaused = false\n #startTime = 0\n #pauseTime = 0\n #offset = 0\n\n constructor(src: string, volume: number, loop: boolean) {\n this.src = src\n this.#volume = clamp01(volume)\n this.#loop = loop\n this.play()\n }\n\n get volume() { return this.#volume }\n set volume(volume: number) {\n this.#volume = clamp01(volume)\n if (this.#gainNode) this.#gainNode.gain.value = this.#volume\n }\n\n async play() {\n // On mobile, avoid starting audio while the page is hidden (often blocked / unreliable)\n if (isMobile && !isPageVisible) return\n\n if (!this.#audioBuffer) {\n if (audioLoader.checkCached(this.src)) {\n this.#audioBuffer = audioLoader.getCached(this.src)\n } else {\n console.info(`Audio not preloaded. Loading now: ${this.src}`)\n this.#audioBuffer = await audioLoader.load(this.src)\n }\n }\n if (!this.#audioBuffer) return\n\n // If already playing, restart cleanly\n if (this.#isPlaying) this.stop()\n\n // If this is not a resume, reset offset to the beginning\n if (!this.#isPaused) this.#offset = 0\n\n this.#isPlaying = true\n this.#isPaused = false\n\n if (!this.#audioContext) this.#audioContext = await getAvailableContext()\n\n // If state changed while awaiting, bail out\n if (!this.#isPlaying) return\n\n if (!this.#gainNode) {\n this.#gainNode = this.#audioContext.createGain()\n this.#gainNode.gain.value = this.#volume\n this.#gainNode.connect(this.#audioContext.destination)\n } else {\n this.#gainNode.gain.value = this.#volume\n }\n\n this.#source = this.#audioContext.createBufferSource()\n this.#source.buffer = this.#audioBuffer\n this.#source.loop = this.#loop\n this.#source.connect(this.#gainNode)\n this.#source.start(0, this.#offset)\n this.#startTime = this.#audioContext.currentTime\n\n this.#source.onended = () => {\n // Only auto-stop for one-shot sounds that were not paused and are not looping\n if (!this.#isPaused && !this.#loop) this.stop()\n }\n }\n\n #clear(): void {\n if (this.#source) {\n // stop() can throw if already stopped; ignore safely\n try { this.#source.stop() } catch { /* noop */ }\n try { this.#source.disconnect() } catch { /* noop */ }\n this.#source = undefined\n }\n }\n\n pause() {\n if (this.#isPlaying && !this.#isPaused) {\n if (this.#audioContext) {\n // Track elapsed time so we can resume from the correct offset\n this.#pauseTime = this.#audioContext.currentTime\n this.#offset += this.#pauseTime - this.#startTime\n }\n this.#isPaused = true\n this.#isPlaying = false\n this.#clear()\n }\n }\n\n stop() {\n // Full stop resets the offset; next play starts from the beginning\n this.#isPlaying = false\n this.#isPaused = false\n this.#offset = 0\n this.#clear()\n }\n}\n\nclass MusicPlayer {\n #volume = 0.7\n #enabled = true\n #currentAudio?: Audio\n #pendingSrc?: string\n\n constructor() {\n const storedVol = parseFloat(safeStorage.getItem('musicVolume') || '')\n this.#volume = Number.isNaN(storedVol) ? this.#volume : clamp01(storedVol)\n\n // Separate from volume: true/false music enable state\n this.#enabled = readBool('musicEnabled', true)\n\n if (isMobile) {\n document.addEventListener('visibilitychange', () => {\n if (document.hidden) {\n // When hidden, pause to avoid mobile audio issues\n this.pause()\n } else {\n isPageVisible = true\n // Only resume if enabled\n if (this.#enabled) this.#currentAudio?.play()\n }\n })\n }\n }\n\n get enabled() { return this.#enabled }\n set enabled(v: boolean) {\n this.#enabled = v\n writeBool('musicEnabled', v)\n\n if (!v) {\n // \"Off\" means: do not output music. Keep the state by pausing (resume later).\n this.pause()\n return\n }\n\n // When turning on, play the last requested track if any; otherwise just resume\n if (this.#pendingSrc) {\n const src = this.#pendingSrc\n this.#pendingSrc = undefined\n this.play(src)\n } else {\n this.#currentAudio?.play()\n }\n }\n\n enable() { this.enabled = true }\n disable() { this.enabled = false }\n toggle() { this.enabled = !this.enabled }\n\n get volume() { return this.#volume }\n set volume(volume: number) {\n this.#volume = clamp01(volume)\n safeStorage.setItem('musicVolume', this.#volume.toString())\n if (this.#currentAudio) this.#currentAudio.volume = this.#volume\n }\n\n play(src: string) {\n // Remember the user's intent even if music is currently disabled\n this.#pendingSrc = src\n if (!this.#enabled) return\n\n // If it's the same track, resume instead of recreating the Audio\n if (this.#currentAudio?.src === src) {\n this.#currentAudio.play()\n return\n }\n\n this.#currentAudio?.stop()\n this.#currentAudio = new Audio(src, this.#volume, true)\n }\n\n pause() {\n this.#currentAudio?.pause()\n }\n\n stop() {\n // stop() is a hard reset (unlike pause)\n this.#currentAudio?.stop()\n this.#currentAudio = undefined\n this.#pendingSrc = undefined\n }\n}\n\nclass SfxPlayer {\n #volume = 1\n #enabled = true\n\n constructor() {\n const storedVol = parseFloat(safeStorage.getItem('sfxVolume') || '')\n this.#volume = Number.isNaN(storedVol) ? this.#volume : clamp01(storedVol)\n\n // Separate from volume: true/false SFX enable state\n this.#enabled = readBool('sfxEnabled', true)\n }\n\n get enabled() { return this.#enabled }\n set enabled(v: boolean) {\n this.#enabled = v\n writeBool('sfxEnabled', v)\n }\n\n enable() { this.enabled = true }\n disable() { this.enabled = false }\n toggle() { this.enabled = !this.enabled }\n\n get volume() { return this.#volume }\n set volume(volume: number) {\n this.#volume = clamp01(volume)\n safeStorage.setItem('sfxVolume', this.#volume.toString())\n }\n\n play(src: string) {\n // If disabled, do not play any one-shot sounds\n if (!this.#enabled) return\n new Audio(src, this.#volume, false)\n }\n\n playRandom(...srcs: string[]) {\n if (!this.#enabled) return\n this.play(srcs[Math.floor(Math.random() * srcs.length)])\n }\n}\n\nexport const musicPlayer = new MusicPlayer()\nexport const sfxPlayer = new SfxPlayer()\n"]}
@@ -1,4 +1,14 @@
1
1
  export declare const audioContext: AudioContext;
2
+ export declare class Audio {
3
+ #private;
4
+ src: string;
5
+ constructor(src: string, volume: number, loop: boolean);
6
+ get volume(): number;
7
+ set volume(volume: number);
8
+ play(): Promise<void>;
9
+ pause(): void;
10
+ stop(): void;
11
+ }
2
12
  declare class MusicPlayer {
3
13
  #private;
4
14
  constructor();
@@ -1 +1 @@
1
- {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../src/asset/audio.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,cAAoE,CAAA;AAiL7F,cAAM,WAAW;;;IA2Bf,IAAI,OAAO,IACI,OAAO,CADgB;IACtC,IAAI,OAAO,CAAC,CAAC,EAAE,OAAO,EAkBrB;IAED,MAAM;IACN,OAAO;IACP,MAAM;IAEN,IAAI,MAAM,IACS,MAAM,CADW;IACpC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAIxB;IAED,IAAI,CAAC,GAAG,EAAE,MAAM;IAehB,KAAK;IAIL,IAAI;CAML;AAED,cAAM,SAAS;;;IAYb,IAAI,OAAO,IACI,OAAO,CADgB;IACtC,IAAI,OAAO,CAAC,CAAC,EAAE,OAAO,EAGrB;IAED,MAAM;IACN,OAAO;IACP,MAAM;IAEN,IAAI,MAAM,IACS,MAAM,CADW;IACpC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAGxB;IAED,IAAI,CAAC,GAAG,EAAE,MAAM;IAMhB,UAAU,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;CAI7B;AAED,eAAO,MAAM,WAAW,aAAoB,CAAA;AAC5C,eAAO,MAAM,SAAS,WAAkB,CAAA"}
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../src/asset/audio.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,cAAoE,CAAA;AAoE7F,qBAAa,KAAK;;IAChB,GAAG,EAAE,MAAM,CAAA;gBAeC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;IAOtD,IAAI,MAAM,IACS,MAAM,CADW;IACpC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAGxB;IAEK,IAAI;IA0DV,KAAK;IAaL,IAAI;CAOL;AAED,cAAM,WAAW;;;IA2Bf,IAAI,OAAO,IACI,OAAO,CADgB;IACtC,IAAI,OAAO,CAAC,CAAC,EAAE,OAAO,EAkBrB;IAED,MAAM;IACN,OAAO;IACP,MAAM;IAEN,IAAI,MAAM,IACS,MAAM,CADW;IACpC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAIxB;IAED,IAAI,CAAC,GAAG,EAAE,MAAM;IAehB,KAAK;IAIL,IAAI;CAML;AAED,cAAM,SAAS;;;IAYb,IAAI,OAAO,IACI,OAAO,CADgB;IACtC,IAAI,OAAO,CAAC,CAAC,EAAE,OAAO,EAGrB;IAED,MAAM;IACN,OAAO;IACP,MAAM;IAEN,IAAI,MAAM,IACS,MAAM,CADW;IACpC,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,EAGxB;IAED,IAAI,CAAC,GAAG,EAAE,MAAM;IAMhB,UAAU,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;CAI7B;AAED,eAAO,MAAM,WAAW,aAAoB,CAAA;AAC5C,eAAO,MAAM,SAAS,WAAkB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiwiengine",
3
- "version": "0.5.16",
3
+ "version": "0.5.17",
4
4
  "types": "./lib/types/index.d.ts",
5
5
  "main": "./lib/index.js",
6
6
  "dependencies": {
@@ -69,7 +69,7 @@ function writeBool(key: string, value: boolean) {
69
69
  safeStorage.setItem(key, value ? '1' : '0')
70
70
  }
71
71
 
72
- class Audio {
72
+ export class Audio {
73
73
  src: string
74
74
  #volume: number
75
75
  #loop: boolean