mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 21:57:04 +00:00
Merge pull request #7662 from ruchirguitar/feat/style-neon-glow
Graphic Styles: built-in Neon & Glow graphic style library
This commit is contained in:
+2
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
**Stage: alpha** · next: beta, ~13 points (ready for real work ~62% → ~75%, and reliable `.ai` exchange) and ~170–270 h away
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-14 · **Change:** minor (Tech Circuit brush library, G5; previously: docs tidy-up, no content change: stray notes at the top moved into the revision table; scores and estimates unchanged; previously minor: Raster effects 85% → 88%, gallery thumbnails and in-dialog preview in; headline numbers unchanged; Symbols area ~87% → ~88%: dynamic instance parts take opacity, blend, gradient and pattern on the canvas; G5 docs sync for Overlap and Pattern auto corners; previously minor: Tools stays beside the canvas with left-side panels; Hindi catalog draft complete under the translation tests; contributor loanword terminology reviewed; wider proofreading welcome; Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; new gradients follow document color mode; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-15 · **Change:** minor (G5: built-in Neon & Glow graphic style library (Cyan Neon, Magenta Laser, Amber Tube, Electric Lime, Pulse Violet, Cobalt Phosphor); G5 estimate unchanged (3–13 h); previously: Tech Circuit brush library, G5; previously: docs tidy-up, no content change: stray notes at the top moved into the revision table; scores and estimates unchanged; previously minor: Raster effects 85% → 88%, gallery thumbnails and in-dialog preview in; headline numbers unchanged; Symbols area ~87% → ~88%: dynamic instance parts take opacity, blend, gradient and pattern on the canvas; G5 docs sync for Overlap and Pattern auto corners; previously minor: Tools stays beside the canvas with left-side panels; Hindi catalog draft complete under the translation tests; contributor loanword terminology reviewed; wider proofreading welcome; Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; new gradients follow document color mode; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
VectorCraft is a clean-room, open-source, pure-Rust reimplementation of the Adobe Illustrator workflow. It runs
|
||||
on macOS, Windows, Linux, FreeBSD and the web (WASM), and agents can drive all of it over MCP, the CLI and a JSON
|
||||
@@ -225,6 +225,7 @@ The full earlier record of what landed is kept in [docs/roadmap.md](docs/roadmap
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-15 | minor | Graphic Styles: built-in Neon & Glow graphic style library (Cyan Neon, Magenta Laser, Amber Tube, Electric Lime, Pulse Violet, Cobalt Phosphor); G5 estimate unchanged (3–13 h). |
|
||||
| 2026-11-14 | minor | Tech Circuit adds three original procedural brushes (Circuit Trace, Bus Lines, Terminal Nodes); ten built-in brush libraries. G5 remaining estimate 3–13 h (estimated); parity scores and headline totals unchanged. |
|
||||
| 2026-11-14 | minor | Gujarati (#6613): contributor proofreading completed for all 387 additions, with 11 wording corrections; 4,673 reviewed catalog rows. Status/error messages remain partial; web selection requires a bundled Gujarati face. Scores and estimates unchanged. |
|
||||
| 2026-11-10 | minor | Tidy-up, no content change: the unheaded change bullets at the top of the file and a revision row inside the headline-numbers table move to this table under their commit dates. Scores and estimates unchanged. |
|
||||
|
||||
@@ -162,6 +162,7 @@ pub const STYLE_LIBRARIES: &[BuiltinStyleLibrary] = &[
|
||||
BuiltinStyleLibrary { id: "blends-transparency", name: "Blends and Transparency", make: blends_transparency },
|
||||
BuiltinStyleLibrary { id: "game-hud", name: "Game HUD", make: game_hud },
|
||||
BuiltinStyleLibrary { id: "status-effects", name: "Status Effects", make: status_effects },
|
||||
BuiltinStyleLibrary { id: "neon-glow", name: "Neon & Glow", make: neon_glow },
|
||||
];
|
||||
|
||||
/// Built-in library `id`, made once.
|
||||
@@ -619,6 +620,44 @@ fn status_effects() -> Vec<GraphicStyle> {
|
||||
]
|
||||
}
|
||||
|
||||
/// Neon & Glow: original multi-layer procedural styles with neon tubes, laser beams, and glowing halos.
|
||||
fn neon_glow() -> Vec<GraphicStyle> {
|
||||
vec![
|
||||
style(
|
||||
"Cyan Neon",
|
||||
vec![S(StrokeLayer { opacity: 0.7, ..round("#00e5ff", 6.0) }), S(round("#ffffff", 1.5))],
|
||||
vec![fx("stylize.dropShadow", json!({"mode": "screen", "opacity": 85.0, "x": 0.0, "y": 0.0, "blur": 8.0, "color": "#00e5ff"}))],
|
||||
),
|
||||
GraphicStyle {
|
||||
blend: BlendMode::Screen,
|
||||
..style(
|
||||
"Magenta Laser",
|
||||
vec![S(StrokeLayer { blend: BlendMode::Screen, ..round("#ff007f", 5.0) }), S(round("#ffffff", 1.5))],
|
||||
vec![fx("stylize.outerGlow", json!({"mode": "screen", "opacity": 90.0, "blur": 8.0, "color": "#ff007f"}))],
|
||||
)
|
||||
},
|
||||
style(
|
||||
"Amber Tube",
|
||||
vec![S(StrokeLayer { opacity: 0.8, ..round("#ff8c00", 6.0) }), S(round("#ffea00", 1.5))],
|
||||
vec![fx("stylize.outerGlow", json!({"mode": "screen", "opacity": 85.0, "blur": 8.0, "color": "#ff8c00"}))],
|
||||
),
|
||||
style(
|
||||
"Electric Lime",
|
||||
vec![S(StrokeLayer { opacity: 0.75, ..round("#39ff14", 6.0) }), S(round("#ffffff", 1.5))],
|
||||
vec![fx("stylize.outerGlow", json!({"mode": "screen", "opacity": 90.0, "blur": 8.0, "color": "#39ff14"}))],
|
||||
),
|
||||
style(
|
||||
"Pulse Violet",
|
||||
vec![S(StrokeLayer { opacity: 0.75, ..round("#7b2cbf", 5.0) }), S(round("#e0aaff", 1.5))],
|
||||
vec![
|
||||
fx("stylize.innerGlow", json!({"mode": "screen", "opacity": 75.0, "blur": 6.0, "color": "#c77dff", "source": "edge"})),
|
||||
fx("stylize.outerGlow", json!({"mode": "screen", "opacity": 85.0, "blur": 8.0, "color": "#7b2cbf"})),
|
||||
],
|
||||
),
|
||||
style("Cobalt Phosphor", vec![S(round("#0047ab", 6.0)), S(round("#ffffff", 1.5))], vec![fx("blur.gaussian", json!({"radius": 2.0}))]),
|
||||
]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -750,4 +789,36 @@ mod tests {
|
||||
let Paint::Gradient(gp) = g.appearance.fill_paint() else { panic!("a gradient") };
|
||||
assert!(gp.swatch.is_none() && gp.gradient.stops.iter().all(|s| s.swatch.is_none() && s.tint == 1.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn neon_and_glow_styles_are_defined_with_multi_strokes_and_effects() {
|
||||
let lib = builtin_style_library("neon-glow").expect("neon-glow library exists");
|
||||
assert_eq!(lib.name, "Neon & Glow");
|
||||
assert_eq!(lib.len(), 6);
|
||||
let names: Vec<&str> = lib.styles.iter().map(|g| g.name.as_str()).collect();
|
||||
assert_eq!(names, ["Cyan Neon", "Magenta Laser", "Amber Tube", "Electric Lime", "Pulse Violet", "Cobalt Phosphor"]);
|
||||
for g in &lib.styles {
|
||||
let strokes = g.appearance.items.iter().filter(|i| matches!(i, AppearanceItem::Stroke(_))).count();
|
||||
assert!(strokes >= 2, "{} has {} strokes, expected >= 2", g.name, strokes);
|
||||
assert!(!g.appearance.effects.is_empty(), "{} has effects", g.name);
|
||||
}
|
||||
let cyan = lib.style("Cyan Neon").unwrap();
|
||||
assert_eq!(cyan.appearance.effects[0].id, "stylize.dropShadow");
|
||||
let magenta = lib.style("Magenta Laser").unwrap();
|
||||
assert_eq!(magenta.blend, BlendMode::Screen);
|
||||
let pulse = lib.style("Pulse Violet").unwrap();
|
||||
let pulse_fx: Vec<&str> = pulse.appearance.effects.iter().map(|e| e.id.as_str()).collect();
|
||||
assert_eq!(pulse_fx, ["stylize.innerGlow", "stylize.outerGlow"]);
|
||||
let cobalt = lib.style("Cobalt Phosphor").unwrap();
|
||||
assert_eq!(cobalt.appearance.effects[0].id, "blur.gaussian");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn neon_glow_round_trips_through_vcstyles() {
|
||||
let lib = builtin_style_library("neon-glow").unwrap();
|
||||
let text = write(&lib);
|
||||
assert!(sniff(&text));
|
||||
let read_back = read(&text, "Fallback").unwrap();
|
||||
assert_eq!(*lib, read_back);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ fn builtin_libraries_are_listed_with_original_styles_using_catalogued_effects()
|
||||
assert!(libs.iter().any(|l| l["id"] == "game-hud" && l["name"] == "Game HUD"), "{libs:?}");
|
||||
assert!(libs.iter().any(|l| l["id"] == "status-effects" && l["name"] == "Status Effects"), "{libs:?}");
|
||||
assert!(libs.iter().any(|l| l["id"] == "textures" && l["name"] == "Textures" && l["count"] == 8), "{libs:?}");
|
||||
assert!(libs.iter().any(|l| l["id"] == "neon-glow" && l["name"] == "Neon & Glow" && l["count"] == 6), "{libs:?}");
|
||||
for l in libs {
|
||||
let id = l["id"].as_str().unwrap();
|
||||
let g = run(&mut s, "graphicStyle.library", json!({"library": id}));
|
||||
@@ -69,6 +70,9 @@ fn builtin_libraries_are_listed_with_original_styles_using_catalogued_effects()
|
||||
let texture_names: Vec<&str> = textures["styles"].as_array().unwrap().iter().map(|x| x["name"].as_str().unwrap()).collect();
|
||||
let expected = ["Fine Grain", "Canvas Weave", "Burlap Sack", "Cracked Glaze", "Mosaic Floor", "Quilted Squares", "Leaded Glass", "Damp Paper"];
|
||||
assert_eq!(texture_names, expected);
|
||||
let neon = run(&mut s, "graphicStyle.library", json!({"library": "neon-glow"}));
|
||||
let neon_names: Vec<&str> = neon["styles"].as_array().unwrap().iter().map(|x| x["name"].as_str().unwrap()).collect();
|
||||
assert_eq!(neon_names, ["Cyan Neon", "Magenta Laser", "Amber Tube", "Electric Lime", "Pulse Violet", "Cobalt Phosphor"]);
|
||||
let id = rect(&mut s, 10.0, 20.0, 40.0, 30.0);
|
||||
let r = run(&mut s, "graphicStyle.addFromLibrary", json!({"library": "game-hud", "name": "Mana Glow", "apply": true, "ids": [id.0]}));
|
||||
assert_eq!((names(&r["added"]), r["applied"].as_str()), (vec!["Mana Glow"], Some("Mana Glow")));
|
||||
@@ -419,3 +423,53 @@ fn every_builtin_style_paints_visibly_on_a_rectangle() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn neon_and_glow_library_adds_and_applies_multi_stroke_styles() {
|
||||
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"] == "neon-glow").expect("neon-glow listed");
|
||||
assert_eq!(libs[at]["name"], "Neon & Glow");
|
||||
assert_eq!(libs[at]["count"], 6);
|
||||
|
||||
let (_, lib) = cmd::stylelib::library(&s, "neon-glow").unwrap();
|
||||
assert_eq!(lib.len(), 6);
|
||||
|
||||
let want = [
|
||||
("Cyan Neon", 2, "stylize.dropShadow"),
|
||||
("Magenta Laser", 2, "stylize.outerGlow"),
|
||||
("Amber Tube", 2, "stylize.outerGlow"),
|
||||
("Electric Lime", 2, "stylize.outerGlow"),
|
||||
("Pulse Violet", 2, "stylize.innerGlow"),
|
||||
("Cobalt Phosphor", 2, "blur.gaussian"),
|
||||
];
|
||||
|
||||
for (i, (name, stroke_count, first_effect)) in want.iter().enumerate() {
|
||||
let id = rect(&mut s, 10.0 + 30.0 * i as f64, 15.0, 25.0, 25.0);
|
||||
let before_undo = undo_len(&s);
|
||||
let r = run(&mut s, "graphicStyle.addFromLibrary", json!({"library": "neon-glow", "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_undo + 1, "{name}");
|
||||
|
||||
let node = doc(&s).node(id).unwrap();
|
||||
let strokes = node.appearance.items.iter().filter(|it| matches!(it, vectorcraft_doc::AppearanceItem::Stroke(_))).count();
|
||||
assert_eq!(strokes, *stroke_count, "{name}");
|
||||
assert_eq!(node.appearance.effects[0].id, *first_effect, "{name}");
|
||||
}
|
||||
|
||||
// Adding existing style dedupes and creates no new undo step.
|
||||
let before = (undo_len(&s), doc(&s).graphic_styles.len());
|
||||
let r = run(&mut s, "graphicStyle.addFromLibrary", json!({"library": "neon-glow", "name": "Cyan Neon"}));
|
||||
assert_eq!((names(&r["added"]), names(&r["existing"])), (vec![], vec!["Cyan Neon"]));
|
||||
assert_eq!((undo_len(&s), doc(&s).graphic_styles.len()), before);
|
||||
|
||||
// Round-trip through serialize / open
|
||||
let b64 = run(&mut s, "document.serialize", json!({}))["dataBase64"].as_str().unwrap().to_string();
|
||||
run(&mut s, "document.open", json!({"name": "neon.vectorcraft", "dataBase64": b64}));
|
||||
for (name, _, _) in want {
|
||||
let d = doc(&s);
|
||||
let st = d.graphic_style(name).unwrap();
|
||||
assert!(st.same_look(lib.style(name).unwrap()), "{name}");
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
File diff suppressed because one or more lines are too long
+2
-1
@@ -1,6 +1,6 @@
|
||||
# Roadmap: milestones and what's next
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-14 · **Change:** minor (Tech Circuit brush library, G5; previously: Graphic Styles list fills a taller panel, #2992; scores and estimates unchanged; previously: PDF import: glyphs in a span with an empty ActualText come in as outlines, #6971; scores and estimates unchanged; previously: library panels' lists fill a taller panel, #2992; scores and estimates unchanged; previously: Swatches list fills a taller panel, #1638; scores and estimates unchanged; previously: icon-strip flyouts also resize from the top edge and the canvas-side top corner, keeping the moved top in workspaces (storytold/craft-libs#1094); scores and estimates unchanged; previously: #6865: explicitly requested oversized editing artboard; Live Paint Bucket fills faces crossed in one drag (#6373); previously: #6404: transform-aware Eyedropper character copying; scores and estimates unchanged; previously: M10/G5: Energy Beams brush library; MCP docs list Energy Beams; previously minor: M10/G5: Skill Icons symbol library; MCP docs list Skill Icons; previously minor: M10/G5: Status Effects graphic style library; MCP docs catch-up for symbol libraries; previously minor: M10/G5: Inventory Icons built-in symbol library; previously minor: Edit › Edit Custom Dictionary…: its dialog adds, deletes and changes the custom dictionary's words, #4936; previously minor: M10/G5: Game HUD graphic style library; previously minor: resizable icon-strip flyouts and bottom-aligned panel footers, #5713; previously minor: M10/G5: Map Markers built-in symbol library; previously minor: right-click on type: Spelling › Auto Spell Check, with its check mark, #4936; previously minor: right-click on a word Auto Spell Check underlined: its suggestions, Ignore All and Add to Dictionary, #4936; previously minor: G2: Effect Gallery thumbnails and in-dialog preview are in; Auto Spell Check: `edit.autoSpellCheck` underlines the unknown words, #4936; previously minor: PDF editable import preserves authored ActualText once, including empty/nested spans and authored ordering (#6165); cross-line/style layout remains approximate; scores and estimates unchanged; PDF marked-text export (#6309): compatible glyphs stay on one layout line with per-glyph offsets; scores and estimates unchanged; interim macOS cursor delivery, #2292; native validation pending; scores and estimates unchanged; Control bar › Snapping includes the existing Snap to Glyph and Alignment Guides toggles (#6164); scores and estimates unchanged; custom dictionary and Ignore All: `text.spelling.addWord`, `removeWord`, `changeWord`, `dictionary` and `ignoreAll`, #4936; previously minor: EPS import: embedded fonts (composite, Type 42, CID-keyed, Type 1, CFF FontSet) draw their glyphs; spell check engine: `text.spelling.check` and `text.spelling.suggest` on craft-proof, #4936; previously minor: floating tab groups collapse into the side icon rail and opened rail panels fold back into it, #5925 in part; M4/M7: `.ai`/EPS type keeps its tab stops, and right-aligned lines with tabs lay out as the file's page, #6147; M4/M7: `.ai`/EPS type from the text document lays its lines out closer to the file's page, within limits, #6137; numeric fields step on wheel hover without taking keyboard focus, #5949; Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen; Selection QoL: marquee modes and visible feedback, #5313; SVG CSS classes survive export and repeated import in all four styling modes (#2480); current-main integration retains event attributes and scripts; #3380 deletion-only review follow-up: independent survivors keep gradient placement, owned subpaths avoid discarded copies, and contracts/status/evidence are clarified; endpoint highlighting remains open; scores and estimates unchanged; Indian-language hyphenation review and license allowlist, #4947; Hindi catalog and contributor loanword preferences; full wording review in progress; Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; shape tools move the selection from its centre point and turn it from the zone outside a box corner, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-15 · **Change:** minor (M10/G5: Neon & Glow built-in graphic style library (Cyan Neon, Magenta Laser, Amber Tube, Electric Lime, Pulse Violet, Cobalt Phosphor); previously: Tech Circuit brush library, G5; previously: Graphic Styles list fills a taller panel, #2992; scores and estimates unchanged; previously: PDF import: glyphs in a span with an empty ActualText come in as outlines, #6971; scores and estimates unchanged; previously: library panels' lists fill a taller panel, #2992; scores and estimates unchanged; previously: Swatches list fills a taller panel, #1638; scores and estimates unchanged; previously: icon-strip flyouts also resize from the top edge and the canvas-side top corner, keeping the moved top in workspaces (storytold/craft-libs#1094); scores and estimates unchanged; previously: #6865: explicitly requested oversized editing artboard; Live Paint Bucket fills faces crossed in one drag (#6373); previously: #6404: transform-aware Eyedropper character copying; scores and estimates unchanged; previously: M10/G5: Energy Beams brush library; MCP docs list Energy Beams; previously minor: M10/G5: Skill Icons symbol library; MCP docs list Skill Icons; previously minor: M10/G5: Status Effects graphic style library; MCP docs catch-up for symbol libraries; previously minor: M10/G5: Inventory Icons built-in symbol library; previously minor: Edit › Edit Custom Dictionary…: its dialog adds, deletes and changes the custom dictionary's words, #4936; previously minor: M10/G5: Game HUD graphic style library; previously minor: resizable icon-strip flyouts and bottom-aligned panel footers, #5713; previously minor: M10/G5: Map Markers built-in symbol library; previously minor: right-click on type: Spelling › Auto Spell Check, with its check mark, #4936; previously minor: right-click on a word Auto Spell Check underlined: its suggestions, Ignore All and Add to Dictionary, #4936; previously minor: G2: Effect Gallery thumbnails and in-dialog preview are in; Auto Spell Check: `edit.autoSpellCheck` underlines the unknown words, #4936; previously minor: PDF editable import preserves authored ActualText once, including empty/nested spans and authored ordering (#6165); cross-line/style layout remains approximate; scores and estimates unchanged; PDF marked-text export (#6309): compatible glyphs stay on one layout line with per-glyph offsets; scores and estimates unchanged; interim macOS cursor delivery, #2292; native validation pending; scores and estimates unchanged; Control bar › Snapping includes the existing Snap to Glyph and Alignment Guides toggles (#6164); scores and estimates unchanged; custom dictionary and Ignore All: `text.spelling.addWord`, `removeWord`, `changeWord`, `dictionary` and `ignoreAll`, #4936; previously minor: EPS import: embedded fonts (composite, Type 42, CID-keyed, Type 1, CFF FontSet) draw their glyphs; spell check engine: `text.spelling.check` and `text.spelling.suggest` on craft-proof, #4936; previously minor: floating tab groups collapse into the side icon rail and opened rail panels fold back into it, #5925 in part; M4/M7: `.ai`/EPS type keeps its tab stops, and right-aligned lines with tabs lay out as the file's page, #6147; M4/M7: `.ai`/EPS type from the text document lays its lines out closer to the file's page, within limits, #6137; numeric fields step on wheel hover without taking keyboard focus, #5949; Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen; Selection QoL: marquee modes and visible feedback, #5313; SVG CSS classes survive export and repeated import in all four styling modes (#2480); current-main integration retains event attributes and scripts; #3380 deletion-only review follow-up: independent survivors keep gradient placement, owned subpaths avoid discarded copies, and contracts/status/evidence are clarified; endpoint highlighting remains open; scores and estimates unchanged; Indian-language hyphenation review and license allowlist, #4947; Hindi catalog and contributor loanword preferences; full wording review in progress; Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; shape tools move the selection from its centre point and turn it from the zone outside a box corner, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
>
|
||||
> Oversized artboard import update (2026-11-12): Explicit editing-data import retains a single artboard beyond a capped 14,400 pt PDF page (#6865).
|
||||
>
|
||||
@@ -207,6 +207,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-15 | minor | M10/G5: Neon & Glow built-in graphic style library (Cyan Neon, Magenta Laser, Amber Tube, Electric Lime, Pulse Violet, Cobalt Phosphor); estimates unchanged |
|
||||
| 2026-11-14 | minor | Tech Circuit adds three original procedural brushes (Circuit Trace, Bus Lines, Terminal Nodes); ten built-in brush libraries. G5 remaining estimate 3–13 h (estimated); parity scores and headline totals unchanged. |
|
||||
| 2026-11-14 | minor | Gujarati (#6613): contributor proofreading completed for all 387 additions, with 11 wording corrections; 4,673 reviewed catalog rows. Status/error messages remain partial; web selection requires a bundled Gujarati face. Scores and estimates unchanged. |
|
||||
| 2026-11-12 | minor | Gujarati (`gu`): 4,286-row machine-assisted catalog reviewed by a native speaker, zero/one singular plurals, desktop font fallback and optional Gujarati craft-fonts fallback; all 72 translation tests pass; a web font and about 2,600 untranslated messages remain; scores and estimates unchanged |
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user