Compare commits

..

1 Commits

Author SHA1 Message Date
BFlat ba8ec97900 Add FigCraft to the Craft App Suite
The thirteenth app: catalog row, details page with four pictures, icon, tagline in every
language, Linux desktop entry, and the lists in the docs and packaging.

- Details pictures move to craft-launcher-assets v2, which adds figcraft/.
- The MSI wizard's icon grid is four to a row in 30 px cells, so thirteen icons fit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:51:10 +07:00
12 changed files with 46 additions and 54 deletions

12
Cargo.lock generated
View File

@ -276,7 +276,7 @@ checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
[[package]]
name = "artcraft-launcher"
version = "0.4.1"
version = "0.4.0"
dependencies = [
"artcraft-launcher-core",
"artcraft-launcher-native",
@ -300,7 +300,7 @@ dependencies = [
[[package]]
name = "artcraft-launcher-core"
version = "0.4.1"
version = "0.4.0"
dependencies = [
"semver",
"serde",
@ -309,7 +309,7 @@ dependencies = [
[[package]]
name = "artcraft-launcher-native"
version = "0.4.1"
version = "0.4.0"
dependencies = [
"artcraft-launcher-core",
"dirs 6.0.0",
@ -327,7 +327,7 @@ dependencies = [
[[package]]
name = "artcraft-launcher-ui-egui"
version = "0.4.1"
version = "0.4.0"
dependencies = [
"artcraft-launcher-core",
"egui",
@ -343,7 +343,7 @@ dependencies = [
[[package]]
name = "artcraft-launcher-web"
version = "0.4.1"
version = "0.4.0"
dependencies = [
"artcraft-launcher-core",
"artcraft-launcher-ui-egui",
@ -5803,7 +5803,7 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
[[package]]
name = "xtask"
version = "0.4.1"
version = "0.4.0"
[[package]]
name = "yoke"

View File

@ -3,7 +3,7 @@ resolver = "3"
members = ["crates/*", "apps/*", "xtask"]
[workspace.package]
version = "0.4.1"
version = "0.4.0"
edition = "2024"
license = "MIT OR Apache-2.0"
rust-version = "1.90"

View File

@ -161,19 +161,12 @@ fn native_options(hidden: bool) -> eframe::NativeOptions {
/// Adrenalin installer leaves the integrated GPU on the OEM driver) it crashes inside
/// `amdvlk64.dll` before the first frame. `WGPU_BACKEND` still overrides the default, and then
/// wgpu picks the adapter itself. Direct3D 12 shaders compile with FXC ([`pin_dx12_compiler`]).
///
/// Direct3D 12 presents through DirectComposition rather than straight to the window. The
/// borderless window's drop shadow moves its client area down a pixel, and a swapchain made from
/// the window is then stretched over it vertically by the compositor, blurring every horizontal
/// edge and line of text. `WGPU_DX12_PRESENTATION_SYSTEM` still overrides it.
#[cfg(windows)]
fn wgpu_options() -> eframe::WgpuConfiguration {
use eframe::wgpu::{Backends, Dx12Compiler, Dx12SwapchainKind, PowerPreference};
use eframe::wgpu::{Backends, Dx12Compiler, PowerPreference};
let mut config = eframe::WgpuConfiguration::default();
pin_dx12_compiler(&mut config, Dx12Compiler::from_env());
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup {
setup.instance_descriptor.backend_options.dx12.presentation_system =
Dx12SwapchainKind::from_env().unwrap_or(Dx12SwapchainKind::DxgiFromVisual);
if let Some(backends) = Backends::from_env() {
setup.instance_descriptor.backends = backends;
} else {

View File

@ -201,7 +201,7 @@ pub const SUITE: [CraftApp; 13] = [
"FigCraft",
"Interface design and prototyping",
AppGroup::New,
[[0x02, 0xda, 0x96], [0x04, 0x7a, 0x56], [0x4f, 0xe8, 0xb6]],
[[0x02, 0xda, 0x96], [0x01, 0x7a, 0x54], [0x3f, 0xe6, 0xae]],
"storytold/figcraft",
),
];

View File

@ -53,7 +53,7 @@ const fn feature(title: &'static str, text: &'static str) -> Feature {
pub const SCREENSHOTS_BASE: &str = "https://raw.githubusercontent.com/storytold/craft-launcher-assets";
/// The tag of the pictures repository the launcher reads. Also part of the saved copies' path.
pub const SCREENSHOTS_REV: &str = "v1";
pub const SCREENSHOTS_REV: &str = "v2";
/// The largest picture the launcher accepts. The real ones are 60 to 150 KB.
pub const MAX_SCREENSHOT_BYTES: usize = 2 << 20;
@ -373,33 +373,39 @@ pub const DETAILS: [AppDetails; 13] = [
},
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.",
headline: "Interface design, rebuilt in pure Rust.",
about: "Frames, auto layout, components and variants, vector networks, styles, variables and prototypes in a \
native app that opens instantly and works offline. No account, no telemetry and no subscription. \
Early alpha.",
features: &[
feature("Familiar by design", "The toolbar, layers panel, Design panel, menus and shortcuts sit where your hands expect them."),
feature(
"Auto layout",
"Rows, columns, wrap and grids with padding, gaps and Hug, Fill or Fixed sizing, plus constraints and layout grids.",
"Layouts that build themselves",
"Auto layout in both directions with wrap and grid, padding, gaps and Hug, Fill and 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.",
"Components that scale",
"Instances with overrides that survive edits, component sets with variants and properties, and styles and variables with light and dark modes.",
),
feature(
"Hand off",
"Inspect mode with measurements, annotations, ready-for-dev status, and code for CSS, HTML, React, SwiftUI and Compose.",
"Real vector networks",
"Pen and pencil, a shape builder, booleans whose operands stay editable, variable-width strokes and smooth corners.",
),
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.",
"Prototype and hand off",
"Connections, triggers and animated transitions, a presentation view, and Dev Mode with measurements, annotations and generated code.",
),
feature(
"Agent-ready",
"Every menu item, tool and gesture is a command, available over the CLI, a JSON control channel or an MCP server.",
),
],
shots: &[],
shots: &[
shot("hero", "Auto layout screens in light and dark"),
shot("components", "Components, variants and the Assets panel"),
shot("prototype", "Prototype connections and flows"),
shot("dev-mode", "Dev Mode with annotations and generated code"),
],
platforms: PLATFORMS,
},
];
@ -448,7 +454,7 @@ mod tests {
let page = AppDetails::by_id("photocraft").unwrap();
assert_eq!(
page.screenshot_url("demo").as_deref(),
Some("https://raw.githubusercontent.com/storytold/craft-launcher-assets/v1/photocraft/demo.jpg")
Some("https://raw.githubusercontent.com/storytold/craft-launcher-assets/v2/photocraft/demo.jpg")
);
for key in ["", "nope", "../vectorcraft/neon", "demo/../masks", "demo.jpg", "/etc/passwd", "demo?x=1", "demo#"] {
assert_eq!(page.screenshot_url(key), None, "{key:?}");

View File

@ -263,9 +263,6 @@ 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]

View File

@ -165,7 +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
figcraft Interface design and prototyping Diseño de interfaces y prototipado
month Jan ene.
month Feb feb.
month Mar mar.

Can't render this file because it contains an unexpected character in line 5 and column 48.

View File

@ -170,7 +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
figcraft Interface design and prototyping Felülettervezés és prototípuskészítés
# Contextual: month abbreviations for date rendering
month Jan jan.

Can't render this file because it contains an unexpected character in line 11 and column 16.

View File

@ -287,9 +287,7 @@ pub fn install_fonts(ctx: &egui::Context, cjk: Option<Lang>) {
("GeistMono-Bold", GEIST_MONO, &[(*b"wght", 700.0)], mono_bold()),
];
for (name, bytes, coords, family) in faces {
// No subpixel binning: these fonts carry no hinting instructions, so a glyph drawn at a
// fractional x smears each stem across two pixels, leaving small text blurry at 100 %.
let tweak = FontTweak { coords: VariationCoords::new(coords.iter().copied()), subpixel_binning: Some(false), ..Default::default() };
let tweak = FontTweak { coords: VariationCoords::new(coords.iter().copied()), ..Default::default() };
fonts.font_data.insert(name.to_owned(), Arc::new(FontData::from_static(bytes).tweak(tweak)));
let mut stack = vec![name.to_owned()];
stack.extend(fallback.iter().cloned());

View File

@ -411,11 +411,9 @@ impl LauncherUi {
// A faint wash in the app's colour fades in under the pointer.
let fill = t.bg.lerp_to_gamma(app_color, 0.05 * lift);
painter.rect(rect, CornerRadius::ZERO, fill, t.hairline(), egui::StrokeKind::Inside);
// On hover, a 2 px rule in the app's colour wipes in from the left along the top, inside the
// hairlines the card shares with its neighbours (the site's rule sits within its grid gaps).
// On hover, a 2 px rule in the app's colour wipes in from the left along the top.
if lift > 0.0 {
let inside = rect.shrink(1.0);
painter.rect_filled(Rect::from_min_size(inside.min, vec2(inside.width() * lift, 2.0)), CornerRadius::ZERO, app_color);
painter.rect_filled(Rect::from_min_size(rect.min, vec2(rect.width() * lift, 2.0)), CornerRadius::ZERO, app_color);
}
// The top strip: the app's number in its colour, and its pages.

View File

@ -20,8 +20,8 @@ description: |-
Install, update and launch the Craft App Suite.
ArtCraft Launcher lists PhotoCraft, LightCraft, FilmCraft, DesignCraft,
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.
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

View File

@ -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 36 px cells divided by hairlines (five rows fit above 312).
# The apps, four to a row, in 30 px cells divided by hairlines.
$pen = New-Object System.Drawing.Pen $line, 1
$left = 22; $top = 118; $cell = 36
$left = 22; $top = 126; $cell = 30
for ($i = 0; $i -lt $icons.Count; $i++) {
$cx = $left + ($i % 3) * $cell
$cy = $top + [math]::Floor($i / 3) * $cell
$cx = $left + ($i % 4) * $cell
$cy = $top + [math]::Floor($i / 4) * $cell
$g.DrawRectangle($pen, $cx, $cy, $cell, $cell)
$g.DrawImage($icons[$i], $cx + 5, $cy + 5, $cell - 10, $cell - 10)
$g.DrawImage($icons[$i], $cx + 4, $cy + 4, $cell - 8, $cell - 8)
}
$pen.Dispose()
}