Files
hcie-rust-v3.05/.kilo/plans/1784990207115-brush-checkerboard-fix-and-agents-md-update.md
Your Name fd205309b6
mandatory-regression-gate / deterministic-tests (push) Waiting to run
mandatory-regression-gate / protected-performance-path (push) Waiting to run
fix: resolve checkerboard artifact in brush strokes and update AGENTS.md for v3.05
2026-07-25 20:39:13 +03:00

12 KiB

Brush Checkerboard Fix + AGENTS.md Update Plan

Context

  • Project root: /mnt/extra/00_PROJECTS/hcie-rust-v3.05
  • Active GUI: hcie-iced-app/ (Iced + wgpu). hcie-egui-app/ is legacy/abandoned.
  • The reported artifact is a regular grid/checkerboard inside brush strokes on white canvas, visible only with certain brushes.
  • AGENTS.md is outdated: it still says "HCIE-Rust v4", lists egui as the active GUI, and omits the iced workspace.

Part 1: Brush Checkerboard Root Cause

The grid comes from deterministic, canvas-space pseudo-random sampling in hcie-brush-engine/src/lib.rs:

  • draw_grain_brush(..., woven: bool) uses:
    let hash = ((x.wrapping_mul(73_856_093) ^ y.wrapping_mul(19_349_663)) & 1023) as f32 / 1023.0;
    if texture < threshold { continue; }
    
  • draw_crayon_brush uses the same constants and a hard continue skip:
    let noise = ((px * 73_856_093) ^ (py * 19_349_663)) & 1023;
    if grain < threshold { continue; }
    

Because the hash depends only on absolute pixel (x, y) and the same pixels are re-sampled on every overlapping dab, the skipped pixels form a rigid canvas-locked checkerboard.

Affected Brush Styles

Style Function Mechanism
Noise draw_grain_brush(..., woven=false) hash threshold skip
Texture draw_grain_brush(..., woven=true) sin/cos woven threshold skip
Pencil draw_pencil_brushdraw_grain_brush hash threshold skip
Charcoal draw_charcoal_brushdraw_grain_brush hash threshold skip
Sketch draw_sketch_brushdraw_grain_brush hash threshold skip
Crayon draw_crayon_brush hash threshold skip

Dry-media presets that map to these styles are also affected:

  • Compressed Charcoal, Vine Charcoal, Charcoal Pencil
  • Soft Pastel, Hard Pastel, Oil Pastel, Water-Soluble Pastel, PanPastel, Chalk Sanguine
  • Graphite Pencils (HB/9B/Carpenter), Wax/Oil/Watercolor Pencils

Styles not affected: Round, HardRound, SoftRound, Square, Star, Spray, Pen, InkPen, Calligraphy, Oil, Airbrush, Watercolor, Marker, Glow, WetPaint, Leaf, Rock, Meadow, Clouds, Dirt, Tree, Bristle, Wood, Mixer, Blender, Bitmap.

Part 2: Proposed Fix

Decision

Apply both mechanisms together:

  1. Per-dab grain seed offset in draw_grain_brush / draw_crayon_brush so consecutive dabs no longer hit the exact same canvas pixels.
  2. Convert hard threshold skip to alpha modulation so "empty" pores become translucent rather than fully transparent, removing the rigid checkerboard.

Implementation Details

2.1 draw_grain_brush changes

Location: hcie-brush-engine/src/lib.rs:1350-1429

// Add inside the function, after radius/bbox calculation:
let seed_x = (cx.to_bits().wrapping_mul(73_856_093)
    ^ cy.to_bits().wrapping_mul(19_349_663)) as u32;
let seed_y = seed_x.wrapping_mul(668_265_263);

// Replace the hash computation with decorrelated coordinates:
let ox = x.wrapping_add(seed_x);
let oy = y.wrapping_add(seed_y);
let hash = ((ox.wrapping_mul(73_856_093) ^ oy.wrapping_mul(19_349_663)) & 1023) as f32 / 1023.0;

// For woven mode, shift the sin/cos arguments by the seed:
let texture = if woven {
    0.55 + 0.45 * ((x as f32 * 0.42 + seed_x as f32 * 0.001).sin()
        * (y as f32 * 0.31 + seed_y as f32 * 0.001).cos()).abs()
} else {
    hash
};

// Replace `if texture < threshold { continue; }` with soft alpha modulation:
let grain_alpha = if texture < threshold {
    (texture / threshold).clamp(0.0, 1.0)
} else {
    0.55 + 0.45 * texture
};

// Use grain_alpha in the final alpha instead of the old `(0.55 + 0.45 * texture)` factor.

2.2 draw_crayon_brush changes

Location: hcie-brush-engine/src/lib.rs:2941-3026

