Skip to content

Latest commit

 

History

History
528 lines (408 loc) · 27 KB

File metadata and controls

528 lines (408 loc) · 27 KB

Vitrine — Product Design Requirements (PDR)

Project Overview

Vitrine is an open-source, touch-optimized system monitoring dashboard purpose-built for the HYTE Y70 Touch Infinite case display panel running on Linux. It replaces the proprietary Windows-only HYTE Nexus software with a native Linux application that provides real-time hardware telemetry, animated visualizations, and full touch interaction on the Y70's integrated 14.9" vertical touchscreen.

The name "Vitrine" is French for "glass display case" or "showcase window" — a direct reference to the Y70's glass panel construction that showcases both hardware and data.

Repository: GitHub (public, open source) License: GPL v3 Target Platform: Linux (primary target: Bazzite / Fedora Atomic, but should work on any modern Linux distribution with Wayland or X11 support) Target Display: HYTE Y70 Touch Infinite — 682 x 2560 pixels (2.5K), 60Hz, 14.9" IPS, 10-point multi-touch, connected via DisplayPort + USB 2.0


Architecture

Technology Stack

Layer Technology Rationale
Application Shell Tauri v2 Lightweight native webview shell (~5-10MB binary), minimal RAM footprint for 24/7 operation alongside games, single-binary distribution
Backend Rust (integrated into Tauri) Zero-overhead sensor reading via sysfs, native Tauri IPC bridge to frontend, TOML config parsing with serde, no separate process to manage
Frontend React 18 + TypeScript Rich component ecosystem, excellent touch event handling, strong Claude Code output quality
Styling shadcn/ui + Tailwind CSS Owned component files (not external dependency), Radix UI primitives for accessibility, Tailwind for rapid custom styling
Data Visualization D3.js Full creative control over every SVG element and animation, required for the animated gauge/graph aesthetic, no pre-built component limitations
Package Manager pnpm Fast, strict dependency resolution, disk-efficient
Configuration TOML Rust-native serde support, human-readable, clean syntax for end users

Application Architecture

Vitrine is a single Tauri application consisting of:

  1. Rust Backend (src-tauri/): Reads hardware sensors from Linux sysfs, /proc, and lm-sensors interfaces. Exposes data to the frontend via Tauri's IPC command/event system. Manages configuration persistence. Handles auto-start and display targeting.

  2. React Frontend (src/): Renders the touch-optimized dashboard UI. Receives sensor data via Tauri event listeners. Manages widget layout state, page navigation, touch gestures, and D3 visualizations.

  3. Configuration Layer: TOML file stored at ~/.config/vitrine/config.toml defining widget layout, theme settings, polling intervals, and page configurations. Editable via the in-app settings UI or manually by the user.

Data Flow

Linux sysfs/proc/lm-sensors
        │
        ▼
Rust Sensor Module (polls at configurable interval)
        │
        ▼
Tauri IPC Event ("sensor-update")
        │
        ▼
React Frontend State (via useEffect listener)
        │
        ▼
D3.js Visualizations (animated gauge/graph updates)

Hardware Sensor Requirements

Data Sources (Rust Backend)

The Rust backend must read the following sensor data from Linux system interfaces. All sensor reading must be non-blocking and async. Failed sensor reads should return null/None rather than crashing — graceful degradation is required since not all hardware exposes all sensors.

CPU Telemetry:

  • Overall CPU utilization percentage (from /proc/stat)
  • Per-core utilization percentages (from /proc/stat, calculated per-core)
  • CPU temperature (from /sys/class/hwmon/ or lm-sensors, typically k10temp for AMD Ryzen)
  • Per-core temperatures if available
  • Current CPU frequency per-core (from /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq)
  • CPU package power draw if available (from hwmon RAPL interface)

GPU Telemetry:

  • GPU utilization percentage (AMDGPU: /sys/class/drm/card*/device/gpu_busy_percent; NVIDIA: nvidia-smi or NVML)
  • GPU temperature (AMDGPU: hwmon temp1_input; NVIDIA: nvidia-smi)
  • GPU clock frequency (AMDGPU: /sys/class/drm/card*/device/pp_dpm_sclk; NVIDIA: nvidia-smi)
  • VRAM usage — used and total (AMDGPU: /sys/class/drm/card*/device/mem_info_vram_used and mem_info_vram_total; NVIDIA: nvidia-smi)
  • GPU power draw if available

