- Add procedural UI sound effects (connect/disconnect, engine start/stop, level complete/fail, star earned, hint, navigation) via Tone.js - Live LFO modulation visualization: knobs animate in real-time showing modulated value, ghost dot shows base value, number glows cyan - Fix wire recalculation on zoom/pan/level re-entry (post-layout refresh) - Fix retry button to keep current patch instead of reloading level - Fix default param detection: newly added modules now populate all default params so level checkers work without manual param changes - Add worlds 7-12: Secuencias y Ritmos, Texturas de Ruido, Síntesis Sustractiva, Espacio y Stereo, Técnicas Avanzadas, Gran Final (48 new levels, 144 new possible stars, 288 total stars) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
90 lines
2.8 KiB
JavaScript
90 lines
2.8 KiB
JavaScript
import React, { useState, useCallback } from 'react';
|
|
import WorldMap from './WorldMap.jsx';
|
|
import PuzzleView from './PuzzleView.jsx';
|
|
import AdminPanel from './AdminPanel.jsx';
|
|
import { WORLD_1 } from './levels/world1.js';
|
|
import { WORLD_2 } from './levels/world2.js';
|
|
import { WORLD_3 } from './levels/world3.js';
|
|
import { WORLD_4 } from './levels/world4.js';
|
|
import { WORLD_5 } from './levels/world5.js';
|
|
import { WORLD_6 } from './levels/world6.js';
|
|
import { WORLD_7 } from './levels/world7.js';
|
|
import { WORLD_8 } from './levels/world8.js';
|
|
import { WORLD_9 } from './levels/world9.js';
|
|
import { WORLD_10 } from './levels/world10.js';
|
|
import { WORLD_11 } from './levels/world11.js';
|
|
import { WORLD_12 } from './levels/world12.js';
|
|
|
|
const allWorlds = [WORLD_1, WORLD_2, WORLD_3, WORLD_4, WORLD_5, WORLD_6, WORLD_7, WORLD_8, WORLD_9, WORLD_10, WORLD_11, WORLD_12];
|
|
|
|
export default function GameApp({ onSwitchToSandbox }) {
|
|
const [view, setView] = useState('map');
|
|
const [currentLevel, setCurrentLevel] = useState(null);
|
|
const [currentLevelIndex, setCurrentLevelIndex] = useState(0);
|
|
const [currentWorld, setCurrentWorld] = useState(null);
|
|
const [showAdmin, setShowAdmin] = useState(false);
|
|
|
|
const handleSelectLevel = useCallback((level, world) => {
|
|
const idx = world.levels.findIndex(l => l.id === level.id);
|
|
setCurrentLevel(level);
|
|
setCurrentLevelIndex(idx);
|
|
setCurrentWorld(world);
|
|
setView('puzzle');
|
|
}, []);
|
|
|
|
const handleBack = useCallback(() => {
|
|
setView('map');
|
|
setCurrentLevel(null);
|
|
setCurrentWorld(null);
|
|
}, []);
|
|
|
|
const handleNextLevel = useCallback(() => {
|
|
if (!currentWorld) return;
|
|
const nextIdx = currentLevelIndex + 1;
|
|
if (nextIdx < currentWorld.levels.length) {
|
|
setCurrentLevel(currentWorld.levels[nextIdx]);
|
|
setCurrentLevelIndex(nextIdx);
|
|
} else {
|
|
// Move to next world's first level if unlocked
|
|
const worldIdx = allWorlds.findIndex(w => w.id === currentWorld.id);
|
|
if (worldIdx < allWorlds.length - 1) {
|
|
const nextWorld = allWorlds[worldIdx + 1];
|
|
setCurrentWorld(nextWorld);
|
|
setCurrentLevel(nextWorld.levels[0]);
|
|
setCurrentLevelIndex(0);
|
|
} else {
|
|
setView('map');
|
|
}
|
|
}
|
|
}, [currentLevelIndex, currentWorld]);
|
|
|
|
if (view === 'puzzle' && currentLevel && currentWorld) {
|
|
return (
|
|
<PuzzleView
|
|
key={currentLevel.id}
|
|
level={currentLevel}
|
|
levelIndex={currentLevelIndex}
|
|
worldLevels={currentWorld.levels}
|
|
onBack={handleBack}
|
|
onNextLevel={handleNextLevel}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<WorldMap
|
|
onSelectLevel={handleSelectLevel}
|
|
onSandbox={onSwitchToSandbox}
|
|
onAdmin={() => setShowAdmin(true)}
|
|
/>
|
|
{showAdmin && (
|
|
<AdminPanel
|
|
worlds={allWorlds}
|
|
onClose={() => setShowAdmin(false)}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|