Apply the same seed + soft alpha approach to the crayon noise loop:

let seed_x = (cx.to_bits().wrapping_mul(73_856_093)
    ^ cy.to_bits().wrapping_mul(19_349_663)) as u32;
let seed_y = seed_x.wrapping_mul(668_265_263);

// inside pixel loop:
let ox = px.wrapping_add(seed_x);
let oy = py.wrapping_add(seed_y);
let noise = (ox.wrapping_mul(73_856_093) ^ oy.wrapping_mul(19_349_663)) & 1023;
let grain = noise as f32 / 1023.0;
let threshold = 0.18 * (1.0 - pressure) + 0.08;
let grain_alpha = if grain < threshold {
    (grain / threshold).clamp(0.0, 1.0)
} else {
    0.35 + 0.65 * grain
};

// use grain_alpha instead of `(0.35 + 0.65 * grain)`.

2.3 Preset tuning (optional, verify visually)

If the new soft alpha makes dry-media strokes too dark or too dense, tune hcie-dry-media-brushes/src/lib.rs:

  • Reduce opacity slightly for charcoal/pastel presets.
  • Increase spacing a little for coarse charcoal presets.

Do not add jitter as the primary fix; jitter alone does not break the canvas-space hash pattern.

Part 3: AGENTS.md Update

AGENTS.md currently describes the old egui-first architecture. Update it to match the actual project state.

3.1 Title & Mission

Change:

# HCIE-Rust v4 — AI-Aware Architecture

to:

# HCIE-Rust v3.05 — AI-Aware Architecture

Add a note:

> Note: `v3.05` is the in-repo identifier for what was previously labelled "v4" in older documentation and paths. The egui workspace is no longer maintained; the active native GUI is the Iced workspace.

3.2 Layer 6 GUI section

Replace the existing Layer 6 table with:

### Layer 6: GUI — open, agents work here

The active native GUI is the Iced workspace. The egui workspace exists for legacy reference but is not the current target.

| Crate / Project | Directory | Responsibility | Dependencies |
|-----------------|-----------|----------------|--------------|
| `hcie-iced-app` | `hcie-iced-app/` | Workspace root for the native Iced GUI. | `hcie-engine-api`, `hcie-iced-gui`, panels |
| `hcie-iced-gui` | `hcie-iced-app/crates/hcie-iced-gui/` | Main binary and application orchestration. | `hcie-engine-api`, panels |
| `iced-panel-adapter` | `hcie-iced-app/crates/iced-panel-adapter/` | Dynamic schema-to-widget UI binder. | `hcie-engine-api` |
| `iced-panel-ai-chat` | `hcie-iced-app/crates/iced-panel-ai-chat/` | AI chat panel. | `hcie-engine-api`, `hcie-ai` |
| `iced-panel-script` | `hcie-iced-app/crates/iced-panel-script/` | Scripting / automation panel. | `hcie-engine-api` |
| `hcie-dry-media-brushes` | `hcie-iced-app/crates/hcie-dry-media-brushes/` | Dry-media brush presets. | `hcie-engine-api` |
| `hcie-watercolor-brushes` | `hcie-iced-app/crates/hcie-watercolor-brushes/` | Watercolor brush presets + splat preview. | `hcie-engine-api` |
| `hcie-ink-brushes` | `hcie-iced-app/crates/hcie-ink-brushes/` | Ink brush presets. | `hcie-engine-api` |
| `hcie-paint-brushes` | `hcie-iced-app/crates/hcie-paint-brushes/` | Paint brush presets. | `hcie-engine-api` |
| `hcie-digital-brushes` | `hcie-iced-app/crates/hcie-digital-brushes/` | Digital/vector brush presets. | `hcie-engine-api` |

Keep the egui workspace mentioned in a short "Legacy / frozen" subsection so existing paths are not a surprise, but mark it clearly as not to be modified.

3.3 Build Order

Update Layer 6 line to:

Layer 6:  hcie-iced-app / hcie-iced-gui

3.4 Performance Protection Notes

Replace egui-specific references with Iced equivalents:

  • hcie-egui-app/crates/hcie-gui-egui/src/app/mod.rshcie-iced-app/crates/hcie-iced-gui/src/app.rs
  • hcie-egui-app/crates/hcie-gui-egui/src/canvas/mod.rshcie-iced-app/crates/hcie-iced-gui/src/canvas/mod.rs
  • Keep all wgpu/Shader/RefCell dirty bounds/Nearest-Neighbor protections as-is (they already describe the Iced path).

3.5 Screenshot & Visual Verification

Replace the egui screenshot section with the Iced CLI and F12 mechanisms documented in hcie-iced-app/crates/hcie-iced-gui/src/cli.rs and screenshot.rs:

