diff --git a/codex-rs/tui/src/avatars/assets.rs b/codex-rs/tui/src/avatars/assets.rs index 74113a7a72..4f8780bd1d 100644 --- a/codex-rs/tui/src/avatars/assets.rs +++ b/codex-rs/tui/src/avatars/assets.rs @@ -15,6 +15,8 @@ const CHLOE_SHEET: &[u8] = include_bytes!("../../assets/chloe-r2-09/sheet.png"); const CHLOE_LOCKED_IN_MANIFEST: &str = include_str!("../../assets/chloe-r2-09-locked-in/avatar.json"); const CHLOE_LOCKED_IN_SHEET: &[u8] = include_bytes!("../../assets/chloe-r2-09-locked-in/sheet.png"); +const CENTURION_MANIFEST: &str = include_str!("../../assets/centurion/avatar.json"); +const CENTURION_SHEET: &[u8] = include_bytes!("../../assets/centurion/sheet.png"); const CLANKER_CHARACTER_MANIFEST: &str = r#"{ "schemaVersion": 1, "id": "clanker", @@ -58,6 +60,11 @@ const BUNDLED_AVATARS: &[BundledAvatar] = &[ manifest: CHLOE_LOCKED_IN_MANIFEST, sheet: CHLOE_LOCKED_IN_SHEET, }, + BundledAvatar { + id: "centurion", + manifest: CENTURION_MANIFEST, + sheet: CENTURION_SHEET, + }, ]; /// Materialize built-in packs without overwriting an existing user-owned id. @@ -206,6 +213,7 @@ mod tests { .is_file() ); assert!(dir.path().join("avatars/clanker/avatar.json").is_file()); + assert!(dir.path().join("avatars/centurion/avatar.json").is_file()); assert!( dir.path() .join("characters/chloe/avatar/locked-in/avatar.json") diff --git a/codex-rs/tui/src/pets/ansi_half_block_tests.rs b/codex-rs/tui/src/pets/ansi_half_block_tests.rs index e60c1aeb9f..0e3e76e577 100644 --- a/codex-rs/tui/src/pets/ansi_half_block_tests.rs +++ b/codex-rs/tui/src/pets/ansi_half_block_tests.rs @@ -41,6 +41,30 @@ fn renders_24px_avatar_as_twelve_truecolor_half_block_rows() { assert_eq!(buffer[(23, 0)].fg, Color::Rgb(0, 0, 255)); } +#[test] +fn renders_bundled_centurion_avatar() { + let sheet = image::load_from_memory(include_bytes!("../../assets/centurion/sheet.png")) + .unwrap() + .into_rgba8(); + let image = image::imageops::crop_imm(&sheet, 0, 0, 24, 24).to_image(); + let frame = AnsiHalfBlockFrame::from_image(image).unwrap(); + let area = Rect::new(0, 0, AVATAR_WIDTH, AVATAR_HEIGHT); + let mut buffer = Buffer::empty(area); + + frame.render(area, &mut buffer); + + let rendered = (0..AVATAR_HEIGHT) + .map(|row| { + (0..AVATAR_WIDTH) + .map(|column| buffer[(column, row)].symbol()) + .collect::() + .replace(' ', "·") + }) + .collect::>() + .join("\n"); + assert_snapshot!(rendered); +} + #[test] fn transparent_pixels_keep_the_default_background() { let mut image = RgbaImage::from_pixel(24, 24, Rgba([0, 0, 0, 0])); diff --git a/codex-rs/tui/src/pets/snapshots/codex_tui__pets__ansi_half_block__tests__renders_bundled_centurion_avatar.snap b/codex-rs/tui/src/pets/snapshots/codex_tui__pets__ansi_half_block__tests__renders_bundled_centurion_avatar.snap new file mode 100644 index 0000000000..6e1aef56ff --- /dev/null +++ b/codex-rs/tui/src/pets/snapshots/codex_tui__pets__ansi_half_block__tests__renders_bundled_centurion_avatar.snap @@ -0,0 +1,16 @@ +--- +source: tui/src/pets/ansi_half_block_tests.rs +expression: rendered +--- +········▄▀▀▄▄▄▄▄▄······· +······▀▀▀▀▀▀▀▀▀▀▀▀▄····▀ +····▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄▄· +···▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀··▄▀· +····▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄···▀ +····▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀·▄▀· +·····▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀· +·····▀▀▀▀▀▀▀▀▀▀▀▀▀▀····· +···▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄··· +···▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀··· +···▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀··· +·····▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀····