From 9f687f7b44cc85c2dc68e8e99d19446846881678 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 1 Oct 2026 14:25:46 -0400 Subject: [PATCH 1/2] Community links: header Discord button, Help menu (Discord, ArtCraft website, FilmCraft app page, GitHub, Report an Issue), Discord in the macOS app menu, About dialog with link buttons (centred, Escape closes), Community row on the Home screen, README links; help.* commands for agents; headless UI test Co-Authored-By: Claude Opus 5.5 --- README.md | 178 ++++++++++++++++------- apps/filmcraft/src/native_menu.rs | 1 + crates/ui-egui/src/header.rs | 15 ++ crates/ui-egui/src/icons.rs | 39 +++++ crates/ui-egui/src/lib.rs | 1 + crates/ui-egui/src/links.rs | 51 +++++++ crates/ui-egui/src/menus.rs | 11 ++ crates/ui-egui/src/panels/dialogs.rs | 66 ++++++++- crates/ui-egui/src/panels/import_mode.rs | 26 +++- crates/ui-egui/tests/links_ui.rs | 115 +++++++++++++++ 10 files changed, 445 insertions(+), 58 deletions(-) create mode 100644 crates/ui-egui/src/links.rs create mode 100644 crates/ui-egui/tests/links_ui.rs diff --git a/README.md b/README.md index 869b70f79..fd1603d03 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,68 @@ +

+ + + + ArtCraft + + +

+

FilmCraft

- Professional video editing, rebuilt from scratch in pure Rust.
- An open-source, clean-room take on the Adobe Premiere Pro workflow: native on macOS, Windows and Linux, and in the browser via WebAssembly.
- By the artcraft team. + Professional video editing, rebuilt from scratch in pure Rust.

+

+ An open-source, clean-room take on the Adobe Premiere Pro workflow: native on macOS, Windows and Linux, and in the browser via WebAssembly.
+ By the ArtCraft team. +

+ +

+ License: MIT or Apache-2.0 + Written in pure Rust + Runs on macOS, Windows and Linux + Status: young and moving fast +

+ +

+ Join the ArtCraft community on Discord +

+ +

+ FilmCraft on getartcraft.com · + ArtCraft · + All Crafting Apps +

+ +
+ +

+ FilmCraft in the Color workspace, mid-way through an Apollo 11 documentary cut from NASA footage: the Program monitor on the Saturn V clearing the launch tower with a Launch Complex 39A lower third and an air-to-ground subtitle, Effect Controls with Lumetri and Scale keyframes on the shot, the Lumetri Color panel, bins of NASA selects, and a timeline with 49 picture cuts, B-roll, titles, a caption track, mission audio, a ducked music bed, named markers, a rendered section and live loudness meters +

+ +

Apollo 11 - Tranquility: a three-minute documentary edit of NASA's 1969 launch, landing and moonwalk film, with subtitles from the mission transcript. Every frame in these screenshots comes from public-domain footage, decoded, composited and graded by FilmCraft's own code.

+ +> [!NOTE] +> **ArtCraft is a community of artists from all walks of life.** Painters, photographers, +> filmmakers, illustrators, designers, animators, hobbyists, and people who picked up a pencil +> last week. If you make things, you're one of us. **[Come say hi on Discord](https://discord.gg/artcraft).** +

Edit · Color · Effects · Audio · + Titles · Formats · Export · Interchange · Agents · - Get started + Get started · + Docs · + Status

-

- FilmCraft in the Color workspace, mid-way through an Apollo 11 documentary cut from NASA footage: the Program monitor on the Saturn V clearing the launch tower with a Launch Complex 39A lower third and an air-to-ground subtitle, Effect Controls with Lumetri and Scale keyframes on the shot, the Lumetri Color panel, bins of NASA selects, and a timeline with 49 picture cuts, B-roll, titles, a caption track, mission audio, a ducked music bed, named markers, a rendered section and live loudness meters -

- -

Apollo 11 — Tranquility: a three-minute documentary edit of NASA's 1969 launch, landing and moonwalk film, with subtitles from the mission transcript. Every frame in these screenshots comes from public-domain footage, decoded, composited and graded by FilmCraft's own code.

-
FilmCraft is a non-linear editor for people who know Premiere: the same panels, workspaces, tools and shortcuts, so your hands already know where everything is. Underneath, it is new from the bitstream up. The H.264, HEVC, ProRes and AAC codecs are our own, written in Rust from the public specifications. A GPU compositor works in linear light. Frame math runs on exact integer time, so edits never drift. And every action in the app is a command that an AI agent can drive as precisely as you can. @@ -33,9 +72,11 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels, ## Edit

- Assembly workspace: Carnival of Souls in the Source monitor with In and Out marks, Night of the Living Dead in the Program monitor, the trailer in the timeline + Assembly workspace: bins of film thumbnails, Carnival of Souls in the Source monitor, a Night of the Living Dead cemetery shot in the Program monitor, and the trailer on a three-track timeline with a Chopin score on A2 and loudness meters

+

The Assembly workspace, cutting a trailer for Night of the Living Dead (1968) with an insert from Carnival of Souls (1962).

+ **A timeline you already know.** Source and Program monitors, bins with thumbnails, a multi-track timeline with patch and target buttons, sync locks and linked selection. The Editing, Assembly, Color, Effects and Audio workspaces are all there, and every panel docks wherever you want it. - **Three-point editing.** Mark In and Out in the Source monitor, then insert (`,`) or overwrite (`.`) onto the patched tracks. Lift (`;`) and extract (`'`) take ranges back out. @@ -46,17 +87,21 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels, - **Never lose work.** Saves are atomic, auto-save keeps a rolling set of versions, and a crash-recovery journal written about a second after each edit brings back unsaved changes after a crash or power cut.

- Timeline detail: Night of the Living Dead shots with dissolves, a Carnival of Souls insert on V2, the Chopin score as a waveform on A2, markers and loudness meters + Timeline close-up: Night of the Living Dead shots with dissolves on V1, a Carnival of Souls insert on V2, the Chopin nocturne as a green waveform on A2, coloured markers along the ruler, and the loudness meter reading momentary, short-term, integrated and true-peak values

+

Up close: dissolves, an insert on V2, the score on A2, coloured markers, and the loudness meters on the right.

+
## Color

- Color workspace: a Lumetri grade on Charade (1963) with curves, colour sliders, waveform and vectorscope + Color workspace on Charade (1963): Cary Grant and Audrey Hepburn in the Program monitor, the waveform and vectorscope on the left, and the trailer bins and timeline below

+

The Color workspace on Charade (1963), with live scopes beside the Program monitor.

+ **A complete Lumetri-style grading panel**, in the order a colourist works: - **Basic Correction:** temperature and tint, exposure, contrast, highlights, shadows, whites, blacks, saturation. @@ -68,8 +113,14 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels, - - + +
The Lumetri Color panel: basic correction sliders with temperature and tint gradients, and three colour wheelsLumetri Scopes: waveform and vectorscope of a Charade frame

Scopes that tell the truth. The waveform and vectorscope are computed from the graded frame. All grading happens in linear light, in 32-bit float.
+ The Lumetri Color panel on Charade (1963): Basic Correction sliders with coloured temperature and tint tracks, collapsed Creative and Curves sections, shadow, midtone and highlight colour wheels, and HSL Secondary and Vignette toggles
+ The Lumetri Color panel. Basic Correction, Color Wheels and every other section, each with its own on/off switch. +
+ Lumetri Scopes: a green luma waveform and a vectorscope of a Charade (1963) frame
+ Scopes that tell the truth. The waveform and vectorscope are computed from the graded frame. All grading happens in linear light, in 32-bit float. +
@@ -78,16 +129,18 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels, ## Effects and motion

