# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview **Alta Video Player (WebAVP)** — a web-based surveillance video player for Alta/Ava Security camera exports. Users drag-drop video files or ZIP archives (including AES-256 encrypted ones) and get a multi-camera synchronized playback experience with timeline, digital zoom, and cryptographic integrity verification. ## Running the App Desktop mode: ```bash npm install npm start ``` Web/Python mode: ```bash python3 app.py # Serves on http://0.0.0.0:5152 ``` The Python server uses only stdlib modules. Electron dependencies are managed through `package.json` and `package-lock.json`. Checks: ```bash npm run check xvfb-run -a npm run smoke ``` ## Architecture ### Backend (`app.py`) Minimal HTTP server with three routes: - `GET /` — serves `templates/index.html` - `GET /static/*` — serves static files with path traversal protection - `GET /api/verify-cert?serial=...&certificateHash=...` — proxies certificate verification to `https://aware.avasecurity.com/api/v1/public/verifyServerCertificate` ### Frontend (`templates/index.html`) Single self-contained HTML file (~4000 lines) with inline CSS and JavaScript in an IIFE. This is the entire application — there is no framework, no build system, no separate JS modules. **State model:** Global `channels` Map keyed by channel name. Each channel holds segments (video blobs + time ranges), metadata, DOM references, color, and zoom state. Global timeline state (`globalStart`, `globalEnd`, `currentTime`) synchronizes all cameras. **Key subsystems:** - **File ingestion** — drag-drop files/folders, ZIP extraction (JSZip for plain, custom AES-256-CTR for encrypted), metadata pairing by base filename, concurrent import guard (`isImporting` flag) - **Multi-camera grid** — responsive CSS grid (1–9 cameras), drag-to-reorder, click-to-expand - **Playback engine** — `requestAnimationFrame` tick loop, per-channel segment visibility management, variable speed (0.25x–8x), frame stepping - **Timeline** — interactive scrub bar with zoom (mouse wheel), minimap, per-channel segment indicators with color-coded dots - **Digital zoom** — per-camera scroll-to-zoom (up to 10x) with click-drag panning - **Magnifier tool** — draw rectangle to zoom into region - **Slideshow mode** — animated grid showing only currently active feeds with transitions - **Integrity verification** — offline X.509 certificate parsing, RSASSA-PKCS1-v1_5 and ECDSA signature verification via Web Crypto API, optional cloud verification through `/api/verify-cert` - **Session persistence** — IndexedDB caching of video blobs and metadata for page refresh survival **External dependency:** `/static/jszip.min.js` (vendored, for unencrypted ZIP parsing). Motion analytics were intentionally removed. Keep future work focused on core video player behavior unless the product direction changes. ## Memory Management Video elements must be properly destroyed to avoid browser memory exhaustion: - **`destroyVideoEl(videoEl)`** — pauses video, removes `src`, calls `.load()` to force browser to release buffered data. Must be called before removing video elements from DOM. - **`video.preload = 'metadata'`** — all playback videos use metadata-only preloading to avoid buffering entire files into RAM. - **`newSession()`** — comprehensive teardown: destroys all video elements, revokes all blob URLs, nulls blob references, releases WebGL contexts, clears all state. - **`isImporting` guard** — prevents concurrent file imports which could cause race conditions and duplicate segments. - Slideshow video elements are destroyed on pane transitions and when slideshow is toggled off. ## Key Conventions - All frontend code lives in `templates/index.html` — CSS at top, then the IIFE script block - Video elements are created on-demand and hidden (not removed) for performance - Segment visibility is recalculated every animation frame during playback - The `batchingSegments` flag defers rendering during bulk file imports - Keyboard shortcuts are defined inline (Space=play/pause, arrows=seek, S=slideshow, M=magnifier, F=fullscreen, [/]=speed, 0=reset zoom) - Right-side panel (log) is the only slide-out; opening it does not affect other panels