Files

283 lines
12 KiB
Markdown
Raw Permalink Normal View History

# 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`.