mirror of
https://github.com/isledecomp/isle.pizza.git
synced 2026-05-03 03:03:56 +00:00
* Plant editor Add Plants tab to the save editor for browsing and editing all 81 plants. Click-to-customize based on selected character matches the original game behavior (Pepper→variant, Mama→sound, Papa→move, Nick→color, Laura→mood). Includes 3D preview with per-variant display tuning, click animations, sound playback, and reset to defaults. * Refactor shared animation code into AnimatedRenderer base class Extract duplicated animation infrastructure (clock, mixer, animation caching, raycaster, keyframe interpolation) from ActorRenderer and PlantRenderer into a new AnimatedRenderer intermediate class. Extract identical sound player code from both editors into createSoundPlayer() utility. Fix PlantRenderer interpolateVertex bug where scale keys had X incorrectly negated. Remove dead PLANT_ANIM_IDS export and redundant textures.clear() calls. * Extract shared editor CSS and fix vehicle nav spacing Move duplicated preview, spinner, navigation, and side-button styles from VehicleEditor, ActorEditor, and PlantEditor into a shared editor-common.css. Standardize class names (nav-index, nav-name, side-btn) and fix VehicleEditor part-info min-width (100px → 150px) to match the other editors. * Add carousel tabs and selection-based nav to save editor Wrap save editor tab buttons in a Carousel to prevent overflow on desktop. Carousel nav buttons now cycle through the selected item (save slot or tab) instead of scrolling, with auto-scroll-into-view. On mobile, tabs reflow with flex-wrap as before. * Update February changelog with plant editor and carousel navigation
92 lines
2.4 KiB
JavaScript
92 lines
2.4 KiB
JavaScript
// Audio utilities
|
|
import { soundEnabled } from '../stores.js';
|
|
import { fetchSoundAsWav } from './assetLoader.js';
|
|
|
|
export function getInstallAudio() {
|
|
return document.getElementById('install-audio');
|
|
}
|
|
|
|
export function pauseInstallAudio() {
|
|
const audio = getInstallAudio();
|
|
if (audio) {
|
|
audio.pause();
|
|
soundEnabled.set(false);
|
|
}
|
|
}
|
|
|
|
export function playInstallAudio() {
|
|
const audio = getInstallAudio();
|
|
if (audio) {
|
|
audio.currentTime = 0;
|
|
audio.load();
|
|
audio.play()
|
|
.then(() => {
|
|
soundEnabled.set(true);
|
|
})
|
|
.catch(() => {
|
|
soundEnabled.set(false);
|
|
});
|
|
}
|
|
}
|
|
|
|
export function toggleInstallAudio() {
|
|
const audio = getInstallAudio();
|
|
if (!audio) return;
|
|
|
|
if (audio.paused) {
|
|
playInstallAudio();
|
|
} else {
|
|
pauseInstallAudio();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a reusable sound player for game asset sounds.
|
|
* Uses Web Audio API with caching and configurable volume.
|
|
* @param {number} volume - Gain value (0-1), default 0.3
|
|
* @returns {{ play: (name: string) => Promise<void>, dispose: () => void }}
|
|
*/
|
|
export function createSoundPlayer(volume = 0.3) {
|
|
let audioContext = null;
|
|
let gainNode = null;
|
|
const cache = new Map();
|
|
|
|
async function play(name) {
|
|
try {
|
|
if (!audioContext) {
|
|
audioContext = new AudioContext();
|
|
gainNode = audioContext.createGain();
|
|
gainNode.gain.value = volume;
|
|
gainNode.connect(audioContext.destination);
|
|
}
|
|
if (audioContext.state === 'suspended') {
|
|
await audioContext.resume();
|
|
}
|
|
|
|
let audioBuffer = cache.get(name);
|
|
if (!audioBuffer) {
|
|
const wav = await fetchSoundAsWav(name);
|
|
if (!wav) return;
|
|
audioBuffer = await audioContext.decodeAudioData(wav);
|
|
cache.set(name, audioBuffer);
|
|
}
|
|
|
|
const source = audioContext.createBufferSource();
|
|
source.buffer = audioBuffer;
|
|
source.connect(gainNode);
|
|
source.start();
|
|
} catch (e) {
|
|
console.error(`Failed to play sound ${name}:`, e);
|
|
}
|
|
}
|
|
|
|
function dispose() {
|
|
audioContext?.close();
|
|
audioContext = null;
|
|
gainNode = null;
|
|
cache.clear();
|
|
}
|
|
|
|
return { play, dispose };
|
|
}
|