11 KiB
Dynamic Tooltip Crop Implementation Plan
Intent: Сделать ручную калибровку пиксель-точной при масштабе 2× и читать строки tooltip переменной ширины без OCR всего кадра.
Current Behavior: Калибратор показывает кадр 1:1, а runtime после поиска Price : использует фиксированную ширину калиброванных строк названия и цены.
Expected Outcome: Кадр размечается в масштабе 2×; найденные строки названия и итоговой цены tooltip локально подгоняются вправо по фактическим белым и жёлтым пикселям до первого устойчивого пустого промежутка, включая текст длиннее калиброванного образца.
Target-Perspective Output: Пользователь выделяет мелкие области на увеличенном кадре и получает название и цену как для короткого, так и для длинного tooltip без постороннего текста за его правой границей.
Truth Owner: src/vision.js владеет определением фактической правой границы OCR-строки; калибровка сохраняет стабильный левый край, положение и высоту строки относительно Price :.
Contract Boundary: Чистый findTextRunEnd(columns, gap) находит конец первого текстового пробега. Canvas-wrapper fitOcrTextRect(canvas, rect, options) сканирует от калиброванного левого края до правой границы кадра, использует gap 12 px и padding 6 px, применяет white mask для названия и white+yellow для цены и возвращает frame-clamped rect либо null, если пробег не найден.
Cutover: analyzeFrame подгоняет nameRect и priceRect перед combineRects; прямое использование фиксированной ширины прекращается.
Displaced Path: Фиксированные ширины itemNameRegion и itemPriceRegion больше не задают окончательную границу и не используются как широкий OCR fallback; при пустой маске item OCR пропускается с диагностикой.
Value Density: Один локальный пиксельный проход по двум тонким строкам вместо OCR широкой области или нескольких OCR-попыток.
Evidence Gate: На реальном тестовом кадре 1920×1080 canvas отображается 3840×2160; выделение в 2× визуально совпадает с целевыми source-пикселями; реальный tooltip читается при искусственно короткой калиброванной ширине, а удалённый соседний текст не попадает в diagnostics crop/OCR.
Acceptance Evidence: Browser geometry и screenshot выделения; границы двух реальных строк разной длины из предоставленного tooltip; diagnostics crop + parsed name/price этого tooltip при намеренно узкой калиброванной ширине; runnable-тест чистого определения конца текстового пробега; production build.
Evidence Lane: Локальный браузер и node --test.
Kill Criteria: В runtime нет второго OCR-пути по широкой области или широкого фиксированного fallback; combineRects не вызывается до успешной подгонки обеих строк.
Architecture Slice: src/main.js, src/vision.js, src/style.css, test/parser.test.js, README.md; документация калибровки уточняет различие зоны поиска и OCR-строк.
Plan Review Gate: Requires PRE review before execution.
Architecture Slice
- Files to create: только этот goal-пакет.
- Files to modify:
src/main.js,src/vision.js,src/style.css,test/parser.test.js,README.md. - Files to avoid: сохранённый формат калибровки, парсер текста tooltip, market outbox и backend.
- Source of truth: найденный
Price :задаёт позицию; пиксели текущего кадра задают фактическую ширину. - Read path: кадр → поиск магазина → поиск
Price :→ калиброванные строки → подгонка по пикселям → OCR → parser. - Write path: без новых сохраняемых полей; существующая калибровка остаётся совместимой.
- Contract boundary: чистый
findTextRunEndи canvas-wrapperfitOcrTextRectв vision-слое. - Integration points: два прямоугольника в
analyzeFrame, CSS-размер canvas. - Migration/cutover: немедленный, без миграции данных.
- Displaced path: фиксированная ширина перестаёт быть OCR fallback; пустая маска становится наблюдаемым
not-foundв diagnostics. - Acceptance evidence gate: 2× browser geometry + screenshot точного выделения + diagnostics реального tooltip + unit test длинной строки + full build.
Runtime Invariants
- Левый край строк названия и цены стабилен относительно найденного
Price :; переменной является правая граница. - Продукт сохраняет только название, количество и итоговую цену; остальные описательные строки tooltip не являются данными продукта.
tooltipSearchRegionможет быть широкой горизонтальной полосой за пределами окна трейда, но исключает нижнийPriceосновного окна; эта полоса используется только для template matching.- Сканирование OCR-строки начинается с её калиброванного левого края, идёт не дальше правой границы кадра, допускает внутренние промежутки меньше 12 px и добавляет не более 6 px после последнего текстового столбца.
- Название использует белую маску; цена использует белую и жёлтую маски.
- Если текстовый пробег не найден, OCR предмета не запускается, а diagnostics явно сообщает причину.
Tasks
- Последовательно изменить
src/main.jsиsrc/style.css: отображать calibration canvas ровно в 2× intrinsic size; координаты остаются корректными через существующийcanvasPoint.- Allowed scope: только display size и crisp integer scaling.
- Verification: браузер показывает intrinsic 1920×1080 и rendered 3840×2160; screenshot известного выделения совпадает с source-пикселями.
- Затем изменить
src/vision.jsиtest/parser.test.js: добавить чистыйfindTextRunEndи локальную подгонку правого края с раздельными масками, gap 12, padding 6 иnullдля пустой маски.- Allowed scope: preprocessing границы; без нового OCR-прохода и без зависимости canvas в Node.
- Verification:
node --testпокрывает длинный текст, внутренние пробелы, удалённый шум и пустую маску.
- После задачи 2 интегрировать подгонку в
src/main.jsдоcombineRects; приnullостановить item OCR и записать причину в diagnostics.- Allowed scope: существующий item OCR branch.
- Verification: diagnostics показывают фактический локальный crop, а широкий search region и удалённый соседний текст не попадают в OCR.
- Обязательно обновить
README.md: широкая полоса ищет толькоPrice :; ширины строк являются начальными левыми/вертикальными ориентирами и подгоняются runtime.- Allowed scope: только инструкции выбора
tooltipSearch,itemNameиitemPrice. - Verification: README больше не требует калибровать ширину по самому длинному предмету.
- Allowed scope: только инструкции выбора
- Прогнать прямые эквиваленты
npm test,npm run build,git diff --checkи визуальную проверку большого кадра; записать реальные результаты вEVIDENCE.md.- Acceptance evidence: geometry 2×, screenshot точного выделения, границы двух реальных строк, diagnostics OCR/parse и вывод проверочных команд.
Non-goals
- Не определять всю рамку tooltip и не сохранять его описательные строки, потому что продукту нужны название, количество и итоговая цена.
- Не искать
Price :по всему кадру без ограничивающей полосы. - Не добавлять настройку масштаба или новый UI-контрол в этом срезе.
- Не менять формат сохранённой калибровки.
Risks
- Слишком короткий допустимый пробел обрежет текст; слишком длинный захватит соседний UI.
- Горизонтальная рамка внутри строки может выглядеть как непрерывный текст; точные вертикальные калиброванные строки остаются обязательными, а пустой/неограниченный пробег должен завершаться
not-found, не широким OCR.