From cbae640688c5fa3daa120a7f5e050f8e24148a47 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 13 Oct 2026 12:28:29 -0400 Subject: [PATCH] Add FigCraft; release 0.4.1 (#313) * Add FigCraft to the launcher FigCraft (storytold/figcraft): interface design and prototyping, the thirteenth Craft App and the sixth in the New group. - Catalog row (brand colour #02da96 from FigCraft's icon README), details page (no pictures yet), Linux desktop categories, icon tables, tagline in every catalog, xtask local mirror list. - Icon copied unmodified from FigCraft's repo; ATTRIBUTION.md row. - The Windows installer art fits five rows of icons. - Test that a companion figcraft-server tarball is never picked as the app. Co-Authored-By: Claude Opus 5.5 * Release 0.4.1 Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- AGENTS.md | 2 +- ATTRIBUTION.md | 1 + Cargo.lock | 12 +++---- Cargo.toml | 2 +- README.md | 3 +- assets/app-icons/figcraft.png | Bin 0 -> 19691 bytes crates/core/src/catalog.rs | 20 +++++++---- crates/core/src/details.rs | 33 +++++++++++++++++- crates/core/src/platform.rs | 3 ++ crates/native/src/desktop_entry.rs | 1 + crates/native/src/install.rs | 1 + crates/ui-egui/src/i18n/cs.tsv | 1 + crates/ui-egui/src/i18n/de.tsv | 3 +- crates/ui-egui/src/i18n/es.tsv | 3 +- crates/ui-egui/src/i18n/fr.tsv | 3 +- crates/ui-egui/src/i18n/hu.tsv | 3 +- crates/ui-egui/src/i18n/ja.tsv | 3 +- crates/ui-egui/src/i18n/pl.tsv | 3 +- crates/ui-egui/src/i18n/pt-BR.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 3 +- crates/ui-egui/src/i18n/zh-CN.tsv | 1 + crates/ui-egui/src/icons.rs | 1 + crates/ui-egui/tests/ui.rs | 6 ++-- ...ryteller.artcraft-launcher.metainfo.xml.in | 4 +-- packaging/linux/nfpm.yaml | 6 ++-- packaging/windows/package.ps1 | 8 ++--- xtask/src/local.rs | 1 + 27 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 assets/app-icons/figcraft.png diff --git a/AGENTS.md b/AGENTS.md index d35ad30..4367002 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ArtCraft Launcher installs, updates and launches the **Craft App Suite** (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, -CADCraft, SoundCraft). It is written in **Rust only** (no JavaScript or TypeScript): the desktop +CADCraft, SoundCraft, FigCraft). It is written in **Rust only** (no JavaScript or TypeScript): the desktop app is native egui/eframe, and the web build is the same Rust compiled to WebAssembly (trunk + wasm-bindgen). **No Tauri, Electron or webview shells**, ever. diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 6ac0fd2..db7b85a 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -42,6 +42,7 @@ licensed like those apps. Refresh them from the source path, never redraw them. | `assets/app-icons/gridcraft.png` | GridCraft app icon (app icon), 128 px | ArtCraft Team and the GridCraft contributors | [`storytold/gridcraft`](https://github.com/storytold/gridcraft) `assets/app-icon/hicolor/128x128/apps/ai.storyteller.gridcraft.png`, copied unmodified | MIT OR Apache-2.0 (GridCraft's [`LICENSE-MIT`](https://github.com/storytold/gridcraft/blob/main/LICENSE-MIT), [`LICENSE-APACHE`](https://github.com/storytold/gridcraft/blob/main/LICENSE-APACHE)) | | `assets/app-icons/cadcraft.png` | CADCraft app icon (app icon), 128 px | ArtCraft Team and the CADCraft contributors | [`storytold/cadcraft`](https://github.com/storytold/cadcraft) `assets/app-icon/hicolor/128x128/apps/ai.storyteller.cadcraft.png`, copied unmodified | MIT OR Apache-2.0 (CADCraft's [`LICENSE-MIT`](https://github.com/storytold/cadcraft/blob/main/LICENSE-MIT), [`LICENSE-APACHE`](https://github.com/storytold/cadcraft/blob/main/LICENSE-APACHE)) | | `assets/app-icons/soundcraft.png` | SoundCraft app icon (nightingale (placeholder)), 128 px | ArtCraft Team and the SoundCraft contributors | [`storytold/soundcraft`](https://github.com/storytold/soundcraft) `assets/app-icon/hicolor/128x128/apps/ai.storyteller.soundcraft.png`, copied unmodified | MIT OR Apache-2.0 (SoundCraft's [`LICENSE-MIT`](https://github.com/storytold/soundcraft/blob/main/LICENSE-MIT), [`LICENSE-APACHE`](https://github.com/storytold/soundcraft/blob/main/LICENSE-APACHE)) | +| `assets/app-icons/figcraft.png` | FigCraft app icon (chameleon), 128 px | ArtCraft Team and the FigCraft contributors | [`storytold/figcraft`](https://github.com/storytold/figcraft) `assets/app-icon/hicolor/128x128/apps/ai.storyteller.figcraft.png`, copied unmodified | MIT OR Apache-2.0 (FigCraft's [`LICENSE-MIT`](https://github.com/storytold/figcraft/blob/main/LICENSE-MIT), [`LICENSE-APACHE`](https://github.com/storytold/figcraft/blob/main/LICENSE-APACHE)) | ## Documentation and README diff --git a/Cargo.lock b/Cargo.lock index ed8f3c7..120e6b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -276,7 +276,7 @@ checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "artcraft-launcher" -version = "0.4.0" +version = "0.4.1" dependencies = [ "artcraft-launcher-core", "artcraft-launcher-native", @@ -300,7 +300,7 @@ dependencies = [ [[package]] name = "artcraft-launcher-core" -version = "0.4.0" +version = "0.4.1" dependencies = [ "semver", "serde", @@ -309,7 +309,7 @@ dependencies = [ [[package]] name = "artcraft-launcher-native" -version = "0.4.0" +version = "0.4.1" dependencies = [ "artcraft-launcher-core", "dirs 6.0.0", @@ -327,7 +327,7 @@ dependencies = [ [[package]] name = "artcraft-launcher-ui-egui" -version = "0.4.0" +version = "0.4.1" dependencies = [ "artcraft-launcher-core", "egui", @@ -343,7 +343,7 @@ dependencies = [ [[package]] name = "artcraft-launcher-web" -version = "0.4.0" +version = "0.4.1" dependencies = [ "artcraft-launcher-core", "artcraft-launcher-ui-egui", @@ -5803,7 +5803,7 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" [[package]] name = "xtask" -version = "0.4.0" +version = "0.4.1" [[package]] name = "yoke" diff --git a/Cargo.toml b/Cargo.toml index a7862b5..99be343 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "3" members = ["crates/*", "apps/*", "xtask"] [workspace.package] -version = "0.4.0" +version = "0.4.1" edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.90" diff --git a/README.md b/README.md index 2a06cb0..2a3b6f6 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@

One place to install, update and open every app in the Craft App Suite, rebuilt in pure Rust.
PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft, WordCraft,
- DeckCraft, GridCraft, CADCraft and SoundCraft: the right build for your computer, kept up to date. + DeckCraft, GridCraft, CADCraft, SoundCraft and FigCraft: the right build for your computer, kept up to date.

@@ -247,6 +247,7 @@ stand on its own. | | **DeckCraft** | Presentations and slide decks | [GitHub](https://github.com/storytold/deckcraft) | [Website](https://getartcraft.com/apps/deckcraft) | | | **CADCraft** | Computer-aided design | [GitHub](https://github.com/storytold/cadcraft) | [Website](https://getartcraft.com/apps/cadcraft) | | | **SoundCraft** | Audio recording and editing | [GitHub](https://github.com/storytold/soundcraft) | [Website](https://getartcraft.com/apps/soundcraft) | +| | **FigCraft** | Interface design and prototyping | [GitHub](https://github.com/storytold/figcraft) | [Website](https://getartcraft.com/apps/figcraft) | And [**ArtCraft**](https://getartcraft.com/) itself, our AI image and video studio for artists who want real control. diff --git a/assets/app-icons/figcraft.png b/assets/app-icons/figcraft.png new file mode 100644 index 0000000000000000000000000000000000000000..48be0b9b1287df17e12876d79e4324d2ec09a2b9 GIT binary patch literal 19691 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 = SUITE.iter().map(|a| a.id).collect(); ids.sort_unstable(); ids.dedup(); diff --git a/crates/core/src/details.rs b/crates/core/src/details.rs index 0b3ed72..4ffe83f 100644 --- a/crates/core/src/details.rs +++ b/crates/core/src/details.rs @@ -67,7 +67,7 @@ pub fn looks_like_jpeg(bytes: &[u8]) -> bool { /// Where every Craft App runs (getartcraft.com lists the same for each of them). const PLATFORMS: &str = "macOS, Windows, Linux, FreeBSD, web"; -pub const DETAILS: [AppDetails; 12] = [ +pub const DETAILS: [AppDetails; 13] = [ AppDetails { id: "photocraft", headline: "The image editor you already know how to use.", @@ -371,6 +371,37 @@ pub const DETAILS: [AppDetails; 12] = [ ], platforms: PLATFORMS, }, + AppDetails { + id: "figcraft", + headline: "Interface design and prototyping, in pure Rust.", + about: "Design screens, components and prototypes in a native app that opens instantly and works offline, \ + with no account and no telemetry. Early alpha.", + features: &[ + feature( + "Auto layout", + "Rows, columns, wrap and grids with padding, gaps and Hug, Fill or Fixed sizing, plus constraints and layout grids.", + ), + feature( + "Components", + "Instances with overrides, variants and properties, styles, and variables with modes bound to fills, strokes and effects.", + ), + feature("Vectors", "Real vector networks, the pen and pencil, the shape builder, editable booleans and variable width strokes."), + feature( + "Prototypes", + "Connections, triggers and animated transitions, variables with conditionals, flows and a presentation view with device frames.", + ), + feature( + "Hand off", + "Inspect mode with measurements, annotations, ready-for-dev status, and code for CSS, HTML, React, SwiftUI and Compose.", + ), + feature( + "Your files", + "Plain .figcraft files on your own disk. SVG, PNG, JPEG, WebP and PDF in and out, and .fig files open, best effort.", + ), + ], + shots: &[], + platforms: PLATFORMS, + }, ]; impl AppDetails { diff --git a/crates/core/src/platform.rs b/crates/core/src/platform.rs index 2c0137c..398b34d 100644 --- a/crates/core/src/platform.rs +++ b/crates/core/src/platform.rs @@ -263,6 +263,9 @@ mod tests { { assert_eq!(parse_asset_name(other, &["photocraft"]), None, "{other}"); } + // FigCraft also ships its collaboration server; that tarball is not the app. + assert_eq!(parse_asset_name("figcraft-server-0.5.1-linux-x86_64.tar.gz", &["figcraft"]), None); + assert!(parse_asset_name("figcraft-0.5.1-linux-x86_64.tar.gz", &["figcraft"]).is_some()); } #[test] diff --git a/crates/native/src/desktop_entry.rs b/crates/native/src/desktop_entry.rs index 09ed281..0a519f5 100644 --- a/crates/native/src/desktop_entry.rs +++ b/crates/native/src/desktop_entry.rs @@ -31,6 +31,7 @@ pub fn meta(app: &CraftApp) -> (&'static str, Option<&'static str>) { "gridcraft" => ("Office;Spreadsheet;", None), "cadcraft" => ("Graphics;Engineering;VectorGraphics;", None), "soundcraft" => ("AudioVideo;Audio;Midi;Mixer;Sequencer;Recorder;", None), + "figcraft" => ("Graphics;2DGraphics;VectorGraphics;X-Design;", Some("figcraft")), _ => ("Graphics;", None), } } diff --git a/crates/native/src/install.rs b/crates/native/src/install.rs index c6f77c6..b33c62a 100644 --- a/crates/native/src/install.rs +++ b/crates/native/src/install.rs @@ -746,6 +746,7 @@ pub(crate) mod linux { "gridcraft" => include_bytes!("../../../assets/app-icons/gridcraft.png"), "cadcraft" => include_bytes!("../../../assets/app-icons/cadcraft.png"), "soundcraft" => include_bytes!("../../../assets/app-icons/soundcraft.png"), + "figcraft" => include_bytes!("../../../assets/app-icons/figcraft.png"), _ => return None, }) } diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index e3022fc..9bfcba5 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -152,6 +152,7 @@ deckcraft Presentations and slide shows Prezentace a promítání snímků gridcraft Spreadsheets and data Tabulky a data cadcraft Computer-aided design and drafting Počítačem podporované navrhování a kreslení soundcraft Recording, editing and mixing audio Nahrávání, úpravy a mixování zvuku +figcraft Interface design and prototyping Návrh rozhraní a prototypování month Jan 1. month Feb 2. month Mar 3. diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 8c2c2c6..3145467 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -14,7 +14,7 @@ # Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite # name "Craft App Suite", # app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft, -# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft), "GitHub", "Discord". +# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft, FigCraft), "GitHub", "Discord". # Shortcut keys keep their key-cap names (Shift, Alt, Ctrl, Cmd, Esc). # Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v}, # {what}, {unit}, {real}, {e} must appear in translation. @@ -170,6 +170,7 @@ deckcraft Presentations and slide shows Präsentationen und Diashows gridcraft Spreadsheets and data Tabellenkalkulation und Daten cadcraft Computer-aided design and drafting Computergestütztes Konstruieren und Zeichnen soundcraft Recording, editing and mixing audio Audio aufnehmen, bearbeiten und mischen +figcraft Interface design and prototyping Interface-Design und Prototyping # Contextual: month abbreviations for date rendering month Jan Jan. diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 71bd155..f5a0163 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -14,7 +14,7 @@ # Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite # name "Craft App Suite", app names (PhotoCraft, LightCraft, FilmCraft, # DesignCraft, VectorCraft, PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft, -# SoundCraft), "GitHub", "Discord", "Finder", "makers". +# SoundCraft, FigCraft), "GitHub", "Discord", "Finder", "makers". # Trailing "…" (U+2026) must be preserved. Placeholders must appear in the translation: # {ago}, {a}, {b}, {count}, {date}, {day}, {done}, {e}, {f}, {installed}, {latest}, {min}, # {month}, {name}, {n}, {os}, {platform}, {sources}, {total}, {version}, {v}, {year}. @@ -165,6 +165,7 @@ deckcraft Presentations and slide shows Presentaciones y diapositivas gridcraft Spreadsheets and data Hojas de cálculo y datos cadcraft Computer-aided design and drafting CAD: diseño y dibujo técnico soundcraft Recording, editing and mixing audio Grabación, edición y mezcla de audio +figcraft Interface design and prototyping Diseño de interfaces y prototipos month Jan ene. month Feb feb. month Mar mar. diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index f0c97c8..2d89a4c 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -12,7 +12,7 @@ # Coverage: the whole interface: every menu string and tl! literal (complete_menus = true). # Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite # name "Craft App Suite", app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, -# PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft), "GitHub", +# PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft, FigCraft), "GitHub", # "Discord". # Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v}, # {what}, {unit}, {real}, {e} must appear in translation. @@ -168,6 +168,7 @@ deckcraft Presentations and slide shows Présentations et diaporamas gridcraft Spreadsheets and data Tableurs et données cadcraft Computer-aided design and drafting Conception et dessin assistés par ordinateur soundcraft Recording, editing and mixing audio Enregistrement, édition et mixage audio +figcraft Interface design and prototyping Design d'interfaces et prototypage # Contextual: month abbreviations for date rendering month Jan janv. diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 8b15ccf..8915ab7 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -14,7 +14,7 @@ # Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite # name "Craft App Suite", # app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft, -# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft), "GitHub", "Discord". +# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft, FigCraft), "GitHub", "Discord". # Shortcut keys keep their key-cap names (Shift, Alt, Ctrl, Cmd, Esc). # Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v}, # {what}, {unit}, {real}, {e} must appear in translation. @@ -170,6 +170,7 @@ deckcraft Presentations and slide shows Prezentációk és diavetítések gridcraft Spreadsheets and data Táblázatok és adatok cadcraft Computer-aided design and drafting Számítógépes tervezés és műszaki rajz soundcraft Recording, editing and mixing audio Hangrögzítés, hangszerkesztés és keverés +figcraft Interface design and prototyping Felülettervezés és prototípus-készítés # Contextual: month abbreviations for date rendering month Jan jan. diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 9dd69df..1548831 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -14,7 +14,7 @@ # Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite # name "Craft App Suite", # app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft, -# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft), "GitHub", "Discord". +# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft, FigCraft), "GitHub", "Discord". # Shortcut keys keep their key-cap names (Shift, Alt, Ctrl, Cmd, Esc). # Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v}, # {what}, {unit}, {real}, {e} must appear in translation. @@ -172,6 +172,7 @@ deckcraft Presentations and slide shows プレゼンテーションとスライ gridcraft Spreadsheets and data 表計算とデータ cadcraft Computer-aided design and drafting コンピューター支援設計と製図 soundcraft Recording, editing and mixing audio オーディオの録音、編集、ミックス +figcraft Interface design and prototyping インターフェースデザインとプロトタイピング # Contextual: month abbreviations for date rendering month Jan 1月 diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index ce0ffb5..f4ee0f7 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -13,7 +13,7 @@ # Coverage: the whole interface — every menu string and tl! literal (complete_menus = true). # Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite # name "Craft App Suite", app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, -# PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft), "GitHub", +# PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft, FigCraft), "GitHub", # "Discord". # Shortcut keys keep their key-cap names (Shift, Alt, Ctrl, Cmd, Esc). # Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v}, @@ -171,6 +171,7 @@ deckcraft Presentations and slide shows Prezentacje i pokazy slajdów gridcraft Spreadsheets and data Arkusze kalkulacyjne i dane cadcraft Computer-aided design and drafting Projektowanie i kreślenie wspomagane komputerowo soundcraft Recording, editing and mixing audio Nagrywanie, edycja i miksowanie dźwięku +figcraft Interface design and prototyping Projektowanie interfejsów i prototypowanie # Contextual: month abbreviations for date rendering month Jan sty diff --git a/crates/ui-egui/src/i18n/pt-BR.tsv b/crates/ui-egui/src/i18n/pt-BR.tsv index eedbcf3..4719861 100644 --- a/crates/ui-egui/src/i18n/pt-BR.tsv +++ b/crates/ui-egui/src/i18n/pt-BR.tsv @@ -158,6 +158,7 @@ deckcraft Presentations and slide shows Apresentações e slides gridcraft Spreadsheets and data Planilhas e dados cadcraft Computer-aided design and drafting Desenho técnico e projeto assistido por computador (CAD) soundcraft Recording, editing and mixing audio Gravação, edição e mixagem de áudio +figcraft Interface design and prototyping Design de interfaces e prototipagem # Contextual: month abbreviations for date rendering month Jan jan. diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index fcd8b67..8179d1d 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -13,7 +13,7 @@ # Left in English on purpose: product name "ArtCraft Launcher" (and its "Launcher" tag), suite # name "Craft App Suite", # app names (PhotoCraft, LightCraft, FilmCraft, DesignCraft, VectorCraft, PdfCraft, EffectCraft, -# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft), "GitHub", "Discord", "Website". +# WordCraft, DeckCraft, GridCraft, CADCraft, SoundCraft, FigCraft), "GitHub", "Discord", "Website". # Shortcut keys keep their key-cap names (Shift, Alt, Ctrl, Cmd, Esc). # Trailing "…" (U+2026) must be preserved. Placeholders {name}, {n}, {version}, {count}, {v}, # {what}, {unit}, {real}, {e} must appear in translation. @@ -168,6 +168,7 @@ deckcraft Presentations and slide shows Презентации и слайд-ш gridcraft Spreadsheets and data Электронные таблицы и данные cadcraft Computer-aided design and drafting Автоматизированное проектирование и черчение soundcraft Recording, editing and mixing audio Запись, редактирование и сведение звука +figcraft Interface design and prototyping Дизайн интерфейсов и прототипирование # Contextual: month abbreviations for date rendering month Jan янв. diff --git a/crates/ui-egui/src/i18n/zh-CN.tsv b/crates/ui-egui/src/i18n/zh-CN.tsv index fb3df06..bdc9e12 100644 --- a/crates/ui-egui/src/i18n/zh-CN.tsv +++ b/crates/ui-egui/src/i18n/zh-CN.tsv @@ -247,6 +247,7 @@ deckcraft Presentations and slide shows 演示文稿与幻灯片 gridcraft Spreadsheets and data 电子表格与数据处理 cadcraft Computer-aided design and drafting 计算机辅助设计与制图 soundcraft Recording, editing and mixing audio 音频录制、编辑与混音 +figcraft Interface design and prototyping 界面设计与原型制作 Show in Files 在文件管理器中显示 Loading ArtCraft Launcher… 正在加载 ArtCraft Launcher… diff --git a/crates/ui-egui/src/icons.rs b/crates/ui-egui/src/icons.rs index 8ad51b1..eb79df5 100644 --- a/crates/ui-egui/src/icons.rs +++ b/crates/ui-egui/src/icons.rs @@ -17,6 +17,7 @@ pub fn app(id: &str) -> Option> { "gridcraft" => egui::include_image!("../../../assets/app-icons/gridcraft.png"), "cadcraft" => egui::include_image!("../../../assets/app-icons/cadcraft.png"), "soundcraft" => egui::include_image!("../../../assets/app-icons/soundcraft.png"), + "figcraft" => egui::include_image!("../../../assets/app-icons/figcraft.png"), _ => return None, }) } diff --git a/crates/ui-egui/tests/ui.rs b/crates/ui-egui/tests/ui.rs index 211beb2..a89a4aa 100644 --- a/crates/ui-egui/tests/ui.rs +++ b/crates/ui-egui/tests/ui.rs @@ -631,8 +631,8 @@ fn links_to_the_website_github_and_each_apps_pages() { // Cards: every app links to its repo and to its own page on getartcraft.com (plus the footer's). let shown_cards = h.query_all_by_label("GitHub").count() - 1; let shown_sites = h.query_all_by_label("Website").count() - 1; - assert!(shown_cards >= 12, "{shown_cards}"); - assert_eq!(shown_sites, 12, "every app has a website page"); + assert!(shown_cards >= 13, "{shown_cards}"); + assert_eq!(shown_sites, 13, "every app has a website page"); // The table's … menu has the app's website and GitHub repo. let (mut h, _) = harness(ViewMode::Table, egui::Theme::Dark, true); h.run_steps(6); @@ -1206,7 +1206,7 @@ fn the_lead_picture_can_be_enlarged() { #[test] fn every_page_opens_and_pages_through_its_pictures() { let (mut h, _sent) = harness(ViewMode::Grid, egui::Theme::Dark, true); - // Tall enough to show all twelve cards at once. + // Tall enough to show all thirteen cards at once. h.set_size(egui::vec2(1180.0, 3000.0)); h.run_steps(8); for d in &artcraft_launcher_core::details::DETAILS { diff --git a/packaging/linux/ai.storyteller.artcraft-launcher.metainfo.xml.in b/packaging/linux/ai.storyteller.artcraft-launcher.metainfo.xml.in index 234acb6..7a885ff 100644 --- a/packaging/linux/ai.storyteller.artcraft-launcher.metainfo.xml.in +++ b/packaging/linux/ai.storyteller.artcraft-launcher.metainfo.xml.in @@ -13,8 +13,8 @@

ArtCraft Launcher lists every app in the Craft App Suite (PhotoCraft, LightCraft, FilmCraft, - DesignCraft, VectorCraft, PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft - and SoundCraft), installs the right build for your computer, and keeps them up to date. + DesignCraft, VectorCraft, PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft, + SoundCraft and FigCraft), installs the right build for your computer, and keeps them up to date.

  • One place to find, install and open every Craft app
  • diff --git a/packaging/linux/nfpm.yaml b/packaging/linux/nfpm.yaml index f8f605b..c6587c3 100644 --- a/packaging/linux/nfpm.yaml +++ b/packaging/linux/nfpm.yaml @@ -19,9 +19,9 @@ license: MIT OR Apache-2.0 description: |- Install, update and launch the Craft App Suite. ArtCraft Launcher lists PhotoCraft, LightCraft, FilmCraft, DesignCraft, - VectorCraft, PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft - and SoundCraft, installs the right build for this computer and keeps them up - to date from GitHub releases. It can live in the system tray. + VectorCraft, PdfCraft, EffectCraft, WordCraft, DeckCraft, GridCraft, CADCraft, + SoundCraft and FigCraft, installs the right build for this computer and keeps + them up to date from GitHub releases. It can live in the system tray. # The binary links only glibc and libgcc_s directly. Windowing (X11/Wayland, xkbcommon) and the # GPU (Vulkan, EGL/GL) are loaded at runtime with dlopen, so they aren't ELF NEEDED entries and diff --git a/packaging/windows/package.ps1 b/packaging/windows/package.ps1 index ac8d44e..52cb1e8 100644 --- a/packaging/windows/package.ps1 +++ b/packaging/windows/package.ps1 @@ -111,7 +111,7 @@ function New-InstallerArt([string] $BannerOut, [string] $DialogOut) { $line = [System.Drawing.Color]::FromArgb(38, 242, 241, 238) # The Craft App Suite, in the launcher's order (crates/core/src/catalog.rs). $apps = 'photocraft', 'vectorcraft', 'filmcraft', 'lightcraft', 'pdfcraft', 'effectcraft', - 'designcraft', 'wordcraft', 'deckcraft', 'gridcraft', 'cadcraft', 'soundcraft' + 'designcraft', 'wordcraft', 'deckcraft', 'gridcraft', 'cadcraft', 'soundcraft', 'figcraft' $mark = [System.Drawing.Image]::FromFile((Join-Path $Root 'assets\app-icon\hicolor\256x256\apps\ai.storyteller.artcraft-launcher.png')) $wordmark = [System.Drawing.Image]::FromFile((Join-Path $Root 'docs\brand\artcraft-logo-white.png')) $icons = $apps | ForEach-Object { [System.Drawing.Image]::FromFile((Join-Path $Root "assets\app-icons\$_.png")) } @@ -148,14 +148,14 @@ function New-InstallerArt([string] $BannerOut, [string] $DialogOut) { $x += $g.MeasureString([string]$ch, $labelFont, 100, [System.Drawing.StringFormat]::GenericTypographic).Width + 1.35 } $brush.Dispose() - # The apps, three to a row, in 40 px cells divided by hairlines. + # The apps, three to a row, in 36 px cells divided by hairlines (five rows fit above 312). $pen = New-Object System.Drawing.Pen $line, 1 - $left = 22; $top = 126; $cell = 40 + $left = 22; $top = 118; $cell = 36 for ($i = 0; $i -lt $icons.Count; $i++) { $cx = $left + ($i % 3) * $cell $cy = $top + [math]::Floor($i / 3) * $cell $g.DrawRectangle($pen, $cx, $cy, $cell, $cell) - $g.DrawImage($icons[$i], $cx + 6, $cy + 6, $cell - 12, $cell - 12) + $g.DrawImage($icons[$i], $cx + 5, $cy + 5, $cell - 10, $cell - 10) } $pen.Dispose() } diff --git a/xtask/src/local.rs b/xtask/src/local.rs index 0634f8e..77283d5 100644 --- a/xtask/src/local.rs +++ b/xtask/src/local.rs @@ -31,6 +31,7 @@ const APPS: &[(&str, &str)] = &[ ("gridcraft", "GridCraft"), ("cadcraft", "CADCraft"), ("soundcraft", "SoundCraft"), + ("figcraft", "FigCraft"), ]; const DEFAULT_PORT: u16 = 8787;