Skip to main content

Overview

Jarvis uses a fully GPU-accelerated rendering pipeline built on wgpu, the portable Rust graphics API. Every pixel—the animated hex grid background, glowing pane borders, boot animation, CRT scanlines—is rendered through custom WGSL shaders.

wgpu-based

Metal on macOS, Vulkan/DX12 on Windows/Linux

Custom Shaders

WGSL shaders for backgrounds and effects

Instanced Quads

UI chrome rendered as GPU-instanced rectangles

VSync

60 FPS with PresentMode::Fifo

Pipeline Architecture

The jarvis-renderer crate is organized into these modules:
ModulePurpose
gpuwgpu device, queue, surface, uniform buffers
backgroundHex grid, gradient, and solid color backgrounds
effectsPer-pane glow, dim, and scanline post-processing
boot_screenFull-screen boot animation with surveillance HUD
quadInstanced rectangle drawing for UI chrome
uiTab bar, status bar, pane border data structures
render_stateOrchestrates all pipelines into per-frame rendering
perfRolling-window FPS timer

GPU Context Initialization

Initialization Sequence

Window → Instance → Surface → Adapter → Device + Queue → Surface Configuration
1

Create wgpu Instance

Uses default backends: Metal on macOS, Vulkan/DX12 on Windows, Vulkan on Linux.
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
    backends: wgpu::Backends::all(),
    ..Default::default()
});
2

Create Surface

Wraps the winit window handle.
let surface = instance.create_surface(window)?;
3

Request Adapter

Prefers HighPerformance (discrete GPU). Falls back to integrated or software rendering.
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions {
    power_preference: wgpu::PowerPreference::HighPerformance,
    compatible_surface: Some(&surface),
    force_fallback_adapter: false,
}).await?;
4

Request Device

Requests device with default limits.
let (device, queue) = adapter.request_device(
    &wgpu::DeviceDescriptor {
        label: Some("jarvis-renderer device"),
        ..Default::default()
    },
    None,
).await?;
5

Configure Surface

Sets up double-buffered vsync rendering.
let config = wgpu::SurfaceConfiguration {
    usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
    format: surface.get_capabilities(&adapter).formats[0],
    width: size.width,
    height: size.height,
    present_mode: wgpu::PresentMode::Fifo, // vsync
    desired_maximum_frame_latency: 2,
    alpha_mode: wgpu::CompositeAlphaMode::Auto,
    view_formats: vec![],
};
surface.configure(&device, &config);

Rendering Pipeline

Per-Frame Render Order

Each frame follows a two-pass pipeline:
1

Pass 1: Background

Clear surface and run background shader (hex grid or gradient) as a full-screen triangle.
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
    label: Some("Background Pass"),
    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
        view: &view,
        resolve_target: None,
        ops: wgpu::Operations {
            load: wgpu::LoadOp::Clear(clear_color),
            store: wgpu::StoreOp::Store,
        },
    })],
    depth_stencil_attachment: None,
    ..Default::default()
});

render_pass.set_pipeline(&background_pipeline);
render_pass.draw(0..3, 0..1); // full-screen triangle
2

Pass 2: UI Chrome

Overlay tab bar, status bar, and pane borders via instanced quad drawing.
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
    label: Some("UI Chrome Pass"),
    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
        view: &view,
        resolve_target: None,
        ops: wgpu::Operations {
            load: wgpu::LoadOp::Load, // preserve background
            store: wgpu::StoreOp::Store,
        },
    })],
    ..Default::default()
});

render_pass.set_pipeline(&quad_pipeline);
render_pass.set_vertex_buffer(0, instance_buffer.slice(..));
render_pass.draw(0..6, 0..instance_count); // instanced quads

Background Modes

Five background modes are supported:
Animated hexagonal grid with parallax scrolling.
[background]
mode = "hex_grid"
hex_size = 32.0
hex_spacing = 8.0
hex_color = "#8b5cf6"
hex_opacity = 0.15
scroll_speed = 0.5
Shader: jarvis-rs/crates/jarvis-renderer/src/shaders/hex_grid.wgsl

Visual Effects

