Component Architecture for the Player
Structure the player as three separate components: `VideoPlayer` (the raw `<video>` element and hls.js integration, controlled entirely through refs), `PlayerControls` (the overlay UI for play/pause, timeline, volume — communicates with VideoPlayer through callback props), and `PlayerShell` (the positioning wrapper that handles fullscreen, aspect ratio, and the dark background overlay). Keeping these separated prevents the UI state of the controls from causing video element re-renders. The VideoPlayer component should be wrapped in `React.memo` to prevent re-rendering when parent state changes.
Implementing Local Watch History
Watch history without a backend is straightforward with `localStorage`. Create a custom hook `useWatchHistory` that reads and writes to `localStorage` with a key like `fluxplays_history`. Store an array of objects: `{ url, title, timestamp, durationWatched, addedAt }`. The hook exposes `addToHistory(url, title)`, `updateProgress(url, timestamp)`, and `getHistory()`. Call `updateProgress` inside the video's `timeupdate` event throttled to once every 5 seconds — updating localStorage more frequently is unnecessary and slightly wastes battery. Clear history older than 30 days on each read.
Dark UI Design Patterns for Video
A streaming UI should not compete with the video for visual attention. Use a dark surface baseline (`#0a0a0a` or similar near-black, not pure `#000000` which causes eye strain contrast issues). Typography should be `text-white/80` for primary content and `text-white/40` for secondary labels. Use a subtle `backdrop-blur` for any overlays that appear over video thumbnails or poster images. Smooth transitions between states matter more in dark UIs — `transition: all 200ms ease` on opacity and transform properties gives the interface a polished, professional feel.