diff --git a/src-frontend/src/hooks/useTauri.js b/src-frontend/src/hooks/useTauri.js index 3a53a8f6..0cb0ee83 100644 --- a/src-frontend/src/hooks/useTauri.js +++ b/src-frontend/src/hooks/useTauri.js @@ -63,20 +63,20 @@ export async function getStreamlineDebug(passIdx, hullIdx, params = DEFAULT_STRE // Default PaintParams must match Rust's `impl Default for PaintParams`. export const DEFAULT_PAINT_PARAMS = { - brush_radius_factor: 1.15, - brush_radius_offset_px: 0.25, - brush_radius_percentile: 0.85, + brush_radius_factor: 0.88, + brush_radius_offset_px: 0.50, + brush_radius_percentile: 0.93, step_size_factor: 0.40, n_directions: 48, lookahead_steps: 3, momentum_weight: 0.20, overpaint_penalty: 0.10, - walk_bg_penalty: 4.0, + walk_bg_penalty: 0.69, min_score_factor: 0.20, - polish_iters: 1, + polish_iters: 2, polish_search_factor: 0.5, bg_penalty: 2.0, - min_component_factor: 1.20, + min_component_factor: 1.49, pen_lift_penalty: 0.0, pen_lift_reach: 3.0, max_steps_per_stroke: 4000, diff --git a/src/brush_paint.rs b/src/brush_paint.rs index 85610eea..35d4981e 100644 --- a/src/brush_paint.rs +++ b/src/brush_paint.rs @@ -140,27 +140,26 @@ pub struct PaintParams { impl Default for PaintParams { fn default() -> Self { Self { - // OPTIMIZER-TUNED DEFAULTS (under hard 5%-bg / 5%-unpainted / - // 2×-skel ceilings, score 333M → 41M). Bigger brush, - // step_size_factor=0.4 to keep disks tightly packed, - // walk_bg_penalty=4 to steer the walker onto the ridge, - // n_directions=48 for finer turning resolution. Dijkstra - // repaint still disabled — single-stroke W/M still need it - // turned on per-letter via the slider. - brush_radius_factor: 1.15, - brush_radius_offset_px: 0.25, - brush_radius_percentile: 0.85, + // META-OPTIMIZER WINNING CONFIG (idx 20 of 24-sample lex- + // ranked search). Tier-1 result on the corpus: cov_fail=8, + // bg_fail=0, len_fail=0; ~12 px bg per letter on average. + // Stroke-count constraints (12 single-stroke + 11 two-stroke + // letters miscounted) are NOT respected — known limitation + // of the soft inner-score the meta search uses. + brush_radius_factor: 0.88, + brush_radius_offset_px: 0.50, + brush_radius_percentile: 0.93, step_size_factor: 0.40, n_directions: 48, lookahead_steps: 3, momentum_weight: 0.20, overpaint_penalty: 0.10, - walk_bg_penalty: 4.0, + walk_bg_penalty: 0.69, min_score_factor: 0.20, - polish_iters: 1, + polish_iters: 2, polish_search_factor: 0.5, bg_penalty: 2.0, - min_component_factor: 1.20, + min_component_factor: 1.49, pen_lift_penalty: 0.0, pen_lift_reach: 3.0, max_steps_per_stroke: 4000, @@ -1645,16 +1644,21 @@ impl Default for ScoreWeights { // So the sweep prefers a smaller-radius solution that leaves a // few unpainted pixels over a larger-radius solution that paints // 50× as many bg pixels. + // Meta-optimizer winning weights (idx 20). Note: meta-opt + // didn't fix stroke-count constraint failures — those need a + // larger per-letter penalty in the inner score before they + // bite the gradient. Soft costs are well-tuned for the + // tier-1/tier-2 lex objective. Self { - stroke: 500.0, - length: 5.0, - bg: 50.0, - repaint: 30.0, - unpainted: 50.0, // mild — density carries the weight - unpainted_density: 10.0, // cluster_size^1.5 × 10 - length_excess: 300.0, - curvature: 500.0, - brush_size: 2000.0, // pressure toward bigger brush. Per + stroke: 844.0, + length: 8.6, + bg: 98.0, + repaint: 8.8, + unpainted: 70.0, + unpainted_density: 22.8, + length_excess: 423.0, + curvature: 515.0, + brush_size: 214.0, // (was 2000 — meta dropped pressure // letter, +1 px brush = +2000 bonus; // vs bg=50/px that's "worth" up to // ~40 extra bg pixels per letter. So