// Main app — orchestrates everything const { useState, useEffect, useRef, useCallback } = React; // Stack diagram component (used inside chapter 10) function StackDiagram({ lang }) { const T = window.T; const nodes = [ { name: "gentle-ai", label: T(lang, "base", "base") }, { name: "autoSDD", label: T(lang, "fork", "fork") }, { name: "Engram fail", label: T(lang, "problema", "problem"), problem: true }, { name: "+ embeddings", label: T(lang, "fix", "fix") }, { name: "CLAUDE.md", label: T(lang, "índice", "index") }, { name: "Stark Kit", label: T(lang, "versionado", "versioned") }, { name: "e2e-forge", label: T(lang, "empresa", "company") }, { name: "be-code-kit", label: T(lang, "merge", "merge") }, { name: "OpenClaw", label: T(lang, "gateway", "gateway") }, { name: "Hermes", label: T(lang, "salto", "leap") }, { name: "Cobalt", label: T(lang, "actual", "current") }]; return (
{T(lang, "Evolución de mi stack", "Stack evolution")}
{nodes.map((n, i) =>
{n.label}
{n.name}
{i < nodes.length - 1 &&
}
)}
); } function App() { const [lang, setLang] = useState("es"); const [activeIdx, setActiveIdx] = useState(0); const [audioOn, setAudioOn] = useState(false); const [videoModal, setVideoModal] = useState(null); const [planState, setPlanState] = useState("balanced"); const [copied, setCopied] = useState(false); const [toast, setToast] = useState(null); const [easter, setEaster] = useState(0); const sectionsRef = useRef([]); const CHAPTERS = window.CHAPTERS; const ChapterContent = window.ChapterContent; const T = window.T; // Scroll observer to determine active chapter // Uses scroll position directly — IntersectionObserver fails for tall sections // that never hit a 40% visibility threshold. useEffect(() => { const onScroll = () => { const sections = sectionsRef.current.filter(Boolean); if (!sections.length) return; // The "anchor" line is 35% from the top of the viewport. // The active section is the last one whose top is above that line. const anchor = window.innerHeight * 0.35; let idx = 0; for (let i = 0; i < sections.length; i++) { const rect = sections[i].getBoundingClientRect(); if (rect.top <= anchor) idx = i; else break; } setActiveIdx(idx); }; onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); window.addEventListener("resize", onScroll); return () => { window.removeEventListener("scroll", onScroll); window.removeEventListener("resize", onScroll); }; }, []); // Apply tone to body + particles + audio useEffect(() => { const tone = CHAPTERS[activeIdx]?.tone || "neutral"; document.body.dataset.tone = tone; if (window.__setParticleTone) window.__setParticleTone(tone); if (window.__audio && window.__audio.isActive()) window.__audio.setTone(tone); }, [activeIdx]); // Duck the immersive audio while a video modal is open, restore on close. // Only restores if audio was on before the modal opened. useEffect(() => { if (!window.__audio) return; if (videoModal) { if (audioOn && window.__audio.isActive()) { window.__audio.stop(); } } else { // Modal just closed — bring audio back if user had it on if (audioOn && !window.__audio.isActive()) { window.__audio.start(); window.__audio.setTone(CHAPTERS[activeIdx]?.tone || "neutral"); } } }, [videoModal, audioOn]); // Reveal-on-scroll useEffect(() => { const reveals = document.querySelectorAll(".reveal"); const obs = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) e.target.classList.add("visible"); }); }, { threshold: .15 }); reveals.forEach((r) => obs.observe(r)); return () => obs.disconnect(); }, [lang]); const scrollTo = useCallback((idx) => { const el = sectionsRef.current[idx]; if (el) el.scrollIntoView({ behavior: "smooth", block: "start" }); }, []); const openVideo = useCallback((id, title) => { setVideoModal({ id, title }); }, []); const copyPrompt = useCallback(async () => { const text = window.SUPERWHISPER_PROMPT || ""; let ok = false; // Try modern clipboard API first try { if (navigator.clipboard && window.isSecureContext) { await navigator.clipboard.writeText(text); ok = true; } } catch (e) {} // Fallback: hidden textarea + execCommand if (!ok) { try { const ta = document.createElement("textarea"); ta.value = text; ta.setAttribute("readonly", ""); ta.style.position = "fixed"; ta.style.top = "-9999px"; ta.style.opacity = "0"; document.body.appendChild(ta); ta.select(); ta.setSelectionRange(0, text.length); ok = document.execCommand("copy"); document.body.removeChild(ta); } catch (e) {} } if (ok) { setCopied(true); setToast(T(lang, "Prompt copiado al portapapeles", "Prompt copied to clipboard")); setTimeout(() => setCopied(false), 2200); setTimeout(() => setToast(null), 2400); } else { setToast(T(lang, "Error al copiar — selecciona manualmente", "Copy failed — select manually")); setTimeout(() => setToast(null), 2400); } }, [lang]); const toggleAudio = useCallback(() => { if (audioOn) { window.__audio.stop(); setAudioOn(false); } else { window.__audio.start(); window.__audio.setTone(CHAPTERS[activeIdx]?.tone || "neutral"); setAudioOn(true); setToast(T(lang, "Modo inmersivo activado", "Immersive mode on")); setTimeout(() => setToast(null), 1800); } }, [audioOn, activeIdx, lang]); // Easter egg: click brand 5x for konami const onBrandClick = () => { setEaster((e) => { const n = e + 1; if (n === 5) { document.body.classList.add("glitch"); setToast(T(lang, "✦ Modo Stark activado ✦", "✦ Stark mode unlocked ✦")); setTimeout(() => { document.body.classList.remove("glitch"); setToast(null); }, 2400); return 0; } return n; }); }; // Keyboard nav useEffect(() => { const onKey = (e) => { if (videoModal) { if (e.key === "Escape") setVideoModal(null); return; } if (e.key === "ArrowDown" || e.key === "PageDown") { if (activeIdx < CHAPTERS.length - 1) {e.preventDefault();scrollTo(activeIdx + 1);} } else if (e.key === "ArrowUp" || e.key === "PageUp") { if (activeIdx > 0) {e.preventDefault();scrollTo(activeIdx - 1);} } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [activeIdx, videoModal]); const progress = (activeIdx + 1) / CHAPTERS.length * 100; return ( <> {/* Topbar */}
AI ROADMAP · {T(lang, "Un viaje", "A journey")}
{/* Sidebar timeline */} {/* Minimap */}
{CHAPTERS.map((ch, i) => )}
{/* Main */}
{CHAPTERS.map((ch, i) => { const fn = ChapterContent[ch.id]; return (
sectionsRef.current[i] = el} data-idx={i} data-tone={ch.tone} data-screen-label={`${ch.num} ${ch.title.es}`} id={`ch-${ch.id}`} className={ch.id === "intro" ? "" : "chapter"}> {ch.id === "intro" ? fn(lang, openVideo) : <>
CHAPTER {ch.num}
{ch.act[lang]}

{ch.title[lang]}

{ch.intro[lang]}

{ch.id === "models" ? fn(lang, openVideo, planState, setPlanState) : ch.id === "voice" ? fn(lang, openVideo, null, copyPrompt, copied) : fn(lang, openVideo)} {/* Stack diagram appears in sovereignty chapter */} {ch.id === "sovereignty" && } }
); })}
{/* Video modal */} {videoModal &&
setVideoModal(null)}>
e.stopPropagation()}>

▶ {videoModal.title}

{T(lang, "Abrir en YouTube ↗", "Open on YouTube ↗")}
} {/* Toast */} {toast &&
{toast}
} {/* Console line easter egg */}
{`> chapter_${String(activeIdx + 1).padStart(2, "0")} loaded`} _
); } ReactDOM.createRoot(document.getElementById("root")).render();