From c4ace05dbfe9ae1e6e10475bc0251894791aaa78 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 21:11:09 -0800 Subject: [PATCH] Graphic Styles: a built-in Painted and Sketched library adds watercolor, charcoal and ink styles The Graphic Styles library menu lists nine libraries. Painted and Sketched follows Hand-Drawn and holds Washed Blue, Bristle Ochre, Pastel Heather, Charcoal Shade, Ink Contour, Wet Ink and Fine Pen. Each style is a solid fill, two with a 1 pt stroke, under one watercolor, dry brush, rough pastels, charcoal, ink outlines, sumi-e or graphic pen effect with every setting given. The library and style names have rows in all 27 catalogs, and docs/mcp.md describes the library. --- crates/doc/src/style_libs.rs | 84 +++++++++++++++++++ crates/engine/src/tests/stylelib.rs | 81 ++++++++++++++++++ crates/ui-egui/src/i18n/bg.tsv | 8 ++ crates/ui-egui/src/i18n/bs.tsv | 8 ++ crates/ui-egui/src/i18n/ca.tsv | 8 ++ crates/ui-egui/src/i18n/cs.tsv | 8 ++ crates/ui-egui/src/i18n/da.tsv | 8 ++ crates/ui-egui/src/i18n/de.tsv | 8 ++ crates/ui-egui/src/i18n/el.tsv | 8 ++ crates/ui-egui/src/i18n/es.tsv | 8 ++ crates/ui-egui/src/i18n/fi.tsv | 8 ++ crates/ui-egui/src/i18n/fr.tsv | 8 ++ crates/ui-egui/src/i18n/hi.tsv | 8 ++ crates/ui-egui/src/i18n/hu.tsv | 8 ++ crates/ui-egui/src/i18n/id.tsv | 8 ++ crates/ui-egui/src/i18n/it.tsv | 8 ++ crates/ui-egui/src/i18n/ja.tsv | 8 ++ crates/ui-egui/src/i18n/ka.tsv | 8 ++ crates/ui-egui/src/i18n/ko.tsv | 8 ++ crates/ui-egui/src/i18n/nl.tsv | 8 ++ crates/ui-egui/src/i18n/pl.tsv | 8 ++ crates/ui-egui/src/i18n/pt-br.tsv | 8 ++ crates/ui-egui/src/i18n/ru.tsv | 8 ++ crates/ui-egui/src/i18n/sv.tsv | 8 ++ crates/ui-egui/src/i18n/tests.rs | 14 ++++ crates/ui-egui/src/i18n/tr.tsv | 8 ++ crates/ui-egui/src/i18n/uk.tsv | 8 ++ crates/ui-egui/src/i18n/vi.tsv | 8 ++ crates/ui-egui/src/i18n/zh-hans.tsv | 8 ++ crates/ui-egui/src/i18n/zh-hant.tsv | 8 ++ .../src/panels/tests_style_libraries.rs | 24 ++++++ docs/gaps.md | 9 +- docs/mcp.md | 9 +- docs/target-app-parity.md | 2 +- 34 files changed, 433 insertions(+), 6 deletions(-) diff --git a/crates/doc/src/style_libs.rs b/crates/doc/src/style_libs.rs index f64bdb430..19bc888c1 100644 --- a/crates/doc/src/style_libs.rs +++ b/crates/doc/src/style_libs.rs @@ -155,6 +155,7 @@ pub const STYLE_LIBRARIES: &[BuiltinStyleLibrary] = &[ BuiltinStyleLibrary { id: "shadows-glows", name: "Shadows and Glows", make: shadows_glows }, BuiltinStyleLibrary { id: "outlines-rules", name: "Outlines and Rules", make: outlines_rules }, BuiltinStyleLibrary { id: "hand-drawn", name: "Hand-Drawn", make: hand_drawn }, + BuiltinStyleLibrary { id: "painted-sketched", name: "Painted and Sketched", make: painted_sketched }, BuiltinStyleLibrary { id: "gradient-finishes", name: "Gradient Finishes", make: gradient_finishes }, BuiltinStyleLibrary { id: "shape-effects", name: "Shape Effects", make: shape_effects }, BuiltinStyleLibrary { id: "blends-transparency", name: "Blends and Transparency", make: blends_transparency }, @@ -322,6 +323,59 @@ fn hand_drawn() -> Vec { ] } +/// Painted and Sketched: one catalog paint or sketch effect over the whole appearance, so it +/// repaints the fill and the stroke together (watercolor, dry brush, pastels, charcoal and ink). +fn painted_sketched() -> Vec { + vec![ + style( + "Washed Blue", + vec![F(fill("#8ab9c9"))], + vec![fx("artistic.watercolor", json!({"brushDetail": 8.0, "shadowIntensity": 2.0, "texture": 2.0}))], + ), + style( + "Bristle Ochre", + vec![F(fill("#c4975a")), S(stroke("#76533d", 1.0))], + vec![fx("artistic.dryBrush", json!({"brushSize": 4.0, "brushDetail": 7.0, "texture": 2.0}))], + ), + style( + "Pastel Heather", + vec![F(fill("#a78ca5"))], + vec![fx( + "artistic.roughPastels", + json!({ + "strokeLength": 8.0, + "strokeDetail": 9.0, + "texture": "canvas", + "scaling": 100.0, + "relief": 5.0, + "lightDirection": "topLeft", + "invert": false + }), + )], + ), + style( + "Charcoal Shade", + vec![F(fill("#666666"))], + vec![fx("sketch.charcoal", json!({"thickness": 3.0, "detail": 3.0, "lightDarkBalance": 55.0}))], + ), + style( + "Ink Contour", + vec![F(fill("#d9e2df")), S(stroke("#26323b", 1.0))], + vec![fx("brushStrokes.inkOutlines", json!({"strokeLength": 6.0, "darkIntensity": 24.0, "lightIntensity": 8.0}))], + ), + style( + "Wet Ink", + vec![F(fill("#637b85"))], + vec![fx("brushStrokes.sumiE", json!({"strokeWidth": 7.0, "strokePressure": 5.0, "contrast": 20.0}))], + ), + style( + "Fine Pen", + vec![F(fill("#d8d4c6"))], + vec![fx("sketch.graphicPen", json!({"strokeLength": 6.0, "lightDarkBalance": 55.0, "strokeDirection": "rightDiagonal"}))], + ), + ] +} + fn gradient_finishes() -> Vec { let rim = |h: &str| S(stroke(h, 1.0)); vec![ @@ -552,6 +606,36 @@ mod tests { assert_eq!(status_names, ["Poison Tint", "Freeze Edge", "Burn Aura", "Stun Pulse", "Stealth Fade", "Shield Buff"]); } + #[test] + fn painted_and_sketched_follows_hand_drawn_with_one_effect_per_style() { + let ids: Vec<&str> = STYLE_LIBRARIES.iter().map(|b| b.id).collect(); + let at = ids.iter().position(|&id| id == "painted-sketched").expect("listed"); + assert_eq!(ids[at - 1], "hand-drawn"); + let lib = builtin_style_library("painted-sketched").unwrap(); + assert_eq!(lib.name, "Painted and Sketched"); + let names: Vec<&str> = lib.styles.iter().map(|g| g.name.as_str()).collect(); + assert_eq!(names, ["Washed Blue", "Bristle Ochre", "Pastel Heather", "Charcoal Shade", "Ink Contour", "Wet Ink", "Fine Pen"]); + let effects: Vec<&str> = lib.styles.iter().flat_map(|g| g.appearance.effects.iter().map(|e| e.id.as_str())).collect(); + assert_eq!( + effects, + [ + "artistic.watercolor", + "artistic.dryBrush", + "artistic.roughPastels", + "sketch.charcoal", + "brushStrokes.inkOutlines", + "brushStrokes.sumiE", + "sketch.graphicPen" + ] + ); + assert!(lib.styles.iter().all(|g| g.appearance.items.iter().all(|i| i.effects().is_empty())), "no effects on a fill or stroke"); + // No other built-in library holds a style of the same name. + for b in STYLE_LIBRARIES.iter().filter(|b| b.id != "painted-sketched") { + let other = builtin_style_library(b.id).unwrap(); + assert!(other.styles.iter().all(|g| !names.contains(&g.name.as_str())), "{}", b.id); + } + } + #[test] fn vcstyles_round_trip() { let mut lib = (*builtin_style_library("gradient-finishes").unwrap()).clone(); diff --git a/crates/engine/src/tests/stylelib.rs b/crates/engine/src/tests/stylelib.rs index 5124fb450..baceb94a6 100644 --- a/crates/engine/src/tests/stylelib.rs +++ b/crates/engine/src/tests/stylelib.rs @@ -82,6 +82,87 @@ fn builtin_libraries_are_listed_with_original_styles_using_catalogued_effects() assert!(s.execute("graphicStyle.library", &json!({"library": "nope"})).is_err()); } +#[test] +fn painted_and_sketched_styles_set_every_effect_setting_and_reopen_applied() { + let mut s = session(); + let list = run(&mut s, "graphicStyle.libraries", json!({})); + let libs = list["libraries"].as_array().unwrap(); + let at = libs.iter().position(|l| l["id"] == "painted-sketched").expect("listed"); + assert_eq!((libs[at]["name"].as_str(), libs[at]["count"].as_u64()), (Some("Painted and Sketched"), Some(7))); + assert_eq!(libs[at - 1]["id"], "hand-drawn"); + let g = run(&mut s, "graphicStyle.library", json!({"library": "Painted and Sketched"})); + let listed: Vec<(&str, &str, Vec<&str>)> = + g["styles"].as_array().unwrap().iter().map(|x| (x["name"].as_str().unwrap(), x["fill"].as_str().unwrap(), names(&x["effects"]))).collect(); + let want = [ + ("Washed Blue", "#8ab9c9", "artistic.watercolor"), + ("Bristle Ochre", "#c4975a", "artistic.dryBrush"), + ("Pastel Heather", "#a78ca5", "artistic.roughPastels"), + ("Charcoal Shade", "#666666", "sketch.charcoal"), + ("Ink Contour", "#d9e2df", "brushStrokes.inkOutlines"), + ("Wet Ink", "#637b85", "brushStrokes.sumiE"), + ("Fine Pen", "#d8d4c6", "sketch.graphicPen"), + ]; + assert_eq!(listed, want.iter().map(|&(n, f, e)| (n, f, vec![e])).collect::>()); + // Every setting of each effect is given, with the catalog's key and kind of value. + let (_, lib) = cmd::stylelib::library(&s, "painted-sketched").unwrap(); + for st in &lib.styles { + let e = &st.appearance.effects[0]; + let defaults = vectorcraft_render::effects::effect_info(&e.id).unwrap().defaults; + let (set, all) = (e.params.as_object().unwrap(), defaults.as_object().unwrap()); + let keys = |m: &serde_json::Map| m.keys().cloned().collect::>(); + assert_eq!(keys(set), keys(all), "{}", st.name); + for (k, v) in set { + let kind = |v: &Value| (v.is_number(), v.is_string(), v.is_boolean()); + assert_eq!(kind(v), kind(&all[k]), "{} / {k}", st.name); + } + } + let strokes: Vec<(&str, f64)> = + lib.styles.iter().filter(|g| g.appearance.stroke_paint() != Paint::None).map(|g| (g.name.as_str(), g.appearance.stroke_width())).collect(); + assert_eq!(strokes, [("Bristle Ochre", 1.0), ("Ink Contour", 1.0)]); + + // Each one adds and applies to a rectangle in one undo step. + let mut ids = vec![]; + for (i, (name, fill, effect)) in want.iter().enumerate() { + let id = rect(&mut s, 10.0 + 25.0 * i as f64, 20.0, 20.0, 30.0); + let before = undo_len(&s); + let r = run(&mut s, "graphicStyle.addFromLibrary", json!({"library": "painted-sketched", "name": name, "apply": true, "ids": [id.0]})); + assert_eq!((names(&r["added"]), r["applied"].as_str()), (vec![*name], Some(*name))); + assert_eq!(undo_len(&s), before + 1, "{name}"); + let node = doc(&s).node(id).unwrap(); + assert_eq!(node.appearance.fill_paint(), Paint::solid(vectorcraft_color::Color::from_hex(fill).unwrap()), "{name}"); + assert_eq!(node.appearance.effects.iter().map(|e| e.id.as_str()).collect::>(), [*effect]); + assert_eq!(node.appearance.effects[0].params, lib.style(name).unwrap().appearance.effects[0].params, "{name}"); + ids.push((id, *name)); + } + // Adding one again reuses it: no new style, no undo step. + let before = (undo_len(&s), doc(&s).graphic_styles.len()); + let r = run(&mut s, "graphicStyle.addFromLibrary", json!({"library": "painted-sketched", "name": "Wet Ink"})); + assert_eq!((names(&r["added"]), names(&r["existing"])), (vec![], vec!["Wet Ink"])); + assert_eq!((undo_len(&s), doc(&s).graphic_styles.len()), before); + // An unknown style or library changes nothing. + assert!(s.execute("graphicStyle.addFromLibrary", &json!({"library": "painted-sketched", "names": ["Wet Ink", "Nope"]})).is_err()); + assert!(s.execute("graphicStyle.addFromLibrary", &json!({"library": "painted-and-sketched", "name": "Wet Ink"})).is_err()); + assert_eq!((undo_len(&s), doc(&s).graphic_styles.len()), before); + + // Saved and opened again, the styles keep their effects and the rectangles stay linked to them. + let b64 = run(&mut s, "document.serialize", json!({}))["dataBase64"].as_str().unwrap().to_string(); + run(&mut s, "document.open", json!({"name": "painted.vectorcraft", "dataBase64": b64})); + for (id, name) in &ids { + let d = doc(&s); + let style = d.graphic_style(name).unwrap(); + assert!(style.same_look(lib.style(name).unwrap()), "{name}"); + let node = d.node(*id).unwrap(); + assert_eq!((node.extras().graphic_style, &node.appearance.effects), (Some(style.id), &style.appearance.effects), "{name}"); + } + + // With nothing selected, `apply` only adds; empty `names` adds the whole library in order. + run(&mut s, "file.new", json!({"width": 100, "height": 100})); + let r = run(&mut s, "graphicStyle.addFromLibrary", json!({"library": "painted-sketched", "name": "Fine Pen", "apply": true})); + assert!(r.get("applied").is_none() && doc(&s).graphic_style("Fine Pen").is_some()); + let r = run(&mut s, "graphicStyle.addFromLibrary", json!({"library": "painted-sketched", "names": []})); + assert_eq!((names(&r["added"]), names(&r["existing"])), (want[..6].iter().map(|w| w.0).collect::>(), vec!["Fine Pen"])); +} + #[test] fn add_dedupes_names_as_one_undo_step() { let mut s = session(); diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index bc67d8fd8..62f130dd1 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -1398,6 +1398,14 @@ font-technology Variable Променливи Hair Space Тънък интервал Hand Tool Инструмент „Ръка“ Hand-Drawn Ръчно рисувани + Painted and Sketched Рисувани и скицирани + Washed Blue Размито синьо + Bristle Ochre Охра с четка + Pastel Heather Пастелен пирен + Charcoal Shade Сянка с въглен + Ink Contour Мастилен контур + Wet Ink Мокро мастило + Fine Pen Фино перо Handles Дръжки Hard Light Твърда светлина Hard Mix Твърдо смесване diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index 6454cffcc..142af7344 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -795,6 +795,14 @@ Shield Buff Štit Outlines and Rules Obrisi i linije Hand-Drawn Ručno crtano + Painted and Sketched Slikano i skicirano + Washed Blue Isprano plavo + Bristle Ochre Oker kistom + Pastel Heather Pastelni vrijesak + Charcoal Shade Sjena ugljenom + Ink Contour Kontura tušem + Wet Ink Mokri tuš + Fine Pen Fino pero Gradient Finishes Gradijentne završnice Shape Effects Efekti oblika Blends and Transparency Stapanja i prozirnost diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 1567e0e8b..9d852140c 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -1905,6 +1905,14 @@ digits Malayalam Malaiàlam Hand Mà Hand Tool Eina de mà Hand-Drawn Dibuixat a mà + Painted and Sketched Pintat i esbossat + Washed Blue Blau rentat + Bristle Ochre Ocre de cerres + Pastel Heather Bruc pastel + Charcoal Shade Ombra de carbó + Ink Contour Contorn de tinta + Wet Ink Tinta humida + Fine Pen Ploma fina Handles Nanses Hard Dur Hard Light Llum dura diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index e9df0812f..7fd853134 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -803,6 +803,14 @@ Shield Buff Štít Outlines and Rules Obrysy a linky Hand-Drawn Ručně kreslené + Painted and Sketched Malované a skicované + Washed Blue Rozmytá modrá + Bristle Ochre Okr štětcem + Pastel Heather Pastelový vřes + Charcoal Shade Stín uhlem + Ink Contour Obrys tuší + Wet Ink Mokrá tuš + Fine Pen Jemné pero Gradient Finishes Přechodové povrchy Shape Effects Efekty tvarů Blends and Transparency Prolnutí a průhlednost diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index e259ecba8..2c53139bf 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -741,6 +741,14 @@ Shield Buff Skjold Outlines and Rules Konturer og linjer Hand-Drawn Håndtegnet + Painted and Sketched Malet og skitseret + Washed Blue Udvasket blå + Bristle Ochre Børsteokker + Pastel Heather Pastellyng + Charcoal Shade Kulskygge + Ink Contour Blækkontur + Wet Ink Vådt blæk + Fine Pen Fin pen Gradient Finishes Gradientfinish Shape Effects Formeffekter Blends and Transparency Blandinger og gennemsigtighed diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index abfaaa13a..2ac8ef385 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -1435,6 +1435,14 @@ file-filter Templates Vorlagen Hair Space Haarspatium Hand Tool Hand-Werkzeug Hand-Drawn Handgezeichnet + Painted and Sketched Gemalt und skizziert + Washed Blue Verwaschenes Blau + Bristle Ochre Borstenocker + Pastel Heather Pastellheide + Charcoal Shade Kohleschatten + Ink Contour Tuschekontur + Wet Ink Nasse Tusche + Fine Pen Feine Feder Handles Griffe Hard Light Hartes Licht Hard Mix Hart mischen diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 4611904ff..386ec443d 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -1373,6 +1373,14 @@ font-technology Variable Μεταβλητές Hair Space Πολύ λεπτό διάστημα Hand Tool Χέρι (Hand Tool) Hand-Drawn Σχεδιασμένο στο χέρι + Painted and Sketched Ζωγραφισμένο και σκιτσαρισμένο + Washed Blue Ξεπλυμένο μπλε + Bristle Ochre Ώχρα με πινέλο + Pastel Heather Παστέλ ρείκι + Charcoal Shade Σκιά με κάρβουνο + Ink Contour Περίγραμμα με μελάνι + Wet Ink Υγρό μελάνι + Fine Pen Λεπτή πένα Handles Λαβές Hard Light Έντονο φως Hard Mix Έντονη ανάμειξη diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index b91d89b8c..f432bc4f2 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -1452,6 +1452,14 @@ font-technology Variable Variables Hair Space Espacio fino Hand Tool Herramienta Mano Hand-Drawn Dibujado a mano + Painted and Sketched Pintado y bocetado + Washed Blue Azul lavado + Bristle Ochre Ocre de cerdas + Pastel Heather Brezo pastel + Charcoal Shade Sombra al carboncillo + Ink Contour Contorno de tinta + Wet Ink Tinta húmeda + Fine Pen Plumilla fina Handles Manejadores Hard Light Luz fuerte Hard Mix Mezcla definida diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index e29645989..98154222f 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -794,6 +794,14 @@ Shield Buff Kilpi Outlines and Rules Ääriviivat ja viivat Hand-Drawn Käsin piirretyt + Painted and Sketched Maalatut ja luonnostellut + Washed Blue Haalea sininen + Bristle Ochre Harjasokra + Pastel Heather Pastellikanerva + Charcoal Shade Hiilivarjo + Ink Contour Mustekontuuri + Wet Ink Märkä muste + Fine Pen Hieno kynä Gradient Finishes Liukuväriviimeistelyt Shape Effects Muototehosteet Blends and Transparency Sulautukset ja läpinäkyvyys diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index ff206b931..a74f88202 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -1446,6 +1446,14 @@ font-technology Variable Variables Hair Space Espace ultrafine Hand Tool Outil Main Hand-Drawn Dessiné à la main + Painted and Sketched Peint et esquissé + Washed Blue Bleu lavé + Bristle Ochre Ocre à la brosse + Pastel Heather Bruyère pastel + Charcoal Shade Ombre au fusain + Ink Contour Contour encré + Wet Ink Encre humide + Fine Pen Plume fine Handles Poignées Hard Light Lumière crue Hard Mix Mélange maximal diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index 6698f10a4..0c6cef82c 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -2100,6 +2100,14 @@ antiAlias Sharp शार्प Hand हैंड Hand Tool हैंड टूल Hand-Drawn हाथ-ड्रन + Painted and Sketched पेंट और स्केच + Washed Blue धुला नीला + Bristle Ochre ब्रश गेरू + Pastel Heather पेस्टल बैंगनी + Charcoal Shade चारकोल छाया + Ink Contour स्याही रूपरेखा + Wet Ink गीली स्याही + Fine Pen बारीक पेन Handles हैंडल्स Hard कठोर Hard Light हार्ड लाइट diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index a8d02ca4c..5252b197b 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -1846,6 +1846,14 @@ file-filter Templates Sablonok Hand Kéz Hand Tool Kéz Hand-Drawn Kézzel rajzolt + Painted and Sketched Festett és vázlatos + Washed Blue Kimosott kék + Bristle Ochre Sörteokker + Pastel Heather Pasztell hanga + Charcoal Shade Szénárnyék + Ink Contour Tuskontúr + Wet Ink Nedves tus + Fine Pen Finom toll Handles Fogantyúk Hard Szigorú Hard Light Kemény fény diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 04581cd72..6163d14a6 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -741,6 +741,14 @@ Shield Buff Perisai Outlines and Rules Garis luar dan garis Hand-Drawn Gambar tangan + Painted and Sketched Lukisan dan sketsa + Washed Blue Biru luntur + Bristle Ochre Oker kuas kering + Pastel Heather Ungu pastel + Charcoal Shade Bayangan arang + Ink Contour Kontur tinta + Wet Ink Tinta basah + Fine Pen Pena halus Gradient Finishes Finishing gradien Shape Effects Efek bentuk Blends and Transparency Blend dan transparansi diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 82827964f..8b3002954 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -1465,6 +1465,14 @@ file-filter Templates Modelli Hair Space Spazio sottilissimo Hand Tool Strumento Mano Hand-Drawn Disegnato a mano + Painted and Sketched Dipinto e schizzato + Washed Blue Blu slavato + Bristle Ochre Ocra a setole + Pastel Heather Erica pastello + Charcoal Shade Ombra a carboncino + Ink Contour Contorno a china + Wet Ink China bagnata + Fine Pen Pennino fine Handles Maniglie Hard Light Luce intensa Hard Mix Miscela intensa diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 42a4aa3cf..02ef74f5b 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -827,6 +827,14 @@ digits Malayalam マラヤーラム数字 Shield Buff シールド Outlines and Rules アウトラインと罫線 Hand-Drawn 手描き風 + Painted and Sketched 絵画とスケッチ + Washed Blue にじみブルー + Bristle Ochre 筆跡オーカー + Pastel Heather パステルヘザー + Charcoal Shade 木炭シェード + Ink Contour インク輪郭 + Wet Ink 濡れ墨 + Fine Pen 細いペン Gradient Finishes グラデーション仕上げ Shape Effects シェイプ効果 Blends and Transparency ブレンドと透明 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 30b0abd6b..82453c673 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -700,6 +700,14 @@ Shield Buff ფარი Outlines and Rules კონტურები და ხაზები Hand-Drawn ხელით დახატული + Painted and Sketched დახატული და ესკიზური + Washed Blue გარეცხილი ლურჯი + Bristle Ochre ფუნჯის ოხრა + Pastel Heather პასტელის იისფერი + Charcoal Shade ნახშირის ჩრდილი + Ink Contour მელნის კონტური + Wet Ink სველი მელანი + Fine Pen წვრილი კალამი Gradient Finishes გრადიენტული ზედაპირები Shape Effects ფიგურის ეფექტები Blends and Transparency გადასვლები და გამჭვირვალობა diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 3bc8360b4..6e3c6cfc0 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -820,6 +820,14 @@ digits Malayalam 말라얄람어 Shield Buff 방패 Outlines and Rules 윤곽선과 괘선 Hand-Drawn 손그림 + Painted and Sketched 페인팅과 스케치 + Washed Blue 번진 파랑 + Bristle Ochre 붓결 황토 + Pastel Heather 파스텔 헤더 + Charcoal Shade 목탄 음영 + Ink Contour 잉크 윤곽 + Wet Ink 젖은 먹 + Fine Pen 가는 펜 Gradient Finishes 그레이디언트 마감 Shape Effects 모양 효과 Blends and Transparency 블렌드와 투명도 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index c6f37b432..6f0096eb1 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -755,6 +755,14 @@ Shield Buff Schild Outlines and Rules Omtrekken en lijnen Hand-Drawn Handgetekend + Painted and Sketched Geschilderd en geschetst + Washed Blue Verwassen blauw + Bristle Ochre Borsteloker + Pastel Heather Pastelheide + Charcoal Shade Houtskoolschaduw + Ink Contour Inktcontour + Wet Ink Natte inkt + Fine Pen Fijne pen Gradient Finishes Verloopafwerkingen Shape Effects Vormeffecten Blends and Transparency Vermengingen en transparantie diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 3647b56f5..57a7567e4 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -750,6 +750,14 @@ Shield Buff Tarcza Outlines and Rules Kontury i linie Hand-Drawn Rysowane odręcznie + Painted and Sketched Malowane i szkicowane + Washed Blue Rozmyty błękit + Bristle Ochre Ochra pędzlem + Pastel Heather Pastelowy wrzos + Charcoal Shade Cień węglem + Ink Contour Kontur tuszem + Wet Ink Mokry tusz + Fine Pen Cienkie pióro Gradient Finishes Wykończenia gradientowe Shape Effects Efekty kształtów Blends and Transparency Przejścia i przezroczystość diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 530a62719..0623cd815 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -1277,6 +1277,14 @@ antiAlias Sharp Nítido Hair Space Espaço Fino Hand Tool Ferramenta Mão Hand-Drawn Desenhado à Mão + Painted and Sketched Pintado e Esboçado + Washed Blue Azul Lavado + Bristle Ochre Ocre de Cerdas + Pastel Heather Urze Pastel + Charcoal Shade Sombra a Carvão + Ink Contour Contorno a Nanquim + Wet Ink Nanquim Úmido + Fine Pen Pena Fina Handles Alças Hard Light Luz Forte Hard Mix Mistura definida diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 341dc196f..1f8ee5bee 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -1462,6 +1462,14 @@ file-filter Templates Шаблоны Hair Space Волосяная шпация Hand Tool Инструмент «Рука» Hand-Drawn Нарисованный от руки + Painted and Sketched Живопись и эскизы + Washed Blue Размытый синий + Bristle Ochre Охра кистью + Pastel Heather Пастельный вереск + Charcoal Shade Тень углём + Ink Contour Контур тушью + Wet Ink Влажная тушь + Fine Pen Тонкое перо Handles Маркеры Hard Light Жёсткий свет Hard Mix Жёсткое наложение diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index ed59d9811..753a6b44d 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -1411,6 +1411,14 @@ font-technology Variable Variabla Hair Space Hårfint blanksteg Hand Tool Handverktyg Hand-Drawn Handritad + Painted and Sketched Målat och skissat + Washed Blue Urtvättad blå + Bristle Ochre Borstockra + Pastel Heather Pastelljung + Charcoal Shade Kolskugga + Ink Contour Tuschkontur + Wet Ink Våt tusch + Fine Pen Fin penna Handles Handtag Hard Light Hårt ljus Hard Mix Hård blandning diff --git a/crates/ui-egui/src/i18n/tests.rs b/crates/ui-egui/src/i18n/tests.rs index c63e00079..44ee531d7 100644 --- a/crates/ui-egui/src/i18n/tests.rs +++ b/crates/ui-egui/src/i18n/tests.rs @@ -238,6 +238,20 @@ fn anti_aliasing_method_labels_are_in_complete_catalogs() { } } +/// The Painted and Sketched graphic style library's name and its styles' names have a row in every +/// bundled catalog. +#[test] +fn painted_and_sketched_style_names_are_in_every_catalog() { + let lib = vectorcraft_doc::style_libs::builtin_style_library("painted-sketched").expect("built in"); + let labels: Vec<&str> = std::iter::once(lib.name.as_str()).chain(lib.styles.iter().map(|g| g.name.as_str())).collect(); + assert_eq!(labels.len(), 8); + for lang in LANGUAGES.iter().filter(|lang| !lang.source.is_empty()) { + for label in &labels { + assert!(lang.catalog().plain(label).is_some(), "{} is missing {label}", lang.code); + } + } +} + /// Each language counts with its own plural rule: the form a count picks (`one`, then `few`, then /// `other`/`many`). #[test] diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index dc89f3380..f0c5cf578 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -1375,6 +1375,14 @@ font-technology Variable Değişken Hair Space Saç Alanı Hand Tool El Aracı Hand-Drawn elle çizilmiş + Painted and Sketched Boyanmış ve Eskiz + Washed Blue Soluk Mavi + Bristle Ochre Fırça Darbeli Toprak Sarısı + Pastel Heather Pastel Funda + Charcoal Shade Kömür Gölge + Ink Contour Mürekkep Kontur + Wet Ink Islak Mürekkep + Fine Pen İnce Kalem Handles Kollar Hard Light Sert Işık Harmony Rules: Uyum Kuralları: diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 8d67846ec..2e41ccb2c 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -1459,6 +1459,14 @@ file-filter Templates Шаблони Hair Space Волосяна шпація Hand Tool Інструмент «Рука» Hand-Drawn Намальований від руки + Painted and Sketched Мальовані та ескізні + Washed Blue Розмитий синій + Bristle Ochre Охра пензлем + Pastel Heather Пастельний верес + Charcoal Shade Тінь вугіллям + Ink Contour Контур тушшю + Wet Ink Мокра туш + Fine Pen Тонке перо Handles Маркери Hard Light Жорстке світло Hard Mix Жорстке накладання diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 8f1ea434f..2712e5321 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -1686,6 +1686,14 @@ file-filter Templates Mẫu Halo Vầng hào quang Hand Tool Công cụ Bàn tay Hand-Drawn Vẽ tay + Painted and Sketched Vẽ màu và phác thảo + Washed Blue Xanh nhạt nhòa + Bristle Ochre Vàng đất cọ khô + Pastel Heather Tím phấn màu + Charcoal Shade Bóng than + Ink Contour Đường viền mực + Wet Ink Mực ướt + Fine Pen Bút mảnh Handles Tay nắm Hard Cứng Hard Light Ánh sáng mạnh diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 05c6539bf..7f0c0aad8 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -1402,6 +1402,14 @@ file-filter Templates 模板 Hair Space 极细空格 Hand Tool 抓手工具 Hand-Drawn 手绘 + Painted and Sketched 绘画与素描 + Washed Blue 水洗蓝 + Bristle Ochre 干刷土黄 + Pastel Heather 粉彩淡紫 + Charcoal Shade 炭笔阴影 + Ink Contour 墨线轮廓 + Wet Ink 湿墨 + Fine Pen 细笔 Handles 手柄 Hard Light 强光 Hard Mix 实色混合 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index cb8a61362..37032585a 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -1430,6 +1430,14 @@ file-filter Templates 範本 Hair Space 極細空格 Hand Tool 手形工具 Hand-Drawn 手繪 + Painted and Sketched 繪畫與素描 + Washed Blue 水洗藍 + Bristle Ochre 乾刷土黃 + Pastel Heather 粉彩淡紫 + Charcoal Shade 炭筆陰影 + Ink Contour 墨線輪廓 + Wet Ink 濕墨 + Fine Pen 細筆 Handles 控制把手 Hard Light 實光 Hard Mix 實色混合 diff --git a/crates/ui-egui/src/panels/tests_style_libraries.rs b/crates/ui-egui/src/panels/tests_style_libraries.rs index a77681938..46c274dee 100644 --- a/crates/ui-egui/src/panels/tests_style_libraries.rs +++ b/crates/ui-egui/src/panels/tests_style_libraries.rs @@ -101,6 +101,30 @@ fn clicking_a_library_style_adds_and_applies_it_in_one_step() { assert!(last_open(&app.ui).is_none()); } +#[test] +fn painted_and_sketched_opens_from_the_window_menu_and_a_click_applies_its_style() { + let mut app = app(); + let entry = crate::menus::menu_entries(&app) + .into_iter() + .find(|e| e.path == ["Window", "Graphic Style Libraries"] && e.label == "Painted and Sketched") + .expect("a Window menu item"); + assert_eq!((entry.command.as_deref(), &entry.params["library"]), (Some("window.graphicStyleLibrary"), &json!("painted-sketched"))); + let rect = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 80, "height": 40})).unwrap()["id"].as_u64().unwrap(); + app.run(entry.command.as_deref().unwrap(), entry.params.clone()).unwrap(); + assert_eq!(last_open(&app.ui).map(|p| (p.kind.as_str(), p.id.as_str())), Some(("graphicStyles", "painted-sketched"))); + let ctx = context(); + let undo = undo_len(&app); + click(&mut app, &ctx, "Charcoal Shade", Modifiers::NONE, 0.0); + let (g, linked) = app.session.selection_graphic_style().expect("applied to the selection"); + assert_eq!((g.name.as_str(), linked), ("Charcoal Shade", true)); + assert_eq!(undo_len(&app), undo + 1, "added and applied as one undo step"); + let node = app.session.doc().unwrap().doc.node(vectorcraft_doc::NodeId(rect)).unwrap().appearance.effects.clone(); + assert_eq!(node.iter().map(|e| e.id.as_str()).collect::>(), ["sketch.charcoal"]); + let lib = GraphicStyleLibraries::get(&app, "painted-sketched").unwrap().1; + let rows = GraphicStyleLibraries::rows(&lib, "ink"); + assert_eq!(rows.iter().map(|r| r.name).collect::>(), ["Ink Contour", "Wet Ink"]); +} + #[test] fn the_window_menu_and_the_panel_open_every_library() { let mut app = app(); diff --git a/docs/gaps.md b/docs/gaps.md index a228181ab..d7daac670 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -646,11 +646,12 @@ macOS cursor delivery (#2292) is narrowed to a native host adapter using the exi Direct Selection of a path, compound path or type inside a dynamic instance also takes opacity and blend (`transparency.set`) and a gradient or pattern fill or stroke (`paint.setFill` / `paint.setStroke`, Eyedropper), for that instance only; - graphic style libraries (Window › Graphic Style Libraries; eight original libraries generated in code, including - Game HUD with Health Fill, Mana Glow, Damage Flash, Quest Outline, Coin Shine and Boss Alert, and Status Effects - with Poison Tint, Freeze Edge, Burn Aura, Stun Pulse, Stealth Fade and Shield Buff; User Defined; Other + graphic style libraries (Window › Graphic Style Libraries; nine original libraries generated in code, including + Game HUD with Health Fill, Mana Glow, Damage Flash, Quest Outline, Coin Shine and Boss Alert, Status Effects + with Poison Tint, Freeze Edge, Burn Aura, Stun Pulse, Stealth Fade and Shield Buff, and Painted and Sketched with + Washed Blue, Bristle Ochre, Pastel Heather, Charcoal Shade, Ink Contour, Wet Ink and Fine Pen; User Defined; Other Library…; `graphicStyle.libraries`, `graphicStyle.addFromLibrary`). -- **Missing:** more built-in brush libraries beyond the six shipped (and further graphic-style libraries beyond the eight shipped, and further symbol libraries beyond Basic +- **Missing:** more built-in brush libraries beyond the six shipped (and further graphic-style libraries beyond the nine shipped, and further symbol libraries beyond Basic Shapes, UI Frames, Map Markers, Inventory Icons and Skill Icons; original, generated in code, never Adobe's); dynamic symbols' `.ai` read and write; Global Edit of groups holding type or images, rotated copies as matches and highlighting matches before the start; 9-slice guides outside the symbol's art (a dragged guide stops at the art's edge). diff --git a/docs/mcp.md b/docs/mcp.md index 7f6df7983..3cd41ab91 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -3353,7 +3353,7 @@ as a value left out. ## Graphic style libraries Graphic style libraries are read-only sets of graphic styles generated in code (Shadows and Glows, Outlines and -Rules, Hand-Drawn, Gradient Finishes, Shape Effects, Blends and Transparency, Game HUD, Status Effects). `graphicStyle.libraries` lists them +Rules, Hand-Drawn, Painted and Sketched, Gradient Finishes, Shape Effects, Blends and Transparency, Game HUD, Status Effects). `graphicStyle.libraries` lists them (`id`, `name`, `category`: `builtIn`, `user` or `loaded`, `count`) and `graphicStyle.library {library}` returns one's styles in the `graphicStyle.list` shape (`library` is an id or a name). `graphicStyle.addFromLibrary {library, name? | names?}` copies styles into the document's Graphic Styles as one undo step (no names: the whole library); styles the @@ -3363,6 +3363,13 @@ the patterns the styles paint with come along. `apply: true` also applies the fi does. Library styles keep placed gradients in unit-box space, so each object gets them at the same place relative to its bounds. +Painted and Sketched (`painted-sketched`) holds Washed Blue, Bristle Ochre, Pastel Heather, Charcoal Shade, Ink +Contour, Wet Ink and Fine Pen. Each is a solid fill (Bristle Ochre and Ink Contour add a 1 pt stroke) under one object +effect that repaints fill and stroke together: `artistic.watercolor`, `artistic.dryBrush`, `artistic.roughPastels`, +`sketch.charcoal`, `brushStrokes.inkOutlines`, `brushStrokes.sumiE` and `sketch.graphicPen`, in that order. The +colors and effect settings are VectorCraft's own. These are raster effects, so the document's raster effects +resolution sets how fine they draw. + ```json {"name":"run_command","arguments":{"command":"graphicStyle.library","params":{"library":"hand-drawn"}}} {"name":"run_command","arguments":{"command":"graphicStyle.addFromLibrary","params":{"library":"hand-drawn","name":"Crosshatch","apply":true}}} diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 908895ad6..09e7620c4 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1354,7 +1354,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - **Transparency:** three-state Knockout Group (on, neutral, off), Opacity & Mask Define Knockout Shape, Page Isolated Blending and Page Knockout Group, on screen and in SVG/PDF. SVG export writes a knockout group of opaque art plainly, without masks, so shapes meeting edge to edge leave no seam; translucent, blended, masked or brushed art knocks out through masks. Blend modes match the standard formulas on screen, in SVG and in PDF, and non-isolated groups blend with the art below. Flatten Transparency with presets, a dialog and a Flattener Preview panel. Flattening for files without transparency (PDF/X-1a, PDF/X-3) in a CMYK document keeps the inks where it rasterizes, as under an image with see-through pixels: the images it makes hold ink amounts, not screen colours the file would separate again, so a C100 M6 Y41 K3 panel stays C100 M6 Y41 K3 there (#2160, `engine/src/cmd/fileio/tests_pdfx.rs`). On the canvas, the renderer no longer draws the picture of the art below back as an image each time it copies the backdrop of a non-isolated group that blends: it keeps that picture and draws the art that follows over it. At 2880 × 1800, 50 translucent groups with Multiply members take 65 ms a frame instead of 299 ms on 8 threads (`vectorcraft-cli bench`), and the frames have the same pixels. Type inside a group, layer, symbol instance, blend or repeat keeps its opacity, blend mode, opacity mask, Opacity & Mask Define Knockout Shape, own effects, perspective and visibility when the effects on the container outline it. Hidden type with a geometry effect of its own is left out of exports. - - **Graphic styles:** styles keep opacity and blend mode, capture groups and type, apply on top with Alt, and link to the objects using them; Redefine, Break Link, Graphic Style Options, Select All Unused, Sort by Name, and Select > Same Graphic Style / Appearance Attribute. The panel has list and thumbnail views with rendered previews, merge, reorder and drag and drop, plus a Control bar Style picker; eight generated style libraries (including Game HUD and Status Effects) save and load as `.vcstyles`. + - **Graphic styles:** styles keep opacity and blend mode, capture groups and type, apply on top with Alt, and link to the objects using them; Redefine, Break Link, Graphic Style Options, Select All Unused, Sort by Name, and Select > Same Graphic Style / Appearance Attribute. The panel has list and thumbnail views with rendered previews, merge, reorder and drag and drop, plus a Control bar Style picker; nine generated style libraries (including Game HUD, Status Effects, and Painted and Sketched, whose seven styles each repaint a solid fill with one watercolor, dry brush, pastel, charcoal or ink effect) save and load as `.vcstyles`. In the Graphic Styles panel, Shift-click selects a range of styles and Ctrl/Cmd-click adds or removes one. Applying a style to several objects, and Redefine Graphic Style, give the objects one shared copy of the style's appearance instead of a copy each; an object that is edited later gets its own copy, and an object whose placed gradients are fitted to its own bounds gets its own. The undo history's memory estimate counts a shared appearance once. Saved files are unchanged (`crates/engine/src/tests/styles.rs`). - **Several text styles at once:** in the Character Styles and Paragraph Styles panels, Shift-click highlights a range of styles and Ctrl/Cmd-click adds or removes one, without applying them; the panel menu's Select All Unused (`charStyle.unused`, `paraStyle.unused`) highlights the styles no type uses (in the layers, opacity masks, symbols, graph designs, pattern tiles and the art of brushes), never the Normal style; Delete, the button or the menu item, deletes every highlighted style but Normal in one undo step (`charStyle.delete {names}`, `paraStyle.delete {names}`). The menu's Duplicate copies every highlighted style in one undo step and highlights the copies. A highlighted row dragged onto Create New Style or Delete carries every highlighted style: dropped on Create New Style it copies them all and highlights the copies, and dropped on Delete it deletes them all but Normal and clears the highlight; a row from outside the highlight carries only its own style. Public reference: [Character and paragraph styles](https://web.archive.org/web/20261015081534/https://helpx.adobe.com/illustrator/using/character-paragraph-styles.html).