Note on GPU support: The primary user will transition from an NVIDIA GTX 1070 (nvidia-smi/NVML) to an AMD RX 9070 XT (AMDGPU sysfs). The backend must support both NVIDIA (via nvidia-smi CLI parsing or NVML bindings) and AMD (via sysfs direct reads). Detection should be automatic based on which GPU driver is loaded.

Memory:

  • Total RAM, used RAM, available RAM (from /proc/meminfo)
  • Usage percentage

Storage (NVMe):

  • NVMe drive temperature (from /sys/class/nvme/nvme*/hwmon*/temp1_input)
  • Read/write throughput (from /proc/diskstats, calculated as delta between polls)
  • Drive identification (model name from /sys/class/nvme/nvme*/model)

Network:

  • Upload speed in bytes/sec (from /proc/net/dev, calculated as delta)
  • Download speed in bytes/sec (from /proc/net/dev, calculated as delta)
  • Active interface detection (skip loopback)

Fan Speeds:

  • All detected fan RPM values from hwmon (from /sys/class/hwmon/hwmon*/fan*_input)
  • Fan label identification where available (from /sys/class/hwmon/hwmon*/fan*_label)

Polling Configuration

The sensor polling interval must be user-configurable via both the TOML config file and the in-app settings UI. The allowed range is 250ms to 5000ms, with a default of 1000ms (1 second). The frontend should interpolate/animate between data points for smooth visual transitions regardless of the polling interval.


Frontend Design Specification

Display Target

The Y70 Touch Infinite panel is 682 pixels wide and 2560 pixels tall at native resolution. The panel is physically oriented vertically (portrait) in the case chassis. All UI design must be optimized for this extreme portrait aspect ratio (approximately 1:3.75).

Visual Design Language

Theme: "Frosted Glass" — Light/White Aesthetic

