Files
Codex ef3bc6d133 fix: габарит мебели равен заявленным размерам (#584)
Указанные ширина и глубина теперь совпадают с видимым габаритом предмета.
Раньше рисунок занимал внутри своего бокса около 88 % стороны, поэтому
«Кухонный напольный модуль» 60 × 60 выглядел меньше «Посудомоечной машины»
60 × 60 примерно на 14 % по стороне и на 30 % по площади: цифры совпадали,
картинка врала.

Пак `fix-584-1` от дизайнера (issue, комментарий от 16.09) проверен исполнением
своей метрикой, а не его отчётом: границы считаются аналитически по той же
математике, что у продакшен-экспорта в PDF. Все 44 плановых SVG заполняют
`viewBox` с худшим отклонением 0.000000 при допуске ТЗ 0,1; `pack.json` и 33
иконки меню побайтно прежние. Для сравнения, прежний набор в `dev` давал 65
нарушений того же контракта.

Что сделано в коде:

- `scripts/svg-path-bounds.mjs` — границы рисунка по настоящим экстремумам
  кривых (дуги приводятся к кубикам). Контрольные точки в габарит не входят:
  иначе «заполняет бокс» проверялось бы по выпуклой оболочке и поля проходили
  бы мимо. Генератор — `.mjs` и обязан работать без сборки TypeScript, поэтому
  разбор здесь свой; тест сверяет его с `parseSvgPath` продакшена на всей
  библиотеке, чтобы реализации не разъехались молча.
- `scripts/furniture-path-join.mjs` — склейка нескольких `<path>` с
  канонизацией только начального `moveto`. Приём подсказан патчем в поставке
  дизайнера; реализация и свидетели свои. Прежний `paths.join(' ')` продолжал
  координаты предыдущего пути: замер показал, что у иконок меню `stairs` и `tv`
  части рисунка уезжали за `viewBox` 110 × 110 — до 119. Теперь склейка
  побайтно воспроизводит «каждый путь из своего нуля».
- генератор проверяет плановый символ по контракту: один путь, подконтуры с
  абсолютной `M`, рисунок заполняет `viewBox` (допуск 0,1).
- `src/furniture.ts` — legacy `plant` растянут от центра в 1/0.96. Это
  единственный из двенадцати retained-примитивов с полями (0.02…0.98 unit box);
  форма прежняя, габарит стал заявленным.

Свидетели: `test/furniture-visual-bounds.test.mjs` (AC1–AC3, AC5 и сверка двух
реализаций границ) и `test/furniture-path-join.test.mjs` (AC4, включая реальные
`stairs`/`tv`). У AC1 есть положительный контроль: та же функция обязана видеть
поля на геометрии из шапки issue — утверждение «полей нет» стоит ровно столько,
сколько стоит измерение. Мутанты `furniture-symbol-may-keep-inner-padding` и
`furniture-paths-joined-without-reset` возвращают прежнее поведение и краснеют;
прогнаны лично через `mutation-gate --id=`.

Миграции пользовательских данных нет: координаты, размеры, поворот и
зеркалирование сохраняются.

npm test 2743/2742/0 fail, typecheck чистый, furniture:check зелёный.

Issue: #584
User-Visible: yes
2026-09-16 23:02:11 +03:00
..