- Effects workspace: Effect Controls, NASA Earth Views from the ISS with a Golden Hour look, and the Effects browser + Effects workspace: Effect Controls with Motion, Opacity, Time Remapping and Lumetri Color, NASA's Earth Views from the ISS in the Program monitor, and the Effects browser open on the Dissolve transitions

+

NASA's Earth Views from the ISS with a look applied, and the Effects browser open on the dissolves.

+ - **Around 55 video effects and 30 transitions.** Blurs, keys, distortions, stylize and colour effects. Cross dissolve, dip to black or white, film dissolve, wipes, irises, pushes, slides, zooms, page peel, cube spin and more. - **Motion and opacity on every clip:** position, scale, rotation, anchor point and anti-flicker, plus 26 blend modes. - **Keyframes like Premiere's:** linear, Bezier, auto and continuous Bezier, hold, ease in and ease out. Effect Controls shows a keyframe lane for every parameter, and each animated parameter opens into **value and velocity graphs** with draggable influence handles. - **A GPU compositor** built on wgpu (Metal, Vulkan, DirectX 12, WebGPU). It samples YUV straight from the decoder with footprint supersampling and blends in linear light. A CPU path renders the same frames, and the two are tested against each other.

- Effect Controls with the value and velocity graphs of an eased Scale push-in on the Night of the Living Dead title + Effect Controls with the value and velocity graphs of an eased Scale push-in on the Night of the Living Dead title card, the Program monitor showing the title over a country road, and the Properties panel with Transform and Crop

An eased push-in on the title card: the value graph, the velocity graph and the Bezier influence handle.

@@ -104,6 +157,13 @@ FilmCraft is a non-linear editor for people who know Premiere: the same panels,
+## Titles and captions + +- **A real text engine:** OpenType shaping with kerning and ligatures, bidirectional text, line breaking, tracking and leading, drawn in linear light and sharp at any scale or rotation. +- **Type, Shape and Pen tools** on the Program monitor: click to type, edit with a caret and selection, drag out rectangles, ellipses and paths. Graphic clips hold text and shape layers with fill, strokes, background and shadow, all keyframable, and edited in the Properties panel. +- **Captions:** caption tracks in Subtitle, CEA-608, CEA-708 and Teletext formats; import and export SRT, WebVTT and SCC with frame-exact timing; edit captions in the Text panel and burn them into exports. +
+ ## Formats and codecs No FFmpeg inside. The video codecs, AAC, Opus and the containers are our own Rust code, implemented from the public ITU-T, ISO and IETF specifications and tested frame by frame against ffmpeg as an external oracle. @@ -128,20 +188,14 @@ MXF and hardware decode are next ([roadmap](ROADMAP.md)).
-## Titles and captions - -- **A real text engine:** OpenType shaping with kerning and ligatures, bidirectional text, line breaking, tracking and leading, drawn in linear light and sharp at any scale or rotation. -- **Type, Shape and Pen tools** on the Program monitor: click to type, edit with a caret and selection, drag out rectangles, ellipses and paths. Graphic clips hold text and shape layers with fill, strokes, background and shadow, all keyframable, and edited in the Properties panel. -- **Captions:** caption tracks in Subtitle, CEA-608, CEA-708 and Teletext formats; import and export SRT, WebVTT and SCC with frame-exact timing; edit captions in the Text panel and burn them into exports. - -
- ## Export

- Export mode with H.264 MP4 settings + Export mode: destinations for Media File, YouTube, Vimeo, TikTok, Instagram and FTP on the left, a Night of the Living Dead frame in the preview, and H.264 settings on the right (1440x1080 at 23.976 fps, 48000 Hz stereo, entire sequence)

+

Export mode, set to write the trailer as H.264 MP4.

+ - **H.264 MP4 with AAC, using our own encoders.** A 6-second 960×540 render takes 1.3 seconds and decodes cleanly in ffmpeg with error concealment switched off. - **Also:** Apple ProRes 422 HQ and Motion JPEG in QuickTime, PNG sequences, animated GIF and WAV. - **Background jobs** with progress and cancel, so you keep editing while it renders. @@ -196,7 +250,7 @@ cargo run --release -p filmcraft-cli -- commands # list every engine c cargo run --release -p filmcraft-cli -- mcp # MCP server (headless) ``` -The control protocol is documented in [docs/control-protocol.md](docs/control-protocol.md). +The control protocol is documented in [docs/control-protocol.md](docs/control-protocol.md). Stuck, or want to show what you made? Ask in [Discord](https://discord.gg/artcraft). ## Documentation @@ -232,32 +286,47 @@ A layered Cargo workspace: Nothing below the front ends depends on a UI toolkit or OS API. `cargo xtask ci` checks formatting, lints, tests, the layering rules, asset attribution and the wasm build. -## Crafting Apps +## The Crafting Apps -Open-source, clean-room, pure-Rust creative tools. Each runs natively on macOS, Windows and Linux, and on the web. +FilmCraft is one of the **Crafting Apps**: free, open-source creative tools from the +[ArtCraft](https://getartcraft.com/) team, each written from scratch in Rust and each able to +stand on its own. - - - - - - - - - - - - - - - - - - - - - -
PhotoCraftImage editing and compositing, Photoshop-class: layers, masks, adjustments and byte-exact PSD/PSB round trips.
DrawCraftVector illustration, Illustrator-class: paths, shapes, type and artboards.
FilmCraftNon-linear video editing, Premiere Pro-class: timeline editing, own codecs, GPU compositing, colour and export. You are here.
LightCraftPhoto library and non-destructive raw developer, Lightroom-class: catalog, culling, develop and export.
PrintCraftPDF viewing and editing, Acrobat-class: pages, annotations, forms and document tools.
+| App | What it's for | Code | Learn more | +|---|---|---|---| +| PhotoCraft | Image editing: layers, masks, type and real PSD files | [GitHub](https://github.com/storytold/photocraft) | [getartcraft.com](https://getartcraft.com/apps/photocraft) | +| VectorCraft | Vector illustration (formerly DrawCraft) | [GitHub](https://github.com/storytold/vectorcraft) | [getartcraft.com](https://getartcraft.com/apps/drawcraft) | +| FilmCraft | **Video editing, color and sound · you are here** | [GitHub](https://github.com/storytold/filmcraft) | [getartcraft.com](https://getartcraft.com/apps/filmcraft) | +| LightCraft | Photo library and raw development | [GitHub](https://github.com/storytold/lightcraft) | [getartcraft.com](https://getartcraft.com/apps/lightcraft) | +| PrintCraft | Reading, organizing and protecting PDFs | [GitHub](https://github.com/storytold/printcraft) | [getartcraft.com](https://getartcraft.com/apps/printcraft) | +| EffectCraft | Motion graphics and visual effects | [GitHub](https://github.com/storytold/effectcraft) | [getartcraft.com](https://getartcraft.com/apps/effectcraft) | +| DesignCraft | Page layout and publishing | [GitHub](https://github.com/storytold/designcraft) | [getartcraft.com](https://getartcraft.com/apps/designcraft) | + +And [**ArtCraft**](https://getartcraft.com/) itself, our AI image and video studio for artists who want real control. + +
+ +

+ Join the ArtCraft community on Discord +