The design must complement the user's white PC build. The visual language is:

  • Background: Subtle gradient or soft solid in off-white/light gray (#F8F9FA to #EBEDF0 range), with optional translucent frosted-glass effect on widget cards
  • Widget Cards: Semi-transparent white cards with soft shadows and subtle border (frosted glass effect using backdrop-blur where supported by the webview). Rounded corners (12-16px radius).
  • Typography: Clean sans-serif font (Inter or system-ui). Large, bold numbers for primary metrics. Lighter weight for labels and secondary info.
  • Accent Colors: Configurable accent color stored in config. Default: soft blue (#60A5FA) for primary indicators and highlights. Accent color is used for gauge fills, graph lines, active states, and interactive element highlights.
  • Data Colors: Temperature uses a gradient from blue (cool) through green (normal) to orange/red (hot) based on configurable threshold values. Utilization percentages use the accent color with opacity mapping to percentage.
  • Animations: All gauge and graph transitions should be smooth (200-400ms easing). D3 transitions must feel fluid, not jarring. Particle effects and ambient animations should be subtle — enhance the aesthetic without being distracting during gaming.
  • Glow Effects: Primary metric values and gauge fills should have a subtle glow/bloom effect using CSS box-shadow or SVG filters, giving the dashboard a modern, luminous quality against the white background.

Layout Architecture

The dashboard uses a swipeable page carousel with a draggable widget grid within each page.

Page Navigation:

  • Horizontal swipe (left/right) navigates between pages
  • Page indicator dots at the bottom of the screen show current position and total pages
  • Swipe gesture must feel native — use momentum-based physics with configurable deceleration
  • Minimum 2 pages in default configuration, user can add/remove pages via settings
  • Swipe threshold: 50px horizontal movement with velocity > 0.3px/ms triggers page transition

Widget Grid (within each page):

  • CSS Grid-based layout, 2 columns wide (each column ~321px accounting for gap and padding)
  • Widgets can span 1 or 2 columns
  • Widgets have a fixed set of height options: small (1 row, ~200px), medium (2 rows, ~420px), large (3 rows, ~640px)
  • Vertical scrolling within a page if widgets exceed viewport height
  • Page padding: 16px on all sides. Grid gap: 12px.

Drag and Drop:

  • Long-press (500ms) on a widget activates drag mode — widget lifts with scale animation (1.05x) and shadow increase
  • Other widgets animate to show available drop zones
  • Drop snaps to grid position
  • Layout changes persist to the TOML config file automatically
  • Drag handle is the entire widget card surface (long-press distinguishes from tap and swipe)

Touch Gesture Specification

Gesture Action
Swipe left/right Navigate between pages
Tap on widget Expand widget to detail view (full-width modal overlay with expanded data, historical graph, and additional metrics)
Long-press on widget (500ms) Activate drag mode for rearranging
Tap outside expanded widget Collapse back to grid view
Swipe down from top edge Open settings panel (slide-down drawer)
Tap page indicator dot Jump to that page

All touch interactions must use passive event listeners where possible for performance. Touch feedback should include subtle haptic-style visual responses (brief scale pulse on tap, etc.).

Widget Specifications

Each widget is a self-contained React component that receives its data via props from the parent page's sensor state. All widgets must implement a compact (grid) view and an expanded (detail) view.

Widget: CPU Monitor

Compact View (2-column span, medium height):

  • Large primary number: CPU temperature in °C with color-coded glow
  • Circular arc gauge (D3) showing overall CPU utilization (0-100%) with animated fill
  • Current frequency displayed below the gauge
  • Small sparkline (last 60 data points) showing temperature history

Expanded View:

  • Per-core utilization bar chart (D3 animated horizontal bars)
  • Per-core frequency readout
  • Per-core temperature if available
  • Temperature history graph (last 5 minutes)
  • CPU power draw if available

Widget: GPU Monitor

Compact View (2-column span, medium height):

  • Large primary number: GPU temperature in °C with color-coded glow
  • Circular arc gauge (D3) showing GPU utilization
  • VRAM usage bar below gauge (used / total with percentage)
  • GPU clock frequency display

Expanded View:

  • Temperature history graph
  • Utilization history graph
  • VRAM usage over time
  • Power draw if available
  • Clock frequency over time

Widget: RAM Usage

Compact View (1-column span, small height):

  • Radial progress ring (D3) showing usage percentage
  • "XX.X / YY.Y GB" text in center
  • Color transitions from accent (low usage) to orange to red as usage increases

Expanded View:

  • Memory usage over time graph
  • Breakdown if available (cached, buffers, swap)

Widget: NVMe Storage

Compact View (1-column span, small height):

  • Drive name/model truncated
  • Temperature with color coding
  • Read/Write throughput as small real-time counters (MB/s)

Expanded View:

  • Per-drive breakdown if multiple NVMe drives detected
  • Throughput history graph
  • Temperature history graph
  • Drive health info if available (from smartctl)

Widget: Network Monitor

Compact View (1-column span, small height):

  • Upload speed (▲ arrow + value in appropriate unit: KB/s, MB/s)
  • Download speed (▼ arrow + value)
  • Small dual-line sparkline showing recent history

Expanded View:

  • Full throughput history graph (upload and download overlaid)
  • Interface name and IP address
  • Total session data transferred

Widget: Tidal / Media Player (MPRIS2)

Compact View (2-column span, medium height):

  • Album art (large, fills most of the widget with rounded corners)
  • Song title (bold, truncated with ellipsis if needed)
  • Artist name (lighter weight)
  • Playback progress bar (thin, accent-colored)
  • Touch controls: previous, play/pause, next (tap targets minimum 44px)

Expanded View:

  • Larger album art
  • Full song title and artist (no truncation)
  • Album name
  • Playback progress with elapsed/remaining time
  • Volume control slider (if supported by MPRIS2)

MPRIS2 Integration: The Rust backend listens to the D-Bus MPRIS2 interface (org.mpris.MediaPlayer2.*) for media player state. It should auto-detect running media players (Tidal desktop app, Spotify, Firefox playing media, etc.) and expose the currently active player's metadata to the frontend. This includes: track title, artist, album, album art URL/path, playback status (playing/paused/stopped), track position, and track duration. Playback control commands (play, pause, next, previous) are sent back through Tauri IPC to the Rust backend, which issues D-Bus method calls to the active player.

Settings Panel

The settings panel slides down from the top of the screen when the user swipes down from the top edge. It provides touch-accessible configuration for:

  • Polling Interval: Slider from 250ms to 5000ms with labeled presets (Fast: 250ms, Normal: 1000ms, Relaxed: 3000ms)
  • Accent Color: Color picker with preset swatches (blue, purple, cyan, green, pink, orange, white) plus a custom hex input
  • Theme: Toggle between light (default, white frosted glass) and dark mode (dark frosted glass for those who want it)
  • Pages: Add/remove pages, rename pages
  • Widget Library: Grid of available widgets that can be dragged onto a page or tapped to add to the current page
  • About: Version info, links to GitHub repo

Settings changes apply immediately (live preview) and persist to the TOML config file on close.


Configuration File

Location: ~/.config/vitrine/config.toml

The configuration file is the source of truth for all user preferences and layout state. It must be human-readable and manually editable. The application watches this file for changes and hot-reloads when modified externally.

Default Configuration

[general]
polling_interval_ms = 1000
auto_start = true
target_display = "auto"  # "auto" detects Y70 panel, or specify output name

[theme]
mode = "light"  # "light" or "dark"
accent_color = "#FF6A13"
background_opacity = 0.85
enable_glow_effects = true
enable_animations = true

[temperature_thresholds]
cpu_warn = 75
cpu_critical = 90
gpu_warn = 80
gpu_critical = 95

[[pages]]
name = "System"
widgets = [
  { type = "cpu_monitor", position = { col = 0, row = 0 }, size = { cols = 2, rows = 2 } },
  { type = "gpu_monitor", position = { col = 0, row = 2 }, size = { cols = 2, rows = 2 } },
  { type = "ram_usage", position = { col = 0, row = 4 }, size = { cols = 1, rows = 1 } },
  { type = "nvme_storage", position = { col = 1, row = 4 }, size = { cols = 1, rows = 1 } },
  { type = "network_monitor", position = { col = 0, row = 5 }, size = { cols = 1, rows = 1 } },
]

[[pages]]
name = "Media"
widgets = [
  { type = "media_player", position = { col = 0, row = 0 }, size = { cols = 2, rows = 2 } },
]

Deployment and Auto-Start

Build Output

Tauri produces a single binary (AppImage or native package). The recommended distribution format for Bazzite and immutable Linux distros is AppImage, since it runs without installation and doesn't require modifying the immutable filesystem.

Auto-Start Kiosk Mode

Vitrine must start automatically on boot and display on the Y70 touch panel without user interaction. The implementation:

  1. Systemd User Service: A systemd user unit file (~/.config/systemd/user/vitrine.service) launches the Vitrine binary on login.

  2. Display Targeting: Vitrine must open its window on the Y70 panel specifically, not on the primary gaming monitor. On Wayland/KDE, this is achieved via KDE Window Rules that match the Vitrine window class and assign it to the Y70 output. On X11, the --display flag or window manager rules achieve the same. The config file's target_display setting specifies which output to use, with "auto" detecting the Y70 panel by its EDID or resolution signature (682x2560 is unique enough to auto-detect reliably).

  3. Window Behavior: The Tauri window must be configured as:

    • Fullscreen on the target display (682x2560)
    • No window decorations (frameless)
    • Always on the assigned display (does not follow focus)
    • Below all other windows (does not steal focus from games)
    • Excluded from taskbar and window switcher
    • Not affected by desktop virtual workspace changes

Installation Script

An install script (install.sh) in the repo root must:

  1. Copy the Vitrine binary to ~/.local/bin/vitrine
  2. Create the default config at ~/.config/vitrine/config.toml if it doesn't exist
  3. Install the systemd user service file
  4. Enable and start the service
  5. Configure KDE Window Rules for display targeting (via kwriteconfig5 or kcm script)

Project Structure

vitrine/
├── README.md
├── LICENSE                          # GPL v3
├── install.sh                       # Installation and auto-start setup script
├── src-tauri/
│   ├── Cargo.toml
│   ├── tauri.conf.json              # Tauri window config (frameless, size, etc.)
│   ├── src/
│   │   ├── main.rs                  # Tauri entry point, app setup, event loop
│   │   ├── sensors/
│   │   │   ├── mod.rs               # Sensor module exports
│   │   │   ├── cpu.rs               # CPU telemetry (temp, freq, utilization)
│   │   │   ├── gpu.rs               # GPU telemetry (AMD sysfs + NVIDIA nvidia-smi)
│   │   │   ├── memory.rs            # RAM usage from /proc/meminfo
│   │   │   ├── nvme.rs              # NVMe temps and throughput
│   │   │   ├── network.rs           # Network interface speeds
│   │   │   └── fans.rs              # Fan RPM from hwmon
│   │   ├── media/
│   │   │   └── mpris.rs             # MPRIS2 D-Bus integration for media player
│   │   ├── config/
│   │   │   ├── mod.rs               # Config module exports
│   │   │   └── schema.rs            # TOML config structs with serde
│   │   └── commands.rs              # Tauri IPC command handlers
│   └── icons/                       # App icons
├── src/
│   ├── main.tsx                     # React entry point
│   ├── App.tsx                      # Root component — page carousel + settings drawer
│   ├── components/
│   │   ├── ui/                      # shadcn/ui components (button, slider, etc.)
│   │   ├── layout/
│   │   │   ├── PageCarousel.tsx     # Swipeable page container with gesture handling
│   │   │   ├── WidgetGrid.tsx       # CSS Grid + drag-and-drop within a page
│   │   │   ├── WidgetCard.tsx       # Individual widget wrapper (card styling, tap/long-press)
│   │   │   └── PageIndicator.tsx    # Dot indicators for page position
│   │   ├── widgets/
│   │   │   ├── CpuMonitor.tsx       # CPU widget — compact and expanded views
│   │   │   ├── GpuMonitor.tsx       # GPU widget — compact and expanded views
│   │   │   ├── RamUsage.tsx         # RAM widget
│   │   │   ├── NvmeStorage.tsx      # NVMe widget
│   │   │   ├── NetworkMonitor.tsx   # Network widget
│   │   │   └── MediaPlayer.tsx      # Tidal/MPRIS2 media widget
│   │   ├── visualizations/
│   │   │   ├── ArcGauge.tsx         # D3 circular arc gauge (reusable)
│   │   │   ├── RadialProgress.tsx   # D3 radial progress ring (reusable)
│   │   │   ├── Sparkline.tsx        # D3 mini line graph (reusable)
│   │   │   ├── HistoryGraph.tsx     # D3 full-width time series graph (reusable)
│   │   │   └── AnimatedBar.tsx      # D3 animated horizontal bar (reusable)
│   │   └── settings/
│   │       ├── SettingsDrawer.tsx   # Slide-down settings panel
│   │       ├── PollingControl.tsx   # Polling interval slider
│   │       ├── ThemeControl.tsx     # Theme and accent color picker
│   │       └── PageManager.tsx      # Add/remove/rename pages, widget library
│   ├── hooks/
│   │   ├── useSensorData.ts         # Hook to subscribe to Tauri sensor events
│   │   ├── useMediaPlayer.ts        # Hook for MPRIS2 media state
│   │   ├── useConfig.ts             # Hook to read/write config via Tauri commands
│   │   ├── useTouchGestures.ts      # Hook for swipe, tap, long-press gesture detection
│   │   └── useWidgetLayout.ts       # Hook for drag-and-drop layout state management
│   ├── lib/
│   │   ├── types.ts                 # TypeScript interfaces for all sensor data and config
│   │   ├── constants.ts             # Default values, thresholds, animation durations
│   │   └── utils.ts                 # Formatting helpers (bytes, frequencies, temperatures)
│   └── styles/
│       └── globals.css              # Tailwind directives and global styles
├── package.json
├── pnpm-lock.yaml
├── tsconfig.json
├── tailwind.config.ts
├── postcss.config.js
├── vite.config.ts                   # Vite config for Tauri frontend
└── components.json                  # shadcn/ui configuration

Development Phases

Phase 1: Scaffold and Sensor Proof-of-Life

Goal: Tauri app launches, reads CPU temperature, displays a single animated D3 gauge on a 682x2560 window.

Tasks:

  1. Initialize Tauri v2 project with React + TypeScript + Vite frontend
  2. Configure pnpm, Tailwind CSS, shadcn/ui
  3. Set Tauri window to 682x2560, frameless, with transparent background
  4. Implement cpu.rs sensor module — read CPU temp and overall utilization from sysfs
  5. Create Tauri IPC command to return sensor data on demand
  6. Set up polling loop in Rust that emits "sensor-update" events at 1-second intervals
  7. Build useSensorData hook in React to listen for Tauri events
  8. Build ArcGauge.tsx D3 component — circular arc gauge with animated transitions and glow effect
  9. Render a single CPU gauge centered on screen to verify the full data pipeline works
  10. Verify the window opens at the correct resolution and can be manually moved to the Y70 panel

Phase 2: Full Sensor Backend

Goal: All sensor modules implemented and emitting data.

Tasks:

  1. Implement gpu.rs — AMD sysfs + NVIDIA nvidia-smi support with auto-detection
  2. Implement memory.rs — /proc/meminfo parsing
  3. Implement nvme.rs — hwmon temperature + /proc/diskstats throughput
  4. Implement network.rs — /proc/net/dev interface speed calculation
  5. Implement fans.rs — hwmon fan RPM enumeration
  6. Implement mpris.rs — D-Bus MPRIS2 listener for media player metadata and controls
  7. Unify all sensors into a single SensorData struct emitted as one JSON payload per tick
  8. Implement config/schema.rs — TOML config deserialization with serde
  9. Make polling interval configurable via config

Phase 3: Widget Library and Layout Engine

Goal: All widgets rendered in a draggable grid with swipeable pages.

Tasks:

  1. Build all D3 visualization components: ArcGauge, RadialProgress, Sparkline, HistoryGraph, AnimatedBar
  2. Build all widget components with compact views: CpuMonitor, GpuMonitor, RamUsage, NvmeStorage, NetworkMonitor, MediaPlayer
  3. Build WidgetCard.tsx — card wrapper with frosted glass styling, tap handler, long-press handler
  4. Build WidgetGrid.tsx — CSS Grid layout with drag-and-drop (use @dnd-kit/core for drag-and-drop)
  5. Build PageCarousel.tsx — horizontal swipe navigation with momentum physics (use framer-motion for gesture handling and page transitions)
  6. Build PageIndicator.tsx — dot navigation at bottom of screen
  7. Implement widget expanded/detail view — full-width modal overlay triggered by tap
  8. Wire layout state to config — persist widget positions and page order to TOML

Phase 4: Settings, Theming, and Polish

Goal: In-app settings panel, theme customization, visual polish, and auto-start.

Tasks:

  1. Build SettingsDrawer.tsx — slide-down panel triggered by swipe from top edge
  2. Implement polling interval control with live preview
  3. Implement accent color picker with preset swatches and custom hex input
  4. Implement light/dark theme toggle
  5. Implement page management (add, remove, rename)
  6. Implement widget library browser (available widgets to add to pages)
  7. Implement config hot-reload — watch config.toml for external changes
  8. Add glow effects and ambient animations to all widgets
  9. Add smooth page transition animations
  10. Build install.sh — binary installation, systemd service, KDE window rules
  11. Write README.md with screenshots, installation instructions, configuration guide, and contributing guidelines

Key Libraries and Dependencies

Rust (Cargo.toml)

  • tauri v2 — application shell and IPC
  • serde + serde_json — JSON serialization for IPC payloads
  • toml + serde — TOML config deserialization
  • tokio — async runtime for sensor polling loop
  • notify — filesystem watcher for config hot-reload
  • zbus — D-Bus client for MPRIS2 media player integration
  • sysinfo — cross-platform system information (supplement to direct sysfs reads)

Frontend (package.json)

  • react + react-dom v18
  • typescript
  • @tauri-apps/api v2 — Tauri frontend bindings
  • d3 + @types/d3 — data visualization
  • framer-motion — gesture handling (swipe, drag) and page transition animations
  • @dnd-kit/core + @dnd-kit/sortable — drag-and-drop widget rearrangement
  • tailwindcss + postcss + autoprefixer — styling
  • class-variance-authority + clsx + tailwind-merge — shadcn/ui utilities
  • lucide-react — icons

Non-Functional Requirements

Performance: The application must use less than 150MB RAM and less than 3% CPU at the default 1-second polling interval. D3 animations must maintain 60fps on the Y70's 60Hz panel. The application runs 24/7 alongside games and must not cause perceptible performance impact.

Reliability: The application must not crash if a sensor becomes unavailable (e.g., GPU removed, NVMe drive disconnected). All sensor reads must be wrapped in error handling that returns null/None for unavailable data, and widgets must display a graceful "N/A" or "—" state.

Startup Time: The application must be ready and displaying data within 3 seconds of launch.

Touch Responsiveness: All touch interactions must respond within 100ms. Gesture recognition must not have perceptible lag.

Graceful Degradation: On systems without a Y70 panel, the application should still run in a resizable window for development and testing purposes. The 682x2560 layout should be the default but not hard-coded as the only option.