# 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: ```rust 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: ```rust 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_brush` → `draw_grain_brush` | hash threshold skip | | `Charcoal` | `draw_charcoal_brush` → `draw_grain_brush` | hash threshold skip | | `Sketch` | `draw_sketch_brush` → `draw_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` ```rust // 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: ```rust 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: ```markdown # HCIE-Rust v4 — AI-Aware Architecture ``` to: ```markdown # HCIE-Rust v3.05 — AI-Aware Architecture ``` Add a note: ```markdown > 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: ```markdown ### 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.rs` → `hcie-iced-app/crates/hcie-iced-gui/src/app.rs` - `hcie-egui-app/crates/hcie-gui-egui/src/canvas/mod.rs` → `hcie-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`: ```bash # 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: ```markdown - `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 ```bash cargo check -p hcie-brush-engine cargo check -p hcie-engine-api cargo check -p hcie-iced-gui ``` ### 4.2 Unit / regression tests ```bash 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: ```bash 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: ```bash ./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`.