+ +

Come make things with us

+ +

+ Our Discord is where artists of every kind hang out: people who paint, shoot, draw, cut film, + set type, and people still figuring out what they like to make. Share what you're working on, + ask for help, tell us what's broken, or tell us what you wish these tools could do. + Whatever your medium and however long you've been at it, you're welcome here. +

+ +

+ discord.gg/artcraft · + getartcraft.com · + The Crafting Apps · + FilmCraft +

+ +
## Credits and clean room @@ -268,3 +337,10 @@ FilmCraft is an independent implementation. It contains no Adobe code, icons, im ## License FilmCraft is dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option. Bundled assets keep their own open licences, listed in [ATTRIBUTION.md](ATTRIBUTION.md). + +
+ +

+ ArtCraft
+ Made by the ArtCraft team and community. +

diff --git a/apps/filmcraft/src/native_menu.rs b/apps/filmcraft/src/native_menu.rs index fd1422948..626a045c8 100644 --- a/apps/filmcraft/src/native_menu.rs +++ b/apps/filmcraft/src/native_menu.rs @@ -29,6 +29,7 @@ pub fn install(app: &FilmcraftApp, ctx: egui::Context) -> (Receiver, Sho let app_menu = Submenu::new("FilmCraft", true); let _ = app_menu.append_items(&[ &MenuItem::with_id("app.about", "About FilmCraft", true, None), + &MenuItem::with_id("help.discord", "Join the ArtCraft Discord…", true, None), &PredefinedMenuItem::separator(), &MenuItem::with_id("app.preferences.autoSave", "Settings…", true, None), &PredefinedMenuItem::separator(), diff --git a/crates/ui-egui/src/header.rs b/crates/ui-egui/src/header.rs index cf40aa910..9d8a4e089 100644 --- a/crates/ui-egui/src/header.rs +++ b/crates/ui-egui/src/header.rs @@ -103,6 +103,21 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) { let wresp = ui.interact(wr, egui::Id::new("hdr-ws-name"), Sense::click()); app.auto.add("header.workspaceName", wr, &ws); p.galley_with_override_text_color(pos2(wr.min.x + 4.0, rect.center().y - wg.size().y / 2.0), wg, if wresp.hovered() { t.text } else { t.text_dim }); + // Community: a labelled Discord button, always one click away. + { + let label = "Discord"; + let g = p.layout_no_wrap(label.to_string(), Tokens::ui(12.0), Color32::WHITE); + let w = g.size().x + 34.0; + let r = Rect::from_min_size(pos2(wr.min.x - w - 14.0, rect.center().y - 12.0), vec2(w, 24.0)); + let resp = ui.interact(r, egui::Id::new("hdr-discord"), Sense::click()).on_hover_text("Join the ArtCraft Discord (discord.gg/artcraft)"); + app.auto.add("header.discord", r, "Join the ArtCraft Discord"); + ui.painter().rect_filled(r, 12.0, if resp.hovered() { t.accent_hover } else { t.accent }); + icons::paint(ui.painter(), Rect::from_center_size(pos2(r.min.x + 14.0, r.center().y), vec2(14.0, 14.0)), Icon::Chat, Color32::WHITE); + ui.painter().galley(pos2(r.min.x + 25.0, r.center().y - g.size().y / 2.0), g, Color32::WHITE); + if resp.clicked() { + crate::links::open(ui.ctx(), crate::links::DISCORD); + } + } let popup_id = egui::Id::new("workspaces-popup"); if ws_resp.clicked() || wresp.clicked() { ui.ctx().data_mut(|d| d.insert_temp(popup_id, true)); diff --git a/crates/ui-egui/src/icons.rs b/crates/ui-egui/src/icons.rs index c947aa24f..d747d5874 100644 --- a/crates/ui-egui/src/icons.rs +++ b/crates/ui-egui/src/icons.rs @@ -80,6 +80,13 @@ pub enum Icon { Undo, Redo, Bell, + /// Community chat (the ArtCraft Discord): a speech bubble with three dots. Our own drawing, + /// not the Discord logo. + Chat, + /// Website: a globe. + Globe, + /// Source code (GitHub repository): angle brackets and a slash. + Code, Sparkle, Grid, Square, @@ -488,6 +495,38 @@ pub fn paint(painter: &Painter, rect: Rect, icon: Icon, color: Color32) { pen.arc(8.0, 7.0, 3.5, 180.0, 360.0); pen.dot(8.0, 13.8, 1.0); } + Chat => { + pen.line(&[ + (3.5, 3.0), + (12.5, 3.0), + (14.0, 4.5), + (14.0, 9.5), + (12.5, 11.0), + (7.0, 11.0), + (4.0, 14.0), + (4.5, 11.0), + (3.5, 11.0), + (2.0, 9.5), + (2.0, 4.5), + (3.5, 3.0), + ]); + pen.dot(5.5, 7.0, 0.9); + pen.dot(8.0, 7.0, 0.9); + pen.dot(10.5, 7.0, 0.9); + } + Globe => { + pen.circle(8.0, 8.0, 6.0); + pen.line(&[(2.0, 8.0), (14.0, 8.0)]); + pen.line(&[(3.0, 5.0), (13.0, 5.0)]); + pen.line(&[(3.0, 11.0), (13.0, 11.0)]); + pen.line(&[(8.0, 2.0), (6.0, 5.0), (5.5, 8.0), (6.0, 11.0), (8.0, 14.0)]); + pen.line(&[(8.0, 2.0), (10.0, 5.0), (10.5, 8.0), (10.0, 11.0), (8.0, 14.0)]); + } + Code => { + pen.line(&[(5.0, 4.0), (1.5, 8.0), (5.0, 12.0)]); + pen.line(&[(11.0, 4.0), (14.5, 8.0), (11.0, 12.0)]); + pen.line(&[(9.5, 2.5), (6.5, 13.5)]); + } Sparkle => { pen.fill(&[(8.0, 1.5), (9.5, 6.5), (14.5, 8.0), (9.5, 9.5), (8.0, 14.5), (6.5, 9.5), (1.5, 8.0), (6.5, 6.5)]); } diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 8b2c24388..874edb80f 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -10,6 +10,7 @@ pub mod dock; pub mod frames; pub mod header; pub mod icons; +pub mod links; pub mod menus; pub mod panels; pub mod state; diff --git a/crates/ui-egui/src/links.rs b/crates/ui-egui/src/links.rs new file mode 100644 index 000000000..641463d52 --- /dev/null +++ b/crates/ui-egui/src/links.rs @@ -0,0 +1,51 @@ +//! Community and project links (Help menu, About dialog, header Discord button, Home screen). +//! +//! FilmCraft is part of the ArtCraft family: the community lives on the ArtCraft Discord, every +//! app has a page on the ArtCraft website and a public GitHub repository. + +/// The app's short name, used in the website and repository URLs. +pub const APP: &str = "filmcraft"; + +/// The ArtCraft community Discord. +pub const DISCORD: &str = "https://discord.gg/artcraft"; +/// The ArtCraft website. +pub const WEBSITE: &str = "https://getartcraft.com"; +/// FilmCraft's page on the ArtCraft website. +pub const APP_PAGE: &str = "https://getartcraft.com/apps/filmcraft"; +/// FilmCraft's source repository. +pub const GITHUB: &str = "https://github.com/storytold/filmcraft"; +/// New issue on FilmCraft's repository. +pub const ISSUES: &str = "https://github.com/storytold/filmcraft/issues"; + +/// (command id, label, url) for every link, in menu order. +pub const ALL: [(&str, &str, &str); 5] = [ + ("help.discord", "Join the ArtCraft Discord…", DISCORD), + ("help.website", "ArtCraft Website", WEBSITE), + ("help.appPage", "FilmCraft on getartcraft.com", APP_PAGE), + ("help.github", "FilmCraft on GitHub", GITHUB), + ("help.reportIssue", "Report an Issue…", ISSUES), +]; + +/// The URL a `help.*` link command opens. +pub fn url_for(command: &str) -> Option<&'static str> { + ALL.iter().find(|(id, _, _)| *id == command).map(|(_, _, u)| *u) +} + +/// Open `url` in the system browser (a new tab on the web). +pub fn open(ctx: &egui::Context, url: &str) { + ctx.open_url(egui::OpenUrl::new_tab(url)); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn urls_follow_the_artcraft_scheme() { + assert_eq!(APP_PAGE, format!("{WEBSITE}/apps/{APP}")); + assert_eq!(GITHUB, format!("https://github.com/storytold/{APP}")); + assert!(ALL.iter().all(|(id, _, u)| id.starts_with("help.") && u.starts_with("https://"))); + assert_eq!(url_for("help.discord"), Some(DISCORD)); + assert_eq!(url_for("help.nope"), None); + } +} diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 490d8c6fb..43c4c2b48 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -68,6 +68,11 @@ pub const UI_COMMANDS: &[UiCommand] = &[ uic!("mode.import", "Import", [], None), uic!("mode.edit", "Edit", [], None), uic!("mode.export", "Export", ["File", "Export"], Some("Cmd+M")), + uic!("help.discord", "Join the ArtCraft Discord…", ["Help"], None), + uic!("help.website", "ArtCraft Website", ["Help"], None), + uic!("help.appPage", "FilmCraft on getartcraft.com", ["Help"], None), + uic!("help.github", "FilmCraft on GitHub", ["Help"], None), + uic!("help.reportIssue", "Report an Issue…", ["Help"], None), uic!("app.about", "About FilmCraft", ["Help"], None), uic!("app.keyboardShortcuts", "Keyboard Shortcuts…", ["Edit"], Some("Cmd+Alt+K")), uic!("app.preferences.autoSave", "Auto Save…", ["Edit", "Preferences"], Some("Cmd+,")), @@ -178,6 +183,12 @@ pub fn invoke(app: &mut FilmcraftApp, ctx: &egui::Context, id: &str, params: Val app.dialog = Some(crate::Dialog::About); return Ok(Value::Null); } + id if crate::links::url_for(id).is_some() => { + let url = crate::links::url_for(id).unwrap_or_default(); + crate::links::open(ctx, url); + app.ui.status = format!("Opened {url}"); + return Ok(json!({"url": url})); + } "help.shortcuts" | "app.keyboardShortcuts" => { crate::panels::shortcuts_dialog::open(app); return Ok(Value::Null); diff --git a/crates/ui-egui/src/panels/dialogs.rs b/crates/ui-egui/src/panels/dialogs.rs index dc18d4ace..f05f64b05 100644 --- a/crates/ui-egui/src/panels/dialogs.rs +++ b/crates/ui-egui/src/panels/dialogs.rs @@ -18,12 +18,15 @@ pub fn show(app: &mut FilmcraftApp, ctx: &egui::Context) { let mut open = true; match d { Dialog::About => { - egui::Window::new("About FilmCraft").open(&mut open).collapsible(false).resizable(false).show(ctx, |ui| { - ui.heading("FilmCraft"); - ui.label(format!("Version {}", env!("CARGO_PKG_VERSION"))); - ui.label("A clean-room, pure-Rust non-linear video editor."); - ui.label("Fonts: Inter and JetBrains Mono (SIL OFL 1.1)."); - }); + egui::Window::new("About FilmCraft") + .open(&mut open) + .collapsible(false) + .resizable(false) + .anchor(egui::Align2::CENTER_CENTER, egui::vec2(0.0, 0.0)) + .show(ctx, |ui| about(app, ui)); + if ctx.input(|i| i.key_pressed(egui::Key::Escape)) { + open = false; + } } Dialog::Shortcuts => { if !crate::panels::shortcuts_dialog::show(app, ctx) && app.dialog == Some(d) { @@ -124,3 +127,54 @@ fn audio_gain(app: &mut FilmcraftApp, ctx: &egui::Context) -> bool { app.ui.audio_gain = draft; keep } + +/// Help ▸ About FilmCraft: version, credits and the ArtCraft community links. Joining the Discord +/// is the first, accented button. +/// +/// Automation ids: `about.discord`, `about.website`, `about.appPage`, `about.github`, +/// `about.reportIssue`. +fn about(app: &mut FilmcraftApp, ui: &mut egui::Ui) { + use crate::icons::{self, Icon}; + use crate::links; + let t = app.tokens; + ui.set_width(380.0); + ui.heading("FilmCraft"); + ui.label(format!("Version {}", env!("CARGO_PKG_VERSION"))); + ui.label("A clean-room, pure-Rust non-linear video editor. Part of the ArtCraft family."); + ui.add_space(10.0); + let mut link = |ui: &mut egui::Ui, id: &str, icon: Icon, label: &str, url: &str, primary: bool| { + let size = egui::vec2(ui.available_width(), if primary { 36.0 } else { 28.0 }); + let (r, resp) = ui.allocate_exact_size(size, egui::Sense::click()); + let resp = resp.on_hover_text(url); + app.auto.add(&format!("about.{id}"), r, label); + let bg = if primary { + if resp.hovered() { t.accent_hover } else { t.accent } + } else if resp.hovered() { + t.hover + } else { + egui::Color32::TRANSPARENT + }; + ui.painter().rect_filled(r, 6.0, bg); + let fg = if primary { egui::Color32::WHITE } else { t.text }; + let ir = egui::Rect::from_center_size(egui::pos2(r.min.x + 20.0, r.center().y), egui::vec2(18.0, 18.0)); + icons::paint(ui.painter(), ir, icon, fg); + ui.painter().text( + egui::pos2(r.min.x + 40.0, r.center().y), + egui::Align2::LEFT_CENTER, + label, + crate::theme::Tokens::ui(if primary { 14.0 } else { 13.0 }), + fg, + ); + if resp.clicked() { + links::open(ui.ctx(), url); + } + }; + link(ui, "discord", Icon::Chat, "Join the ArtCraft Discord", links::DISCORD, true); + ui.add_space(6.0); + link(ui, "website", Icon::Globe, "getartcraft.com", links::WEBSITE, false); + link(ui, "appPage", Icon::Globe, "FilmCraft on getartcraft.com", links::APP_PAGE, false); + link(ui, "github", Icon::Code, "Source code on GitHub", links::GITHUB, false); + link(ui, "reportIssue", Icon::Code, "Report an issue", links::ISSUES, false); + ui.add_space(10.0); + ui.label(egui::RichText::new("MIT OR Apache-2.0. Fonts: Inter, Noto Serif and JetBrains Mono (SIL OFL 1.1).").small().color(t.text_dim)); +} diff --git a/crates/ui-egui/src/panels/import_mode.rs b/crates/ui-egui/src/panels/import_mode.rs index fa2bf0c64..a004dc03e 100644 --- a/crates/ui-egui/src/panels/import_mode.rs +++ b/crates/ui-egui/src/panels/import_mode.rs @@ -43,5 +43,29 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) { app.ui.mode = crate::state::Mode::Edit; } } - let _ = pos2(0.0, 0.0); + // Community and project links. + let y = 90.0 + 150.0 + 36.0; + ui.painter().text(rect.min + vec2(24.0, y), Align2::LEFT_CENTER, "Community", Tokens::semibold(15.0), t.text); + let mut x = rect.min.x + 24.0; + for (i, (id, label, url)) in crate::links::ALL.iter().take(4).enumerate() { + let primary = i == 0; + let label = if primary { "Join us on Discord" } else { *label }; + let g = ui.painter().layout_no_wrap(label.to_string(), Tokens::ui(13.0), t.text); + let r = Rect::from_min_size(pos2(x, rect.min.y + y + 18.0), vec2(g.size().x + 44.0, 34.0)); + let resp = ui.interact(r, egui::Id::new(("imp-link", *id)), Sense::click()).on_hover_text(*url); + app.auto.add(&format!("import.link.{}", id.trim_start_matches("help.")), r, label); + let (bg, fg) = if primary { + (if resp.hovered() { t.accent_hover } else { t.accent }, Color32::WHITE) + } else { + (if resp.hovered() { t.hover } else { t.tl_header_bg }, t.text) + }; + ui.painter().rect_filled(r, 8.0, bg); + let icon = [crate::icons::Icon::Chat, crate::icons::Icon::Globe, crate::icons::Icon::Globe, crate::icons::Icon::Code][i]; + crate::icons::paint(ui.painter(), Rect::from_center_size(pos2(r.min.x + 20.0, r.center().y), vec2(16.0, 16.0)), icon, fg); + ui.painter().galley(pos2(r.min.x + 34.0, r.center().y - g.size().y / 2.0), g, fg); + if resp.clicked() { + crate::links::open(&ctx, url); + } + x = r.max.x + 12.0; + } } diff --git a/crates/ui-egui/tests/links_ui.rs b/crates/ui-egui/tests/links_ui.rs new file mode 100644 index 000000000..6d05a303e --- /dev/null +++ b/crates/ui-egui/tests/links_ui.rs @@ -0,0 +1,115 @@ +//! Headless UI test of the community links: Help menu commands, the header Discord button, the +//! About dialog and the Home (Import) screen. +//! +//! Set `FILMCRAFT_UI_SNAPSHOT_DIR=` to also render the window offscreen with wgpu and write +//! `links-*.png` there; without it no GPU is needed. + +use std::sync::mpsc::{Sender, channel}; + +use egui_kittest::Harness; +use filmcraft_engine::Session; +use filmcraft_ui_egui::FilmcraftApp; +use filmcraft_ui_egui::control::ControlRequest; +use filmcraft_ui_egui::links; +use serde_json::{Value, json}; + +struct Driver { + harness: Harness<'static, FilmcraftApp>, + tx: Sender, + snapshots: Option, +} + +impl Driver { + fn demo() -> Self { + let mut session = Session::default(); + session.execute("file.openDemoProject", json!({})).expect("demo project"); + let (tx, rx) = channel(); + let app = FilmcraftApp::new(session).with_control(rx); + let snapshots = std::env::var_os("FILMCRAFT_UI_SNAPSHOT_DIR").map(std::path::PathBuf::from); + let mut b = Harness::builder().with_size(egui::vec2(1600.0, 980.0)).with_max_steps(10_000); + if snapshots.is_some() { + b = b.wgpu(); + } + let harness = b.build_eframe(move |_cc| app); + let mut d = Driver { harness, tx, snapshots }; + d.frames(4); + d + } + + fn frames(&mut self, n: usize) { + for _ in 0..n { + let ctx = self.harness.ctx.clone(); + let mut raw = std::mem::take(self.harness.input_mut()); + eframe::App::raw_input_hook(self.harness.state_mut(), &ctx, &mut raw); + *self.harness.input_mut() = raw; + self.harness.step(); + } + } + + fn ok(&mut self, method: &str, params: Value) -> Value { + let (req, reply) = ControlRequest::new(method, params.clone()); + self.tx.send(req).unwrap(); + for _ in 0..600 { + self.frames(1); + if let Ok(v) = reply.try_recv() { + assert_eq!(v["ok"], json!(true), "{method} {params} failed: {v}"); + return v["result"].clone(); + } + } + panic!("no reply to {method} {params}"); + } + + fn ids(&mut self, prefix: &str) -> Vec { + let v = self.ok("ui.elements", json!({"prefix": prefix})); + v.as_array().unwrap().iter().filter_map(|e| e["id"].as_str().map(str::to_string)).collect() + } + + fn snapshot(&mut self, name: &str) { + let Some(dir) = self.snapshots.clone() else { return }; + self.frames(2); + match self.harness.render() { + Ok(img) => { + std::fs::create_dir_all(&dir).unwrap(); + img.save(dir.join(format!("links-{name}.png"))).unwrap(); + } + Err(e) => eprintln!("snapshot {name} skipped: {e}"), + } + } +} + +#[test] +fn community_links_everywhere() { + let mut d = Driver::demo(); + // Help menu: every link is a command that reports the URL it opened. + for (id, _, url) in links::ALL { + let r = d.ok("engine.execute", json!({"command": id, "params": {}})); + assert_eq!(r["url"], json!(url), "{id}"); + } + let menu = d.ok("ui.menu.list", json!({})); + let text = menu.to_string(); + for (id, label, _) in links::ALL { + assert!(text.contains(id) && text.contains(label), "Help menu lists {id}"); + } + // Header: the Discord button is always there. + assert_eq!(d.ids("header.discord"), vec!["header.discord".to_string()]); + d.snapshot("header"); + // About dialog: Discord first, then website, app page, GitHub, issues. + d.ok("engine.execute", json!({"command": "app.about", "params": {}})); + d.frames(3); + let about = d.ids("about."); + for id in ["about.discord", "about.website", "about.appPage", "about.github", "about.reportIssue"] { + assert!(about.iter().any(|a| a == id), "{id} in {about:?}"); + } + d.snapshot("about"); + d.ok("ui.key", json!({"key": "Escape"})); + d.frames(3); + assert!(d.ids("about.").is_empty(), "Escape closes About"); + // Home screen (Import mode): community links. + d.ok("engine.execute", json!({"command": "mode.import", "params": {}})); + d.frames(3); + let home = d.ids("import.link."); + for id in ["import.link.discord", "import.link.website", "import.link.appPage", "import.link.github"] { + assert!(home.iter().any(|a| a == id), "{id} in {home:?}"); + } + d.snapshot("home"); +} From 3e834442eac6493a27b4d687a6e7244c02943cea Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 1 Oct 2026 14:52:40 -0400 Subject: [PATCH 2/2] =?UTF-8?q?ArtCraft=20brand=20marks:=20docs/brand=20lo?= =?UTF-8?q?gos=20with=20sidecars=20(ArtCraft=20trademark,=20all=20rights?= =?UTF-8?q?=20reserved,=20used=20with=20permission),=20AGENTS.md=20=C2=A71?= =?UTF-8?q?.8=20first-party=20exception,=20wordmark=20in=20the=20About=20d?= =?UTF-8?q?ialog=20and=20on=20the=20Home=20screen;=20README=20licence=20no?= =?UTF-8?q?tes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 5 +++ ATTRIBUTION.md | 16 +++++++++ README.md | 4 +-- crates/ui-egui/Cargo.toml | 3 +- crates/ui-egui/src/brand.rs | 33 ++++++++++++++++++ crates/ui-egui/src/lib.rs | 1 + crates/ui-egui/src/panels/dialogs.rs | 4 +++ crates/ui-egui/src/panels/import_mode.rs | 5 ++- docs/brand/artcraft-logo-white.png | Bin 0 -> 32161 bytes .../brand/artcraft-logo-white.png.attribution | 8 +++++ docs/brand/artcraft-logo-white.svg | 7 ++++ .../brand/artcraft-logo-white.svg.attribution | 8 +++++ docs/brand/artcraft-logo.png | Bin 0 -> 31302 bytes docs/brand/artcraft-logo.png.attribution | 8 +++++ docs/brand/artcraft-logo.svg | 7 ++++ docs/brand/artcraft-logo.svg.attribution | 8 +++++ docs/brand/artcraft-mark-black.png | Bin 0 -> 26793 bytes .../brand/artcraft-mark-black.png.attribution | 8 +++++ docs/brand/artcraft-mark-black.svg | 4 +++ .../brand/artcraft-mark-black.svg.attribution | 8 +++++ docs/brand/artcraft-mark.png | Bin 0 -> 24715 bytes docs/brand/artcraft-mark.png.attribution | 8 +++++ docs/brand/artcraft-mark.svg | 4 +++ docs/brand/artcraft-mark.svg.attribution | 8 +++++ 24 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 crates/ui-egui/src/brand.rs create mode 100644 docs/brand/artcraft-logo-white.png create mode 100644 docs/brand/artcraft-logo-white.png.attribution create mode 100644 docs/brand/artcraft-logo-white.svg create mode 100644 docs/brand/artcraft-logo-white.svg.attribution create mode 100644 docs/brand/artcraft-logo.png create mode 100644 docs/brand/artcraft-logo.png.attribution create mode 100644 docs/brand/artcraft-logo.svg create mode 100644 docs/brand/artcraft-logo.svg.attribution create mode 100644 docs/brand/artcraft-mark-black.png create mode 100644 docs/brand/artcraft-mark-black.png.attribution create mode 100644 docs/brand/artcraft-mark-black.svg create mode 100644 docs/brand/artcraft-mark-black.svg.attribution create mode 100644 docs/brand/artcraft-mark.png create mode 100644 docs/brand/artcraft-mark.png.attribution create mode 100644 docs/brand/artcraft-mark.svg create mode 100644 docs/brand/artcraft-mark.svg.attribution diff --git a/AGENTS.md b/AGENTS.md index b7a843652..b7c56fc30 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -43,6 +43,11 @@ reproduce an image (for example, point lists traced from someone else's icon). `crates/media`, procedural looks in `crates/render`) are original work under the project licence and are listed in `ATTRIBUTION.md`. 7. **When in doubt, leave it out** and draw or generate it yourself. +8. **The one exception: first-party ArtCraft brand marks.** The ArtCraft name and logos in `docs/brand/` + (supplied by the ArtCraft team) are trademarks, all rights reserved, used with permission. They still + need a sidecar and an `ATTRIBUTION.md` row (licence `LicenseRef-ArtCraft-Trademark`). No other + non-open asset is allowed, and this exception never covers third-party marks (Adobe, Discord, GitHub + and other logos stay out; draw a generic icon instead). ## 2. Clean-room code diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index c87d06aea..ba2c24343 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -77,3 +77,19 @@ is traced or derived from Adobe artwork. | Demo footage (ocean sunset, aurora, city night, dunes, forest, plasma), bars and tone, counting leader, colour matte | `crates/media/src/generators.rs` | | Lumetri "Look" presets (Teal & Orange, Warm Film, …) | `crates/render/src/effects.rs` (`apply_look`): procedural colour transforms, not LUT files | | Colour palette and layout metrics | `crates/ui-egui/src/theme.rs`: colour values and sizes only; no artwork | + +## First-party brand marks + +The ArtCraft name and logo are trademarks of the ArtCraft team, used in FilmCraft with permission. They are not +openly licensed and are not covered by the project licence; forks must remove or replace them (AGENTS.md §1.8). + +| File | Author | Source | Licence | +|---|---|---|---| +| `docs/brand/artcraft-logo-white.png` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft wordmark, light ink for dark backgrounds) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | +| `docs/brand/artcraft-logo-white.svg` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft wordmark, light ink for dark backgrounds) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | +| `docs/brand/artcraft-logo.png` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft wordmark (symbol + "ARTCRAFT"), dark ink for light backgrounds) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | +| `docs/brand/artcraft-logo.svg` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft wordmark (symbol + "ARTCRAFT"), dark ink for light backgrounds) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | +| `docs/brand/artcraft-mark-black.png` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft symbol ("A" mark), black) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | +| `docs/brand/artcraft-mark-black.svg` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft symbol ("A" mark), black) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | +| `docs/brand/artcraft-mark.png` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft symbol ("A" mark), blue) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | +| `docs/brand/artcraft-mark.svg` | ArtCraft team | Original work: first-party ArtCraft brand mark (ArtCraft symbol ("A" mark), blue) | ArtCraft trademark, all rights reserved; used with permission (not MIT/Apache) | diff --git a/README.md b/README.md index fd1603d03..60f0871cb 100644 --- a/README.md +++ b/README.md @@ -332,11 +332,11 @@ And [**ArtCraft**](https://getartcraft.com/) itself, our AI image and video stud **Footage and music in the screenshots:** NASA's Apollo 11 film and television footage from [images.nasa.gov](https://images.nasa.gov) (launch, Launch Control Center, lunar surface and recovery) and the Apollo 11 air-to-ground voice transcript, all US Government works in the public domain (NASA does not endorse this project); *Night of the Living Dead* (1968), *Carnival of Souls* (1962) and *Charade* (1963), all in the US public domain; *Earth Views from the ISS* by NASA; Chopin's Nocturne Op. 48 No. 1 and Ballade No. 1, performed for Musopen and released under CC0. The media itself is not in this repository. Sources and details for every asset are in [ATTRIBUTION.md](ATTRIBUTION.md). -FilmCraft is an independent implementation. It contains no Adobe code, icons, images, presets or LUTs, and no GPL or LGPL code; every icon is drawn in code and every asset is openly licensed and attributed ([AGENTS.md](AGENTS.md)). ffmpeg is used only as an external test oracle. Adobe and Premiere Pro are trademarks of Adobe Inc.; FilmCraft is not affiliated with Adobe. +FilmCraft is an independent implementation. It contains no Adobe code, icons, images, presets or LUTs, and no GPL or LGPL code; every icon is drawn in code and every asset is openly licensed and attributed ([AGENTS.md](AGENTS.md)), apart from the ArtCraft name and logo, which are trademarks of the ArtCraft team used with permission. ffmpeg is used only as an external test oracle. Adobe and Premiere Pro are trademarks of Adobe Inc.; FilmCraft is not affiliated with Adobe. ## License -FilmCraft is dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option. Bundled assets keep their own open licences, listed in [ATTRIBUTION.md](ATTRIBUTION.md). +FilmCraft is dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at your option. Bundled assets keep their own open licences, listed in [ATTRIBUTION.md](ATTRIBUTION.md). The ArtCraft name and logos in `docs/brand/` are trademarks of the ArtCraft team and are not covered by this licence.
diff --git a/crates/ui-egui/Cargo.toml b/crates/ui-egui/Cargo.toml index bba3e4ed7..691a76851 100644 --- a/crates/ui-egui/Cargo.toml +++ b/crates/ui-egui/Cargo.toml @@ -28,6 +28,8 @@ serde = { workspace = true } serde_json = { workspace = true } log = { workspace = true } rayon = { workspace = true } +# ArtCraft wordmark (PNG) for the About dialog and Home screen. +image = { version = "0.25", default-features = false, features = ["png"] } # Thread/process CPU clocks for frame-job profiling (safe wrappers; see frames.rs). [target.'cfg(unix)'.dependencies] @@ -37,4 +39,3 @@ rustix = { version = "1", default-features = false, features = ["std", "time"] } pollster = "0.4" filmcraft-codecs = { workspace = true } egui_kittest = { workspace = true, features = ["eframe", "wgpu"] } -image = { version = "0.25", default-features = false, features = ["png"] } diff --git a/crates/ui-egui/src/brand.rs b/crates/ui-egui/src/brand.rs new file mode 100644 index 000000000..4c41d080e --- /dev/null +++ b/crates/ui-egui/src/brand.rs @@ -0,0 +1,33 @@ +//! The ArtCraft wordmark (first-party trademark, used with permission; see `docs/brand/` and +//! AGENTS.md §1.8), decoded once and kept as a texture. + +const LOGO_LIGHT_INK: &[u8] = include_bytes!("../../../docs/brand/artcraft-logo-white.png"); +const LOGO_DARK_INK: &[u8] = include_bytes!("../../../docs/brand/artcraft-logo.png"); + +/// The wordmark for a dark (`dark = true`) or light UI: light ink on dark themes. Its aspect +/// ratio is width / height of the returned texture. +pub fn wordmark(ctx: &egui::Context, dark: bool) -> Option { + let id = egui::Id::new(("artcraft-wordmark", dark)); + if let Some(t) = ctx.data(|d| d.get_temp::(id)) { + return Some(t); + } + let bytes = if dark { LOGO_LIGHT_INK } else { LOGO_DARK_INK }; + let img = image::load_from_memory_with_format(bytes, image::ImageFormat::Png).ok()?; + // Large enough to stay sharp at 2x for the sizes we draw (≤ 320 pt wide). + let img = img.resize(1024, 1024, image::imageops::FilterType::Lanczos3).to_rgba8(); + let color = egui::ColorImage::from_rgba_unmultiplied([img.width() as usize, img.height() as usize], img.as_raw()); + let tex = ctx.load_texture("artcraft-wordmark", color, egui::TextureOptions::LINEAR); + ctx.data_mut(|d| d.insert_temp(id, tex.clone())); + Some(tex) +} + +/// Draw the wordmark `height` points tall with its left edge at `left_center` (vertically centred). +/// Returns the drawn rect. +pub fn paint_wordmark(ui: &egui::Ui, left_center: egui::Pos2, height: f32, dark: bool) -> Option { + let tex = wordmark(ui.ctx(), dark)?; + let [w, h] = tex.size(); + let width = height * w as f32 / h.max(1) as f32; + let r = egui::Rect::from_min_size(egui::pos2(left_center.x, left_center.y - height / 2.0), egui::vec2(width, height)); + ui.painter().image(tex.id(), r, egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)), egui::Color32::WHITE); + Some(r) +} diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 874edb80f..410c0959a 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -5,6 +5,7 @@ //! control-channel handlers. Swap it for another toolkit without touching the engine. pub mod automation; +pub mod brand; pub mod control; pub mod dock; pub mod frames; diff --git a/crates/ui-egui/src/panels/dialogs.rs b/crates/ui-egui/src/panels/dialogs.rs index f05f64b05..6bdd92a18 100644 --- a/crates/ui-egui/src/panels/dialogs.rs +++ b/crates/ui-egui/src/panels/dialogs.rs @@ -138,6 +138,10 @@ fn about(app: &mut FilmcraftApp, ui: &mut egui::Ui) { use crate::links; let t = app.tokens; ui.set_width(380.0); + // ArtCraft wordmark (first-party trademark, docs/brand/). + let (r, _) = ui.allocate_exact_size(egui::vec2(ui.available_width(), 30.0), egui::Sense::hover()); + crate::brand::paint_wordmark(ui, egui::pos2(r.min.x, r.center().y), 20.0, app.ui.dark); + ui.add_space(6.0); ui.heading("FilmCraft"); ui.label(format!("Version {}", env!("CARGO_PKG_VERSION"))); ui.label("A clean-room, pure-Rust non-linear video editor. Part of the ArtCraft family."); diff --git a/crates/ui-egui/src/panels/import_mode.rs b/crates/ui-egui/src/panels/import_mode.rs index a004dc03e..813eea973 100644 --- a/crates/ui-egui/src/panels/import_mode.rs +++ b/crates/ui-egui/src/panels/import_mode.rs @@ -45,7 +45,10 @@ pub fn show(app: &mut FilmcraftApp, ui: &mut egui::Ui, rect: Rect) { } // Community and project links. let y = 90.0 + 150.0 + 36.0; - ui.painter().text(rect.min + vec2(24.0, y), Align2::LEFT_CENTER, "Community", Tokens::semibold(15.0), t.text); + // ArtCraft wordmark (first-party trademark, docs/brand/), then the section title. + let logo = crate::brand::paint_wordmark(ui, rect.min + vec2(24.0, y), 15.0, app.ui.dark); + let tx = logo.map_or(rect.min.x + 24.0, |r| r.max.x + 12.0); + ui.painter().text(pos2(tx, rect.min.y + y), Align2::LEFT_CENTER, "Community", Tokens::semibold(15.0), t.text); let mut x = rect.min.x + 24.0; for (i, (id, label, url)) in crate::links::ALL.iter().take(4).enumerate() { let primary = i == 0; diff --git a/docs/brand/artcraft-logo-white.png b/docs/brand/artcraft-logo-white.png new file mode 100644 index 0000000000000000000000000000000000000000..8cfb31d940f6663ecaf93da2bc04c5904704b4af GIT binary patch literal 32161 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 + ArtCraft + + + + + diff --git a/docs/brand/artcraft-logo-white.svg.attribution b/docs/brand/artcraft-logo-white.svg.attribution new file mode 100644 index 000000000..2932cd460 --- /dev/null +++ b/docs/brand/artcraft-logo-white.svg.attribution @@ -0,0 +1,8 @@ +asset: artcraft-logo-white.svg +title: ArtCraft wordmark, light ink for dark backgrounds +author: ArtCraft team (Storyteller) +source: original work (first-party ArtCraft brand asset supplied by the ArtCraft team) +license: LicenseRef-ArtCraft-Trademark — ArtCraft name and logo are trademarks of the ArtCraft team, all rights reserved; used in FilmCraft with permission. Not covered by the project's MIT OR Apache-2.0 licence. +license-file: +added: 2026-10-01 by Claude (agent) for Brandon Thomas +notes: SVG. Bundled in the app (About dialog, Home screen) and shown in the README header. First-party brand mark: the one exception to the open-licence rule (AGENTS.md §1.8). Forks and redistributions must remove or replace it unless they have permission. diff --git a/docs/brand/artcraft-logo.png b/docs/brand/artcraft-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a4d1544caa4c8b8dae14e1d10d79afa197261e3b GIT binary patch literal 31302 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/brand/artcraft-logo.png.attribution b/docs/brand/artcraft-logo.png.attribution new file mode 100644 index 000000000..4402860ab --- /dev/null +++ b/docs/brand/artcraft-logo.png.attribution @@ -0,0 +1,8 @@ +asset: artcraft-logo.png +title: ArtCraft wordmark (symbol + "ARTCRAFT"), dark ink for light backgrounds +author: ArtCraft team (Storyteller) +source: original work (first-party ArtCraft brand asset supplied by the ArtCraft team) +license: LicenseRef-ArtCraft-Trademark — ArtCraft name and logo are trademarks of the ArtCraft team, all rights reserved; used in FilmCraft with permission. Not covered by the project's MIT OR Apache-2.0 licence. +license-file: +added: 2026-10-01 by Claude (agent) for Brandon Thomas +notes: 3200x333 PNG. Bundled in the app (About dialog, Home screen) and shown in the README header. First-party brand mark: the one exception to the open-licence rule (AGENTS.md §1.8). Forks and redistributions must remove or replace it unless they have permission. diff --git a/docs/brand/artcraft-logo.svg b/docs/brand/artcraft-logo.svg new file mode 100644 index 000000000..d63f3eae1 --- /dev/null +++ b/docs/brand/artcraft-logo.svg @@ -0,0 +1,7 @@ + + ArtCraft + + + + + diff --git a/docs/brand/artcraft-logo.svg.attribution b/docs/brand/artcraft-logo.svg.attribution new file mode 100644 index 000000000..048a9c925 --- /dev/null +++ b/docs/brand/artcraft-logo.svg.attribution @@ -0,0 +1,8 @@ +asset: artcraft-logo.svg +title: ArtCraft wordmark (symbol + "ARTCRAFT"), dark ink for light backgrounds +author: ArtCraft team (Storyteller) +source: original work (first-party ArtCraft brand asset supplied by the ArtCraft team) +license: LicenseRef-ArtCraft-Trademark — ArtCraft name and logo are trademarks of the ArtCraft team, all rights reserved; used in FilmCraft with permission. Not covered by the project's MIT OR Apache-2.0 licence. +license-file: +added: 2026-10-01 by Claude (agent) for Brandon Thomas +notes: SVG. Bundled in the app (About dialog, Home screen) and shown in the README header. First-party brand mark: the one exception to the open-licence rule (AGENTS.md §1.8). Forks and redistributions must remove or replace it unless they have permission. diff --git a/docs/brand/artcraft-mark-black.png b/docs/brand/artcraft-mark-black.png new file mode 100644 index 0000000000000000000000000000000000000000..27664bc119d2b485ba6fee213ee749df658ab508 GIT binary patch literal 26793 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 literal 0 HcmV?d00001 diff --git a/docs/brand/artcraft-mark-black.png.attribution b/docs/brand/artcraft-mark-black.png.attribution new file mode 100644 index 000000000..db190c1e5 --- /dev/null +++ b/docs/brand/artcraft-mark-black.png.attribution @@ -0,0 +1,8 @@ +asset: artcraft-mark-black.png +title: ArtCraft symbol ("A" mark), black +author: ArtCraft team (Storyteller) +source: original work (first-party ArtCraft brand asset supplied by the ArtCraft team) +license: LicenseRef-ArtCraft-Trademark — ArtCraft name and logo are trademarks of the ArtCraft team, all rights reserved; used in FilmCraft with permission. Not covered by the project's MIT OR Apache-2.0 licence. +license-file: +added: 2026-10-01 by Claude (agent) for Brandon Thomas +notes: 1024x1024 PNG. Kept for brand use (README, docs). First-party brand mark: the one exception to the open-licence rule (AGENTS.md §1.8). Forks and redistributions must remove or replace it unless they have permission. diff --git a/docs/brand/artcraft-mark-black.svg b/docs/brand/artcraft-mark-black.svg new file mode 100644 index 000000000..639435378 --- /dev/null +++ b/docs/brand/artcraft-mark-black.svg @@ -0,0 +1,4 @@ + + ArtCraft + + diff --git a/docs/brand/artcraft-mark-black.svg.attribution b/docs/brand/artcraft-mark-black.svg.attribution new file mode 100644 index 000000000..d7fdfc91c --- /dev/null +++ b/docs/brand/artcraft-mark-black.svg.attribution @@ -0,0 +1,8 @@ +asset: artcraft-mark-black.svg +title: ArtCraft symbol ("A" mark), black +author: ArtCraft team (Storyteller) +source: original work (first-party ArtCraft brand asset supplied by the ArtCraft team) +license: LicenseRef-ArtCraft-Trademark — ArtCraft name and logo are trademarks of the ArtCraft team, all rights reserved; used in FilmCraft with permission. Not covered by the project's MIT OR Apache-2.0 licence. +license-file: +added: 2026-10-01 by Claude (agent) for Brandon Thomas +notes: SVG. Kept for brand use (README, docs). First-party brand mark: the one exception to the open-licence rule (AGENTS.md §1.8). Forks and redistributions must remove or replace it unless they have permission. diff --git a/docs/brand/artcraft-mark.png b/docs/brand/artcraft-mark.png new file mode 100644 index 0000000000000000000000000000000000000000..dbb3dc08955f8214561c7922730e78266600aa36 GIT binary patch literal 24715 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 Cm;%NC literal 0 HcmV?d00001 diff --git a/docs/brand/artcraft-mark.png.attribution b/docs/brand/artcraft-mark.png.attribution new file mode 100644 index 000000000..0976b0f42 --- /dev/null +++ b/docs/brand/artcraft-mark.png.attribution @@ -0,0 +1,8 @@ +asset: artcraft-mark.png +title: ArtCraft symbol ("A" mark), blue +author: ArtCraft team (Storyteller) +source: original work (first-party ArtCraft brand asset supplied by the ArtCraft team) +license: LicenseRef-ArtCraft-Trademark — ArtCraft name and logo are trademarks of the ArtCraft team, all rights reserved; used in FilmCraft with permission. Not covered by the project's MIT OR Apache-2.0 licence. +license-file: +added: 2026-10-01 by Claude (agent) for Brandon Thomas +notes: 1024x1024 PNG. Bundled in the app (About dialog, Home screen) and shown in the README header. First-party brand mark: the one exception to the open-licence rule (AGENTS.md §1.8). Forks and redistributions must remove or replace it unless they have permission. diff --git a/docs/brand/artcraft-mark.svg b/docs/brand/artcraft-mark.svg new file mode 100644 index 000000000..72e191f8a --- /dev/null +++ b/docs/brand/artcraft-mark.svg @@ -0,0 +1,4 @@ + + ArtCraft + + diff --git a/docs/brand/artcraft-mark.svg.attribution b/docs/brand/artcraft-mark.svg.attribution new file mode 100644 index 000000000..4e98a893a --- /dev/null +++ b/docs/brand/artcraft-mark.svg.attribution @@ -0,0 +1,8 @@ +asset: artcraft-mark.svg +title: ArtCraft symbol ("A" mark), blue +author: ArtCraft team (Storyteller) +source: original work (first-party ArtCraft brand asset supplied by the ArtCraft team) +license: LicenseRef-ArtCraft-Trademark — ArtCraft name and logo are trademarks of the ArtCraft team, all rights reserved; used in FilmCraft with permission. Not covered by the project's MIT OR Apache-2.0 licence. +license-file: +added: 2026-10-01 by Claude (agent) for Brandon Thomas +notes: SVG. Bundled in the app (About dialog, Home screen) and shown in the README header. First-party brand mark: the one exception to the open-licence rule (AGENTS.md §1.8). Forks and redistributions must remove or replace it unless they have permission.