diff --git a/crates/engine/src/cmd/buildcmds.rs b/crates/engine/src/cmd/buildcmds.rs
--- a/crates/engine/src/cmd/buildcmds.rs
+++ b/crates/engine/src/cmd/buildcmds.rs
@@ -138,7 +138,7 @@ pub fn specs() -> Vec<CommandSpec> {
             "Make and Expand",
             ["Object", "Image Trace"],
             None,
-            "{…as imageTrace.make} same as imageTrace.make, then expand → {id, paths, anchors, colors}",
+            "{…as imageTrace.make, byColor?: false (each color's paths in a group of their own, as imageTrace.expand)} same as imageTrace.make, then expand → {id, paths, anchors, colors}",
             has_selection_or_ids,
             |s, p| trace_make(s, p, true)
         ),
@@ -156,7 +156,7 @@ pub fn specs() -> Vec<CommandSpec> {
             "Expand",
             ["Object", "Image Trace"],
             None,
-            "{id?, ids?: [id…] (instead of id)} keep only the traced paths (drop the source image) → {ids}",
+            "{id?, ids?: [id…] (instead of id), byColor?: false (each color's paths in a group of their own, named by the swatch the color links to or as #rrggbb, gradient fills in one group named Gradients; the groups stack by their lowest path and keep their paths' order; a color whose paths overlap another color's from above and below gets a group for each part, so the art draws the same; not for a trace made with autoGrouping)} keep only the traced paths (drop the source image) → {ids}",
             has_selection_or_ids,
             trace_expand
         ),
@@ -1103,10 +1103,98 @@ fn grouped(d: &mut Document, nodes: Vec<Node>, parents: &[Option<usize>]) -> Vec
     roots.iter().filter_map(|&r| built.get_mut(r)?.take()).chain(ring).collect()
 }
 
