M8: Tidy up keeps the second layer after a narrow first one when the gap is negative

raise_negative_gap raised a negative gap from the interior widths only, so a first layer narrower than the gap's size let the second start before it (widths 10, 100 x5 at X 0, 80, 200, 260, 400, 460: the modal -40 gave X 0, -30, 30, ...). The second must start after the first, g > -w(0), in whole pixels floor(-w(0)) + 1. Figma kept the order in every measured run; a narrow first layer was not measured, so this bound keeps the order rather than follow a reading. Test: tidy_tests::a_narrow_first_layer_still_keeps_the_second_after_it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model-Effort: Opus 5.5 drove and wrote
This commit is contained in:
Trevor Brown
2026-11-13 01:43:34 -05:00
co-authored by Claude Opus 5.5
parent fc90078333
commit 1a68ded581
2 changed files with 20 additions and 2 deletions
+7 -2
View File
@@ -167,13 +167,18 @@ fn even_gap(gaps: &[f64], spacing: Option<f64>) -> f64 {
/// in Figma's web app on 2026-11-13: interior widths of 10, 20 and 30 among 100s gave -4, -9 and
/// -14, and widths of 100 left the most common gap, -40, alone. Only those three widths were
/// measured; other widths follow the same formula.
///
/// The first layer has no layer two places before it, but the second must still start after it:
/// `g > -w(0)`, in whole pixels `floor(-w(0)) + 1`. Figma kept the order in every run; a narrow
/// first layer was not measured, so this bound keeps that order rather than following a reading.
fn raise_negative_gap(gap: f64, widths: &[f64]) -> f64 {
let interior = widths.get(1..widths.len().saturating_sub(1)).unwrap_or(&[]);
let w_min = interior.iter().copied().fold(f64::INFINITY, f64::min);
if widths.len() < 3 || !w_min.is_finite() {
let Some(first) = widths.first().copied() else { return gap };
if widths.len() < 3 || !w_min.is_finite() || !first.is_finite() {
return gap;
}
gap.max((-w_min / 2.0).floor() + 1.0)
gap.max((-w_min / 2.0).floor() + 1.0).max((-first).floor() + 1.0)
}
/// A row (`vertical` false) or a column: the first layer stays, each next one follows the last at
+13
View File
@@ -339,6 +339,19 @@ fn a_negative_gap_is_raised_so_no_layer_reaches_the_one_two_before() {
}
}
#[test]
fn a_narrow_first_layer_still_keeps_the_second_after_it() {
// Not measured in Figma (it kept the order in every run): the modal gap -40 would start the
// second layer at -30, before a 10 wide first layer, so the gap is raised to -9.
let mut s = Session::new();
let xs = [0., 80., 200., 260., 400., 460.];
let widths = [10., 100., 100., 100., 100., 100.];
let pairs: Vec<(f64, f64)> = xs.iter().copied().zip(widths).collect();
let ids = bars(&mut s, &pairs);
tidy(&mut s, &ids);
assert_eq!(xs_of(&s, &ids), vec![0., 1., 92., 183., 274., 365.]);
}
#[test]
fn a_negative_gap_between_equal_widths_is_the_most_common_gap() {
let mut s = Session::new();