Files

11 KiB
Raw Permalink Blame History

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-wrapper fitOcrTextRect в 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

  1. Последовательно изменить 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-пикселями.
  2. Затем изменить src/vision.js и test/parser.test.js: добавить чистый findTextRunEnd и локальную подгонку правого края с раздельными масками, gap 12, padding 6 и null для пустой маски.
    • Allowed scope: preprocessing границы; без нового OCR-прохода и без зависимости canvas в Node.
    • Verification: node --test покрывает длинный текст, внутренние пробелы, удалённый шум и пустую маску.
  3. После задачи 2 интегрировать подгонку в src/main.js до combineRects; при null остановить item OCR и записать причину в diagnostics.
    • Allowed scope: существующий item OCR branch.
    • Verification: diagnostics показывают фактический локальный crop, а широкий search region и удалённый соседний текст не попадают в OCR.
  4. Обязательно обновить README.md: широкая полоса ищет только Price :; ширины строк являются начальными левыми/вертикальными ориентирами и подгоняются runtime.
    • Allowed scope: только инструкции выбора tooltipSearch, itemName и itemPrice.
    • Verification: README больше не требует калибровать ширину по самому длинному предмету.
  5. Прогнать прямые эквиваленты 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.