# Full viewport
cargo run -p hcie-iced-gui -- --screenshot output.png

# Named panel
cargo run -p hcie-iced-gui -- --screenshot-panel "Brushes" output.png

Available panel names: inspect src/screenshot.rs / src/dock/state.rs for the exact name list.

3.6 Open Files List

Update the "Open Files" section to the iced paths:

- `hcie-iced-app/crates/hcie-iced-gui/src/*.rs`
- `hcie-iced-app/crates/hcie-iced-gui/Cargo.toml`
- `hcie-iced-app/crates/iced-panel-adapter/src/*.rs`
- `hcie-iced-app/crates/iced-panel-ai-chat/src/*.rs`
- `hcie-iced-app/crates/iced-panel-script/src/*.rs`
- `hcie-iced-app/crates/hcie-dry-media-brushes/src/*.rs`
- `hcie-iced-app/crates/hcie-watercolor-brushes/src/*.rs`
- `hcie-iced-app/crates/hcie-ink-brushes/src/*.rs`
- `hcie-iced-app/crates/hcie-paint-brushes/src/*.rs`
- `hcie-iced-app/crates/hcie-digital-brushes/src/*.rs`

3.7 Important Notes

Update to:

  • Never add an egui dependency to any engine crate.
  • Never access hcie-protocol directly from GUI code.
  • Never import a locked engine crate directly from GUI code; route everything through hcie-engine-api.
  • The active GUI workspace is hcie-iced-app/. Treat hcie-egui-app/ as read-only legacy reference.

Part 4: Validation Steps

4.1 Compile

cargo check -p hcie-brush-engine
cargo check -p hcie-engine-api
cargo check -p hcie-iced-gui

4.2 Unit / regression tests

cargo test -p hcie-engine-api --test visual_regression
cargo test -p hcie-engine-api --test performance_stroke_4k -- --nocapture
cargo test -p hcie-dry-media-brushes

4.3 Visual verification (Iced)

  1. Launch the Iced GUI.
  2. Select a dry-media preset (e.g., Soft Pastel, Charcoal Pencil).
  3. Draw several overlapping strokes on white canvas.
  4. Confirm the checkerboard is gone and a soft paper-grain texture remains.
  5. Compare with a round soft brush to ensure regular brushes are unchanged.
  6. Capture before/after screenshots:
    cargo run -p hcie-iced-gui -- --screenshot after_brushes.png
    

4.4 Lock crate after edits

Because hcie-brush-engine is a locked engine crate, unlock before editing and lock after:

./unlock.sh hcie-brush-engine
# ... apply source edits ...
cargo test -p hcie-engine-api --test visual_regression
./lock.sh hcie-brush-engine

Risks & Rollback

  • Risk: The alpha-modulation change may darken/lighten existing dry-media presets.
    • Mitigation: Tune preset opacity/spacing after visual comparison.
  • Risk: visual_regression golden hashes may change because brush pixel output changes.
    • Mitigation: If the new output is visually correct, regenerate golden hashes with HCIE_REGEN_GOLDENS=1 cargo test -p hcie-engine-api --test visual_regression -- --nocapture and commit the updated hashes.
  • Risk: AGENTS.md references to exact line numbers may drift.
    • Mitigation: Replace line-number citations with file paths or function names where possible.

Task Summary

  1. Unlock hcie-brush-engine — file already writable (666), directory 555.
  2. Edit draw_grain_brush — per-dab seed offset + soft alpha modulation applied.
  3. Edit draw_crayon_brush — per-dab seed offset + soft alpha modulation applied.
  4. Fix generate_star_stamp — changed from 5-pointed star to 4-pointed plus-cross.
  5. Enhance draw_star_brush — added sparkle particle scatter around main dab.
  6. Iced GUI: Renamed "Star" → "Star Sparkle", moved to Effects category.
  7. Iced GUI: Updated media_preset_category to handle "Effects" category.
  8. Egui GUI: Renamed "Stipple Dots" → "Star Sparkle" in styles grid.
  9. Added "Star Sparkle" preset to hcie-dry-media-brushes crate (id: star_sparkle).
  10. Updated preset count assertions (dry-media: 19→20, iced panel: 47→48).
  11. cargo check passes for brush-engine, dry-media-brushes, iced-gui.
  12. cargo test -p hcie-dry-media-brushes passes.
  13. Build and run visual_regression + performance_stroke_4k tests (needs full rebuild).
  14. Run Iced GUI, test affected presets, capture before/after screenshots.
  15. Update AGENTS.md to reflect v3.05 naming, the Iced workspace, and current open/locked boundaries.
  16. Lock hcie-brush-engine and hcie-egui-app.