From 26d8bfdd3a6affb01f1761c797a09d7533168750 Mon Sep 17 00:00:00 2001 From: Nikita Rakitin Date: Wed, 14 Oct 2026 06:21:07 +0300 Subject: [PATCH] UI: Design Effects applies a theme effect scheme design.effects replaces the theme's format scheme (fills, lines and effects) with DeckCraft, Soft, Crisp, Lift, Glow or Plain. Colours and fonts stay. The scheme already in use is not an undo step. Co-authored-by: Cursor --- ROADMAP.md | 4 +- crates/engine/src/cmd/design.rs | 74 ++++++++++++++++++++++++++++- crates/model/src/theme.rs | 56 +++++++++++++++++++++- crates/ui-egui/src/effects_tests.rs | 45 ++++++++++++++++++ crates/ui-egui/src/ribbon.rs | 14 ++++++ docs/architecture.md | 5 +- docs/gaps.md | 3 +- docs/target-app-parity.md | 10 ++-- docs/ui-parity.md | 6 ++- 9 files changed, 204 insertions(+), 13 deletions(-) create mode 100644 crates/ui-egui/src/effects_tests.rs diff --git a/ROADMAP.md b/ROADMAP.md index 46a87add..2bfc79e1 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~20 points and ~120–210 h away -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (hours to ~95% per audience added; ready 56% → 55%; stage stays alpha; previous: major, full re-measure against PowerPoint for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) +> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** trivial (progress log: Design ▸ Effects; percentages unchanged) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) DeckCraft aims at full PowerPoint parity, and to be better: faster, open (a documented zip+JSON format plus PPTX), scriptable by agents (CLI, JSON control channel, MCP), and available everywhere @@ -128,6 +128,7 @@ app's JSON control channel (`deckcraft --control PORT`). | Date | What landed | |---|---| +| 2026-10-14 | Design ▸ Effects: named effect schemes (DeckCraft, Soft, Crisp, Lift, Glow, Plain) replace the theme's fills, lines and effects and leave colours and fonts. `design.effects` | | 2026-10-13 | Slide transitions like PowerPoint: every transition and option measured frame by frame against PowerPoint's video export and retuned (curves, directions, soft edges, 3-D perspective, contents moving over backgrounds); PowerPoint's own XML elements and defaults read and written (diagonal Wipe, Zoom, Shape In/Out, Glitter Hexagons, Shred In/Out, Page Curl Single); `deckcraft-cli render-transition` renders frames headless | | 2026-10-13 | Wild text cases measured against PowerPoint (102 synthetic slides): bidi by run language, East Asian vertical text upright, mongolianVert/wordArtVert/wordArtVertRtl, underline styles and strikethrough at the font's metrics, centre/right/decimal tabs, East Asian, Thai, Hindi, Arabic and Hebrew numbering, small caps, all-caps "ß", transparent text, soft hyphens, kinsoku, rtlCol and just/dist anchoring, emoji presentation, fallback faces that no longer move the baseline | | 2026-10-13 | Render matches PowerPoint more closely on wild shape, picture and table cases: even-odd custom paths, dashes and caps, arrowheads, radial and path gradients, tile rects, rotWithShape, gradient lines, shadows cast by what is drawn (group and perspective too), group fill, picture borders, tiles, reflection, recolour (biLevel, alphaInv, brightness/contrast), table borders and grid default, 20+ preset shapes by their ECMA formulas, default miter joins, and approximate 3-D bevels, cameras and face lighting | @@ -150,6 +151,7 @@ app's JSON control channel (`deckcraft --control PORT`). | Date | Change | Summary | |---|---|---| +| 2026-10-14 | trivial | Progress log: Design ▸ Effects | | 2026-10-13 | trivial | Progress log: wild text cases | | 2026-10-12 | trivial | Progress log: File tab (Backstage, #76) | | 2026-10-12 | trivial | Progress log: lines in scaled groups (#233) | diff --git a/crates/engine/src/cmd/design.rs b/crates/engine/src/cmd/design.rs index 3cad3f00..9d6ac1a2 100644 --- a/crates/engine/src/cmd/design.rs +++ b/crates/engine/src/cmd/design.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use deckcraft_geom::Size; use deckcraft_model::text::{Run, RunKind, TextBody}; -use deckcraft_model::theme::{builtin_color_schemes, builtin_font_schemes, builtin_themes}; +use deckcraft_model::theme::{builtin_color_schemes, builtin_font_schemes, builtin_format_schemes, builtin_themes}; use deckcraft_model::{Background, Fill, PhType, Presentation, Shape, ShapeId, defaults}; use serde_json::{Value, json}; @@ -15,9 +15,10 @@ use crate::{Result, Session, Target}; pub fn specs() -> Vec { vec![ cmd!("design.theme", "Themes", ["Design", "Themes"], None, "{name} (see design.themes)", has_doc, theme), - cmd!(query "design.themes", "Theme Gallery", [], None, "{} → themes, colour schemes and font schemes", always, themes), + cmd!(query "design.themes", "Theme Gallery", [], None, "{} → themes, colour schemes, font schemes and effect schemes", always, themes), cmd!("design.colors", "Colors", ["Design", "Variants"], None, "{name} | {colors: {accent1: #RRGGBB, …}}", has_doc, colors), cmd!("design.fonts", "Fonts", ["Design", "Variants"], None, "{name} | {major, minor}", has_doc, fonts), + cmd!("design.effects", "Effects", ["Design", "Variants"], None, "{name} (see design.themes)", has_doc, effects), cmd!( "design.background", "Format Background", @@ -91,6 +92,7 @@ fn themes(_s: &mut Session, _p: &Value) -> Result { "themes": builtin_themes().iter().map(|t| json!({"name": t.name, "major": t.fonts.major.latin, "minor": t.fonts.minor.latin, "colors": t.colors.colors.iter().map(|c| format!("#{}", c.hex())).collect::>()})).collect::>(), "colorSchemes": builtin_color_schemes().iter().map(|c| c.name.clone()).collect::>(), "fontSchemes": builtin_font_schemes().iter().map(|f| json!({"name": f.name, "major": f.major.latin, "minor": f.minor.latin})).collect::>(), + "effectSchemes": builtin_format_schemes().iter().map(|f| f.name.clone()).collect::>(), })) } @@ -148,6 +150,29 @@ fn fonts(s: &mut Session, p: &Value) -> Result { ok() } +fn effects(s: &mut Session, p: &Value) -> Result { + let name = str_param(p, "name").ok_or_else(|| bad("design.effects", "missing `name`"))?; + let scheme = builtin_format_schemes() + .into_iter() + .find(|f| f.name.eq_ignore_ascii_case(name)) + .ok_or_else(|| bad("design.effects", format!("no effect scheme `{name}`")))?; + let stored = scheme.name.clone(); + let same = { + let st = s.doc()?; + let mi = master_index(&st.doc, &st.selection); + st.doc.masters.get(mi).is_some_and(|m| m.theme.format == scheme) + }; + if same { + return Ok(json!({"name": stored})); + } + s.edit(|doc, sel| { + let mi = master_index(doc, sel); + Arc::make_mut(doc.masters.get_mut(mi).ok_or_else(|| bad("design.effects", "no master"))?).theme.format = scheme; + Ok(()) + })?; + Ok(json!({"name": stored})) +} + fn background(s: &mut Session, p: &Value) -> Result { let bg: Option = if bool_or(p, "reset", false) { None @@ -558,9 +583,54 @@ fn insert_placeholder(s: &mut Session, p: &Value) -> Result { #[cfg(test)] mod tests { + use serde_json::json; + #[test] fn civil_dates() { assert_eq!(super::civil(0), (1970, 1, 1)); assert_eq!(super::civil(20_734), (2026, 10, 8)); } + + fn undo_len(s: &crate::Session) -> usize { + s.doc().unwrap().history.undo.len() + } + + #[test] + fn effect_scheme_replaces_format_and_keeps_colours_and_fonts() { + let mut s = crate::Session::with_new(); + let listed = s.execute("design.themes", &json!({})).unwrap(); + let names: Vec = listed["effectSchemes"].as_array().unwrap().iter().filter_map(|v| v.as_str().map(str::to_string)).collect(); + assert_eq!(names, ["DeckCraft", "Soft", "Crisp", "Lift", "Glow", "Plain"]); + + let n = undo_len(&s); + s.execute("design.effects", &json!({"name": "DeckCraft"})).unwrap(); + assert_eq!(undo_len(&s), n, "the scheme already on the theme is not an undo step"); + let err = s.execute("design.effects", &json!({"name": "Office"})).unwrap_err().to_string(); + assert!(err.contains("no effect scheme"), "{err}"); + assert!(s.execute("design.effects", &json!({})).is_err()); + assert_eq!(undo_len(&s), n); + + s.execute("design.theme", &json!({"name": "Harbor"})).unwrap(); + let before = s.doc().unwrap().doc.masters[0].theme.clone(); + s.execute("design.effects", &json!({"name": "soft"})).unwrap(); + let theme = s.doc().unwrap().doc.masters[0].theme.clone(); + assert_eq!(theme.name, "Harbor"); + assert_eq!(theme.colors, before.colors); + assert_eq!(theme.fonts, before.fonts); + assert_eq!(theme.format.name, "Soft"); + assert!(theme.format.effects[0].outer_shadow.is_some()); + assert_eq!(s.doc().unwrap().history.undo.last().unwrap().label, "Effects"); + + let n = undo_len(&s); + s.execute("design.effects", &json!({"name": "Soft"})).unwrap(); + assert_eq!(undo_len(&s), n, "the same scheme is not an undo step"); + + s.execute("design.effects", &json!({"name": "Glow"})).unwrap(); + let glow = s.doc().unwrap().doc.masters[0].theme.format.effects[2].glow.clone(); + assert!(glow.is_some_and(|g| (g.radius - 12.0).abs() < 1e-6)); + s.execute("design.effects", &json!({"name": "Plain"})).unwrap(); + let plain = s.doc().unwrap().doc.masters[0].theme.format.clone(); + assert!(plain.effects.iter().all(|e| e.outer_shadow.is_none() && e.glow.is_none())); + assert_eq!(plain.lines[2].width, Some(0.75)); + } } diff --git a/crates/model/src/theme.rs b/crates/model/src/theme.rs index 582f0728..cd5dc496 100644 --- a/crates/model/src/theme.rs +++ b/crates/model/src/theme.rs @@ -3,7 +3,7 @@ use deckcraft_color::{ColorScheme, ColorTransform, Rgba, SchemeSlot}; use serde::{Deserialize, Serialize}; -use crate::style::{ColorRef, Effects, Fill, Gradient, GradientShape, GradientStop, Line, Shadow}; +use crate::style::{ColorRef, Effects, Fill, Glow, Gradient, GradientShape, GradientStop, Line, Shadow}; #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[serde(default, rename_all = "camelCase")] @@ -268,3 +268,57 @@ pub fn builtin_font_schemes() -> Vec { f("Times / Arial", "Liberation Serif", "Liberation Sans"), ] } + +fn shadow(blur: f64, dist: f64, alpha: i32) -> Effects { + Effects { + outer_shadow: Some(Shadow { + color: ColorRef::rgb(Rgba::BLACK).with(ColorTransform::Alpha(alpha)), + blur, + dist, + dir: 90.0, + inner: false, + sx: 1.0, + sy: 1.0, + kx: 0.0, + ky: 0.0, + align: "b".into(), + rotate_with_shape: false, + }), + ..Default::default() + } +} + +fn glow(radius: f64) -> Effects { + Effects { glow: Some(Glow { color: ph().with(ColorTransform::Alpha(60_000)), radius }), ..Default::default() } +} + +/// Named effect schemes for Design ▸ Effects. Each one replaces the theme's format scheme +/// (subtle, moderate and intense fills, lines and effects) and leaves the colour and font schemes. +pub fn builtin_format_schemes() -> Vec { + let mut soft = default_format(); + soft.name = "Soft".into(); + soft.lines = vec![Line::solid(ph(), 0.5), Line::solid(ph(), 0.75), Line::solid(ph(), 1.0)]; + soft.effects = vec![shadow(16.0, 1.0, 18_000), shadow(12.0, 2.0, 22_000), shadow(10.0, 3.0, 28_000)]; + + let mut crisp = default_format(); + crisp.name = "Crisp".into(); + crisp.fills = vec![Fill::solid(ph()), Fill::solid(ph()), Fill::solid(ph())]; + crisp.lines = vec![Line::solid(ph(), 1.0), Line::solid(ph(), 1.5), Line::solid(ph(), 2.25)]; + crisp.effects = vec![Effects::default(), Effects::default(), shadow(0.0, 2.0, 55_000)]; + + let mut lift = default_format(); + lift.name = "Lift".into(); + lift.effects = vec![Effects::default(), shadow(8.0, 6.0, 28_000), shadow(12.0, 10.0, 35_000)]; + + let mut glow_scheme = default_format(); + glow_scheme.name = "Glow".into(); + glow_scheme.effects = vec![Effects::default(), glow(6.0), glow(12.0)]; + + let mut plain = default_format(); + plain.name = "Plain".into(); + plain.fills = vec![Fill::solid(ph()), Fill::solid(ph()), Fill::solid(ph())]; + plain.lines = vec![Line::solid(ph(), 0.75), Line::solid(ph(), 0.75), Line::solid(ph(), 0.75)]; + plain.effects = vec![Effects::default(), Effects::default(), Effects::default()]; + + vec![default_format(), soft, crisp, lift, glow_scheme, plain] +} diff --git a/crates/ui-egui/src/effects_tests.rs b/crates/ui-egui/src/effects_tests.rs new file mode 100644 index 00000000..37d856fe --- /dev/null +++ b/crates/ui-egui/src/effects_tests.rs @@ -0,0 +1,45 @@ +//! Design ▸ Effects: the menu applies a theme effect scheme. + +use deckcraft_engine::Session; +use egui_kittest::Harness; +use egui_kittest::kittest::Queryable; + +use crate::{Services, SlideApp}; + +fn harness() -> Harness<'static, SlideApp> { + let mut app = SlideApp::new(Session::with_new(), Services::default()); + app.ui.tab = "Design".into(); + let mut h = Harness::builder().with_size(egui::vec2(1800.0, 900.0)).build_ui_state( + |ui, app: &mut SlideApp| { + app.logic(ui.ctx()); + app.ui(ui); + }, + app, + ); + h.run_steps(3); + h +} + +fn format_name(h: &Harness<'_, SlideApp>) -> String { + h.state().session.active().unwrap().doc.masters[0].theme.format.name.clone() +} + +#[test] +fn effects_menu_applies_a_scheme_once() { + let mut h = harness(); + assert_eq!(format_name(&h), "DeckCraft"); + let n = h.state().session.active().unwrap().history.undo.len(); + h.get_by_label("Effects").click(); + h.run_steps(2); + h.get_by_label("Soft").click(); + h.run_steps(2); + assert_eq!(format_name(&h), "Soft"); + assert_eq!(h.state().session.active().unwrap().history.undo.len(), n + 1); + assert_eq!(h.state().session.active().unwrap().doc.masters[0].theme.name, "DeckCraft"); + + h.get_by_label("Effects").click(); + h.run_steps(2); + h.get_by_label("Soft").click(); + h.run_steps(2); + assert_eq!(h.state().session.active().unwrap().history.undo.len(), n + 1, "the same scheme is not an undo step"); +} diff --git a/crates/ui-egui/src/ribbon.rs b/crates/ui-egui/src/ribbon.rs index 428eff0b..0fe012c6 100644 --- a/crates/ui-egui/src/ribbon.rs +++ b/crates/ui-egui/src/ribbon.rs @@ -1263,6 +1263,16 @@ fn design(app: &mut SlideApp, ui: &mut Ui) { } } }); + let r = big_button(ui, Icon::ShapeEffects, "Effects", true); + r.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, "Effects")); + egui::Popup::menu(&r).width(180.0).show(|ui| { + for fs in deckcraft_model::theme::builtin_format_schemes() { + if ui.button(&fs.name).clicked() { + run(app, "design.effects", json!({"name": fs.name})); + ui.close(); + } + } + }); let r = big_button(ui, Icon::BackgroundStyles, "Background\nStyles", true); egui::Popup::menu(&r).show(|ui| { egui::Grid::new("bgstyles").show(ui, |ui| { @@ -2420,3 +2430,7 @@ fn paint_freeform_icon(p: &egui::Painter, r: Rect, name: &str, ink: Color32) { }; p.add(egui::Shape::line(pts, egui::Stroke::new(1.3, ink))); } + +#[cfg(test)] +#[path = "effects_tests.rs"] +mod effects_tests; diff --git a/docs/architecture.md b/docs/architecture.md index 2849f870..1ba7fbe6 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # DeckCraft architecture -> **Last reviewed:** 2026-10-13 · **Last updated:** 2026-10-13 · **Change:** minor (transition frames: perspective meshes, slide parts, headless compositor; previous: created from the code on main at d556ff9) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) +> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (command registry 227; dialogs stay 27; previous: transition frames) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) How DeckCraft is built today. The binding rules (layering, everything is a command, thin UI, never break wasm, never crash) are in [AGENTS.md](../AGENTS.md) §3–§5; this document describes what @@ -20,7 +20,7 @@ nothing below L6 uses egui, eframe, winit or rfd. | L2 | `text`, `anim`, `format`, `media` | Shaping (HarfRust), UAX #9 bidi, UAX #14 line breaking, autofit, caret hit testing; per-shape animation state over time, the show state machine, transition frame layouts, Morph matching; `.deckcraft` (zip + JSON + media) and outline text; media probing, decoding, mixer and clock | | L3 | `render`, `pptx` | `vello_cpu` raster of slides, masters and layouts (fills, outlines, effects, pictures, tables, charts, Morph frames); PPTX import/export from ECMA-376 | | L4 | `pdf` | PDF export through krilla | -| L5 | `engine` | Sessions, documents, selection, undo history on shared slide snapshots, the command registry (226 commands in `cmd/*`), pointer tools, keys, AutoRecover, the panic guard (`guard.rs`) | +| L5 | `engine` | Sessions, documents, selection, undo history on shared slide snapshots, the command registry (227 commands in `cmd/*`), pointer tools, keys, AutoRecover, the panic guard (`guard.rs`) | | L6 | `ui-egui`, `mcp` | The PowerPoint-style interface (ribbon with 10 tabs + contextual tabs, canvas, thumbnails, panes, 27 dialogs, show and presenter windows, the JSON control channel); the MCP server (JSON-RPC 2.0 over stdio), headless or connected to a running app | | apps | `deckcraft` (desktop: eframe/wgpu, cpal audio, logging), `deckcraft-cli` (run, render, convert, mcp, app), `deckcraft-web` (trunk; WebGPU with WebGL2 fallback), `xtask` | Exempt from layering | @@ -78,5 +78,6 @@ macOS, Windows, Linux, FreeBSD and web artifacts. | Date | Change | Summary | |---|---|---| +| 2026-10-14 | minor | Command registry is 227 (`design.effects`). Dialogs stay 27. The test-count line stays 504 | | 2026-10-13 | minor | Transitions: perspective meshes, background/content parts, CPU compositor | | 2026-10-10 | major | Created from the code on main (d556ff9) and AGENTS.md §4 | diff --git a/docs/gaps.md b/docs/gaps.md index a2894b42..48f3b262 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Where DeckCraft falls short of PowerPoint -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (3-D bevel, camera and face lighting rendered; previous: minor, IME composition and CJK interface text landed, #101; previous: minor, core-workflow alpha gate added; stage stays alpha; before that: major, first itemized gap list; full re-measure against PowerPoint for Mac 16.113.4 and the open GitHub issues) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) +> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (Design ▸ Effects; checklist row stays P so breadth stays 79%; previous: 3-D bevel, camera and face lighting rendered) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) Every known shortfall, one entry each, ranked by how much it stops someone who presents with PowerPoint from switching. This is the work list: pick from the top. Numbers are summarized in @@ -256,6 +256,7 @@ Detail in [localization-parity.md](localization-parity.md). | Date | Change | Summary | |---|---|---| +| 2026-10-14 | minor | Design ▸ Effects applies a named effect scheme. The checklist row stays P, so breadth stays 79%. Dialogs stay 27 | | 2026-10-13 | minor | Shape, picture and table rendering checked against PowerPoint on ~150 synthetic edge-case slides; 3-D bevels, cameras and face lighting now render approximately (gap narrowed to extrusion, rigs and the 3-D pane) | | 2026-10-12 | minor | IME composition in slide text and notes, and CJK interface text with real glyphs (#101): the IME gap is now Korean on the web and table-cell underlines | | 2026-10-12 | minor | EMF/WMF text, pattern and hatch brushes drawn; legacy OLE and ActiveX previews shown; the SVG gap keeps only EMF clip regions | diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 99653dc7..d0669488 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1,6 +1,6 @@ # DeckCraft vs Microsoft PowerPoint: parity assessment -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (hours to ~95% per audience added; ready recomputed from written weights, 56% → 55%; stage stays alpha; previous: major, full re-measure against PowerPoint for Mac 16.113.4; replaces the parity sections of ROADMAP.md) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) +> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (Design ▸ Effects; percentages unchanged; previous: hours to ~95% per audience, ready ~55%) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) The authoritative answer to "how close is DeckCraft to PowerPoint, and how much work is left?". [ROADMAP.md](../ROADMAP.md) summarizes it; [gaps.md](gaps.md) itemizes every shortfall; @@ -183,7 +183,7 @@ it is the Features row of the dimension table. Automation and Platforms are scor | Files (commands) | 4 | 69% | ~50% | see file formats | Print, reuse slides, passwords, legacy and macro formats | [file-format-parity.md](file-format-parity.md) | | Slides and sections | 6 | 90% | ~85% | 3–5 | Zoom (summary/section/slide), copying slides between decks keeps formatting only partly | [parity-checklist.md](parity-checklist.md) | | Views | 4 | 90% | ~80% | 3–6 | Snap to grid and grid options, New Window | [ui-parity.md](ui-parity.md) | -| Masters and themes | 7 | 85% | ~70% | 8–14 | Notes and Handout masters, theme variants, `.thmx`, effect schemes | [parity-checklist.md](parity-checklist.md) | +| Masters and themes | 7 | 85% | ~70% | 8–14 | Notes and Handout masters, theme variants, `.thmx` | [parity-checklist.md](parity-checklist.md) | | Shapes | 7 | 86% | ~75% | 8–14 | Edit points, text warp, WordArt depth | [ui-parity.md](ui-parity.md) | | Format (fill, line, effects) | 6 | 81% | ~65% | 8–14 | Format Shape pane depth, bevel and 3-D, picture/texture fill options | [ui-parity.md](ui-parity.md) | | Arrange | 3 | 100% | ~90% | 1–2 | Align to slide vs selected as a menu choice, More Rotation Options | [ui-parity.md](ui-parity.md) | @@ -211,6 +211,7 @@ Carried from the 2026-10-07 ROADMAP status and updated with what has landed sinc inheritance (slide → layout → master → theme), sections, notes, comments, custom shows, header/footer fields, embedded media, unlimited undo on shared slide snapshots. - **Themes:** 8 original themes with colour and font schemes, custom colours and fonts, + effect schemes (Design ▸ Effects: DeckCraft, Soft, Crisp, Lift, Glow, Plain), backgrounds (solid, gradient, picture, pattern), slide size presets. - **Shapes:** ~180 preset geometries with adjustment handles, text boxes, pictures (crop, corrections, animated GIFs that play and pause), tables with styles, charts (column, bar, line, @@ -239,8 +240,8 @@ Carried from the 2026-10-07 ROADMAP status and updated with what has landed sinc - **Files:** `.deckcraft` (zip + JSON), PPTX import/export (also opens `.potx`/`.ppsx`), PDF export (slides, notes, handouts 1–9 per page, text layer, links, bookmarks), PNG/JPEG, outline text, AutoRecover. -- **Automation:** 226 commands, every one reachable from `deckcraft-cli`, the JSON control channel - and MCP. +- **Automation:** 227 commands, every one reachable from `deckcraft-cli`, the JSON control channel + and MCP. The menu-bar measurement and the d556ff9 snapshot still count 226. - **Platforms:** signed releases for macOS (universal), Windows x64/x86/arm64, Linux (AppImage/deb/rpm/tar.gz/Flatpak, x86_64 and aarch64), FreeBSD and the web (v0.4.0, 2026-10-09). @@ -276,6 +277,7 @@ scored done (16 open issues). | Date | Change | Summary | |---|---|---| +| 2026-10-14 | minor | Design ▸ Effects noted under what works today. Percentages stay 79% / ~60% / ~55%. The d556ff9 snapshot and the menu measurement stay at 226 commands; the live registry is 227 | | 2026-10-10 | minor | Added the readiness-by-audience table: each number gets its own hours to ~95% (full 340–600, mainstream 150–250, essentials 50–90). The full number stays an additive weighted sum; no change to the percentages | | 2026-10-10 | minor | Added the mainstream practitioner (~53%) and essentials user (~62%) numbers with written weights, discounts and user evidence. Features dimension recomputed from written area weights (66% judgement → 62.4% weighted mean), which moves ready for real work from ~56% to ~55%; stage unchanged | | 2026-10-10 | minor | Stage checked against the core-workflow gate (all six pass); stays alpha | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index c403f05e..5f190376 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,8 +1,8 @@ # UI parity with PowerPoint -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (File tab / Backstage, #76; previous: off-slide objects in Normal view, #270) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) +> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (Design ▸ Effects; dialogs stay 27) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) -> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (text editing keys observed in PowerPoint for Windows, #268) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) +> **Last reviewed:** 2026-10-14 · **Last updated:** 2026-10-14 · **Change:** minor (Design ▸ Effects; dialogs stay 27) · **Target:** Microsoft PowerPoint for Mac 16.113 (Microsoft 365) How DeckCraft looks and feels next to PowerPoint: the shell, the ribbon, menus, panes, dialogs, direct manipulation, keyboard and precision. Observations of PowerPoint are kept locally in @@ -64,6 +64,7 @@ menu colours taken from the theme tokens (menu `chrome`, page `card`). | Animation Pane | list + advanced timeline | list, reorder, timing; no timeline | | Comments pane (threads) | yes | yes | | Design Ideas (Designer) | yes (cloud) | no | +| Design ▸ Effects | named theme effect schemes | DeckCraft, Soft, Crisp, Lift, Glow and Plain (`design.effects`); colours and fonts stay | | Dialogs | ~60 (Font, Paragraph, Bullets and Numbering, Find, Replace, Replace Fonts, Hyperlink, Action Settings, Header and Footer, Slide Size, Set Up Show, Custom Shows, Print, Page Setup, Insert Object, Symbol, Equation, Chart data sheet, SmartArt chooser, Preferences…) | 27 (`crates/ui-egui/src/dialogs.rs`): Table, Slide Size, Header and Footer, Hyperlink, Set Up Show, Zoom, Comment, Alt Text, Outline, Rename (section, shape, layout), Paragraph, About, Preferences, Export, Symbol, Equation (placeholder), Spelling, Accessibility, Language, Custom Shows, Chart Data, Trim Media, SmartArt chooser, Quit, Notes Pages | ## Direct manipulation @@ -148,6 +149,7 @@ imitate Microsoft's. No pixel comparison against PowerPoint screenshots has been | Date | Change | Summary | |---|---|---| +| 2026-10-14 | minor | Design ▸ Effects applies a named effect scheme (fills, lines and effects). Not a new dialog; dialogs stay 27 | | 2026-10-12 | minor | File tab (Backstage) observed in PowerPoint for Windows and matched (#76); the start screen is File › Home | | 2026-10-12 | minor | Off-slide objects drawn and editable around the slide in Normal view (#270) | | 2026-10-12 | minor | Selection Pane matched to PowerPoint (#133): drag and drop, arrows, groups, eye, Lock |