#[cfg(target_os = "macos")]
use core_animation::prelude::*;
#[cfg(target_os = "macos")]
fn main() {
println!("Breathing Circle - Soft Pulsing Orb\n");
let window = WindowBuilder::new()
.title("Breathing Circle")
.size(400.0, 400.0)
.centered()
.background_color(Color::rgb(0.05, 0.05, 0.12))
.build();
let (width, height) = window.size();
let center = CGPoint::new(width / 2.0, height / 2.0);
let circle_size = 160.0;
let circle_path = unsafe {
CGPath::with_ellipse_in_rect(
CGRect::new(CGPoint::ZERO, CGSize::new(circle_size, circle_size)),
std::ptr::null(),
)
};
let orb_color = Color::rgb(0.4, 0.5, 0.95);
let breath_duration = 3000u64.millis();
let breathing_orb = CAShapeLayerBuilder::new()
.path(circle_path)
.fill_color(orb_color)
.bounds(CGRect::new(
CGPoint::ZERO,
CGSize::new(circle_size, circle_size),
))
.position(center)
.animate("scale", KeyPath::TransformScale, |a| {
a.values(0.85, 1.15)
.duration(breath_duration)
.easing(Easing::InOut)
.autoreverses()
.repeat(Repeat::Forever)
})
.animate("opacity", KeyPath::Opacity, |a| {
a.values(1.0, 0.5)
.duration(breath_duration)
.easing(Easing::InOut)
.autoreverses()
.repeat(Repeat::Forever)
.phase_offset(0.5)
})
.build();
let glow_size = 200.0;
let glow_path = unsafe {
CGPath::with_ellipse_in_rect(
CGRect::new(CGPoint::ZERO, CGSize::new(glow_size, glow_size)),
std::ptr::null(),
)
};
let glow_ring = CAShapeLayerBuilder::new()
.path(glow_path)
.fill_color(Color::TRANSPARENT)
.stroke_color(orb_color.with_alpha(0.3))
.line_width(3.0)
.bounds(CGRect::new(
CGPoint::ZERO,
CGSize::new(glow_size, glow_size),
))
.position(center)
.animate("scale", KeyPath::TransformScale, |a| {
a.values(0.9, 1.1)
.duration(breath_duration)
.easing(Easing::InOut)
.autoreverses()
.repeat(Repeat::Forever)
.phase_offset(0.5)
})
.animate("opacity", KeyPath::Opacity, |a| {
a.values(0.6, 0.2)
.duration(breath_duration)
.easing(Easing::InOut)
.autoreverses()
.repeat(Repeat::Forever)
})
.build();
window.container().add_sublayer(&glow_ring);
window.container().add_sublayer(&breathing_orb);
println!("Watch the breathing orb for 10 seconds...");
println!("Notice how opacity peaks when the circle is smallest.\n");
window.show_for(10.seconds());
println!("Done!");
}
#[cfg(not(target_os = "macos"))]
fn main() {
eprintln!("This example only runs on macOS");
}