@ -253,7 +253,8 @@
}
/* Hover Interaction for Minimized State */
#visual-nav-wrapper.shrunk:hover {
/* Only active when the 'interactive' class is added after animation completes */
#visual-nav-wrapper.shrunk.interactive:hover {
transform: scale(0.85);
/* Expand to readable size (not quite full to save space) */
opacity: 1;
@ -606,567 +607,178 @@
<!-- INTERACTIVE VISUAL MAP -->
< div id = "visual-nav-placeholder" >
< div id = "visual-nav-wrapper" class = "rounded-xl p-4 md:p-6 mb-8" >
< div class = "flex justify-between items-center mb-4" >
< h2 class = "text-sm font-bold text-slate-400 uppercase tracking-widest m-0" > Visual Navigation Map
< / h2 >
< span class = "text-xs text-slate-400 italic" > Click a UI element to see its code< / span >
< / div >
< div id = "visual-nav-content" class = "max-w-4xl mx-auto" >
<!-- Core Architecture Wrapper -->
< div class = "core-wrapper" onclick = "scrollToSection('architecture')" >
<!-- New Layout: Ecosystem + Injector -->
< div class = "flex gap-4 h-[380px]" >
<!-- Left: App Ecosystem Rectangle -->
< div class = "flex-grow flex flex-col gap-4" >
<!-- Top Row: Main UI Components -->
< div class = "flex-grow grid grid-cols-11 gap-4 min-h-0" >
<!-- 1. Data Explorer & Sidebar -->
< div class = "col-span-12 md:col-span-2 h-full" >
< div class = "wireframe-box h-full bg-amber-50/50 border-amber-200 text-amber-600 flex flex-col justify-center text-center p-2"
onclick="event.stopPropagation(); scrollToSection('ui')"
title="src/dataExplorer.js, src/ui.js">
Data Explorer & Sidebar
< / div >
< / div >
<!-- 2. Radar Canvas (Center) -->
< div class = "col-span-12 md:col-span-6 h-full" >
< div class = "wireframe-box h-full bg-emerald-50/50 border-emerald-200 text-emerald-600 flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('visualization')"
title="src/p5/radarSketch.js">
Radar Visualization Canvas< br >
< span class = "text-xs font-normal opacity-75 mt-1" > (p5.js Render Loop)< / span >
< / div >
< / div >
<!-- 3. Video & Graph (Right) -->
< div class = "col-span-12 md:col-span-3 h-full flex flex-col gap-4" >
< div class = "wireframe-box h-1/2 bg-red-50/50 border-red-200 text-red-600 flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('sync')"
title="src/sync.js">
Video Player< br >
< span class = "text-xs font-normal opacity-75 mt-1" > (Sync Engine)< / span >
< / div >
< div class = "wireframe-box h-1/2 bg-emerald-50/50 border-emerald-200 text-emerald-600 flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('visualization')"
title="src/p5/speedGraphSketch.js">
Speed Graph
< / div >
< / div >
< / div >
<!-- Bottom Row: Controls (Fits Ecosystem Width) -->
< div class = "h-14" >
< div class = "wireframe-box h-full bg-amber-50/50 border-amber-200 text-amber-600"
onclick="event.stopPropagation(); scrollToSection('ui')"
title="src/dom.js & src/ui.js">
Playback Controls & Timeline
< / div >
< / div >
< / div >
<!-- Right: Pipeline/Storage (The "Data Injector" - Full Height) -->
< div class = "w-16 h-full flex flex-col pt-2 relative" >
<!-- Data Flow Arrows (Precisely Aligned) -->
< div class = "absolute inset-0 -left-6 pointer-events-none z-10" >
<!-- Top Arrow (Video) -->
< div class = "absolute top-[75px] w-6" >
< svg viewBox = "0 0 24 12" class = "text-blue-500 drop-shadow-sm" >
< path d = "M2 6h20 M2 6l4-4 M2 6l4 4 M22 6l-4-4 M22 6l-4 4"
fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
< / svg >
< / div >
<!-- Mid Arrow (Graph) -->
< div class = "absolute top-[235px] w-6" >
< svg viewBox = "0 0 24 12" class = "text-blue-500 drop-shadow-sm" >
< path d = "M2 6h20 M2 6l4-4 M2 6l4 4 M22 6l-4-4 M22 6l-4 4"
fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
< / svg >
< / div >
<!-- Low Arrow (Controls) -->
< div class = "absolute top-[350px] w-6" >
< svg viewBox = "0 0 24 12" class = "text-blue-500 drop-shadow-sm" >
< path d = "M2 6h20 M2 6l4-4 M2 6l4 4 M22 6l-4-4 M22 6l-4 4"
fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
< / svg >
< / div >
< / div >
< div class = "database-unit h-full flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('pipeline')"
title="src/fileLoader.js, src/db.js">
< div style = "writing-mode: vertical-rl; text-orientation: mixed;" class = "flex flex-col items-center gap-2 px-2 py-4" >
< span class = "font-bold uppercase tracking-tighter text-blue-700 text-[11px]" > Data Pipeline & Storage< / span >
< span class = "text-[9px] font-semibold text-blue-500 opacity-80" > (Loader/DB)< / span >
< / div >
< / div >
<!-- Small shadow for the base -->
< div class = "h-2 w-full bg-slate-300 rounded-[50%] blur-[2px] mt-1 opacity-40" > < / div >
<!-- Top Area: Visual Map + File Structure -->
< div class = "flex flex-col lg:flex-row gap-8 mb-12 items-start relative" >
<!-- LEFT: INTERACTIVE VISUAL MAP -->
< div id = "visual-nav-placeholder" class = "flex-grow w-full lg:w-3/4 transition-all duration-500" >
< div id = "visual-nav-wrapper" class = "rounded-xl p-4 md:p-6 mb-8" >
< div class = "flex justify-between items-center mb-4" >
< h2 class = "text-sm font-bold text-slate-400 uppercase tracking-widest m-0" > Visual Navigation Map< / h2 >
< span class = "text-xs text-slate-400 italic" > Click a UI element to see its code< / span >
< / div >
< div id = "visual-nav-content" class = "max-w-4xl mx-auto" >
<!-- Core Architecture Wrapper -->
< div class = "core-wrapper" onclick = "scrollToSection('architecture')" >
<!-- Main Grid Layout (Matches App Interface) -->
< div class = "flex gap-4 h-[380px]" >
<!-- Left: App Ecosystem Rectangle -->
< div class = "flex-grow flex flex-col gap-4" >
<!-- Top Row: Main UI Components -->
< div class = "flex-grow grid grid-cols-11 gap-4 min-h-0" >
<!-- 1. Data Explorer & Sidebar -->
< div class = "col-span-12 md:col-span-2 h-full" >
< div class = "wireframe-box h-full bg-amber-50/50 border-amber-200 text-amber-600 flex flex-col justify-center text-center p-2"
onclick="event.stopPropagation(); scrollToSection('ui')"
title="src/dataExplorer.js, src/ui.js">
Data Explorer & Sidebar
< / div >
< / div >
<!-- 2. Radar Canvas (Center) -->
< div class = "col-span-12 md:col-span-6 h-full" >
< div class = "wireframe-box h-full bg-emerald-50/50 border-emerald-200 text-emerald-600 flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('visualization')"
title="src/p5/radarSketch.js">
Radar Visualization Canvas< br >
< span class = "text-xs font-normal opacity-75 mt-1" > (p5.js Render Loop)< / span >
< / div >
< / div >
<!-- 3. Video & Graph (Right) -->
< div class = "col-span-12 md:col-span-3 h-full flex flex-col gap-4" >
< div class = "wireframe-box h-1/2 bg-red-50/50 border-red-200 text-red-600 flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('sync')"
title="src/sync.js">
Video Player< br >
< span class = "text-xs font-normal opacity-75 mt-1" > (Sync Engine)< / span >
< / div >
< div class = "wireframe-box h-1/2 bg-emerald-50/50 border-emerald-200 text-emerald-600 flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('visualization')"
title="src/p5/speedGraphSketch.js">
Speed Graph
< / div >
< / div >
< / div >
<!-- Bottom Row: Controls (Fits Ecosystem Width) -->
< div class = "h-14" >
< div class = "wireframe-box h-full bg-amber-50/50 border-amber-200 text-amber-600"
onclick="event.stopPropagation(); scrollToSection('ui')"
title="src/dom.js & src/ui.js">
Playback Controls & Timeline
< / div >
< / div >
< / div >
<!-- Right: Pipeline/Storage (The "Data Injector" - Full Height) -->
< div class = "w-16 h-full flex flex-col pt-2 relative" >
<!-- Data Flow Arrows (Precisely Aligned) -->
< div class = "absolute inset-0 -left-6 pointer-events-none z-10" >
<!-- Top Arrow (Video) -->
< div class = "absolute top-[75px] w-6" >
< svg viewBox = "0 0 24 12" class = "text-blue-500 drop-shadow-sm" >
< path d = "M2 6h20 M2 6l4-4 M2 6l4 4 M22 6l-4-4 M22 6l-4 4"
fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
< / svg >
< / div >
<!-- Mid Arrow (Graph) -->
< div class = "absolute top-[235px] w-6" >
< svg viewBox = "0 0 24 12" class = "text-blue-500 drop-shadow-sm" >
< path d = "M2 6h20 M2 6l4-4 M2 6l4 4 M22 6l-4-4 M22 6l-4 4"
fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
< / svg >
< / div >
<!-- Low Arrow (Controls) -->
< div class = "absolute top-[350px] w-6" >
< svg viewBox = "0 0 24 12" class = "text-blue-500 drop-shadow-sm" >
< path d = "M2 6h20 M2 6l4-4 M2 6l4 4 M22 6l-4-4 M22 6l-4 4"
fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
< / svg >
< / div >
< / div >
< div class = "database-unit h-full flex flex-col justify-center"
onclick="event.stopPropagation(); scrollToSection('pipeline')"
title="src/fileLoader.js, src/db.js">
< div style = "writing-mode: vertical-rl; text-orientation: mixed;" class = "flex flex-col items-center justify-center h-full py-4 gap-1" >
< span class = "font-bold uppercase tracking-widest text-blue-700 text-[10px] whitespace-nowrap" > Data Pipeline & Storage< / span >
< span class = "text-[9px] font-medium text-blue-500 opacity-80 tracking-wide" > (Loader/DB)< / span >
< / div >
< / div > <!-- Small shadow for the base -->
< div class = "h-2 w-full bg-slate-300 rounded-[50%] blur-[2px] mt-1 opacity-40" > < / div >
< / div >
< / div >
< / div > <!-- End Core Wrapper -->
< / div >
< / div >
< / div >
< / div >
<!-- RIGHT: FILE STRUCTURE PANEL (Disappears on scroll) -->
< div id = "file-structure-panel" class = "w-full lg:w-1/4 h-full pt-4 transition-opacity duration-300 overflow-y-auto custom-scrollbar" style = "max-height: 80vh;" >
< div class = "bg-white rounded-xl shadow-sm border border-slate-200 p-5 sticky top-0" >
< h3 class = "text-xs font-bold text-slate-400 uppercase tracking-widest mb-4 border-b pb-2 flex justify-between" >
< span > Project Files< / span >
< span class = "text-[10px] opacity-60" > src/< / span >
< / h3 >
< ul class = "file-tree text-xs space-y-1.5 font-mono leading-tight" >
< li class = "file opacity-50" > index.html< / li >
< li class = "file opacity-50" > readme.md< / li >
< / div >
< / div > <!-- End Core Wrapper -->
<!-- SRC Folder -->
< li class = "folder text-slate-800 font-bold mt-2" > src/
< ul class = "file-tree pl-3 border-l-2 border-slate-100 ml-1 mt-1 space-y-1.5" >
<!-- Core (Purple) -->
< li class = "file group cursor-help" title = "Application Entry Point" onclick = "scrollToSection('architecture')" > < span class = "bg-purple-100 text-purple-700 font-medium px-1.5 py-0.5 rounded border border-purple-200 group-hover:bg-purple-200 transition-colors" > main.js< / span > < / li >
< li class = "file group" > < span class = "bg-purple-50 text-purple-600 px-1.5 py-0.5 rounded group-hover:bg-purple-100 transition-colors" > state.js< / span > < / li >
< li class = "file group" > < span class = "bg-purple-50 text-purple-600 px-1.5 py-0.5 rounded group-hover:bg-purple-100 transition-colors" > constants.js< / span > < / li >
<!-- Pipeline (Blue) -->
< li class = "file group cursor-help mt-2" title = "File Input Handler" onclick = "scrollToSection('pipeline')" > < span class = "bg-blue-100 text-blue-700 font-medium px-1.5 py-0.5 rounded border border-blue-200" > fileLoader.js< / span > < / li >
< li class = "file group" > < span class = "bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded" > fileParsers.js< / span > < / li >
< li class = "file group" > < span class = "bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded" > parser.worker.js< / span > < / li >
< li class = "file group" > < span class = "bg-blue-50 text-blue-600 px-1.5 py-0.5 rounded" > db.js< / span > < / li >
<!-- Sync (Red) -->
< li class = "file group cursor-help mt-2" title = "Master Sync Engine" onclick = "scrollToSection('sync')" > < span class = "bg-red-100 text-red-700 font-medium px-1.5 py-0.5 rounded border border-red-200" > sync.js< / span > < / li >
< li class = "file group" > < span class = "bg-red-50 text-red-700 px-1.5 py-0.5 rounded" > utils.js< / span > < / li >
<!-- UI (Amber) -->
< li class = "file group cursor-help mt-2" title = "DOM Reference Cache" onclick = "scrollToSection('ui')" > < span class = "bg-amber-100 text-amber-700 font-medium px-1.5 py-0.5 rounded border border-amber-200" > dom.js< / span > < / li >
< li class = "file group" > < span class = "bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded" > ui.js< / span > < / li >
< li class = "file group" > < span class = "bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded" > keyboard.js< / span > < / li >
< li class = "file group" > < span class = "bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded" > dataExplorer.js< / span > < / li >
< li class = "file group" > < span class = "bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded" > session.js< / span > < / li >
< li class = "file group" > < span class = "bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded" > theme.js< / span > < / li >
< li class = "file group" > < span class = "bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded" > modal.js< / span > < / li >
< li class = "file group" > < span class = "bg-amber-50 text-amber-700 px-1.5 py-0.5 rounded" > debug.js< / span > < / li >
<!-- Viz (Emerald) -->
< li class = "file group cursor-help mt-2" title = "Core Drawing Library" onclick = "scrollToSection('visualization')" > < span class = "bg-emerald-100 text-emerald-800 font-medium px-1.5 py-0.5 rounded border border-emerald-200" > drawUtils.js< / span > < / li >
< li class = "folder text-slate-700 font-medium mt-1" > p5/
< ul class = "file-tree pl-3 border-l-2 border-emerald-100 ml-1 mt-1 space-y-1" >
< li class = "file group cursor-help" title = "Main Radar Renderer" onclick = "scrollToSection('visualization')" > < span class = "bg-emerald-100 text-emerald-800 font-medium px-1.5 py-0.5 rounded border border-emerald-200" > radarSketch.js< / span > < / li >
< li class = "file" > < span class = "bg-emerald-50 text-emerald-700 px-1.5 py-0.5 rounded" > speedGraphSketch.js< / span > < / li >
< li class = "file" > < span class = "bg-emerald-50 text-emerald-700 px-1.5 py-0.5 rounded" > zoomSketch.js< / span > < / li >
< / ul >
< / li >
< / ul >
< / li >
< / ul >
< / div >
< / div >
< / div >
<!-- 1. Core Architecture (Purple) -->
< section id = "architecture" >
< div class = "border border-purple-200 bg-purple-50/50 rounded-2xl p-6 md:p-8 shadow-sm" >
@ -1664,34 +1276,103 @@
}
}
// Shrink-on-scroll effect
const navWrapper = document.getElementById('visual-nav-wrapper');
const navPlaceholder = document.getElementById('visual-nav-placeholder');
const navContent = document.getElementById('visual-nav-content');
// Shrink-on-scroll effect
window.addEventListener('scroll', () => {
const currentScrollY = window.scrollY;
const navWrapper = document.getElementById('visual-nav-wrapper');
// Threshold: When the user scrolls past the initial header + some buffer
if (currentScrollY > 100) {
if (!navWrapper.classList.contains('shrunk')) {
// Lock the height of the placeholder to prevent layout shift
navPlaceholder.style.height = navWrapper.offsetHeight + 'px';
const navPlaceholder = document.getElementById('visual-nav-placeholder');
navWrapper.classList.add('shrunk');
navWrapper.title = "Hover to expand map";
}
} else {
if (navWrapper.classList.contains('shrunk')) {
navWrapper.classList.remove('shrunk');
navWrapper.title = "";
const filePanel = document.getElementById('file-structure-panel');
// Unlock the height
navPlaceholder.style.height = 'auto';
}
}
}, { passive: true });
< / script >
< / body >
let interactTimeout = null;
window.addEventListener('scroll', () => {
const currentScrollY = window.scrollY;
// Threshold: When the user scrolls past the initial header + some buffer
if (currentScrollY > 100) {
if (!navWrapper.classList.contains('shrunk')) {
// Lock the height of the placeholder to prevent layout shift
navPlaceholder.style.height = navWrapper.offsetHeight + 'px';
navWrapper.classList.add('shrunk');
navWrapper.title = "Hover to expand map";
// Enable hover interaction ONLY after animation completes (500ms)
if (interactTimeout) clearTimeout(interactTimeout);
interactTimeout = setTimeout(() => {
navWrapper.classList.add('interactive');
}, 500);
// Hide File Structure (Only on Desktop where it sits alongside)
if (filePanel & & window.innerWidth >= 1024) {
filePanel.style.opacity = '0';
filePanel.style.pointerEvents = 'none';
}
}
} else {
if (navWrapper.classList.contains('shrunk')) {
// Reset interaction state immediately
navWrapper.classList.remove('shrunk', 'interactive');
if (interactTimeout) clearTimeout(interactTimeout);
navWrapper.title = "";
// Unlock the height
navPlaceholder.style.height = 'auto';
// Show File Structure
if (filePanel) {
filePanel.style.opacity = '1';
filePanel.style.pointerEvents = 'auto';
}
}
}
}, { passive: true });
< / script > < / body >
< / html >