forked from 1b-agent/fieldcraft-upstream
feat: application icon family (a meshed bracket) drawn with VectorCraft (#37)
cargo xtask app-icon computes an isometric L bracket with a bolt hole and a structured hexahedral mesh (O-grid around the hole), draws it with vectorcraft-cli and writes icon.svg/png, small-size artwork, the iconset, icns, ico, an Icon Composer ModelCraft.icon (floor grid Default/Dark, part, mesh) and its actool Assets.car. The desktop app uses the 256 px export as its window icon, falling back to eframe's default if it cannot be decoded. Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
34 files changed
+1145
-1
No files matched your search
@@ -20,6 +20,17 @@ const USAGE: &str = "usage: modelcraft [--sample] [--control PORT]";
|
||||
const DEPTH_BITS: u8 = 24;
|
||||
const MSAA: u16 = 4;
|
||||
|
||||
/// The window and Dock icon: the 256 px export of the application icon (assets/app-icon).
|
||||
const ICON_PNG: &[u8] = include_bytes!("../../../assets/app-icon/icon.iconset/icon_128x128@2x.png");
|
||||
|
||||
/// The application icon for the window; eframe's default icon if the PNG cannot be decoded.
|
||||
fn app_icon() -> egui::IconData {
|
||||
eframe::icon_data::from_png_bytes(ICON_PNG).unwrap_or_else(|e| {
|
||||
log::warn!("app icon: {e}");
|
||||
egui::IconData::default()
|
||||
})
|
||||
}
|
||||
|
||||
/// How often unsaved changes are autosaved for recovery (seconds).
|
||||
const AUTOSAVE_SECONDS: f64 = 30.0;
|
||||
|
||||
@@ -108,7 +119,11 @@ fn main() -> eframe::Result {
|
||||
}
|
||||
};
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_title("ModelCraft").with_inner_size([1400.0, 900.0]).with_min_inner_size([800.0, 500.0]),
|
||||
viewport: egui::ViewportBuilder::default()
|
||||
.with_title("ModelCraft")
|
||||
.with_icon(app_icon())
|
||||
.with_inner_size([1400.0, 900.0])
|
||||
.with_min_inner_size([800.0, 500.0]),
|
||||
depth_buffer: DEPTH_BITS,
|
||||
multisampling: MSAA,
|
||||
..Default::default()
|
||||
@@ -145,6 +160,13 @@ fn main() -> eframe::Result {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn the_app_icon_decodes() {
|
||||
let icon = super::app_icon();
|
||||
assert_eq!((icon.width, icon.height), (256, 256));
|
||||
assert_eq!(icon.rgba.len(), 256 * 256 * 4);
|
||||
}
|
||||
|
||||
use super::*;
|
||||
|
||||
fn parse(a: &[&str], env: Option<&str>) -> Result<Option<Args>, String> {
|
||||
|
||||
Reference in new issue
Block a user