feat!: replace CPU rendering with GPU via wgpu/WGSL

Drop tiny-skia and tempfile. All rendering now runs on the GPU using a
WGSL fragment shader with rounded-rect SDF, gaussian glow falloff, and
cursor avoidance. Add color temperature support with presets (warm, cool,
studio, daylight, golden) and custom Kelvin values. Suppress MangoHUD
via environment variable.
This commit is contained in:
swaits committed 2026-04-07 12:28:36 -06:00
1 parent 81d6237e2f
commit bdd3482b75
6 files changed
+1419 -502

No files matched your search

+75
View File
@@ -0,0 +1,75 @@
struct Uniforms {
screen_size: vec2f,
cursor_pos: vec2f,
// Outer rounded rect: inset from screen edge
outer_inset: f32,
outer_corner_radius: f32,
// Inner rounded rect: inset further by ring_width
ring_width: f32,
inner_corner_radius: f32,
// Glow
glow_spread: f32,
// Cursor avoidance
cursor_avoid_radius: f32,
cursor_avoid_falloff: f32,
// Color temperature (linear RGB)
_pad: f32,
color: vec3f,
_pad2: f32,
}
@group(0) @binding(0) var<uniform> u: Uniforms;
@vertex
fn vs_main(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
let x = f32(i32(i) / 2) * 4.0 - 1.0;
let y = f32(i32(i) % 2) * 4.0 - 1.0;
return vec4f(x, y, 0.0, 1.0);
}
// Rounded rectangle SDF (Inigo Quilez).
fn rounded_rect_sdf(p: vec2f, h: vec2f, r: f32) -> f32 {
let q = abs(p) - h + vec2f(r);
return length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - r;
}
@fragment
fn fs_main(@builtin(position) pos: vec4f) -> @location(0) vec4f {
let center = u.screen_size / 2.0;
let p = pos.xy - center;
// Outer rounded rect
let outer_half = center - vec2f(u.outer_inset);
let sd_outer = rounded_rect_sdf(p, outer_half, u.outer_corner_radius);
// Inner rounded rect
let inner_half = outer_half - vec2f(u.ring_width);
let sd_inner = rounded_rect_sdf(p, inner_half, u.inner_corner_radius);
// Ring: inside outer AND outside inner = solid at full brightness
var alpha: f32;
if sd_outer <= 0.0 && sd_inner >= 0.0 {
alpha = 1.0;
} else if sd_outer > 0.0 {
// Gaussian glow fading outward
let t = sd_outer / u.glow_spread;
alpha = exp(-3.0 * t * t);
} else {
// Gaussian glow fading inward
let t = -sd_inner / u.glow_spread;
alpha = exp(-3.0 * t * t);
}
// Cursor avoidance
let cursor_dist = distance(pos.xy, u.cursor_pos);
let avoid_start = u.cursor_avoid_radius;
let avoid_end = u.cursor_avoid_radius + u.cursor_avoid_falloff;
if cursor_dist < avoid_end {
let t_avoid = clamp((cursor_dist - avoid_start) / (avoid_end - avoid_start), 0.0, 1.0);
alpha *= t_avoid * t_avoid * (3.0 - 2.0 * t_avoid);
}
// Premultiplied color output
let rgb = u.color * alpha;
return vec4f(rgb, alpha);
}