- Add ThumbnailCache: a worker thread extracts 256x144 thumbnails and media metadata with FFmpeg, SBS-aware cropping, and an on-disk cache under ~/.cache/pixelvr/thumbs. - Draw thumbnails on browser cards through a new rounded-corner thumb.frag pipeline with per-card descriptor sets. - Redesign the browser as a sidebar + card grid, with horizontal stick navigation and direct shortcuts to Network/Home/Videos/Downloads/Drives. - Expand Settings: screen curvature, UI text scale and colour, accent colour and UI distance, organised into sections. - Downloads window: per-job state, progress, speed and ETA, plus pause/resume and cancel-active controls. - Decoder: multi-threaded software decode and four V4L2 output buffers. - docs: unified UI concept, redesign plan and mockups. Release packaging is now reproducible: tools/run.sh is the shipped launcher, tools/package-release.sh assembles the tarball, and a GitHub Actions workflow builds it natively on ARM64 for every v* tag. Stop committing release tarballs; they are attached to releases instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
11 KiB
Pixel VR Player: Implementation Plan for Modern Spatial UI
This document details the concrete implementation plan to bring Mockup #1 (Spatial Card Media Browser) and Mockup #2 (Floating Cinema Transport Dock) into Pixel VR Player, including the Flat vs. Curved Cinema Screen engine and 180°/360° VR contextual adaptations, without breaking existing hardware-accelerated playback or network functionality.
1. Architectural Overview & Design Decisions
Selected Concepts
- File Browser: Concept #1 (Spatial Media Browser) — 3x2 / 4x2 responsive card grid, 16:9 thumbnail previews, format badges (
VR180 3D,4K HEVC), breadcrumb path bar, source tabs (Local,SMB Shares,Downloads), left navigation rail. - Video Controls: Concept #2 (Floating Transport Dock) — Frosted glassmorphic pill dock, prominent glowing central Play/Pause hero button, wide tactile scrubber bar with buffered track & hover timestamp, quick format pill (
VR 180° SBS), audio track pill (ENG 5.1), screen distance/tilt controls, and download status badge. - Cinema Screen: Parametric Flat ↔ Curved Screen Engine — Dynamically adjustable curvature (from
0.0flat plane to1.0IMAX-style cylindrical wrap around the viewer). - 180° / 360° VR Adaptation: Context-aware HUD positioning, torso/yaw "lazy follow", auto-hide fading, and 180°-specific controls (Horizon Tilt & FOV Zoom).
Visual Mockups
Mockup #1: Spatial Media Browser (Card Grid & Navigation Rail)
Mockup #2: Floating Cinema Transport Dock (Interactive Control HUD)
Mockup #3: Minimalist Floating HUD Alternative
graph TD
subgraph "Vulkan Graphics Pipeline"
QuadVert["quad.vert (Parametric Curvature)"]
UIFrag["ui.frag (SDF Pills, Halos, Frosted Glass)"]
TextEngine["text_atlas.cpp (Proportional Sans-Serif SDF)"]
ThumbPool["VkImage Thumbnail Texture Array"]
end
subgraph "Core UI Layer (C++20)"
BrowserView["Browser Grid & Navigation (ui/browser.cpp)"]
ThumbService["Thumbnail Extractor (media/thumb_service.cpp)"]
HUDView["Transport Dock & 180VR Tracker (ui/hud_view.cpp)"]
SettingsDrawer["Tabbed Settings Modal (ui/settings_menu.cpp)"]
end
subgraph "Playback Engine"
HWDecoder["FFmpeg V4L2 M2M Zero-Copy"]
OpenXRInput["Valve Steam Frame Controllers"]
end
QuadVert --> HWDecoder
UIFrag --> HUDView
UIFrag --> BrowserView
TextEngine --> BrowserView
TextEngine --> HUDView
ThumbPool --> ThumbService
ThumbService --> BrowserView
OpenXRInput --> HUDView
OpenXRInput --> BrowserView
2. Flat vs. Curved Cinema Screen Engine
2.1 The Problem
Currently, in shaders/quad.vert, the flat screen is a hardcoded 6-vertex 2D planar quad (vec2 positions[6] = ...). It cannot curve, which leads to edge perspective stretching and focal mismatch in VR headsets when viewing large cinema screens.
2.2 The Curved Mesh Solution
We replace the 2-triangle flat quad with a tessellated parametric cylindrical ribbon (e.g. 64 horizontal subdivisions):
\theta(u) = (u - 0.5) \cdot \alpha_{\text{arc}}, \quad \text{where } \alpha_{\text{arc}} = \frac{W_{\text{screen}}}{R} \cdot \text{curvature}
x(u) = R \cdot \sin(\theta(u)), \quad z(u) = -R \cdot (1 - \cos(\theta(u)))
- Curvature Parameter (
C \in [0.0, 1.0]):C = 0.0: Perfectly flat planar screen (z = 0).C = 0.5: Gentle cinema curve (subtle focal distance equalization).C = 1.0: Immersive IMAX deep wrap (constant focal distance to the eyes across the entire field of view).
- Aspect Ratio & Stereo Preservation:
- Full SBS, Half-SBS, and Top-Bottom stereo scaling remain completely intact.
- Anamorphic widescreen formats (2.39:1, 21:9) wrap naturally around the viewer.
- In-HUD & Settings Control:
- Users can toggle between Flat and Curved or adjust curvature smoothly using thumbstick left/right while pointing at the screen geometry pill.
3. 180° and 360° VR Video Adaptations
When playing VR180 or 360° videos, the video is projected onto a hemisphere/sphere around the user. The UI needs specific behavioral adaptations:
3.1 Lazy-Follow (Torso / Gaze Smoothing)
- Problem: If the HUD is locked in world space, turning around in a 180°/360° scene leaves the controls behind you. If rigidly head-locked, the controls shake with head micro-movements and induce motion sickness.
- Solution (Torso Follow with Deadband):
- Allow a
\pm 20^\circyaw deadband: Small head turns leave the HUD stationary. - When the user turns past
20^\circ, the HUD smoothly glides (exponential damping,\tau = 0.35\text{s}) to catch up with their forward orientation. - Positioned
15^\circbelow horizontal eye-level so it never blocks the primary focal center of the 180VR scene.
- Allow a
3.2 Auto-Fade Immersion Timer
- During active 180VR/360VR playback, the HUD automatically fades out after 3.5 seconds of inactivity.
- Woken up instantly by:
- Moving the controller (velocity threshold).
- Touching the thumbstick or trigger.
- Looking downward toward the dock position.
3.3 Dynamic Context Controls
In Flat/Cinema mode, the controls adjust Screen Distance and Screen Curvature. In 180VR/360VR, these concepts do not exist. The controls dynamically adapt:
| Feature | Cinema / Flat Mode | 180° / 360° VR Mode |
|---|---|---|
| Geometry Pill | [ Flat / Curved Screen ] |
[ Horizon Level / FOV ] |
| Thumbstick Up/Down | Screen Distance (1.5m – 7.0m) | Horizon Pitch Tilt (spherePitch_) |
| Thumbstick Left/Right | Screen Curvature (0% – 100%) | FOV Zoom / IPD scale (sphereZoom_) |
| Bumper Action | Recenter Screen to view line | Recenter 180° Longitude to view line |
| Comfort Depth | Positioned just below bottom bezel | Floats at 1.8m depth, angled 18° up toward eyes |
4. Step-by-Step Implementation Roadmap
flowchart LR
P1["Phase 1<br>Vulkan Shaders & Fonts"] --> P2["Phase 2<br>Curved Screen Engine"]
P2 --> P3["Phase 3<br>Transport Dock (HUD)"]
P3 --> P4["Phase 4<br>Thumbnail Engine"]
P4 --> P5["Phase 5<br>Spatial Media Browser"]
P5 --> P6["Phase 6<br>180VR Polish & QA"]
Phase 1: Vulkan Shaders & Proportional Font Engine
Goal: Provide the visual primitives for modern UI without touching playback logic.
- Shader Primitives (
shaders/ui.frag):- Add new SDF shape types:
UiShape::Pill(stadium shape for badges and buttons).UiShape::GlowRing(for hero play/pause button active halo).UiShape::GradientCard(smooth two-stop vertical gradient for cards).
- Add frosted glass background tinting with antialiased borders.
- Add new SDF shape types:
- Proportional Font Engine (
src/gfx/text_atlas.cpp):- Update
buildFontAtlasto support proportional fonts (Inter-Regular.ttf/Roboto-Medium.ttf). - Store proportional advance and bearing metrics in
Glyphstruct. - Maintain ASCII & common Unicode symbol support (
✓,‹,›,✕,●,★).
- Update
Phase 2: Parametric Curved Screen Engine
Goal: Support seamless switching between flat cinema screen and curved cinema screen.
- Curvature Geometry in
vulkan_renderer.cpp:- Create a static index/vertex buffer for a 64x1 tessellated ribbon or evaluate parametric cylindrical curvature in
quad.vert. - Pass
screenCurvature(0.0 \dots 1.0) through the vertex push constants.
- Create a static index/vertex buffer for a 64x1 tessellated ribbon or evaluate parametric cylindrical curvature in
- Raycasting Update:
- When raycasting against the curved screen (for direct laser pointer scrub), intersect ray with cylinder
(x^2 + z^2 = R^2).
- When raycasting against the curved screen (for direct laser pointer scrub), intersect ray with cylinder
Phase 3: Modern Floating Transport Dock (Mockup #2)
Goal: Implement the sleek, intuitive playback dock.
- Dock Layout Architecture:
- Left section: Download status badge & duration readout.
- Center section: Hero Play/Pause button (
\varnothing 68\text{mm}) + Seek -10s / +10s + tactile scrubber. - Right section: Format Pill (
VR 180° SBS), Audio Pill (ENG 5.1), Geometry Pill (Flat/CurvedorHorizon/FOV).
- 180VR Lazy Follow & Auto-Hide:
- Integrate yaw deadband tracking and alpha fade timer into
src/app/app.cppandvulkan_renderer.cpp. - Smooth alpha transition (
0.0 \to 1.0in 150ms).
- Integrate yaw deadband tracking and alpha fade timer into
Phase 4: Thumbnail Extraction & Caching Engine
Goal: Enable visual preview cards in the browser without UI thread stalls.
- Lightweight Extractor (
src/media/thumbnail_service.cpp):- Background worker thread with queue.
- For local and downloaded files: reads first keyframe at
t \approx 10\%usingavformat_open_input+avcodec_receive_frame. - Rescales to 256x144 RGBA thumbnail.
- Caches to
~/.cache/pixelvr/thumbs/<hash>.bin.
- Vulkan Texture Pool:
- Allocate a
VkImage2D Texture Array (e.g. 16–32 slots) for currently visible browser cards. - Stream loaded thumbnails into the array descriptors.
- Allocate a
Phase 5: Spatial Media Browser (Mockup #1)
Goal: Implement the 3D curved card grid file browser.
- Browser Layout Tree:
- Left Navigation Rail (Home, Videos, SMB Shares, Downloads).
- Top Header (Breadcrumb trail, Source tabs, View toggle).
- 3x2 Grid of Media Cards:
- 16:9 Thumbnail quad.
- Title string with proportional font.
- Format pill badges (
VR180 3D,4K HEVC). - Duration pill (
32:45).
- Input & Pointer Physics:
- 2D grid raycasting: maps hit point directly to
(col, row). - Magnetic snap: gentle suction on laser ray when near card center.
- Smooth thumbstick grid navigation (Up/Down/Left/Right).
- 2D grid raycasting: maps hit point directly to
Phase 6: System Verification & Rigorous QA
Goal: Ensure zero regressions across both desktop and ARM64 hardware.
- Hardware Validation:
- Cross-compile for aarch64 Steam Frame.
- Verify 90 Hz / 120 Hz render loop budget with Vulkan pipeline timers.
- Confirm zero-copy DMA-BUF hardware decode remains unaffected.
- Functional Validation:
- SMB network streaming and background downloading.
- Multi-audio stream switching and eye swapping.
- Controller button remapping.
5. Non-Breaking Safety Guarantees
- Zero External Heavy Dependencies: No Qt, no WebViews, no massive libraries. Everything builds with existing CMake toolchain and Vulkan/OpenXR/FreeType/FFmpeg stack.
- Graceful Fallback: If thumbnails are not yet extracted or unavailable (e.g. slow SMB network share), the browser instantly displays clean stylized gradient placeholder cards with format icons.
- Model Separation:
BrowserandSettingsMenuremain headless data models. All new visual enhancements live purely in the presentation/renderer layer.