# Animated Icon Plan Animate a Discord emote (GIF) as the app's window/taskbar icon using eframe/egui. ## Steps ### 1. Add the `image` crate ```bash cargo add image ``` ### 2. Place your GIF Save your Discord emote as `assets/emote.gif` in the project root. ### 3. Load GIF frames ```rust use eframe::egui::{ViewportCommand, IconData}; use image::codecs::gif::GifDecoder; use image::AnimationDecoder; use std::time::Instant; fn load_gif_frames(gif_bytes: &[u8]) -> Vec { let decoder = GifDecoder::new(gif_bytes).unwrap(); decoder.into_frames() .collect_frames() .unwrap() .into_iter() .map(|f| { let rgba = f.into_buffer(); let (w, h) = (rgba.width(), rgba.height()); IconData { rgba: rgba.into_raw(), width: w, height: h } }) .collect() } ``` Embed the GIF at compile time: ```rust let gif_bytes = include_bytes!("../assets/emote.gif"); let icon_frames = load_gif_frames(gif_bytes); ``` ### 4. Add fields to the app struct ```rust icon_frames: Vec, current_frame: usize, last_icon_swap: Instant, ``` ### 5. Cycle the icon in `update()` ```rust if !self.icon_frames.is_empty() { let elapsed = self.last_icon_swap.elapsed().as_millis(); if elapsed > 100 { // ~10 FPS self.current_frame = (self.current_frame + 1) % self.icon_frames.len(); let icon = self.icon_frames[self.current_frame].clone(); ctx.send_viewport_cmd(ViewportCommand::Icon(Some(std::sync::Arc::new(icon)))); self.last_icon_swap = Instant::now(); ctx.request_repaint(); } } ``` ## Notes - The icon animates in both the taskbar and the window title bar on Windows. - Adjust the `100`ms interval to control animation speed. - Discord emotes are typically small (48x48 or 128x128) which works fine for icons.