+/// The `byColor` param of an Expand (false when not given).
+fn by_color_param(cmd: &str, p: &Value) -> Result<bool> {
+    match p.get("byColor").filter(|v| !v.is_null()) {
+        Some(v) => v.as_bool().ok_or_else(|| bad(cmd, "byColor must be true or false")),
+        None => Ok(false),
+    }
+}
+
+/// Whether a trace made with `params` can have paths that overlap, as in [`tr::trace_within`]'s
+/// Auto Grouping: stacked layers, Flat Logo's shapes and stroked lines.
+fn stacked_trace(params: &tr::TraceParams) -> bool {
+    params.method == tr::Method::Overlapping || params.mode == tr::Mode::Logo || params.strokes
+}
+
+/// Expand by color: an expanded trace's `items` (bottom-most first) in a group for each paint, a
+/// stroked line counted by its stroke. A solid color's group is named by the swatch it links to (a
+/// tint with its percentage) or as `#rrggbb`, and gradient fills share one group, "Gradients". The
+/// groups stack in the order of the lowest item in each, and each keeps its items' order. When the
+/// paths can overlap (`stacked`), an item joins its paint's last group only if no item of a later
+/// group overlaps it (by the boxes of everything they paint, effects included); otherwise it starts
+/// another group of that paint, so the art draws as before. A group among `items` (Auto Grouping)
+/// is refused.
+fn color_groups(cmd: &str, d: &mut Document, items: Vec<Arc<Node>>, stacked: bool) -> Result<Vec<Arc<Node>>> {
+    use vectorcraft_color::tint_percent;
+    // Grouped by the paint: unlinked (its #rrggbb), linked (the swatch and its exact tint), a
+    // gradient, or another paint (its label). The name is apart from it: a swatch may be named as
+    // a color's `#rrggbb` or as "Gradients".
+    type PaintKey = (u8, String, u32);
+    struct Run {
+        key: PaintKey,
+        name: String,
+        members: Vec<Arc<Node>>,
+        boxes: Vec<Rect>,
+        union: Option<Rect>,
+    }
+    let meet = |a: &Rect, b: &Rect| a.x0 < b.x1 && b.x0 < a.x1 && a.y0 < b.y1 && b.y0 < a.y1;
+    let mut groups: Vec<Run> = vec![];
+    for item in items {
+        if matches!(item.kind, NodeKind::Group { .. }) {
+            return Err(bad(cmd, "byColor can't split Auto Grouping groups: trace without Auto Grouping"));
+        }
+        let paint = match item.appearance.fill_paint() {
+            Paint::None => item.appearance.stroke_paint(),
+            fill => fill,
+        };
+        let (key, name) = match &paint {
+            Paint::Solid { swatch: Some(n), tint, .. } => {
+                let percent = tint_percent(*tint);
+                let name = if *tint < 1.0 { format!("{n} {percent}%") } else { n.clone() };
+                ((1, n.clone(), tint.to_bits()), name)
+            }
+            Paint::Solid { color, .. } => ((0, color.to_hex(), 0), color.to_hex()),
+            Paint::Gradient(_) => ((2, String::new(), 0), "Gradients".to_string()),
+            other => ((3, other.label(), 0), other.label()),
+        };
+        let bounds = if stacked { vectorcraft_render::painted_bounds(d, &item) } else { None };
+        // Joining an earlier group moves the item under every later group's items.
+        let hidden_by_later = |at: usize| {
+            bounds.is_some_and(|b| groups.iter().skip(at + 1).any(|g| g.union.is_some_and(|u| meet(&u, &b)) && g.boxes.iter().any(|m| meet(m, &b))))
+        };
+        let at = groups.iter().rposition(|g| g.key == key).filter(|&at| !hidden_by_later(at));
+        let mut started = Run { key, name, members: vec![], boxes: vec![], union: None };
+        let joins = at.and_then(|at| groups.get_mut(at));
+        let new = joins.is_none();
+        let g = joins.unwrap_or(&mut started);
+        if let Some(b) = bounds {
+            g.boxes.push(b);
+            g.union = Some(g.union.map_or(b, |u| u.union(b)));
+        }
+        g.members.push(item);
+        if new {
+            groups.push(started);
+        }
+    }
+    Ok(groups
+        .into_iter()
+        .map(|run| {
+            let mut g = Node::group(d.alloc_id(), run.members);
+            g.name = Some(run.name);
+            Arc::new(g)
+        })
+        .collect())
+}
+
 fn trace_make(s: &mut Session, p: &Value, expand: bool) -> Result<Value> {
     let c = if expand { "imageTrace.makeAndExpand" } else { "imageTrace.make" };
     let mut params = trace_params(c, p)?;
     let view = view_param(c, p)?;
+    let by_color = expand && by_color_param(c, p)?;
+    if by_color && params.auto_grouping {
+        return Err(bad(c, "byColor can't split Auto Grouping groups: trace without Auto Grouping"));
+    }
     let params_json = serde_json::to_value(&params).map_err(|e| EngineError::Other(e.to_string()))?;
     // The preset's name if the parameters are exactly that preset's or its enhanced version's,
     // else "Custom".
@@ -1193,6 +1281,9 @@ fn trace_make(s: &mut Session, p: &Value, expand: bool) -> Result<Value> {
             traced.push(n);
         }
         children.extend(grouped(d, traced, &res.parents));
+        if by_color {
+            children = color_groups(c, d, children, stacked_trace(&params))?;
+        }
         let gid = d.alloc_id();
         let mut g = Node::group(gid, children);
         g.name = if expand { None } else { Some(TRACE_NAME.into()) };
@@ -1291,7 +1382,17 @@ fn trace_release(s: &mut Session, p: &Value) -> Result<Value> {
 }
 
 fn trace_expand(s: &mut Session, p: &Value) -> Result<Value> {
+    const C: &str = "imageTrace.expand";
+    let by_color = by_color_param(C, p)?;
     let targets = trace_targets(s, p)?;
+    if by_color {
+        // A trace made with Auto Grouping is refused even when none of its paths were grouped.
+        let d = &s.doc()?.doc;
+        let grouped = |n: &Node| n.extras().trace.as_deref().and_then(|t| t.pointer("/params/autoGrouping")).and_then(Value::as_bool) == Some(true);
+        if targets.iter().any(|g| d.node(*g).is_some_and(grouped)) {
+            return Err(bad(C, "byColor can't split Auto Grouping groups: trace without Auto Grouping"));
+        }
+    }
     s.edit("Expand Image Trace", |d, sel| {
         for g in &targets {
             let n = d.node_mut(*g).ok_or(EngineError::NoNode(*g))?;
@@ -1300,6 +1401,15 @@ fn trace_expand(s: &mut Session, p: &Value) -> Result<Value> {
             if let Some(ch) = n.children_mut() {
                 ch.retain(|c| !matches!(c.kind, NodeKind::Image(_)));
             }
+            if by_color {
+                let items = d.node(*g).and_then(Node::children).cloned().unwrap_or_default();
+                // The paths may have been moved or reshaped since the trace was made, so any trace's
+                // paths are taken to overlap.
+                let groups = color_groups(C, d, items, true)?;
+                if let Some(ch) = d.node_mut(*g).and_then(Node::children_mut) {
+                    *ch = groups;
+                }
+            }
         }
         sel.set(targets.iter().copied());
         Ok(())
diff --git a/crates/engine/src/tests_build.rs b/crates/engine/src/tests_build.rs
--- a/crates/engine/src/tests_build.rs
+++ b/crates/engine/src/tests_build.rs
@@ -2517,6 +2517,256 @@ fn image_trace_release_and_expand() {
     assert!(s.execute("imageTrace.release", &json!({})).is_err());
 }
 
+/// Expand by color: each color's paths in a group of their own, named by the color, the groups
+/// stacked by the lowest path in each and the art drawn as before; Release to Layers then gives a
+/// sublayer for each color.
+#[test]
+fn image_trace_expand_by_color_groups_each_colors_paths() {
+    // A light field with a black ring and a red square on it.
+    let art = vectorcraft_trace::Raster::from_fn(200, 150, |x, y| {
+        let r = (f64::from(x) + 0.5 - 70.0).hypot(f64::from(y) + 0.5 - 75.0);
+        if (34.0..=40.0).contains(&r) {
+            [0, 0, 0, 255]
+        } else if (130..170).contains(&x) && (55..95).contains(&y) {
+            [200, 40, 50, 255]
+        } else {
+            [240, 240, 220, 255]
+        }
+    });
+    let names = |n: &Node| n.children().unwrap().iter().map(|c| c.name.clone().unwrap_or_default()).collect::<Vec<_>>();
+    let hex = |n: &Node| n.appearance.fill_paint().color().unwrap().to_hex();
+    let shot = |s: &Session| {
+        let img = render_doc(s, false);
+        (0..200).flat_map(|x| (0..150).map(move |y| (x, y))).map(|(x, y)| img.pixel(x, y)).collect::<Vec<_>>()
+    };
+    for method in ["abutting", "overlapping"] {
+        let params = json!({"mode": "color", "palette": "limited", "colors": 3, "method": method});
+        let expand = |by_color: bool| {
+            let mut s = session();
+            add_image(&mut s, &art, Affine::IDENTITY);
+            let r = s.execute("imageTrace.makeAndExpand", &json!({"params": params, "byColor": by_color})).unwrap();
+            let g = NodeId(r["id"].as_u64().unwrap());
+            (s, g)
+        };
+        let (flat, fg) = expand(false);
+        let (mut s, g) = expand(true);
+        let paths = node(&flat, fg).children().unwrap().clone();
+        // The colors in the order they first come in, bottom to top.
+        let mut order: Vec<String> = vec![];
+        for p in &paths {
+            if !order.contains(&hex(p)) {
+                order.push(hex(p));
+            }
+        }
+        let mut sorted = order.clone();
+        sorted.sort();
+        assert_eq!(sorted, ["#000000", "#c82832", "#f0f0dc"], "{method}");
+        let n = node(&s, g);
+        assert_eq!(names(&n), order, "{method}");
+        // Each group holds its color's paths, and in turn they are the paths of the trace without
+        // byColor, in their order.
+        let groups = n.children().unwrap();
+        for c in groups {
+            assert!(matches!(c.kind, NodeKind::Group { .. }), "{method}");
+            assert!(c.children().unwrap().iter().all(|m| Some(hex(m)) == c.name), "{method}: {:?}", c.name);
+        }
+        let members: Vec<Arc<Node>> = groups.iter().flat_map(|c| c.children().unwrap().iter().cloned()).collect();
+        assert!(members == paths, "{method}");
+        assert!(shot(&s) == shot(&flat), "{method}: the art changed");
+        // Release to Layers: a sublayer for each color, in the same order.
+        let r = s.execute("layer.releaseToLayers", &json!({"id": g.0})).unwrap();
+        let subs = ids(&r);
+        assert_eq!(subs.len(), 3, "{method}");
+        for (sub, name) in subs.iter().zip(&order) {
+            let l = node(&s, *sub);
+            assert!(matches!(l.kind, NodeKind::Layer { .. }), "{method}");
+            assert_eq!(names(&l), std::slice::from_ref(name), "{method}");
+        }
+    }
+
+    // imageTrace.expand takes it too, as one undo step.
+    let mut s = session();
+    add_image(&mut s, &art, Affine::IDENTITY);
+    let params = json!({"mode": "color", "palette": "limited", "colors": 3});
+    let g = NodeId(s.execute("imageTrace.make", &json!({"params": params})).unwrap()["id"].as_u64().unwrap());
+    let steps = s.doc().unwrap().history.undo.len();
+    s.execute("imageTrace.expand", &json!({"byColor": true})).unwrap();
+    assert_eq!(s.doc().unwrap().history.undo.len(), steps + 1);
+    let mut got = names(&node(&s, g));
+    got.sort();
+    assert_eq!(got, ["#000000", "#c82832", "#f0f0dc"]);
+    s.execute("edit.undo", &json!({})).unwrap();
+    assert_eq!(node(&s, g).name.as_deref(), Some("Image Trace"));
+
+    // Auto Grouping's groups are not split: refused, and the trace stays as it was.
+    let mut grouped = params.clone();
+    grouped["autoGrouping"] = json!(true);
+    let e = s.execute("imageTrace.makeAndExpand", &json!({"id": g.0, "params": grouped, "byColor": true})).unwrap_err().to_string();
+    assert!(e.contains("Auto Grouping"), "{e}");
+    let g = NodeId(s.execute("imageTrace.make", &json!({"id": g.0, "params": grouped})).unwrap()["id"].as_u64().unwrap());
+    let e = s.execute("imageTrace.expand", &json!({"byColor": true})).unwrap_err().to_string();
+    assert!(e.contains("Auto Grouping"), "{e}");
+    assert_eq!(node(&s, g).name.as_deref(), Some("Image Trace"));
+    let e = s.execute("imageTrace.expand", &json!({"byColor": "yes"})).unwrap_err().to_string();
+    assert!(e.contains("true or false"), "{e}");
+    // Refused too when Auto Grouping grouped nothing, as with side-by-side stripes.
+    let mut s = session();
+    let stripes = vectorcraft_trace::Raster::from_fn(60, 60, |x, _| match x / 20 {
+        0 => [200, 40, 40, 255],
+        1 => [40, 160, 60, 255],
+        _ => [40, 70, 200, 255],
+    });
+    add_image(&mut s, &stripes, Affine::IDENTITY);
+    let g = NodeId(s.execute("imageTrace.make", &json!({"params": grouped})).unwrap()["id"].as_u64().unwrap());
+    assert!(node(&s, g).children().unwrap().iter().all(|c| !matches!(c.kind, NodeKind::Group { .. })));
+    let e = s.execute("imageTrace.expand", &json!({"byColor": true})).unwrap_err().to_string();
+    assert!(e.contains("Auto Grouping"), "{e}");
+    assert_eq!(node(&s, g).name.as_deref(), Some("Image Trace"));
+
+    // A color linked to a global swatch goes by the swatch's name, a tint with its percentage.
+    let mut s = session();
+    s.execute("swatch.new", &json!({"name": "Ink", "color": "#c82828", "global": true})).unwrap();
+    s.execute("swatch.new", &json!({"name": "Sky", "color": "#2846c8", "global": true})).unwrap();
+    let r = vectorcraft_trace::Raster::from_fn(60, 60, |x, y| match (x < 30, y < 30) {
+        (true, _) => [200, 40, 40, 255],
+        (false, true) => [40, 160, 60, 255],
+        (false, false) => [40, 70, 200, 255],
+    });
+    add_image(&mut s, &r, Affine::IDENTITY);
+    let limited = json!({"mode": "color", "palette": "limited", "colors": 3});
+    let g = NodeId(s.execute("imageTrace.make", &json!({"params": limited})).unwrap()["id"].as_u64().unwrap());
+    let paths: Vec<(u64, String)> =
+        node(&s, g).children().unwrap().iter().filter(|c| !matches!(c.kind, NodeKind::Image(_))).map(|c| (c.id.0, hex(c))).collect();
+    let mut colors: Vec<&str> = paths.iter().map(|(_, h)| h.as_str()).collect();
+    colors.sort();
+    colors.dedup();
+    assert_eq!(colors, ["#2846c8", "#28a03c", "#c82828"]);
+    // The red paths link to Ink and the blue ones to Sky at 50%; green stays a plain color.
+    let pick = |want: &str| paths.iter().filter(|(_, h)| h == want).map(|(id, _)| *id).collect::<Vec<_>>();
+    s.execute("paint.setFill", &json!({"ids": pick("#c82828"), "swatch": "Ink"})).unwrap();
+    s.execute("paint.setFill", &json!({"ids": pick("#2846c8"), "swatch": "Sky", "tint": 50})).unwrap();
+    s.execute("imageTrace.expand", &json!({"id": g.0, "byColor": true})).unwrap();
+    let mut got = names(&node(&s, g));
+    got.sort();
+    assert_eq!(got, ["#28a03c", "Ink", "Sky 50%"]);
+    // A swatch named as another color's #rrggbb still gets a group of its own.
+    s.execute("edit.undo", &json!({})).unwrap();
+    s.execute("swatch.edit", &json!({"name": "Ink", "newName": "#28a03c"})).unwrap();
+    s.execute("imageTrace.expand", &json!({"id": g.0, "byColor": true})).unwrap();
+    let mut got = names(&node(&s, g));
+    got.sort();
+    assert_eq!(got, ["#28a03c", "#28a03c", "Sky 50%"]);
+
+    // Gradient fills share one group, and a stroked line goes by its stroke.
+    let ramp = vectorcraft_trace::Raster::from_fn(100, 60, |x, _| {
+        let t = (f64::from(x) + 0.5) / 100.0;
+        [(20.0 + 200.0 * t) as u8, 40, (220.0 - 180.0 * t) as u8, 255]
+    });
+    let line =
+        vectorcraft_trace::Raster::from_fn(100, 100, |x, y| if (10..90).contains(&x) && (49..52).contains(&y) { [0, 0, 0, 255] } else { [255; 4] });
+    for (art, params, want) in [
+        (ramp, json!({"preset": "6 Colors", "params": {"gradients": true}, "byColor": true}), "Gradients"),
+        (line, json!({"params": {"ignoreWhite": true, "strokes": true, "strokeWidth": 5}, "byColor": true}), "#000000"),
+    ] {
+        let mut s = session();
+        add_image(&mut s, &art, Affine::IDENTITY);
+        let res = s.execute("imageTrace.makeAndExpand", &params).unwrap();
+        assert_eq!(names(&node(&s, NodeId(res["id"].as_u64().unwrap()))), [want]);
+    }
+
+    // Flat Logo stacks its shapes biggest first without cutting holes under white: a black ring's
+    // outline, a white disc on it and a black dot on that. Black keeps a group below white and one
+    // above it, and the art draws as before, through Make and Expand and through Expand.
+    let target = vectorcraft_trace::Raster::from_fn(120, 120, |x, y| {
+        let r = (f64::from(x) + 0.5 - 60.0).hypot(f64::from(y) + 0.5 - 60.0);
+        if r < 15.0 || (30.0..50.0).contains(&r) {
+            [0, 0, 0, 255]
+        } else if r < 30.0 {
+            [255, 255, 255, 255]
+        } else {
+            [0, 0, 0, 0]
+        }
+    });
+    let logo = json!({"mode": "logo", "logoColors": ["#000000"]});
+    let traced = |by_color: bool, expand_after: bool| {
+        let mut s = session();
+        add_image(&mut s, &target, Affine::IDENTITY);
+        let g = if expand_after {
+            let g = s.execute("imageTrace.make", &json!({"params": logo})).unwrap()["id"].as_u64().unwrap();
+            s.execute("imageTrace.expand", &json!({"byColor": by_color})).unwrap();
+            g
+        } else {
+            s.execute("imageTrace.makeAndExpand", &json!({"params": logo, "byColor": by_color})).unwrap()["id"].as_u64().unwrap()
+        };
+        (s, NodeId(g))
+    };
+    for expand_after in [false, true] {
+        let (flat, fg) = traced(false, expand_after);
+        let (s, g) = traced(true, expand_after);
+        let paths = node(&flat, fg).children().unwrap().clone();
+        assert_eq!(paths.iter().map(|p| hex(p)).collect::<Vec<_>>(), ["#000000", "#ffffff", "#000000"]);
+        assert_eq!(names(&node(&s, g)), ["#000000", "#ffffff", "#000000"], "expand after: {expand_after}");
+        let members: Vec<Arc<Node>> = node(&s, g).children().unwrap().iter().flat_map(|c| c.children().unwrap().iter().cloned()).collect();
+        assert!(members == paths, "expand after: {expand_after}");
+        assert!(shot(&s) == shot(&flat), "expand after: {expand_after}: the art changed");
+    }
+
+    // An Abutting trace's top path, given the bottom path's color and moved onto the middle one (by
+    // a move or by a Transform effect), or moved clear of it with a drop shadow cast onto it, before
+    // Expand, still draws on top of it.
+    let stripes = vectorcraft_trace::Raster::from_fn(90, 30, |x, _| match x / 30 {
+        0 => [200, 40, 40, 255],
+        1 => [40, 160, 60, 255],
+        _ => [40, 70, 200, 255],
+    });
+    let edited = |by_color: bool, how: &str| {
+        let mut s = session();
+        add_image(&mut s, &stripes, Affine::IDENTITY);
+        let limited = json!({"mode": "color", "palette": "limited", "colors": 3, "method": "abutting"});
+        let g = NodeId(s.execute("imageTrace.make", &json!({"params": limited})).unwrap()["id"].as_u64().unwrap());
+        let paths: Vec<Arc<Node>> = node(&s, g).children().unwrap().iter().filter(|c| !matches!(c.kind, NodeKind::Image(_))).cloned().collect();
+        assert_eq!(paths.len(), 3);
+        let (first, middle, last) = (&paths[0], &paths[1], &paths[2]);
+        s.execute("paint.setFill", &json!({"ids": [last.id.0], "color": hex(first)})).unwrap();
+        let (to, from) = (middle.visual_bounds().unwrap(), last.visual_bounds().unwrap());
+        let (dx, dy) = (to.x0 - from.x0, to.y0 - from.y0);
+        match how {
+            "move" => s.execute("object.move", &json!({"ids": [last.id.0], "dx": dx, "dy": dy})).unwrap(),
+            "transform" => {
+                s.execute("effect.apply", &json!({"ids": [last.id.0], "effect": "distort.transform", "params": {"moveH": dx, "moveV": dy}})).unwrap()
+            }
+            _ => {
+                s.execute("object.move", &json!({"ids": [last.id.0], "dx": 40, "dy": 0})).unwrap();
+                s.execute("effect.apply", &json!({"ids": [last.id.0], "effect": "stylize.dropShadow", "params": {"x": -70, "y": 0, "blur": 0}}))
+                    .unwrap()
+            }
+        };
+        s.execute("imageTrace.expand", &json!({"id": g.0, "byColor": by_color})).unwrap();
+        (s, g)
+    };
+    for how in ["move", "transform", "shadow"] {
+        let (flat, _) = edited(false, how);
+        let (s, g) = edited(true, how);
+        assert_eq!(names(&node(&s, g)).len(), 3, "{how}");
+        assert!(shot(&s) == shot(&flat), "{how}: the edited art changed");
+    }
+
+    // Two tints of one swatch that round to the same percentage are still two colors.
+    let mut s = session();
+    s.execute("swatch.new", &json!({"name": "Sky", "color": "#2846c8", "global": true})).unwrap();
+    add_image(&mut s, &stripes, Affine::IDENTITY);
+    let limited = json!({"mode": "color", "palette": "limited", "colors": 3});
+    let g = NodeId(s.execute("imageTrace.make", &json!({"params": limited})).unwrap()["id"].as_u64().unwrap());
+    let paths: Vec<u64> = node(&s, g).children().unwrap().iter().filter(|c| !matches!(c.kind, NodeKind::Image(_))).map(|c| c.id.0).collect();
+    assert_eq!(paths.len(), 3);
+    s.execute("paint.setFill", &json!({"ids": [paths[0]], "swatch": "Sky", "tint": 50.1})).unwrap();
+    s.execute("paint.setFill", &json!({"ids": [paths[1], paths[2]], "swatch": "Sky", "tint": 50.4})).unwrap();
+    s.execute("imageTrace.expand", &json!({"id": g.0, "byColor": true})).unwrap();
+    let groups = node(&s, g).children().unwrap().clone();
+    assert_eq!(names(&node(&s, g)), ["Sky 50%", "Sky 50%"]);
+    assert_eq!(groups.iter().map(|c| c.children().unwrap().len()).collect::<Vec<_>>(), [1, 2]);
+}
+
 #[test]
 fn image_trace_make_and_expand_and_color_presets() {
     let mut s = session();
diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv
--- a/crates/ui-egui/src/i18n/cs.tsv
+++ b/crates/ui-egui/src/i18n/cs.tsv
@@ -5393,6 +5393,8 @@ mark-style	Japanese	Japonské
 @msg	too many library panels were opened in this session	v této relaci bylo otevřeno příliš mnoho panelů knihoven
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Obraz má {_1} × {_2} pixelů, na jedné straně více než {LARGE_TRACE_SIDE}: vektorizuje se, ale pomaleji. Rychleji se vektorizuje s předvolbou nižší věrnosti nebo menší kopie obrazu.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Obraz byl vektorizován v rozlišení {_1} × {_2} pixelů, zmenšený z {_3} × {_4} (nejvýše {_5} megapixelů).
+@msg	byColor must be true or false	byColor musí být true nebo false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor nerozdělí skupiny z Automatického seskupení: vektorizujte bez Automatického seskupení
 	Snapping	Přichytávání
 	Snap to Tangent	Přichytávat k tečně
 	Snap to Perpendicular	Přichytávat ke kolmici
diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv
--- a/crates/ui-egui/src/i18n/de.tsv
+++ b/crates/ui-egui/src/i18n/de.tsv
@@ -4972,6 +4972,8 @@ effect	Soft	Weich
 @msg	too many library panels were opened in this session	in dieser Sitzung wurden zu viele Bibliotheksbedienfelder geöffnet
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Das Bild hat {_1} × {_2} Pixel, mehr als {LARGE_TRACE_SIDE} auf einer Seite: Es wird nachgezeichnet, aber langsamer. Eine Vorgabe mit geringerer Detailtreue oder eine kleinere Kopie des Bildes geht schneller.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Das Bild wurde mit {_1} × {_2} Pixeln nachgezeichnet, verkleinert von {_3} × {_4} (höchstens {_5} Megapixel).
+@msg	byColor must be true or false	byColor muss true oder false sein
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor kann Gruppen aus Automatisch gruppieren nicht aufteilen: ohne Automatisch gruppieren nachzeichnen
 	Snapping	Einrasten
 	Snap to Tangent	An Tangente ausrichten
 	Snap to Perpendicular	An Senkrechter ausrichten
diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv
--- a/crates/ui-egui/src/i18n/el.tsv
+++ b/crates/ui-egui/src/i18n/el.tsv
@@ -5345,6 +5345,8 @@ effect	Points	Σημεία
 @msg	too many library panels were opened in this session	άνοιξαν πάρα πολλοί πίνακες βιβλιοθηκών σε αυτή τη συνεδρία
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Η εικόνα είναι {_1} × {_2} εικονοστοιχεία, πάνω από {LARGE_TRACE_SIDE} σε μία πλευρά: ανιχνεύεται, αλλά πιο αργά. Μια προρύθμιση χαμηλότερης πιστότητας ή ένα μικρότερο αντίγραφο της εικόνας ανιχνεύεται γρηγορότερα.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Η εικόνα ανιχνεύτηκε σε {_1} × {_2} εικονοστοιχεία, σμικρυμένη από {_3} × {_4} (το πολύ {_5} megapixel).
+@msg	byColor must be true or false	το byColor πρέπει να είναι true ή false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	το byColor δεν μπορεί να χωρίσει τις ομάδες της Αυτόματης ομαδοποίησης: ανιχνεύστε χωρίς Αυτόματη ομαδοποίηση
 	Snapping	Προσκόλληση
 	Snap to Tangent	Προσκόλληση σε εφαπτομένη
 	Snap to Perpendicular	Προσκόλληση σε κάθετο
diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv
--- a/crates/ui-egui/src/i18n/es.tsv
+++ b/crates/ui-egui/src/i18n/es.tsv
@@ -5335,6 +5335,8 @@ mark-style	Japanese	Japonesas
 @msg	too many library panels were opened in this session	se abrieron demasiados paneles de biblioteca en esta sesión
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	La imagen tiene {_1} × {_2} píxeles, más de {LARGE_TRACE_SIDE} en un lado: se calcará, pero más despacio. Un ajuste preestablecido de menor fidelidad o una copia más pequeña de la imagen se calcan más rápido.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	La imagen se calcó a {_1} × {_2} píxeles, reducida desde {_3} × {_4} ({_5} megapíxeles como máximo).
+@msg	byColor must be true or false	byColor debe ser true o false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor no puede dividir los grupos de Agrupación automática: calque sin Agrupación automática
 	Snapping	Ajuste
 	Snap to Tangent	Ajustar a tangente
 	Snap to Perpendicular	Ajustar a perpendicular
diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv
--- a/crates/ui-egui/src/i18n/fi.tsv
+++ b/crates/ui-egui/src/i18n/fi.tsv
@@ -5357,6 +5357,8 @@ mark-style	Japanese	Japanilainen
 @msg	too many library panels were opened in this session	tässä istunnossa on avattu liian monta kirjastopaneelia
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Kuva on {_1} × {_2} kuvapistettä, yhdeltä sivultaan yli {LARGE_TRACE_SIDE}: se jäljitetään, mutta hitaammin. Pienemmän tarkkuuden esiasetus tai kuvan pienempi kopio jäljittyy nopeammin.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Kuva jäljitettiin kokoon {_1} × {_2} kuvapistettä pienennettynä koosta {_3} × {_4} (enintään {_5} megapikseliä).
+@msg	byColor must be true or false	byColor-arvon on oltava true tai false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor ei voi jakaa Automaattisen ryhmittelyn ryhmiä: jäljitä ilman Automaattista ryhmittelyä
 	Snapping	Tartunta
 	Snap to Tangent	Kohdista tangenttiin
 	Snap to Perpendicular	Kohdista kohtisuoraan
diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv
--- a/crates/ui-egui/src/i18n/fr.tsv
+++ b/crates/ui-egui/src/i18n/fr.tsv
@@ -5392,6 +5392,8 @@ theme	Appearance	Apparence
 @msg	too many library panels were opened in this session	trop de panneaux de bibliothèque ont été ouverts dans cette session
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	L’image fait {_1} × {_2} pixels, plus de {LARGE_TRACE_SIDE} sur un côté : elle est vectorisée, mais plus lentement. Un paramètre prédéfini moins fidèle ou une copie plus petite de l’image se vectorise plus vite.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	L’image a été vectorisée à {_1} × {_2} pixels, réduite de {_3} × {_4} ({_5} mégapixels au plus).
+@msg	byColor must be true or false	byColor doit être true ou false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor ne peut pas scinder les groupes du Groupement automatique : vectorisez sans Groupement automatique
 	Snapping	Magnétisme
 	Snap to Tangent	Magnétisme de la tangente
 	Snap to Perpendicular	Magnétisme de la perpendiculaire
diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv
--- a/crates/ui-egui/src/i18n/hu.tsv
+++ b/crates/ui-egui/src/i18n/hu.tsv
@@ -5379,6 +5379,8 @@ imageTrace	Outline	Körvonal
 @msg	too many library panels were opened in this session	ebben a munkamenetben túl sok könyvtárpanel nyílt meg
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	A kép {_1} × {_2} képpont, egyik oldalán több mint {LARGE_TRACE_SIDE}: a vektorizálás megtörténik, de lassabban. Kisebb hűségű előbeállítással vagy a kép kisebb másolatával gyorsabb.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	A kép vektorizálása {_1} × {_2} képponton történt, {_3} × {_4} méretről kicsinyítve (legfeljebb {_5} megapixel).
+@msg	byColor must be true or false	a byColor értéke true vagy false lehet
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	a byColor nem bontja fel az Automatikus csoportosítás csoportjait: vektorizáljon Automatikus csoportosítás nélkül
 	Snapping	Illesztés
 	Snap to Tangent	Illesztés érintőre
 	Snap to Perpendicular	Illesztés merőlegesre
diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv
--- a/crates/ui-egui/src/i18n/it.tsv
+++ b/crates/ui-egui/src/i18n/it.tsv
@@ -5006,6 +5006,8 @@ lighting	Light	Luce
 @msg	too many library panels were opened in this session	in questa sessione sono stati aperti troppi pannelli libreria
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	L’immagine è di {_1} × {_2} pixel, più di {LARGE_TRACE_SIDE} su un lato: viene vettorializzata, ma più lentamente. Un predefinito a fedeltà più bassa o una copia più piccola dell’immagine è più veloce.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	L’immagine è stata vettorializzata a {_1} × {_2} pixel, ridotta da {_3} × {_4} (al massimo {_5} megapixel).
+@msg	byColor must be true or false	byColor deve essere true o false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor non può dividere i gruppi di Raggruppamento automatico: vettorializza senza Raggruppamento automatico
 	Snapping	Aggancio
 	Snap to Tangent	Aggancia alla tangente
 	Snap to Perpendicular	Aggancia alla perpendicolare
diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv
--- a/crates/ui-egui/src/i18n/ja.tsv
+++ b/crates/ui-egui/src/i18n/ja.tsv
@@ -5046,6 +5046,8 @@ lighting	Light	ライト
 @msg	too many library panels were opened in this session	このセッションで開いたライブラリパネルが多すぎます
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	画像は {_1} × {_2} ピクセルで、一辺が {LARGE_TRACE_SIDE} を超えています。トレースはできますが、時間がかかります。忠実度の低いプリセットや画像の小さいコピーを使うと速くなります。
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	画像は {_3} × {_4} から縮小した {_1} × {_2} ピクセルでトレースされました (最大 {_5} メガピクセル)。
+@msg	byColor must be true or false	byColor は true または false にしてください
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor は自動グループ化のグループを分割できません: 自動グループ化なしでトレースしてください
 	Snapping	スナップ
 	Snap to Tangent	接線にスナップ
 	Snap to Perpendicular	垂線にスナップ
diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv
--- a/crates/ui-egui/src/i18n/ka.tsv
+++ b/crates/ui-egui/src/i18n/ka.tsv
@@ -5239,6 +5239,8 @@ imageTrace	Outline	კონტური
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	გამოსახულება არის {_1} × {_2} პიქსელი, ანუ ერთ მხარეზე {LARGE_TRACE_SIDE}-ზე მეტი: ის ვექტორიზდება, მაგრამ უფრო ნელა. ნაკლები სიზუსტის პრესეტი ან გამოსახულების უფრო პატარა ასლი უფრო სწრაფად ვექტორიზდება.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	გამოსახულება ვექტორიზდა {_1} × {_2} პიქსელზე, შემცირდა {_3} × {_4}-დან (მაქსიმუმ {_5} მეგაპიქსელი).
 @msg	Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}.	ბრტყელი ლოგოს რეჟიმში გამოსახულება ვექტორიზდა {_1} × {_2} პიქსელზე, საშუალოს გამოთვლით შემცირდა {_3} × {_4}-დან.
+@msg	byColor must be true or false	byColor უნდა იყოს true ან false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor ვერ დაყოფს ავტომატური დაჯგუფების ჯგუფებს: ვექტორიზება გააკეთეთ ავტომატური დაჯგუფების გარეშე
 @msg	`{given}` isn't a library panel (see window.swatchLibrary)	`{given}` ბიბლიოთეკის პანელი არ არის (იხ. window.swatchLibrary)
 @msg	`{key}` must be a #rrggbb color	`{key}` უნდა იყოს #rrggbb ფერი
 @msg	a key object sits on that point	ამ წერტილზე საკვანძო ობიექტი მდებარეობს
diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv
--- a/crates/ui-egui/src/i18n/ko.tsv
+++ b/crates/ui-egui/src/i18n/ko.tsv
@@ -4969,6 +4969,8 @@ lighting	Light	광원
 @msg	too many library panels were opened in this session	이 세션에서 라이브러리 패널을 너무 많이 열었습니다
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	이미지가 {_1} × {_2}픽셀로 한 변이 {LARGE_TRACE_SIDE}을 넘습니다. 추적은 되지만 더 느립니다. 충실도가 낮은 사전 설정이나 이미지의 작은 사본을 사용하면 더 빠릅니다.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	이미지를 {_3} × {_4}에서 축소한 {_1} × {_2}픽셀로 추적했습니다(최대 {_5}메가픽셀).
+@msg	byColor must be true or false	byColor는 true 또는 false여야 합니다
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor는 자동 그룹화 그룹을 나눌 수 없습니다. 자동 그룹화 없이 추적하세요
 	Snapping	스냅
 	Snap to Tangent	접선에 스냅
 	Snap to Perpendicular	수직선에 스냅
diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv
--- a/crates/ui-egui/src/i18n/pl.tsv
+++ b/crates/ui-egui/src/i18n/pl.tsv
@@ -5245,6 +5245,8 @@ mark-style	Japanese	Japońskie
 @msg	too many library panels were opened in this session	w tej sesji otwarto zbyt wiele paneli bibliotek
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Obraz ma {_1} × {_2} pikseli, ponad {LARGE_TRACE_SIDE} na jednym boku: zostanie obrysowany, ale wolniej. Ustawienie wstępne o niższej wierności lub mniejsza kopia obrazu obrysuje się szybciej.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Obraz obrysowano w rozdzielczości {_1} × {_2} pikseli, po zmniejszeniu z {_3} × {_4} (najwyżej {_5} megapikseli).
+@msg	byColor must be true or false	byColor musi mieć wartość true lub false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor nie może podzielić grup Automatycznego grupowania: obrysuj bez Automatycznego grupowania
 	Snapping	Przyciąganie
 	Snap to Tangent	Przyciągaj do stycznych
 	Snap to Perpendicular	Przyciągaj do prostopadłych
diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv
--- a/crates/ui-egui/src/i18n/pt-br.tsv
+++ b/crates/ui-egui/src/i18n/pt-br.tsv
@@ -5310,6 +5310,8 @@ mark-style	Japanese	Japonesas
 @msg	too many library panels were opened in this session	foram abertos painéis de biblioteca demais nesta sessão
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	A imagem tem {_1} × {_2} pixels, mais de {LARGE_TRACE_SIDE} em um lado: ela é traçada, mas mais devagar. Uma predefinição de menor fidelidade ou uma cópia menor da imagem traça mais rápido.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	A imagem foi traçada em {_1} × {_2} pixels, reduzida de {_3} × {_4} (no máximo {_5} megapixels).
+@msg	byColor must be true or false	byColor deve ser true ou false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor não pode dividir os grupos de Agrupamento Automático: trace sem Agrupamento Automático
 	Snapping	Ajuste
 	Snap to Tangent	Ajustar à Tangente
 	Snap to Perpendicular	Ajustar à Perpendicular
diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv
--- a/crates/ui-egui/src/i18n/ru.tsv
+++ b/crates/ui-egui/src/i18n/ru.tsv
@@ -5002,6 +5002,8 @@ lighting	Light	Свет
 @msg	too many library panels were opened in this session	в этом сеансе открыто слишком много панелей библиотек
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Изображение {_1} × {_2} пикселей, больше {LARGE_TRACE_SIDE} по одной стороне: трассировка выполняется, но медленнее. Стиль с меньшей точностью или уменьшенная копия изображения трассируются быстрее.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Изображение трассировано в размере {_1} × {_2} пикселей, уменьшенное с {_3} × {_4} (не более {_5} мегапикселей).
+@msg	byColor must be true or false	byColor должен иметь значение true или false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor не может разделить группы автогруппировки: трассируйте без автогруппировки
 	Snapping	Привязка
 	Snap to Tangent	Привязать к касательной
 	Snap to Perpendicular	Привязать к перпендикуляру
diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv
--- a/crates/ui-egui/src/i18n/sv.tsv
+++ b/crates/ui-egui/src/i18n/sv.tsv
@@ -5416,6 +5416,8 @@ swatch	Yellow Green	Gulgrön
 @msg	“{name}” is not a file	”{name}” är inte en fil
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Bilden är {_1} × {_2} pixlar, mer än {LARGE_TRACE_SIDE} på en sida: den vektoriseras, men långsammare. En förinställning med lägre återgivning eller en mindre kopia av bilden går snabbare.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Bilden vektoriserades vid {_1} × {_2} pixlar, nedskalad från {_3} × {_4} (högst {_5} megapixlar).
+@msg	byColor must be true or false	byColor måste vara true eller false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor kan inte dela upp grupper från Automatisk gruppering: vektorisera utan Automatisk gruppering
 	Snapping	Fästning
 	Snap to Tangent	Fäst mot tangent
 	Snap to Perpendicular	Fäst mot vinkelrät
diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv
--- a/crates/ui-egui/src/i18n/tr.tsv
+++ b/crates/ui-egui/src/i18n/tr.tsv
@@ -5391,6 +5391,8 @@ theme	Appearance	Görünüm
 @msg	library panel `{given}` isn't missing its library	`{given}` kitaplık panelinin kitaplığı eksik değil
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Görüntü {_1} × {_2} piksel, bir kenarı {LARGE_TRACE_SIDE} değerinden büyük: izlenir, ancak daha yavaş. Daha düşük doğruluklu bir ön ayar veya görüntünün daha küçük bir kopyası daha hızlı izlenir.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Görüntü {_3} × {_4} boyutundan küçültülerek {_1} × {_2} pikselde izlendi (en fazla {_5} megapiksel).
+@msg	byColor must be true or false	byColor true veya false olmalıdır
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor, Otomatik Gruplama gruplarını bölemez: Otomatik Gruplama olmadan izleyin
 	Gap Length:	Boşluk Uzunluğu:
 @msg	Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}.	Düz Logo modu görüntüyü {_3} × {_4} boyutundan ortalama alarak küçültüp {_1} × {_2} pikselde izledi.
 @plural	{n} more export waiting|{n} more exports waiting	{n} dışa aktarma daha bekliyor|{n} dışa aktarma daha bekliyor
diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv
--- a/crates/ui-egui/src/i18n/uk.tsv
+++ b/crates/ui-egui/src/i18n/uk.tsv
@@ -4986,6 +4986,8 @@ lighting	Light	Світло
 @msg	too many library panels were opened in this session	у цьому сеансі відкрито забагато панелей бібліотек
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Зображення {_1} × {_2} пікселів, понад {LARGE_TRACE_SIDE} з одного боку: трасування виконується, але повільніше. Стиль із нижчою точністю або менша копія зображення трасуються швидше.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Зображення трасовано в розмірі {_1} × {_2} пікселів, зменшене з {_3} × {_4} (щонайбільше {_5} мегапікселів).
+@msg	byColor must be true or false	byColor має мати значення true або false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor не може розділити групи автогрупування: трасуйте без автогрупування
 	Snapping	Прив’язка
 	Snap to Tangent	Прив’язати до дотичної
 	Snap to Perpendicular	Прив’язати до перпендикуляра
diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv
--- a/crates/ui-egui/src/i18n/vi.tsv
+++ b/crates/ui-egui/src/i18n/vi.tsv
@@ -4986,6 +4986,8 @@ theme	Appearance	Giao diện
 @msg	too many library panels were opened in this session	đã mở quá nhiều bảng thư viện trong phiên này
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	Ảnh có kích thước {_1} × {_2} điểm ảnh, hơn {LARGE_TRACE_SIDE} ở một cạnh: ảnh vẫn được dò, nhưng chậm hơn. Một thiết lập sẵn có độ trung thực thấp hơn hoặc một bản sao nhỏ hơn của ảnh sẽ dò nhanh hơn.
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	Ảnh đã được dò ở {_1} × {_2} điểm ảnh, thu nhỏ từ {_3} × {_4} (tối đa {_5} megapixel).
+@msg	byColor must be true or false	byColor phải là true hoặc false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor không thể tách các nhóm của Tự động nhóm: hãy dò mà không bật Tự động nhóm
 	Snapping	Hút
 	Snap to Tangent	Hút vào tiếp tuyến
 	Snap to Perpendicular	Hút vào đường vuông góc
diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv
--- a/crates/ui-egui/src/i18n/zh-hans.tsv
+++ b/crates/ui-egui/src/i18n/zh-hans.tsv
@@ -5225,6 +5225,8 @@ lighting	Light	光源
 @msg	too many library panels were opened in this session	本次会话中打开的库面板过多
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	图像为 {_1} × {_2} 像素，某一边超过 {LARGE_TRACE_SIDE}：会进行描摹，但速度较慢。使用保真度较低的预设或图像的较小副本会更快。
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	图像已按 {_1} × {_2} 像素描摹，由 {_3} × {_4} 缩小而来（最多 {_5} 百万像素）。
+@msg	byColor must be true or false	byColor 必须是 true 或 false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor 无法拆分自动编组生成的编组：请在不使用自动编组的情况下描摹
 	Snapping	对齐
 	Snap to Tangent	对齐切线
 	Snap to Perpendicular	对齐垂线
diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv
--- a/crates/ui-egui/src/i18n/zh-hant.tsv
+++ b/crates/ui-egui/src/i18n/zh-hant.tsv
@@ -2375,6 +2375,8 @@ file-filter	Templates	範本
 @msg	The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster.	影像為 {_1} × {_2} 像素，有一邊超過 {LARGE_TRACE_SIDE}：仍會描圖，但速度較慢。使用精確度較低的預設集或較小的影像拷貝，描圖會較快。
 @msg	The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most).	影像已以 {_1} × {_2} 像素描圖，由 {_3} × {_4} 縮小而來 (最多 {_5} 百萬像素)。
 @msg	Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}.	「扁平標誌」模式已以 {_1} × {_2} 像素描圖，由 {_3} × {_4} 平均縮小而來。
+@msg	byColor must be true or false	byColor 必須是 true 或 false
+@msg	byColor can't split Auto Grouping groups: trace without Auto Grouping	byColor 無法拆分自動群組產生的群組：請不使用自動群組來描圖
 # Links and Attributes: files and URLs handed to other apps.
 @msg	Edit Original opens image and document files only; “{name}” is not one	「編輯原稿」只能開啟影像與文件檔案；「{name}」不屬於這兩類
 @msg	only http, https and mailto URLs open in the browser, not “{url}”	只有 http、https 和 mailto URL 會在瀏覽器中開啟，「{url}」不會
diff --git a/docs/mcp.md b/docs/mcp.md
--- a/docs/mcp.md
+++ b/docs/mcp.md
@@ -1496,6 +1496,15 @@ already walks Image Trace. Short agent entry points:
 - Image Trace: `imageTrace.presets`, `imageTrace.make {id?, preset?, params?, view?}` (or `imageTrace.makeAndExpand`),
   `imageTrace.setView`, `imageTrace.expand`, `imageTrace.release`. A key inside `params` that is not one of the trace
   settings, such as `colours`, is an error that names it and the nearest setting (`colors`), as for a command's own keys.
+  With `byColor: true`, `imageTrace.expand` and `imageTrace.makeAndExpand` put each color's paths in a group of their
+  own, named by the global swatch the color links to (a tint with its percentage, as `Sky 50%`) or as `#rrggbb`;
+  gradient fills share a group named `Gradients`. The groups stack in the order of the lowest path in each, and each
+  keeps its paths' order. With `imageTrace.expand`, and with `imageTrace.makeAndExpand` when the trace's paths can
+  overlap (Overlapping, Flat Logo, Create Strokes), a path that would move under an overlapping path of another color
+  (by the bounding boxes of what they paint, effects and shadows included) if it joined its color's group starts
+  another group of its color instead, and the renderer draws the art unchanged. In a Flat Logo trace of a black ring
+  around a white disc around a black dot, black gets two groups. `layer.releaseToLayers` on the expanded group then
+  gives each group a sublayer. A trace made with `autoGrouping` is refused.
 - Live Paint: `livePaint.make`, `livePaint.merge`, `livePaint.fill {group?, point}`, `livePaint.strokeEdge`,
   `livePaint.info {group}`, `livePaint.release`, `livePaint.expand`, and `livePaint.gapOptions {ids?, detect?, size?,
   color?, closeGaps?}` (Object › Live Paint › Gap Options). With `detect: true`, paint stops at the gaps that run