Effects are applied per-pane and stacked in this order:
Outer glow around focused pane.
[effects.glow]
enabled = true
color = "#8b5cf6"
radius = 8.0
intensity = 0.8
Renders a blurred quad behind the pane border.
Darkens unfocused panes.
[effects.dim]
enabled = true
opacity = 0.6
Overlays a semi-transparent black quad.
CRT-style horizontal scanlines.
[effects.scanlines]
enabled = true
spacing = 2.0
intensity = 0.3
Shader draws alternating transparent/dark horizontal lines.
Darkens screen edges.
[effects.vignette]
enabled = true
intensity = 0.5
radius = 0.8
Applied in the background shader pass.
Light bleed effect on bright areas.
[effects.bloom]
enabled = false
threshold = 0.8
intensity = 0.5
Bloom requires additional render passes and impacts performance.

Boot Animation

The boot sequence runs a three-pass pipeline:
1

Boot Shader Pass

Full-screen surveillance HUD with scan line, corner brackets, and vignette.Shader: jarvis-rs/crates/jarvis-renderer/src/shaders/boot.wgsl
2

Boot Quad Pass

Progress bar track and fill rectangles.
3

Boot Text Pass

Title (“J A R V I S”), cycling status messages, percentage counter.Rendered with glyphon text engine.

Boot Sequence Timeline

0ms   - Show title + corner brackets
500ms - "Initializing systems..."
1000ms - Progress bar appears
1500ms - "Loading configuration..."
2000ms - "Starting renderer..." (50% progress)
2500ms - "Connecting services..." (75% progress)
3000ms - "System ready" (100% progress)
3500ms - Fade to main UI

Quad Renderer

UI chrome (borders, bars) is drawn using instanced quads:
pub struct QuadInstance {
    pub position: [f32; 2],  // top-left corner
    pub size: [f32; 2],      // width, height
    pub color: [f32; 4],     // RGBA
    pub border_radius: f32,  // corner rounding
}
One draw call renders all quads:
render_pass.set_vertex_buffer(0, instance_buffer.slice(..));
render_pass.draw(0..6, 0..instance_count); // 6 vertices, N instances
Instancing allows drawing thousands of rectangles in a single GPU call.

Performance Presets

[performance]
preset = "balanced"  # "low", "balanced", "high", "ultra"
vsync = true
target_fps = 60
PresetEffectsShadowsBlurTarget FPS
LowDisabledDisabledDisabled30
BalancedGlow onlyDisabled2px60
HighAll except bloomEnabled4px60
UltraAllEnabled8px120

Frame Timing

The FrameTimer tracks rolling-window FPS:
pub struct FrameTimer {
    frame_times: VecDeque<Instant>,
    window_size: usize,
}

impl FrameTimer {
    pub fn tick(&mut self) {
        self.frame_times.push_back(Instant::now());
        if self.frame_times.len() > self.window_size {
            self.frame_times.pop_front();
        }
    }
    
    pub fn fps(&self) -> f64 {
        if self.frame_times.len() < 2 { return 0.0; }
        let elapsed = self.frame_times.back().unwrap()
            .duration_since(*self.frame_times.front().unwrap());
        (self.frame_times.len() - 1) as f64 / elapsed.as_secs_f64()
    }
}

Color Management

All colors are stored as linear RGB internally and converted to sRGB for rendering:
fn linear_to_srgb(linear: f32) -> f32 {
    if linear <= 0.0031308 {
        linear * 12.92
    } else {
        1.055 * linear.powf(1.0 / 2.4) - 0.055
    }
}
The surface format is typically Bgra8UnormSrgb, which applies automatic sRGB conversion.

Shader Reference

hex_grid.wgsl

Animated hexagonal background with parallax

gradient.wgsl

Two-color linear gradient

boot.wgsl

Surveillance HUD boot animation

quad.wgsl

Instanced rectangle rendering

Source References

  • jarvis-rs/crates/jarvis-renderer/src/render_state/state.rs - Frame orchestration
  • jarvis-rs/crates/jarvis-renderer/src/gpu.rs - GPU context
  • jarvis-rs/crates/jarvis-renderer/src/background/ - Background modes
  • jarvis-rs/crates/jarvis-renderer/src/effects/ - Visual effects
  • jarvis-rs/crates/jarvis-renderer/src/shaders/ - WGSL shaders
  • docs/manual/10-renderer.md - Complete reference