From e5b5c6629e735594f91dfd8014e2bbe74559ac45 Mon Sep 17 00:00:00 2001 From: rakadu1 Date: Fri, 28 Nov 2025 10:20:03 +0530 Subject: [PATCH] Updated context.md and Readme.md --- steps/context.md | 109 ++++++++++++++++++++++++++++++----------------- steps/readme.md | 22 ++++++---- steps/src/dom.js | 15 ++++++- 3 files changed, 96 insertions(+), 50 deletions(-) diff --git a/steps/context.md b/steps/context.md index 9e675db..0c25072 100644 --- a/steps/context.md +++ b/steps/context.md @@ -10,7 +10,7 @@ Context Document: Radar and Video Synchronizer Application - **Visualization**: `p5.js` for the main radar plot, a zoomed-in "god mode" view, and a time-series speed graph. - **Data Handling**: - **Web Workers** (`parser.worker.js`) with the `Clarinet.js` streaming library to parse large JSON files off the main thread, preventing UI freezes. - - `Oboe.js` is also loaded but the primary implementation uses the worker. + - `Oboe.js` is included in vendor files but `Clarinet.js` is the active parser. - **Data Exploration**: `AG-Grid` for tabular data view and `Chart.js` for plotting data from the grid. - **Persistence**: `IndexedDB` for caching large files (JSON, Video) and `localStorage` for user settings (UI state, theme, file references). @@ -20,65 +20,96 @@ The application uses a modular ES6 structure. All source code resides in the `/s - **`index.html`**: The main HTML shell. Defines the DOM structure, including the main layout, collapsible sidebar, data explorer panel, and modal dialogs. It loads all necessary CDN libraries and the main JS module. -- **`/src/main.js`**: **The Orchestrator**. This is the application's entry point. It initializes all modules, wires up all event listeners (clicks, drag-drop, keydown), and manages the file loading pipeline and application lifecycle. +- **`/src/main.js`**: **The Orchestrator**. This is the application's entry point. It initializes the database, theme, and data explorer. It sets up the initial event listeners for the UI and delegates specialized tasks to other modules (`fileLoader.js`, `keyboard.js`, `sync.js`). - **`/src/state.js`**: **The Single Source of Truth**. Exports a single global `appState` object that holds all dynamic data (e.g., `vizData`, `isPlaying`, `currentFrame`). All modules import from this file. -- **`/src/dom.js`**: **The UI Abstraction Layer**. Exports constants for every key DOM element and contains functions that directly manipulate the DOM, such as `updateFrame()`, `resetUIForNewLoad()`, and `updatePersistentOverlays()`. +- **`/src/fileLoader.js`**: **File Management**. Handles the file loading pipeline. It manages drag-and-drop interactions, file input changes, and the unified processing of JSON and Video files. It handles caching logic (saving/loading from `IndexedDB`) and triggers the parsing worker. -- **`/src/sync.js`**: **The Heartbeat/Clock**. Contains the `animationLoop()` function. It uses `performance.now()` to create a high-precision clock, calculates the current media time, finds the corresponding radar frame, and handles resynchronization with the video element. +- **`/src/keyboard.js`**: **Input Handling**. Manages all keyboard shortcuts. It creates a centralized `keydown` listener that triggers UI actions (play/pause, seeking, toggles) and prevents interference with input fields. + +- **`/src/sync.js`**: **The Heartbeat & Controller**. Contains the core logic for playback and synchronization. + - `animationLoop()`: The main render loop that keeps the UI updated. + - `videoFrameCallback()`: The high-precision video timing loop. + - `updateFrame()`: The central function that updates the current frame index, synchronizes the video (handling drift), and updates UI elements (sliders, counters, overlays). + - `resetVisualization()`: Resets the playback state. + - Handles timeline interactions (input, scroll wheel) and video panel scrolling. + +- **`/src/dom.js`**: **The UI Interface**. Exports constants for every key DOM element. It contains functions to update specific UI components like persistent overlays (`updatePersistentOverlays`), debug overlays (`updateDebugOverlay`), and custom TTC scheme inputs. *Note: Core playback-driven UI updates have moved to `sync.js`.* - **`/src/fileParsers.js`**: **The Data Processor**. Contains `parseVisualizationJson()`, which takes the raw parsed JSON object and enriches it with calculated `timestampMs` values relative to the video start time and determines global SNR ranges. -- **`/src/parser.worker.js`**: **The Heavy Lifter**. A Web Worker that uses `Clarinet.js` to stream-parse the JSON file, preventing the main thread from freezing. It posts progress updates and the final parsed object back to `main.js`. +- **`/src/parser.worker.js`**: **The Heavy Lifter**. A Web Worker that uses `Clarinet.js` to stream-parse the JSON file, preventing the main thread from freezing. It posts progress updates and the final parsed object back to `main.js` (via `fileLoader.js`). - **`/src/db.js`**: **The Caching Layer**. Manages all interactions with `IndexedDB` to save and load file blobs and their metadata, enabling fast session reloads. -- **`/src/dataExplorer.js`**: **The Inspector**. Manages the "Data Explorer" panel. It uses AG-Grid to display data in a table and Chart.js to plot selected columns. +- **`/src/dataExplorer.js`**: **The Inspector**. Manages the "Data Explorer" panel. It uses AG-Grid to display data in a table and Chart.js to plot selected columns. It includes `throttledUpdateExplorer` to efficiently update the view during playback. -- **`/src/p5/radarSketch.js`**: The p5.js sketch for the main radar visualization (point cloud, tracks, axes, ego vehicle). +- **`/src/debug.js`**: **Debug Configuration**. Exports `debugFlags` to toggle logging for various subsystems (sync, drawing, file loading) and configure constants like video load timeouts. -- **`/src/p5/speedGraphSketch.js`**: The p5.js sketch for the time-series speed graph. +- **`/src/utils.js`**: **Toolbox**. A collection of pure, reusable helper functions (e.g., `findRadarFrameIndexForTime` (binary search), timestamp parsers, `throttle`, `precomputeRadarVideoSync`). -- **`/src/p5/zoomSketch.js`**: The p5.js sketch for the "GOD MODE" magnified view that follows the mouse. +- **`/src/modal.js`**: **User Feedback**. Manages the logic for pop-up modal dialogs, including notifications, confirmations, and loading progress bars. -- **`/src/drawUtils.js`**: **The Artist's Toolkit**. Contains pure drawing functions called by the p5 sketches (e.g., `drawPointCloud`, `drawTrajectories`). This is where the visual appearance of radar objects is defined. +- **`/src/theme.js`**: **Styling**. Handles the dark/light mode theme switching. -- **`/src/utils.js`**: A collection of pure, reusable helper functions (e.g., `findRadarFrameIndexForTime` (binary search), timestamp parsers, `throttle`). +- **`/src/constants.js`**: **Configuration**. Stores shared, static values like `VIDEO_FPS` and radar plot boundaries. -- **`/src/modal.js`**: Manages the logic for pop-up modal dialogs, including notifications, confirmations, and loading progress bars. +- **`/src/p5/`**: **Visualization Modules**. + - **`radarSketch.js`**: The main radar visualization (point cloud, tracks, axes, ego vehicle). + - **`speedGraphSketch.js`**: The time-series speed graph. + - **`zoomSketch.js`**: The "GOD MODE" magnified view. -- **`/src/theme.js`**: Handles the dark/light mode theme switching. - -- **`/src/constants.js`**: Stores shared, static values like `VIDEO_FPS` and radar plot boundaries. +- **`/src/drawUtils.js`**: **The Artist's Toolkit**. Contains pure drawing functions called by the p5 sketches (e.g., `drawPointCloud`, `drawTrajectories`). This is where the visual appearance of radar objects is defined. ### 3. Data Flow & State Management -**File Loading Pipeline (`main.js`):** -1. **User Action**: User drops files or uses "Load" buttons. The `handleFiles()` function is triggered. -2. **UI Reset**: `resetUIForNewLoad()` is called to clear the previous state. -3. **Pipeline Start**: `processFilePipeline()` begins. A loading modal is shown. -4. **JSON Parsing**: If a JSON file exists, it's sent to `parser.worker.js`. The worker streams the file, posts progress updates, and finally returns the complete parsed object. -5. **JSON Processing**: The parsed object is processed by `parseVisualizationJson()` to calculate relative timestamps and SNR ranges. The result is stored in `appState.vizData`. -6. **Video Loading (Two-Stage)**: - - **Stage A (Metadata)**: An event listener waits for `loadedmetadata`. When this fires, the video's `duration` is known. The `finalizeSetup()` function is called, which creates the p5 sketches and sets up the speed graph. - - **Stage B (Buffering)**: A separate listener waits for `canplaythrough`. When this fires, it signals that the video is ready for smooth playback, and the loading modal is hidden. -7. **Finalization**: `finalizeSetup()` creates the p5 instances and `resetVisualization()` is called to display the first frame. +**File Loading Pipeline (`fileLoader.js`):** +1. **Input**: User drops files or clicks load buttons. `handleFiles()` identifies the file types. +2. **Processing (`processFilePipeline`)**: A loading modal is shown. +3. **Caching**: Files are saved to `IndexedDB` (non-blocking). +4. **Offset**: Timestamp offset is calculated from filenames. +5. **JSON Parsing**: JSON is sent to `parser.worker.js`. The worker streams the file and returns the object. +6. **Post-Processing**: `parseVisualizationJson()` (in `fileParsers.js`) enriches the data. `precomputeRadarVideoSync()` (in `utils.js`) bakes sync times. +7. **Video Loading**: The video is loaded into the player. +8. **Finalization**: `finalizeSetup()` (in `fileLoader.js`) resets the visualization, creates/updates p5 sketches, and updates the UI. + +**Playback & Synchronization (`sync.js`):** +- **Video Master**: The video element's time is the source of truth when playing. +- **`videoFrameCallback`**: Runs on every video frame, finds the corresponding radar frame index, and updates `appState.currentFrame`. +- **`animationLoop`**: Runs on `requestAnimationFrame` (~60Hz). It calls `updateFrame()` to reflect the state on the screen. +- **`updateFrame()`**: + - Updates UI (slider, counter). + - Updates overlays (Ego speed, CAN speed). + - Calls `throttledUpdateExplorer`. + - Handles Video Seek: If `forceVideoSeek` is true (e.g., user scrubbed the timeline), it sets `videoPlayer.currentTime`. +- **Drift Correction**: If the video drifts significantly from the target radar frame time, `updateFrame` forces a seek to resync. **State Management (`appState`):** The `appState` object in `state.js` is the central hub. Key properties include: - `vizData`: The large object containing all radar frames and track data. -- `isPlaying`: A boolean that controls the `animationLoop`. -- `currentFrame`: The integer index of the currently displayed radar frame. -- `videoStartDate`, `radarStartTimeMs`: Date objects used to calculate the time offset. -- `p5_instance`, `speedGraphInstance`, `zoomSketchInstance`: References to the active p5.js sketches. - -### 4. Key Logic and Interaction Flows - -**Playback Synchronization (`sync.js`)**: The `animationLoop` is the core. It uses `performance.now()` to create a high-resolution timer independent of the video's `timeupdate` event. It calculates what the video's `currentTime` *should* be, finds the corresponding radar frame using a binary search (`findRadarFrameIndexForTime` in `utils.js`), and periodically corrects the video's `currentTime` if it drifts. - -**UI Updates (`dom.js`)**: The `updateFrame(frame, forceVideoSeek)` function is the primary entry point for changing what's on screen. It updates the frame counter, seeks the video if `forceVideoSeek` is true, and calls the `.redraw()` methods on the p5 sketches. It's called by both the `animationLoop` (for smooth playback) and by UI event listeners like the timeline slider (for seeking). - -**Session Persistence (`main.js` & `db.js`)**: On `DOMContentLoaded`, the app checks `localStorage` for saved filenames. It then calls `loadFreshFileFromDB()` to attempt to load the corresponding blobs from `IndexedDB`. If successful, `handleFiles()` is called with the cached blobs, bypassing the need for user file selection. - -**Keyboard Shortcuts (`main.js`)**: A single `keydown` event listener on the document handles all shortcuts. It programmatically triggers `.click()` events on the corresponding DOM elements (e.g., Spacebar clicks `playPauseBtn`). It includes a check to prevent shortcuts from firing when the user is typing in an input field. \ No newline at end of file +- `isPlaying`: Boolean controlling the loop. +- `currentFrame`: Integer index of the currently displayed radar frame. +- `offset`: Manual or auto-calculated time offset (ms). +- `videoStartDate`, `radarStartTimeMs`: Timestamps for absolute time calculation. +- `p5_instance`, `speedGraphInstance`: References to active sketches. +- `videoMissing`: Flag for JSON-only mode. + +### 4. Key Interaction Flows + +**Timeline Scrubbing (`sync.js`)**: +- **Drag**: `handleTimelineInput` updates the UI immediately for responsiveness but debounces the expensive video seek until the user stops dragging. +- **Scroll Wheel**: `handleTimelineWheel` allows frame-by-frame or accelerated seeking. It also updates UI immediately and debounces the video seek. + +**Data Explorer (`dataExplorer.js`)**: +- Activated by `I` key or canvas click. +- Shows Tree, Grid, and Plot views. +- Updates are throttled to prevent performance degradation during playback. + +**Session Management (`main.js` & `db.js`)**: +- `saveSessionBtn` saves current filenames, offset, and toggles to a JSON file. +- `loadSessionBtn` reads the session file. It verifies that the referenced files exist in `IndexedDB` (via `loadFreshFileFromDB`) before applying settings and reloading the page. + +**Keyboard Shortcuts (`keyboard.js`)**: +- Centralized handler for `Play/Pause` (Space), `Seek` (Arrows), `Toggle Views` (1-4, T, D, G, P, C), `Debug` (A), `Theme` (Q). +- Smartly ignores shortcuts when input fields are focused. \ No newline at end of file diff --git a/steps/readme.md b/steps/readme.md index 4049243..3a30f03 100644 --- a/steps/readme.md +++ b/steps/readme.md @@ -22,7 +22,7 @@ Uses a binary search (utils.js::findRadarFrameIndexForTime) to efficiently find Periodically checks for drift (>150ms) between the master clock's calculated time and videoPlayer.currentTime, forcing a video seek if needed to maintain sync. -Unified File Loading (main.js): +Unified File Loading (fileLoader.js): Handles loading JSON (radar data) and Video files through both button clicks (loadJsonBtn, loadVideoBtn) and drag-and-drop onto the main content area (
). @@ -30,7 +30,7 @@ The handleFiles function identifies file types (.json, video/*) and triggers the Note: Dedicated CAN log loading (loadCanBtn, canFileInput) has been removed. CAN speed data (canVehSpeed_kmph) is now expected within the JSON structure, associated with each radarFrame. -Efficient JSON Parsing (parser.worker.js, main.js, fileParsers.js): +Efficient JSON Parsing (parser.worker.js, fileLoader.js, fileParsers.js): The processFilePipeline function initiates a Web Worker (parser.worker.js). @@ -116,15 +116,15 @@ SNR range inputs (snrMinInput, snrMaxInput) update appState.globalMinSnr/MaxSnr TTC coloring mode (ttcModeDefault, ttcModeCustom) and custom inputs (ttcColorCritical, ttcTimeCritical, etc.) update appState.useCustomTtcScheme and appState.customTtcScheme respectively (dom.js event listeners). drawUtils.js::drawTrajectories uses this state to color tracks. -Playback Controls & Navigation (main.js, dom.js): +Playback Controls & Navigation (sync.js, main.js, dom.js): Standard buttons (playPauseBtn, stopBtn) modify appState.isPlaying and call videoPlayer.play/pause/currentTime. timelineSlider input event updates appState.currentFrame and calls dom.js::updateFrame(frame, true) (forcing video seek). Throttled for performance during drag, debounced for final sync on release. -timelineSlider wheel event calculates scroll speed and dynamically seeks frames, also debounced for final sync (main.js). +timelineSlider wheel event calculates scroll speed and dynamically seeks frames, also debounced for final sync (sync.js). -timelineSlider mousemove event calculates hover position to display frame/time in #timeline-tooltip (main.js). +timelineSlider mousemove event calculates hover position to display frame/time in #timeline-tooltip (sync.js). speedSlider updates videoPlayer.playbackRate (main.js). @@ -148,7 +148,7 @@ saveSessionBtn gathers current state (appState filenames, offsetInput.value, tog loadSessionBtn reads a chosen session JSON file. It verifies that the files mentioned in the session currently exist and are valid in IndexedDB using loadFreshFileFromDB before applying settings to localStorage and reloading the page (main.js). -Keyboard Shortcuts (main.js): +Keyboard Shortcuts (keyboard.js): A comprehensive keydown listener intercepts keys (Space, Arrows, 1-4, S, T, D, G, P, A, M, Q, R, C, I). @@ -180,10 +180,13 @@ Project Structure ├── constants.js # Shared constants (radar bounds, FPS) ├── dataExplorer.js # NEW: Logic for the Data Explorer panel ├── db.js # IndexedDB logic for caching files + ├── debug.js # Debug logging flags ├── dom.js # DOM element references and UI update functions ├── drawUtils.js # p5.js drawing helpers (points, tracks, axes, legends) + ├── fileLoader.js # File handling pipeline (Dropzone, Inputs, Worker trigger) ├── fileParsers.js # Post-processing logic for parsed JSON - ├── main.js # Main application entry point, event wiring, initialization + ├── keyboard.js # Keyboard shortcut handler + ├── main.js # Main application entry point, initialization ├── modal.js # Logic for pop-up modal dialogs & progress bar ├── parser.worker.js # Web Worker for background JSON parsing (uses Clarinet.js) ├── state.js # Centralized application state management object (appState) @@ -195,9 +198,10 @@ Project Structure ├── speedGraphSketch.js # p5.js sketch for the speed graph └── zoomSketch.js # p5.js sketch for the magnified zoom window ("GOD MODE") ├── tests/ # Simple unit tests (optional) +│ ├── fileLoader.test.js +│ ├── fileParsers.test.js │ ├── test-runner.html -│ ├── utils.test.js -│ └── fileParsers.test.js +│ └── utils.test.js └── context.md # Detailed technical overview for AI assistance diff --git a/steps/src/dom.js b/steps/src/dom.js index 6cc9a21..d36b7e1 100644 --- a/steps/src/dom.js +++ b/steps/src/dom.js @@ -148,7 +148,13 @@ export function updateDebugOverlay(currentMediaTime) { if (appState.videoStartDate) { const videoAbsoluteTimeMs = appState.videoStartDate.getTime() + currentMediaTime * 1000; - content.push(`Media Time (s): ${currentMediaTime.toFixed(3)}`); + + let timeString = `Media Time (s): ${currentMediaTime.toFixed(2)}`; // Two decimal places + if (videoPlayer && !isNaN(videoPlayer.duration) && videoPlayer.duration > 0) { + timeString += ` / ${videoPlayer.duration.toFixed(2)}`; // Add total duration with two decimal places + } + content.push(timeString); + content.push(`Video Frame: ${Math.floor(currentMediaTime * VIDEO_FPS)}`); content.push( `Vid Abs Time: ${new Date(videoAbsoluteTimeMs) @@ -274,10 +280,15 @@ export function updatePersistentOverlays(currentMediaTime) { appState.videoStartDate.getTime() + currentMediaTime * 1000 ); const videoFrame = Math.floor(currentMediaTime * VIDEO_FPS); - //console.warn('Could not load radarframes ', appState.vizData.radarFrames) console warning for reference + + let timeDisplay = `Elapsed Time: ${currentMediaTime.toFixed(2)}s`; + if (videoPlayer && !isNaN(videoPlayer.duration) && videoPlayer.duration > 0) { + timeDisplay += ` / ${videoPlayer.duration.toFixed(2)}s`; + } videoInfoOverlay.innerHTML = ` Frame: ${videoFrame} + | ${timeDisplay} | Abs Time: ${formatUTCTime(absVideoTime)} `; }