(function (root) { "use strict"; const BEATS = Object.freeze([ Object.freeze({ panel: 0, duration: 15000, voice: "intro-narration-1", subtitle: "Before shadow crossed the northern road, Princess Lima walked among her people—listening before she ruled, and helping before she asked." }), Object.freeze({ panel: 1, duration: 14000, voice: "intro-narration-2", effect: "door", subtitle: "Then Lord Malrec descended from the Fortress of Shadows. His riders carried fear through the valleys, searching for the royal oath." }), Object.freeze({ panel: 2, duration: 15000, voice: "intro-narration-3", effect: "attack", subtitle: "Lima stood between the riders and the village. Malrec could not bend her will, so he bound her in shadow and carried her beyond the mountains." }), Object.freeze({ panel: 3, duration: 15000, voice: "intro-narration-4", effect: "quest", subtitle: "At dawn, a lone traveller reached the broken village. The road was dangerous, but every rescued life would become another light leading to Lima." }), Object.freeze({ panel: 3, duration: 8000, voice: null, effect: "victory", subtitle: "RESCUE PRINCESS LIMA — Chapter One: The Broken Village" }) ]); function create(container, actions) { const element = container.querySelector("[data-lima-intro]"); const picture = element.querySelector("[data-lima-intro-picture]"); const subtitle = element.querySelector("[data-lima-intro-subtitle]"); const progress = element.querySelector("[data-lima-intro-progress]"); const pauseButton = element.querySelector("[data-lima-intro-pause]"); const muteButton = element.querySelector("[data-lima-intro-mute]"); let beatIndex = 0; let elapsed = 0; let startedAt = 0; let timer = 0; let paused = false; let replay = false; let escapeStarted = 0; let running = false; function start(options) { stopTimer(); beatIndex = 0; elapsed = 0; paused = false; replay = Boolean(options && options.replay); running = true; element.hidden = false; container.classList.add("is-intro-running"); actions.onLock(true); actions.onAudioUnlock(); renderBeat(); element.focus(); } function renderBeat() { const beat = BEATS[beatIndex]; picture.dataset.panel = String(beat.panel); subtitle.textContent = beat.subtitle; subtitle.hidden = !actions.subtitlesEnabled(); progress.style.width = `${beatIndex / BEATS.length * 100}%`; progress.parentElement.setAttribute("aria-valuenow", String(beatIndex + 1)); if (beat.voice && actions.narrationEnabled()) actions.playVoice(beat.voice); if (beat.effect) actions.playEffect(beat.effect, 0.55); startedAt = Date.now(); timer = window.setTimeout(next, beat.duration); pauseButton.textContent = "Pause"; pauseButton.setAttribute("aria-pressed", "false"); } function next() { stopTimer(); actions.stopVoice(); beatIndex += 1; elapsed = 0; if (beatIndex >= BEATS.length) return finish(false); renderBeat(); } function togglePause() { if (!running) return; paused = !paused; if (paused) { elapsed += Date.now() - startedAt; stopTimer(); actions.stopVoice(); } else { const beat = BEATS[beatIndex]; startedAt = Date.now(); timer = window.setTimeout(next, Math.max(500, beat.duration - elapsed)); if (beat.voice && actions.narrationEnabled()) actions.playVoice(beat.voice); } pauseButton.textContent = paused ? "Resume" : "Pause"; pauseButton.setAttribute("aria-pressed", String(paused)); element.classList.toggle("is-paused", paused); } function finish(skipped) { if (!running) return; running = false; stopTimer(); actions.stopVoice(); progress.style.width = "100%"; element.hidden = true; element.classList.remove("is-paused"); container.classList.remove("is-intro-running"); actions.onComplete({ replay, skipped }); } function stopTimer() { if (timer) window.clearTimeout(timer); timer = 0; } function updateMute() { const enabled = actions.soundEnabled(); muteButton.textContent = enabled ? "Mute" : "Enable sound"; muteButton.setAttribute("aria-pressed", String(!enabled)); } pauseButton.addEventListener("click", togglePause); muteButton.addEventListener("click", () => { actions.toggleSound(); updateMute(); }); element.querySelector("[data-lima-intro-skip]").addEventListener("click", () => finish(true)); document.addEventListener("keydown", (event) => { if (!running) return; if (event.key === "Escape" && !escapeStarted) { event.preventDefault(); escapeStarted = Date.now(); } else if (event.key.toLowerCase() === "p") { event.preventDefault(); togglePause(); } }); document.addEventListener("keyup", (event) => { if (!running || event.key !== "Escape") return; event.preventDefault(); if (escapeStarted && Date.now() - escapeStarted >= 900) finish(true); else actions.status("Hold Escape for one second to skip the introduction."); escapeStarted = 0; }); return Object.freeze({ start, finish, togglePause, isRunning: () => running, updateMute, BEATS }); } const api = Object.freeze({ create, BEATS }); if (typeof module === "object" && module.exports) module.exports = api; root.PrincessLimaIntro = api; }(typeof globalThis !== "undefined" ? globalThis : this));