From 03a2da13ba7789214432d458ba3a30106285bc90 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 22 Oct 2026 00:30:39 +0700 Subject: [PATCH 1/2] =?UTF-8?q?G2:=20Effect=20=E2=80=BA=20Artistic=20?= =?UTF-8?q?=E2=80=BA=20Colored=20Pencil=20raster=20filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed from #3028 onto main. --- crates/effects/src/lib.rs | 7 ++++ crates/effects/src/pixel/artistic.rs | 52 +++++++++++++++++++++++- crates/effects/src/pixel/mod.rs | 16 +++++++- crates/effects/src/pixel/tests.rs | 30 +++++++++++++- crates/engine/src/tests_rasterfilters.rs | 3 +- crates/ui-egui/src/i18n/bg.tsv | 2 + crates/ui-egui/src/i18n/cs.tsv | 2 + crates/ui-egui/src/i18n/da.tsv | 2 + crates/ui-egui/src/i18n/de.tsv | 2 + crates/ui-egui/src/i18n/el.tsv | 2 + crates/ui-egui/src/i18n/es.tsv | 2 + crates/ui-egui/src/i18n/fi.tsv | 2 + crates/ui-egui/src/i18n/fr.tsv | 2 + crates/ui-egui/src/i18n/hu.tsv | 2 + crates/ui-egui/src/i18n/id.tsv | 2 + crates/ui-egui/src/i18n/it.tsv | 2 + crates/ui-egui/src/i18n/ja.tsv | 2 + crates/ui-egui/src/i18n/ka.tsv | 2 + crates/ui-egui/src/i18n/ko.tsv | 2 + crates/ui-egui/src/i18n/nl.tsv | 2 + crates/ui-egui/src/i18n/pl.tsv | 2 + crates/ui-egui/src/i18n/pt-br.tsv | 2 + crates/ui-egui/src/i18n/ru.tsv | 2 + crates/ui-egui/src/i18n/sv.tsv | 2 + crates/ui-egui/src/i18n/uk.tsv | 2 + crates/ui-egui/src/i18n/vi.tsv | 2 + crates/ui-egui/src/i18n/zh-hans.tsv | 2 + crates/ui-egui/src/i18n/zh-hant.tsv | 2 + crates/ui-egui/src/tests_labels.rs | 5 ++- docs/effects-parity.md | 4 +- docs/gaps.md | 9 ++-- 31 files changed, 158 insertions(+), 14 deletions(-) diff --git a/crates/effects/src/lib.rs b/crates/effects/src/lib.rs index d5aea1d79..691527682 100644 --- a/crates/effects/src/lib.rs +++ b/crates/effects/src/lib.rs @@ -350,6 +350,13 @@ pub fn effect_catalog() -> Vec { ), r("stylize.feather", "Feather…", STYLIZE, "{radius: pt (5)}", json!({"radius": 5.0})), r("blur.gaussian", "Gaussian Blur…", BLUR, "{radius: pt (5)}", json!({"radius": 5.0})), + r( + "artistic.coloredPencil", + "Colored Pencil…", + ARTISTIC, + "{pencilWidth: 1..24 (5; stroke spacing in document units), strokePressure: 0..15 (5; how heavily the strokes darken), paperBrightness: 0..50 (25; lifts lighter areas toward the paper)} redraws the object in coloured pencil strokes along its edges, keeping its hues and coverage. Original visual approximation; chosen VectorCraft defaults.", + json!({"pencilWidth": 5.0, "strokePressure": 5.0, "paperBrightness": 25.0}), + ), r( "artistic.cutout", "Cutout…", diff --git a/crates/effects/src/pixel/artistic.rs b/crates/effects/src/pixel/artistic.rs index f14671a12..20b8662aa 100644 --- a/crates/effects/src/pixel/artistic.rs +++ b/crates/effects/src/pixel/artistic.rs @@ -1,4 +1,4 @@ -//! Effect › Artistic (Cutout, Dry Brush, Film Grain, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster +//! Effect › Artistic (Colored Pencil, Cutout, Dry Brush, Film Grain, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster //! Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting and Watercolor). Original filters built from //! public behaviour documentation: //! and @@ -71,6 +71,7 @@ impl PaintDaubBrush { pub(super) fn paint_daub_radius(size: f64) -> f64 { size.clamp(1.0, 50.0) * 0.48 } +const SALT_PENCIL: u64 = 304; /// Keep the last cell's four corner values: magnified adjacent pixels often share a cell. /// The cache changes only cost, never the field, and needs constant storage per raster. @@ -219,6 +220,55 @@ fn planes(px: &[[u8; 4]]) -> ([Vec; 3], Vec) { (std::array::from_fn(|k| colours.iter().map(|c| c[k]).collect()), px.iter().map(|p| f32::from(p[3]) / 255.0).collect()) } +/// How far (document units) Colored Pencil reaches at pencil width `width`: soften at +/// `0.12 * width` and the Sobel neighbourhood around it. +pub(super) fn colored_pencil_reach(width: f64) -> f64 { + 3.0 * 0.12 * width.clamp(1.0, 24.0) + 1.0 +} + +/// Colored Pencil: the object redrawn with coloured pencil strokes along local edges, keeping its +/// hues. `width` (1..24) sets the stroke spacing in document units; `pressure` (0..15) darkens +/// along the strokes; `paper` (0..50) lifts lighter areas toward the paper. Coverage is kept. +pub(super) fn colored_pencil(px: &mut [[u8; 4]], w: usize, h: usize, space: &PixelSpace, width: f64, pressure: f64, paper: f64) { + if !([width, pressure, paper].iter().all(|v| v.is_finite()) && space.px.is_finite() && space.px > 0.0) { + return; + } + let width = width.clamp(1.0, 24.0); + let pressure = (pressure / 15.0).clamp(0.0, 1.0) as f32; + let paper_lift = (paper / 50.0).clamp(0.0, 1.0) as f32; + if pressure == 0.0 && paper_lift == 0.0 { + return; + } + let Some(place) = Place::new(space, w, h) else { return }; + let (mut colour, alpha) = planes(px); + soften(&mut colour, &alpha, w, h, (0.12 * width) / space.px); + let tones: Vec = (0..px.len()).map(|k| luma([colour[0][k], colour[1][k], colour[2][k]])).collect(); + let mut edges = vec![0.0f32; px.len()]; + for (e, s) in edges.iter_mut().zip(sobel(&tones, w, h)) { + *e = (s / 4.0).min(1.0); + } + let spacing = (0.35 * width).max(1.0); + place.each(px, |x, y, p| { + if p[3] == 0 { + return; + } + let k = y * w + x; + let c = [colour[0][k], colour[1][k], colour[2][k]]; + let gx = tone_at(&tones, w, h, x as isize + 1, y as isize) - tone_at(&tones, w, h, x as isize - 1, y as isize); + let gy = tone_at(&tones, w, h, x as isize, y as isize + 1) - tone_at(&tones, w, h, x as isize, y as isize - 1); + let angle = gy.atan2(gx) + std::f32::consts::FRAC_PI_2; + let (dx, dy) = (angle.cos() as f64, angle.sin() as f64); + let q = place.at(x, y); + let along = q.x * dx + q.y * dy; + let grain = value_noise(SALT_PENCIL, along / spacing, (q.x * 0.37 + q.y * 0.11) / spacing); + let stroke = (0.5 + 0.5 * (along / spacing * TAU + grain * 3.0).sin()) as f32; + let ink = pressure * (0.3 + 0.55 * stroke) * (0.55 + 0.45 * edges[k]); + let lift = paper_lift * (1.0 - luma(c)) * 0.35; + let c = c.map(|v| (v * (1.0 - ink * 0.45) + lift * (1.0 - v)).clamp(0.0, 1.0)); + *p = premultiply(c, f32::from(p[3]) / 255.0); + }); +} + /// Cutout: the object as flat pieces of coloured paper. Its colours, softened as `simplicity` /// (0..10) asks and less as `fidelity` (1..3) keeps detail, fall into `levels` (2..8) steps per /// colour channel; each step's piece is painted in the average colour of what falls into it, so diff --git a/crates/effects/src/pixel/mod.rs b/crates/effects/src/pixel/mod.rs index d3734ad75..69b9c3953 100644 --- a/crates/effects/src/pixel/mod.rs +++ b/crates/effects/src/pixel/mod.rs @@ -1,4 +1,4 @@ -//! Photoshop-style raster effects (Effect › Artistic › Cutout, Dry Brush, Film Grain, Neon Glow, Paint Daubs, Plastic Wrap and +//! Photoshop-style raster effects (Effect › Artistic › Colored Pencil, Cutout, Dry Brush, Film Grain, Neon Glow, Paint Daubs, Plastic Wrap and //! Poster Edges, Rough Pastels, Smudge Stick, Sponge and Watercolor, Blur › Radial Blur and Smart Blur, Brush Strokes › Accented Edges, Angled Strokes, //! Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes and Sumi-e, Distort › Diffuse //! Glow, Glass and Ocean Ripple, Pixelate › Color Halftone, Crystallize, Mezzotint and Pointillize, @@ -44,7 +44,8 @@ pub use sketch::{HALFTONE_TYPES, HalftonePattern}; pub use texture::{GRAIN_TYPES, Grain, LIGHT_DIRECTIONS, Light, TEXTURES, TEXTURES_LOADED, Texture}; /// The Photoshop-style effect ids (all raster effects, see [`crate::is_raster`]). -pub const PIXEL_EFFECTS: [&str; 52] = [ +pub const PIXEL_EFFECTS: [&str; 53] = [ + "artistic.coloredPencil", "artistic.cutout", "artistic.dryBrush", "artistic.filmGrain", @@ -103,6 +104,9 @@ pub const PIXEL_EFFECTS: [&str; 52] = [ /// are in document units. #[derive(Clone, Debug, PartialEq)] pub enum PixelFx { + /// Artistic › Colored Pencil: coloured strokes `width` (1..24) apart, as heavy as `pressure` + /// (0..15), on paper lifted by `paper` (0..50). + ColoredPencil { width: f64, pressure: f64, paper: f64 }, /// Artistic › Cutout: flat pieces of colour in `levels` (2..8) steps per channel, their /// edges as simple as `simplicity` (0..10) and as faithful as `fidelity` (1..3) say. Cutout { levels: f64, simplicity: f64, fidelity: f64 }, @@ -312,6 +316,11 @@ pub(crate) fn parse(id: &str, p: &Value) -> Option { levels.iter().find(|(name, _)| name.eq_ignore_ascii_case(q)).map_or(default, |(_, v)| *v) }; Some(match id { + "artistic.coloredPencil" => PixelFx::ColoredPencil { + width: num(p, "pencilWidth", 5.0).clamp(1.0, 24.0), + pressure: num(p, "strokePressure", 5.0).clamp(0.0, 15.0), + paper: num(p, "paperBrightness", 25.0).clamp(0.0, 50.0), + }, "artistic.cutout" => PixelFx::Cutout { levels: num(p, "levels", 4.0).round().clamp(2.0, 8.0), simplicity: num(p, "edgeSimplicity", 4.0).clamp(0.0, 10.0), @@ -600,6 +609,7 @@ impl PixelFx { // These three keep the object's coverage. PixelFx::SmudgeStick { .. } | PixelFx::Sponge { .. } | PixelFx::Watercolor { .. } => 0.0, PixelFx::FilmGrain { .. } + | PixelFx::ColoredPencil { .. } | PixelFx::Cutout { .. } | PixelFx::DryBrush { .. } | PixelFx::NeonGlow { .. } @@ -658,6 +668,7 @@ impl PixelFx { // The cells around the pixel's, and the cells around theirs. PixelFx::ColorHalftone { max_radius, .. } => Some(3.0 * std::f64::consts::SQRT_2 * max_radius), PixelFx::Crystallize { cell } => Some(1.5 * cell), + PixelFx::ColoredPencil { width, .. } => Some(artistic::colored_pencil_reach(width)), PixelFx::ChalkCharcoal { .. } => Some(sketch::CHALK_CHARCOAL_REACH), PixelFx::Chrome { smoothness, .. } => Some(sketch::chrome_reach(smoothness)), PixelFx::FilmGrain { .. } @@ -699,6 +710,7 @@ impl PixelFx { let Some(px) = pixels(data, w, h) else { return }; let to_px = |len: f64| len / space.px.max(1e-9); match *self { + PixelFx::ColoredPencil { width, pressure, paper } => artistic::colored_pencil(px, w, h, space, width, pressure, paper), PixelFx::Cutout { levels, simplicity, fidelity } => artistic::cutout(px, w, h, space, levels, simplicity, fidelity), PixelFx::DryBrush { size, detail, texture } => artistic::dry_brush(px, w, h, space, size, detail, texture), PixelFx::FilmGrain { grain, highlight, intensity } => artistic::film_grain(px, w, h, space, grain, highlight, intensity), diff --git a/crates/effects/src/pixel/tests.rs b/crates/effects/src/pixel/tests.rs index edce4b431..b682d7e62 100644 --- a/crates/effects/src/pixel/tests.rs +++ b/crates/effects/src/pixel/tests.rs @@ -2421,6 +2421,12 @@ fn ramp(w: usize, h: usize) -> Vec { #[test] fn artistic_params_take_defaults_and_stay_in_range() { + assert_eq!(fx("artistic.coloredPencil", json!({})), PixelFx::ColoredPencil { width: 5.0, pressure: 5.0, paper: 25.0 }); + assert_eq!( + fx("artistic.coloredPencil", json!({"pencilWidth": 0, "strokePressure": 200, "paperBrightness": -5})), + PixelFx::ColoredPencil { width: 1.0, pressure: 15.0, paper: 0.0 } + ); + assert_eq!(fx("artistic.coloredPencil", json!({})).reach(), Some(artistic::colored_pencil_reach(5.0))); assert_eq!(fx("artistic.cutout", json!({})), PixelFx::Cutout { levels: 4.0, simplicity: 4.0, fidelity: 2.0 }); assert_eq!( fx("artistic.cutout", json!({"levels": 1e308, "edgeSimplicity": -5, "edgeFidelity": "NaN"})), @@ -2484,8 +2490,15 @@ fn artistic_params_take_defaults_and_stay_in_range() { fx("artistic.plasticWrap", json!({"highlightStrength": -1, "detail": 99, "smoothness": 0})), PixelFx::PlasticWrap { highlight: 0.0, detail: 15.0, smoothness: 1.0 } ); - for id in ["artistic.cutout", "artistic.dryBrush", "artistic.neonGlow", "artistic.plasticWrap", "artistic.posterEdges", "artistic.underpainting"] - { + for id in [ + "artistic.coloredPencil", + "artistic.cutout", + "artistic.dryBrush", + "artistic.neonGlow", + "artistic.plasticWrap", + "artistic.posterEdges", + "artistic.underpainting", + ] { assert_eq!(fx(id, json!({})).outset(Rect::new(0.0, 0.0, 40.0, 30.0)), 0.0, "{id} keeps the object's shape"); } assert_eq!(fx("artistic.paintDaubs", json!({})), PixelFx::PaintDaubs { size: 10.0, sharpness: 25.0, kind: PaintDaubBrush::Simple }); @@ -2509,6 +2522,19 @@ fn artistic_params_take_defaults_and_stay_in_range() { assert!(fx("artistic.roughPastels", json!({})).outset(Rect::new(0.0, 0.0, 40.0, 30.0)) > 0.0); } +#[test] +fn colored_pencil_strokes_change_pixels_and_keep_coverage() { + let (w, h) = (48, 32); + let src = ramp(w, h); + let mut out = src.clone(); + fx("artistic.coloredPencil", json!({"strokePressure": 12})).apply(&mut out, w, h, &space(w, h)); + assert_ne!(out, src); + assert!(out.as_chunks::<4>().0.iter().zip(src.as_chunks::<4>().0).all(|(o, s)| o[3] == s[3])); + let mut mild = src.clone(); + fx("artistic.coloredPencil", json!({"strokePressure": 0, "paperBrightness": 0})).apply(&mut mild, w, h, &space(w, h)); + assert_eq!(mild, src, "zero pressure and paper leaves the art unchanged"); +} + #[test] fn artistic_filters_leave_invalid_coordinate_spaces_alone() { let (w, h) = (16, 12); diff --git a/crates/engine/src/tests_rasterfilters.rs b/crates/engine/src/tests_rasterfilters.rs index ca709de50..b5142fc2c 100644 --- a/crates/engine/src/tests_rasterfilters.rs +++ b/crates/engine/src/tests_rasterfilters.rs @@ -31,7 +31,8 @@ const BRUSH_STROKES: [(&str, &str); 8] = [ ]; /// Effect › Artistic, at their defaults. -const ARTISTIC: [(&str, &str); 13] = [ +const ARTISTIC: [(&str, &str); 14] = [ + ("artistic.coloredPencil", "{}"), ("artistic.cutout", "{}"), ("artistic.dryBrush", "{}"), ("artistic.filmGrain", "{}"), diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index c7dbcf346..ffd3cc038 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -4557,6 +4557,8 @@ lighting Light Светлина Reset Ruler Origin Нулиране началото на линийката Artistic Художествени Film Grain… Филмова зърнистост… + Colored Pencil… Цветен молив… + Colored Pencil Цветен молив Cutout… Апликация… Cutout Апликация Dry Brush… Суха четка… diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 69b7b087d..3f23b24ce 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -5056,6 +5056,8 @@ imageTrace Outline Obrys DWG (use DXF) DWG (použijte DXF) Artistic Umělecké Film Grain… Filmové zrno… + Colored Pencil… Barevná tužka… + Colored Pencil Barevná tužka Cutout… Výřez… Cutout Výřez Dry Brush… Suchý štětec… diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index f4fc9d500..6ddf99786 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -5182,6 +5182,8 @@ swatch Bright Violet Kraftig violet Lock Variables Lås variabler Unlock Variables Lås variabler op Change to Artboard Rulers Skift til kunstpladelinealer + Colored Pencil… Farveblyant… + Colored Pencil Farveblyant Cutout… Udklip… Dry Brush… Tør pensel… Neon Glow… Neonglød… diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index f2954f330..c36145fec 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4637,6 +4637,8 @@ lighting Light Licht Reset Ruler Origin Linealursprung zurücksetzen Artistic Kunstfilter Film Grain… Filmkörnung… + Colored Pencil… Buntstift… + Colored Pencil Buntstift Simple Einfach Light Rough Leicht rau Dark Rough Dunkel rau diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index b530c8469..8566e058e 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -2266,6 +2266,8 @@ lighting Light Φως Left Diagonal Αριστερή διαγώνιος Artistic Καλλιτεχνικό Film Grain… Κόκκος φιλμ… + Colored Pencil… Έγχρωμο μολύβι… + Colored Pencil Έγχρωμο μολύβι Cutout… Αποκοπή… Cutout Αποκοπή Dry Brush… Ξηρό πινέλο… diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 877b5826e..0d5ee1098 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4644,6 +4644,8 @@ lighting Light Luz Reset Ruler Origin Restablecer el origen de las reglas Artistic Artístico Film Grain… Granulado de película… + Colored Pencil… Lápiz de color… + Colored Pencil Lápiz de color Cutout… Recorte… Cutout Recorte Dry Brush… Pincel seco… diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 365452e4c..84af613c4 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4951,6 +4951,8 @@ imageTrace Outline Ääriviiva DWG (use DXF) DWG (käytä DXF:ää) Artistic Taiteelliset Film Grain… Filmin rakeisuus… + Colored Pencil… Väriliitu… + Colored Pencil Väriliitu Cutout… Leikkaus… Cutout Leikkaus Dry Brush… Kuiva sivellin… diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 4c4fbe06b..cc4af21e3 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -4654,6 +4654,8 @@ lighting Light Lumière Reset Ruler Origin Réinitialiser l’origine des règles Artistic Artistique Film Grain… Grain photographique… + Colored Pencil… Crayon de couleur… + Colored Pencil Crayon de couleur Cutout… Découpage… Cutout Découpage Dry Brush… Pinceau sec… diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 63455d978..10adcbe9e 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -1587,6 +1587,8 @@ file-filter Templates Sablonok Select Segments Szakaszok kijelölése Artistic Művészi Film Grain… Filmszemcse… + Colored Pencil… Színes ceruza… + Colored Pencil Színes ceruza Cutout… Kivágás… Cutout Kivágás Dry Brush… Száraz ecset… diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index b3a3051bc..9b65f48e0 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -5182,6 +5182,8 @@ swatch Bright Violet Violet cerah Lock Variables Kunci variabel Unlock Variables Buka kunci variabel Change to Artboard Rulers Ubah ke penggaris artboard + Colored Pencil… Pensil warna… + Colored Pencil Pensil warna Cutout… Potongan… Dry Brush… Kuas kering… Neon Glow… Pendar neon… diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index f52676205..41df7fbc6 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4686,6 +4686,8 @@ lighting Light Luce Reset Ruler Origin Ripristina origine dei righelli Artistic Artistico Film Grain… Grana della pellicola… + Colored Pencil… Matita colorata… + Colored Pencil Matita colorata Cutout… Ritaglio… Cutout Ritaglio Dry Brush… Pennello secco… diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index b24e36167..3c4904a66 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4725,6 +4725,8 @@ lighting Light ライト Reset Ruler Origin 定規の原点をリセット Artistic アーティスティック Film Grain… フィルム粒子… + Colored Pencil… 色鉛筆… + Colored Pencil 色鉛筆 Cutout… カットアウト… Cutout カットアウト Dry Brush… ドライブラシ… diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index c1e30279f..055096c7b 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -5018,6 +5018,8 @@ imageTrace Outline კონტური Create Slice from Selection ნაჭრის შექმნა მონიშნულიდან Create Slices from Guides ნაჭრების შექმნა დამხმარე ხაზებიდან Cutout აპლიკაცია + Colored Pencil… ფერადი ფანქარი… + Colored Pencil ფერადი ფანქარი Dry Brush მშრალი ფერწანი Cutout… აპლიკაცია… Dry Brush… მშრალი ფერწანი… diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 02935f068..800daeac1 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4649,6 +4649,8 @@ lighting Light 광원 X11 (XWayland) X11 (XWayland) Artistic 예술 효과 Film Grain… 필름 그레인… + Colored Pencil… 색연필… + Colored Pencil 색연필 Cutout… 오려내기… Cutout 오려내기 Dry Brush… 드라이 브러시… diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 805597607..38cd0a07a 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -5193,6 +5193,8 @@ swatch Bright Violet Felviolet Lock Variables Variabelen vergrendelen Unlock Variables Variabelen ontgrendelen Change to Artboard Rulers Wijzigen in tekenbordlinialen + Colored Pencil… Gekleurd potlood… + Colored Pencil Gekleurd potlood Cutout… Knipsel… Dry Brush… Droog penseel… Neon Glow… Neongloed… diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index e14037421..f4ab658c3 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -4889,6 +4889,8 @@ imageTrace Outline Kontur DWG (use DXF) DWG (użyj DXF) Artistic Artystyczne Film Grain… Ziarno filmu… + Colored Pencil… Kolorowa kredka… + Colored Pencil Kolorowa kredka Cutout… Wycinanka… Cutout Wycinanka Dry Brush… Suchy pędzel… diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index aba95ccdf..97f179076 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -4039,6 +4039,8 @@ axis Both Ambos Reset Ruler Origin Redefinir origem das réguas Artistic Artístico Film Grain… Granulação de filme… + Colored Pencil… Lápis de cor… + Colored Pencil Lápis de cor Cutout… Recorte… Cutout Recorte Dry Brush… Pincel seco… diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 71728573e..893f12ece 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4682,6 +4682,8 @@ lighting Light Свет Reset Ruler Origin Сбросить начало координат линеек Artistic Художественные Film Grain… Зернистость плёнки… + Colored Pencil… Цветной карандаш… + Colored Pencil Цветной карандаш Cutout… Аппликация… Cutout Аппликация Dry Brush… Сухая кисть… diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index fc43028ae..4b7070d4f 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -4563,6 +4563,8 @@ lighting Light Ljus Reset Ruler Origin Återställ linjalens origo Artistic Konstnärligt Film Grain… Filmkorn… + Colored Pencil… Färgpenna… + Colored Pencil Färgpenna Cutout… Urklipp… Cutout Urklipp Dry Brush… Torr pensel… diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 9ab75b00c..61dc3865e 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4666,6 +4666,8 @@ lighting Light Світло Reset Ruler Origin Скинути початок координат лінійок Artistic Художні Film Grain… Зернистість плівки… + Colored Pencil… Кольоровий олівець… + Colored Pencil Кольоровий олівець Cutout… Аплікація… Cutout Аплікація Dry Brush… Суха кисть… diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index b508807cf..d80001204 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -1268,6 +1268,8 @@ Fill: click for swatches, Shift-click for the color mixer Tô: bấm để xem mẫu màu, Shift-bấm để trộn màu Fills Vùng tô Film Grain… Hạt phim… + Colored Pencil… Bút chì màu… + Colored Pencil Bút chì màu Cutout… Cắt dán… Cutout Cắt dán Dry Brush… Cọ khô… diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index a6f520b2b..5ab3f370b 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -4950,6 +4950,8 @@ lighting Light 光源 Reset Ruler Origin 重置标尺原点 Artistic 艺术效果 Film Grain… 胶片颗粒… + Colored Pencil… 彩色铅笔… + Colored Pencil 彩色铅笔 Cutout… 剪纸… Dry Brush… 干画笔… Cutout 剪纸 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 549615b26..dc853661e 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4756,6 +4756,8 @@ lighting Light 光源 Reset Ruler Origin 重設尺標原點 Artistic 藝術效果 Film Grain… 底片顆粒… + Colored Pencil… 彩色鉛筆… + Colored Pencil 彩色鉛筆 Cutout… 剪紙… Dry Brush… 乾畫筆… Cutout 剪紙 diff --git a/crates/ui-egui/src/tests_labels.rs b/crates/ui-egui/src/tests_labels.rs index eb9da8a14..3529257bd 100644 --- a/crates/ui-egui/src/tests_labels.rs +++ b/crates/ui-egui/src/tests_labels.rs @@ -89,6 +89,7 @@ fn effect_menu_lists_the_artistic_filters_before_blur() { assert_eq!( labels, [ + "Colored Pencil…", "Cutout…", "Dry Brush…", "Film Grain…", @@ -105,8 +106,8 @@ fn effect_menu_lists_the_artistic_filters_before_blur() { ] ); assert!(artistic.iter().all(|e| e.command.as_deref() == Some("effect.dialog"))); - assert_eq!(artistic[1].params, json!({"effect": "artistic.dryBrush"})); - assert_eq!(artistic[3].params, json!({"effect": "artistic.neonGlow"})); + assert_eq!(artistic[2].params, json!({"effect": "artistic.dryBrush"})); + assert_eq!(artistic[4].params, json!({"effect": "artistic.neonGlow"})); let at = |name: &str| entries.iter().position(|e| e.path == ["Effect", name]).unwrap(); assert!(at("Artistic") < at("Blur")); } diff --git a/docs/effects-parity.md b/docs/effects-parity.md index 06cbf2acd..130c94d70 100644 --- a/docs/effects-parity.md +++ b/docs/effects-parity.md @@ -12,6 +12,7 @@ Part of [target-app-parity.md](target-app-parity.md); open work is in [gaps.md]( | Group | Illustrator | VectorCraft | % | Remaining (h) | |---|---:|---:|---:|---:| | Illustrator effects (vector and stylize) | 50 | 46 | 92% | 6–10 | +| Photoshop effects (raster, Effect Gallery) | 57 | 49 | 86% | 7–12 | | Photoshop effects (raster, Effect Gallery) | 57 | 48 | 84% | 8–14 | | 3D and Materials | 4 (+3 Classic) | 4 (initial: Extrude & Bevel, Revolve, Inflate, Rotate) | ~25% | 25–45 | | Beyond Illustrator: Effect › Color Adjustments (6), effect plug-ins (WebAssembly) | — | 6 + plug-ins | — | — | @@ -38,6 +39,7 @@ its resolution, PDF export warns once per object with the requested and the lowe | Submenu | Items | Ours | Missing | |---|---|---:|---| +| Artistic | Colored Pencil, Cutout, Dry Brush, Film Grain, Fresco, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting, Watercolor | 10/15 (approximate Colored Pencil, Cutout, Dry Brush, Film Grain, Neon Glow, Plastic Wrap, Poster Edges, Smudge Stick, Sponge, Watercolor) | Fresco, Paint Daubs, Palette Knife, Rough Pastels, Underpainting | | Artistic | Colored Pencil, Cutout, Dry Brush, Film Grain, Fresco, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting, Watercolor | 9/15 (approximate Cutout, Film Grain, Neon Glow, Paint Daubs, Plastic Wrap, Poster Edges, Smudge Stick, Sponge, Watercolor) | Colored Pencil, Dry Brush, Fresco, Palette Knife, Rough Pastels, Underpainting | | Blur | Gaussian Blur, Radial Blur, Smart Blur | 3/3 | — | | Brush Strokes | Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e | 8/8 | — | @@ -52,7 +54,7 @@ its resolution, PDF export warns once per object with the requested and the lowe The pixel-filter pipeline (`vectorcraft_effects::pixel`) is in place: each new filter is one function, a catalogue row, a menu entry and translations. Measured throughput: 0.7–1.2 agent hours per filter -(see [calibration](target-app-parity.md#calibration)), so the 12 missing filters are ~8–14 h and the Effect +(see [calibration](target-app-parity.md#calibration)), so the 10 missing filters are ~7–12 h and the Effect Gallery dialog another 4–6 h. These parallelize well across agents. Film Grain (`artistic.filmGrain`, Effect › Artistic) adds stable monochrome noise to shadows and diff --git a/docs/gaps.md b/docs/gaps.md index 8dda09bbe..62de3c1f1 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -234,12 +234,11 @@ from G14 and the budget run of G15: **~170–270 h** one agent, ~50–80 h wall ## G2 Photoshop-style raster effects and the Effect Gallery - **Done:** Effect › Texture › Texturizer › Load Texture… (stored grayscale `textureImage`, Loaded Texture in the Texture menu), matching Glass. -- **Missing:** 24 of 57 filters (the remaining 11 Artistic filters and 13 of Sketch's 14), the Effect Gallery dialog. Measured in -- **Missing:** 10 of 57 filters (7 Artistic, 2 Sketch and 1 more), the Effect Gallery dialog, Load - Texture for Texturizer. Measured in +- **Missing:** 8 of 57 filters (5 Artistic, 2 Sketch and 1 more), the Effect Gallery dialog. Measured in [effects-parity.md](effects-parity.md). -- **Done:** the pixel-filter pipeline and 45 filters (Artistic: Cutout, Film Grain, Neon Glow, Plastic Wrap, Poster Edges, Smudge Stick, Sponge, Watercolor; Blur, Brush Strokes, Distort, Pixelate, Sharpen; Sketch: - Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Graphic Pen, Halftone Pattern, Photocopy, Plaster, Reticulation, Stamp; Stylize, Texture, Video), with live preview and editable native settings. Smart Blur supports Edge Only and Overlay Edge +- **Done:** Effect › Artistic › Colored Pencil (`artistic.coloredPencil`, pencil width, stroke pressure, paper brightness; original visual approximation). +- **Done:** the pixel-filter pipeline and 49 filters (Artistic: Colored Pencil, Cutout, Dry Brush, Film Grain, Neon Glow, Plastic Wrap, Poster Edges, Smudge Stick, Sponge, Watercolor; Blur, Brush Strokes, Distort, Pixelate, Sharpen; Sketch: + Bas Relief, Chalk & Charcoal, Charcoal, Chrome, Graphic Pen, Halftone Pattern, Note Paper, Photocopy, Plaster, Reticulation, Stamp, Water Paper; Stylize, Texture, Video), with live preview and editable native settings. Smart Blur supports Edge Only and Overlay Edge modes. - **Estimate:** 8–14 h (measured 0.7–1.2 h per filter); parallelizes well. From 0c9a7a89a093e40b218c0f82dcc237d68f1ae3a7 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 22 Oct 2026 00:31:30 +0700 Subject: [PATCH 2/2] Docs: Photoshop filter count after Colored Pencil (52/57), one Artistic row --- ROADMAP.md | 2 +- docs/effects-parity.md | 8 +++----- docs/roadmap.md | 2 +- docs/target-app-parity.md | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index d50f4f57b..0cc068d6e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -29,7 +29,7 @@ blocking it ([Alpha gate](docs/roadmap.md#alpha-gate)). | | Value | Kind | |---|---|---| -| **Feature breadth** (Illustrator's menu items, tools, effects, formats exist) | **~88%** | measured in part: menu items 348/375 wired (92.8%), tools 89/92, Illustrator effects 46/50, Photoshop effects 51/57, 3D 4/4 (initial types, no materials) | +| **Feature breadth** (Illustrator's menu items, tools, effects, formats exist) | **~88%** | measured in part: menu items 348/375 wired (92.8%), tools 89/92, Illustrator effects 46/50, Photoshop effects 52/57, 3D 4/4 (initial types, no materials) | | **Feature depth** (weighted by use, scored by behaviour) | **~75%** | estimated | | **To beta** | **~170–270 h** one agent · ~50–80 h with 4–6 agents | estimated | | **To full parity** | **~360–590 h** one agent · ~95–165 h with 4–6 agents | estimated | diff --git a/docs/effects-parity.md b/docs/effects-parity.md index 130c94d70..47c0851cd 100644 --- a/docs/effects-parity.md +++ b/docs/effects-parity.md @@ -12,8 +12,7 @@ Part of [target-app-parity.md](target-app-parity.md); open work is in [gaps.md]( | Group | Illustrator | VectorCraft | % | Remaining (h) | |---|---:|---:|---:|---:| | Illustrator effects (vector and stylize) | 50 | 46 | 92% | 6–10 | -| Photoshop effects (raster, Effect Gallery) | 57 | 49 | 86% | 7–12 | -| Photoshop effects (raster, Effect Gallery) | 57 | 48 | 84% | 8–14 | +| Photoshop effects (raster, Effect Gallery) | 57 | 52 | 91% | 4–6 | | 3D and Materials | 4 (+3 Classic) | 4 (initial: Extrude & Bevel, Revolve, Inflate, Rotate) | ~25% | 25–45 | | Beyond Illustrator: Effect › Color Adjustments (6), effect plug-ins (WebAssembly) | — | 6 + plug-ins | — | — | @@ -39,8 +38,7 @@ its resolution, PDF export warns once per object with the requested and the lowe | Submenu | Items | Ours | Missing | |---|---|---:|---| -| Artistic | Colored Pencil, Cutout, Dry Brush, Film Grain, Fresco, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting, Watercolor | 10/15 (approximate Colored Pencil, Cutout, Dry Brush, Film Grain, Neon Glow, Plastic Wrap, Poster Edges, Smudge Stick, Sponge, Watercolor) | Fresco, Paint Daubs, Palette Knife, Rough Pastels, Underpainting | -| Artistic | Colored Pencil, Cutout, Dry Brush, Film Grain, Fresco, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting, Watercolor | 9/15 (approximate Cutout, Film Grain, Neon Glow, Paint Daubs, Plastic Wrap, Poster Edges, Smudge Stick, Sponge, Watercolor) | Colored Pencil, Dry Brush, Fresco, Palette Knife, Rough Pastels, Underpainting | +| Artistic | Colored Pencil, Cutout, Dry Brush, Film Grain, Fresco, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting, Watercolor | 14/15 (approximate Colored Pencil, Cutout, Dry Brush, Film Grain, Neon Glow, Paint Daubs, Palette Knife, Plastic Wrap, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting, Watercolor) | Fresco | | Blur | Gaussian Blur, Radial Blur, Smart Blur | 3/3 | — | | Brush Strokes | Accented Edges, Angled Strokes, Crosshatch, Dark Strokes, Ink Outlines, Spatter, Sprayed Strokes, Sumi-e | 8/8 | — | | Distort | Diffuse Glow, Glass, Ocean Ripple | 3/3 | — | @@ -54,7 +52,7 @@ its resolution, PDF export warns once per object with the requested and the lowe The pixel-filter pipeline (`vectorcraft_effects::pixel`) is in place: each new filter is one function, a catalogue row, a menu entry and translations. Measured throughput: 0.7–1.2 agent hours per filter -(see [calibration](target-app-parity.md#calibration)), so the 10 missing filters are ~7–12 h and the Effect +(see [calibration](target-app-parity.md#calibration)), so the 5 missing filters are ~4–6 h and the Effect Gallery dialog another 4–6 h. These parallelize well across agents. Film Grain (`artistic.filmGrain`, Effect › Artistic) adds stable monochrome noise to shadows and diff --git a/docs/roadmap.md b/docs/roadmap.md index a7f838d66..f4f60415f 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -60,7 +60,7 @@ Checked 2026-10-10 from the code, tests and open issues; no workflow fails, so V | M6 | Path operations (Pathfinder, Shape Builder, offset…) | ✅ mostly done (single-result Pathfinder names and SVG IDs retained (#1293); Divide open-cutting-path geometry, appearance and history verified (#1307; existing segment cap remains); Simplify preview/counts and rewritten-path component selection verified (#1272; auto/slider/advanced UI remains open); Compound appearance and member fill-rule edits verified (#1197); Boolean precision on almost-horizontal edges fixed and the property tests made deterministic; Shape Builder gap detection, large-offset bug open) | 3–6 | | M7 | Type (point/area/path, editing, styles, OpenType, threading, glyphs) | 🟡 Fullwidth `!` / `?` keep an upright fallback in vertical type; Document-point character controls after object/group scaling (#1034; optional font-size preservation remains separate), Character/Paragraph Styles (explicit Auto-leading resets and local leading overrides), per-paragraph paragraph attributes, mixed paragraph alignment indication (headless regressions, full integration CI and visual review pass), Area Type Options (with Width/Height, Auto Size and Shrink Text to Fit; overflow reported to agents and vertical Align), type areas resized by their handles and reshaped with Direct Selection, threaded text, Fit Headline, Glyphs, OpenType panel, Find Font, installed system fonts in every font menu (fonts registered with Windows outside its font folders, the XDG and Flatpak host font folders on Linux, and fonts installed while the app runs, listed when it comes back to the front; searchable; the Character and Properties menus show each family's sample of the selected text, preview it live under the pointer or ↑/↓, filter by script and kind, list a family's styles, and star favourites; the Glyphs panel and Find Font's Replace With use the same menu without the live preview) and found by name on open/import (full-name aliases and Missing Fonts searches verified, #1258; Windows font-service QA pending), variable fonts' named instances as styles, CJK names in the UI, input methods (marked text in place, candidate window at the caret; Japanese IME), Text Wrap (offset, invert, both sides of an object; follows edits), Type on a Path effects and Options with draggable start/centre/end brackets (slide, flip), tab stops + Tabs panel (Above Text floats it over the selected text, its ruler at the canvas zoom so stops line up with the columns, #729), inline symbols in text (beyond parity), Hebrew/Arabic bidirectional text, Paragraph Direction, Every-line/Single-line Composer per object (ragged text too) done; tab leaders, spell check, vertical type pending | 45–60 | | M8 | Transform & distort (Puppet Warp, Liquify tools, Envelopes, Blends, Perspective Grid) | ✅ done (M8.1–M8.20 on 2026-10-06, fidelity pass): Liquify Tool Options with one shared brush, pen pressure, hold-to-apply, a safe scope and incremental strokes; tool options that last; Puppet Warp rotation, multi-select, Control bar and a rest-shape session that follows Undo; Width tool on compound paths; Envelope dialogs with preview, Reset with Warp/Mesh, full Envelope Options, type/images/symbols/appearance/gradients/patterns distorted on canvas and in every export, warps that keep their frame, Edit Contents, mesh handles and Control bar; Blend Options, anchor-targeted Blend tool, editable spine, keys picked on the canvas, faithful interpolation and knockout; Anchor Point spine conversion/handle editing and selection priority (#2544), with #2425 Shift reshape preserved; Perspective Grid with Define Grid, presets, lock/snap/rulers, widgets, the 1–4 plane switch, movable planes, Perspective Selection scale/copy/perpendicular/Transform Again, and type and symbols truly projected with Edit Text. Left: Anti-Alias and Preserve Shape output, warp-envelope point editing, brush interpolation in blends, Free Transform/Scale/Reflect along a rotated box | 2–4 | -| M9 | Live effects (+ 3D & Materials) | 🟡 2D effects done incl. Effect → Pathfinder, Color Adjustments and Document Raster Effects Settings; PDF export warns when the pixel cap lowers raster-effect resolution; Artistic › Cutout, Dry Brush, Film Grain, Neon Glow, Paint Daubs, Palette Knife, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting and Watercolor and Sketch › Halftone Pattern, Bas Relief, Charcoal, Photocopy and Stamp done (51/57 Photoshop filters); Revolve with automatic smooth vector shading, default-on circular caps and continuous rims, Extrude & Bevel, Inflate and Rotate with one to ten colored directional lights and four original lighting presets; SVG Filters, remaining raster effects and 3D materials and shadows pending | 81–130 | +| M9 | Live effects (+ 3D & Materials) | 🟡 2D effects done incl. Effect → Pathfinder, Color Adjustments and Document Raster Effects Settings; PDF export warns when the pixel cap lowers raster-effect resolution; Artistic › Colored Pencil, Cutout, Dry Brush, Film Grain, Neon Glow, Paint Daubs, Palette Knife, Poster Edges, Rough Pastels, Smudge Stick, Sponge, Underpainting and Watercolor and Sketch › Halftone Pattern, Bas Relief, Charcoal, Photocopy and Stamp done (52/57 Photoshop filters); Revolve with automatic smooth vector shading, default-on circular caps and continuous rims, Extrude & Bevel, Inflate and Rotate with one to ten colored directional lights and four original lighting presets; SVG Filters, remaining raster effects and 3D materials and shadows pending | 81–130 | | M10 | Brushes, symbols, patterns, Repeat | 🟡 pattern swatches (5 tile types, Pattern Options, editing mode, SVG ``/PDF export) and live Repeat (radial/grid/mirror) done; interactive selected mirror axis implemented (focused and native checks passed; full CI blocked by an unrelated text test); brushes/symbols in progress | 23–37 | | M11 | Artboards & views (selected-set deletion shared by Artboards menu, trash and Properties, retaining artboard 1 when all are selected; Artboard deletion keys keep the first of an all-selected set and protect artwork; history prunes invalid indices while preserving valid multiselection (history tests and full workspace CI pass); click-to-fit objects with the Artboard tool (#1227), artboard escape routing and document setup modal handoff done; artboard panel/tool with Move Artwork for X/Y fields and Artboard Options, Trim View, middle-button pan, print tiling and the status bar's artboard navigator with synchronized Artboard tool selection done; multiple windows, presentation polish) (cached canvas reprojection preserves scale during resize, rotation and DPI changes; regression-tested and contributor-confirmed 2026-10-19; estimates unchanged) (cached canvas dimensions match the renderer limit before cache-key creation, view construction and worker submission; regression-tested; estimates unchanged) | 🟡 | 15–25 | | M12 | Advanced color & art (CMYK/ICC, separations, Gradient Mesh, Live Paint, Image Trace, Graphs) | 🟡 Gradient Mesh, Live Paint, Image Trace (junction-returning pieces retain their positioned boundaries; a simpler contour walk with identical output; an edge's sub-pixel shift is the same from either side; notches read only their own piece; collapsed loops keep few segments; large images trace with a warning; Auto Color keeps rare distinct colours; quick presets trace at once and the Image Trace button opens the adjustment controls; Properties reopens them; tiny fitted contours retain islands and holes; Create Strokes: exact crop EDT, Guo–Hall thinning and maximal-disc graph simplification; 15 presets, the 14 documented ones each with an enhanced version; Ignore Color, Shapes, Auto Grouping and Gradients options; measured in `image-trace-quality.md`; closed outlines retain their interior after straightening; the Flat Logo mode places edges to a fraction of a pixel, restores sharp corners, snaps lines and circles, and refuses gradients; live trace result bounds and selection highlights exclude the retained bitmap except in source-image views), Recolor Artwork, colour management (ICC, soft proofing, separations preview), Graphs (all 9 tools, Graph Data/Type, group-selected series colours persist through regenerate/save/open) done; Graph Design and Marker designs, Transpose and Switch x/y, `\|` label line breaks, the pie options, drop shadows, the legend across the top, overlapping widths, First Row/Column in Front, filled lines, kept label formatting and the Graph Data worksheet done; graph Column designs pending | 6–10 | diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index f5eba9185..6675f96ed 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -79,7 +79,7 @@ dominate; 3D, graphs and automation are specialist). They sum to 105. Feature de | 3D and Materials (and Turntable) | 4 | ~25% | live Revolve with automatic smooth vector shading and default-on continuous circular caps, Extrude & Bevel (twist, taper, caps, five bevel shapes), Inflate and Rotate with Position presets (colored Inflate uses smooth membrane lighting; white-light Inflate retains its existing shading; Extrude & Bevel and Rotate retain planar shading; one to ten colored lights, shared neutral ambient, original lighting presets, painter visibility); materials, shadows, ray tracing, 3D Classic, Turntable views, 3D export | 30–55 | estimated (Extrude & Bevel, Inflate and Rotate added 2026-10-12) | | Type core | 9 | 80% | Auto-leading style resets are implemented; remaining: hyphenation and justification options, Optical Margin Alignment, Middle Eastern features beyond bidi layout, optional group font-size preservation; transformed character controls fixed (#1034), see [type-parity.md](type-parity.md) | 14–19 | estimated; full-name font matches regression-tested (#1258); mixed paragraph alignment indication implemented; headless regressions, full integration CI and visual review pass; localized legacy family-name fallback with loaded/catalog regressions (#2208); Fractional Widths per type object regression-tested; scores and hours unchanged | | Type advanced (CJK, spelling, Touch Type, Retype) | 4 | 50% | CJK vertical composition (mojikumi), variable font axes, tab leaders, spell check, Touch Type, Retype | 20–28 | estimated; No Break keeps marked characters on one line; upright fallback for fullwidth `!` / `?` regression-tested; score and hours unchanged | -| Raster effects (Effect Gallery) | 4 | 49% | 6 Photoshop-style filters (Artistic › Colored Pencil and Fresco among them), the Effect Gallery dialog, Load Texture | 8–14 | measured count 51/57 (Artistic › Paint Daubs, Palette Knife, Rough Pastels and Underpainting added); texture redraw distances optimized (#1257), pixels verified; depth estimated | +| Raster effects (Effect Gallery) | 4 | 49% | 5 Photoshop-style filters (Artistic › Fresco among them), the Effect Gallery dialog, Load Texture | 8–14 | measured count 52/57 (Artistic › Colored Pencil, Paint Daubs, Palette Knife, Rough Pastels and Underpainting added); texture redraw distances optimized (#1257), pixels verified; depth estimated | | Symbols, blends, envelopes, Repeat, perspective | 5 | 87% | 30.7's Blend panel with ease in/out, dynamic symbols, symbol libraries, Start Global Edit, envelope Anti-Alias/Preserve Shape; Symbol Options › Registration, Export Type (Graphic / Movie Clip) and 9-slice guide settings (stored, not drawn) are done | 5–9 | estimated; interactive selected mirror axis implemented; bounding-box handles take priority over the axis line (focused regression and native checks passed; full CI blocked by an unrelated text test); #2544 spine Anchor Point conversion and picking regression-tested; scores and hours unchanged | | Image Trace, graphs, image tools | 3 | 75% | graph Column designs, Image Trace Create Strokes depth (Create Object Mosaic is done; junction-returning piece survival has source-generated regressions in `image-trace-quality.md`; simpler contour walk, identical output; an edge's sub-pixel shift is the same from either side; notches read only their own piece; collapsed loops keep few segments, so Paths is monotone on the code-drawn sweep) | 5–8 | estimated (raised from 72%); quick presets reveal adjustment controls, Properties reopens them; Live trace result bounds and selection highlights exclude the retained bitmap except in source-image views (scores/hours unchanged) | | Symbols, blends, envelopes, Repeat, perspective | 5 | 87% | 30.7's Blend panel with ease in/out, dynamic symbols, symbol libraries, Start Global Edit, envelope Anti-Alias/Preserve Shape; Symbol Options › Registration and Export Type (Graphic / Movie Clip) are done | 5–9 | estimated |