openpencil/apps/web
Fini 98211e6226 fix(ai): heuristic image-area detection for non-canonical frame placeholders
Why: 2026-05-09 user report — the food-app card design landed with
empty colored rectangles where restaurant photos should be (Bella
Italia / Green Bowl / Margherita Pizza). Root cause: the model emitted
plain frames named "Image" / "Photo" / "Cover" with a solid fill as
the card-top image area, instead of using add_image_placeholder_v1
(which sets role: 'image-placeholder'). The auto-search pipeline
strict-checks role and missed all of them, so scanAndFillImages found
nothing to search and the cards stayed solid-colored.

What: new isImageAreaFrameByHeuristic(node) supplements the strict
role check. Conservative match — only fires when ALL of:
  - frame node WITHOUT role='image-placeholder' (strict path handles
    that)
  - name matches /\\b(image|photo|cover|hero|thumbnail|thumb|picture|
    banner|poster)\\b/i
  - width >= 80 AND height >= 60 (filters tiny color swatches)
  - exactly one solid (non-image) fill (gradient = decorative, image
    = already filled, both skip)
  - 0 or 1 children (an icon child is OK, multi-child = real layout)

collectImageSearchTargets walks both the strict and heuristic paths
and produces the same kind: 'placeholder-frame' target either way, so
the existing query / aspect / search code-path runs unchanged.

10 new tests cover positive matches (Image / Photo / Cover / Hero /
Thumbnail / Banner / Poster), negative for canonical placeholder
(double-counting prevented), unrelated names (Card / Wrapper),
already-filled image fills, gradients, content-rich frames, single-
icon-child acceptance, undersize frames, and non-numeric dimensions.
26 / 26 tests in image-search-pipeline.test.ts pass (was 16; +10).
1098 / 1098 AI service tests pass (unchanged).
2026-05-09 20:59:49 +08:00
..
public V0.5.0 (#67) 2026-03-22 09:44:04 +08:00
server fix(ai): explicit skipped reason for builtin providers in vision validate 2026-05-09 20:59:34 +08:00
src fix(ai): heuristic image-area detection for non-canonical frame placeholders 2026-05-09 20:59:49 +08:00
CLAUDE.md V0.7.0 (#95) 2026-04-11 23:25:13 +08:00
components.json V0.7.0 (#95) 2026-04-11 23:25:13 +08:00
dev.ts V0.7.2-bugfix (#109) 2026-04-14 21:42:56 +08:00
package.json Merge branch 'v0.8.0' of github.com:ZSeven-W/openpencil into v0.8.0 2026-05-05 22:51:00 +08:00
tsconfig.json V0.7.2-bugfix (#109) 2026-04-14 21:42:56 +08:00
vite.config.ts Merge origin/v0.8.0 into feat/rust-ification 2026-05-03 21:00:00 +08:00