diff --git a/ui-gpui/src/components/pulsing_dot.rs b/ui-gpui/src/components/pulsing_dot.rs index 9d9d65c..35a199b 100644 --- a/ui-gpui/src/components/pulsing_dot.rs +++ b/ui-gpui/src/components/pulsing_dot.rs @@ -46,37 +46,46 @@ impl PulsingDot { } } - fn current_opacity(&self) -> f32 { + /// Interpolate between the bright color and background (SURFACE0) based on sine wave + fn current_color(&self) -> Rgba { + let base = self.base_color(); if !self.should_pulse() { - return 1.0; + return base; } let elapsed = self.start_time.elapsed().as_secs_f32(); - // Sine wave: 2s period, oscillates between 0.4 and 1.0 - 0.7 + 0.3 * (elapsed * std::f32::consts::PI).sin() + // t oscillates 0.0 (bright) to 1.0 (dim) with 2s period + let t = 0.5 - 0.5 * (elapsed * std::f32::consts::PI).sin(); + + // Lerp between base color and SURFACE0 (background) + let bg = theme::SURFACE0; + Rgba { + r: base.r + (bg.r - base.r) * t, + g: base.g + (bg.g - base.g) * t, + b: base.b + (bg.b - base.b) * t, + a: 1.0, + } } } impl Render for PulsingDot { fn render(&mut self, window: &mut Window, _cx: &mut Context) -> impl IntoElement { - let base = self.base_color(); - let alpha = self.current_opacity(); + let color = self.current_color(); - // Schedule next frame if pulsing — this is how GPUI does continuous animation + // Schedule next frame if pulsing if self.should_pulse() { window.request_animation_frame(); } - let r = (base.r * 255.0) as u32; - let g = (base.g * 255.0) as u32; - let b = (base.b * 255.0) as u32; - let a = (alpha * 255.0) as u32; - let color = rgba(r * 0x1000000 + g * 0x10000 + b * 0x100 + a); + let r = (color.r * 255.0) as u32; + let g = (color.g * 255.0) as u32; + let b = (color.b * 255.0) as u32; + let hex = rgba(r * 0x1000000 + g * 0x10000 + b * 0x100 + 0xFF); div() .w(px(self.size)) .h(px(self.size)) .rounded(px(self.size / 2.0)) - .bg(color) + .bg(hex) .flex_shrink_0() } }