Я заменил дизайнера нейронкой. Вот так, сорян

Заранее извиняюсь перед дизайнерами, которые сейчас будут кидаться в меня Figma-файлами. Тема неприятная, но обсудить её надо.

Десять лет я так или иначе занимаюсь продуктами. И все эти десять лет в каждом проекте повторялся один и тот же ритуал: дизайнер рисует макет, разработчик смотрит на макет, разработчик делает похоже. Ключевое слово — «похоже».

Дальше начинается известный жанр. «А почему отступ 20, а не 24?» — «Ну там компонент такой». «А почему кнопка серая?» — «А это disabled из старой библиотеки, её никто не трогал с 2021». «А сделай как в макете» — «Так в макете нарисовано то, чего у нас в коде нет».

И вот что обидно: формально виноватых нет. Дизайнер нарисовал по дизайн-системе. Разработчик собрал из компонентов. Просто дизайн-система в Figma и дизайн-система в коде — это два разных документа, которые расходятся тихо, годами, и никто не замечает, пока не начинаешь сверять по пикселям.

Как я вляпался

У меня был проект — SaaS с картами, довольно зрелый фронтенд на React. Я, как обычно, собирал макеты в Figma. Аккуратно, из компонентов, не из прямоугольников. Гордился собой.

А потом выяснилось, что аналитик в этой же команде давно делает по-другому. Он взял форк фронтенда, поднял Storybook и собирает макеты прямо из настоящих React-компонентов. Разработчик открывает такой макет и видит не картинку, а готовый JSX, который можно скопировать.

В его инструкции была фраза, от которой мне поплохело: «макет заменяет статичный фрейм в Figma».

То есть моя работа — это то, от чего он уходит.

Интересненько.

Первая мысль была неправильная

Первая мысль была: ну и ладно, пусть код-макеты, дизайн больше не нужен, надо переучиваться.

Вторая мысль оказалась полезнее. Я сел и сравнил его цвета с моими токенами. Совпали. Все. Тот же синий #4350AF, те же варианты кнопок, та же шкала шрифтов.

Это не две дизайн-системы. Это одна, просто в двух носителях. И проблема не в том, что кто-то из нас лишний, а в том, что между носителями нет моста. Каждый ведёт свою копию правды.

У Figma для этого вообще-то есть штатный механизм — Code Connect, он привязывает компонент в макете к компоненту в коде. Я обрадовался, полез — и упёрся в «нужен план Organization или Enterprise». У меня Professional. Спасибо, до свидания.

Ну ладно. Мост сделаем сами.

Мост

Идея простая до неприличия: завести файл, где для каждого компонента Figma написано, каким компонентом кода он является и как его свойства ложатся на пропсы. Обычный JSON, лежит в репозитории, версионируется.

И вот тут, когда я начал этот файл заполнять, полезло всё, что годами пряталось.

Кнопки. В Figma у меня был один монолитный компонент: Type × Size × State. Внутри Type лежало вперемешку: и Primary/Ghost (это варианты), и Link (а это, оказывается, вообще другой компонент в коде — легаси-обёртка над MUI), и квадратные иконочные (а это третий компонент). Цвета не было как отдельной оси вообще, хотя в коде она есть.

Состояния. У меня были нарисованы Hover и Active как варианты компонента. В коде их нет и быть не может — это CSS-псевдоклассы. Я годами рисовал сущности, которых в природе не существует.

Типографика. В Figma 13 текстовых стилей. В коде — 10. Три стиля я исправно применял в макетах, а разработчику приходилось каждый раз что-то придумывать.

Знаете, что самое неприятное? Ни один разработчик мне за все эти годы про это не сказал. Они просто молча подставляли ближайшее похожее. И были правы — объяснять дизайнеру, что его дизайн-система врёт, дороже, чем поставить body-m-400 вместо несуществующего стиля.

Я пересобрал кнопку в Figma заново. Оси назвал ровно как пропсы в коде, значения — ровно как значения в коде, вплоть до регистра: variant, color, size, disabled. Получилось 54 варианта. Hover и Active выкинул. Теперь маппинг тождественный: что видишь в макете — то и пишется в коде, переводчик не нужен.

Что получилось в итоге

Пайплайн сейчас выглядит так.

Я собираю макет в Figma строго из компонентов. Не рисую, а именно собираю — ни одного отсоединённого инстанса, ни одного нарисованного руками прямоугольника, который «выглядит как инпут».

Дальше агент читает этот макет через MCP. Не картинку — структуру: какой компонент, в каком варианте, с каким текстом. По манифесту переводит это в реальные компоненты кода, лезет в репозиторий, читает их настоящие сигнатуры и собирает .stories.tsx.

Потом tsc. Ноль ошибок — значит, я в макете не наврал. Есть ошибки — значит, наврал, и мне это скажут через минуту, а не через две недели на код-ревью.

Разработчик открывает Storybook и видит готовый JSX из тех же компонентов, которые он и так использует. Копипастит.

Скриншоты в этом процессе не участвуют вообще. Совсем. Это принципиально: как только в цепочке появляется картинка, кто-то начинает угадывать.

Где нейронка налажала

Раз уж пошёл разговор на чистоту.

Она отрисовала кнопку «Reset to defaults», которой в макете не было. То есть была — но скрытая, отключённая. Агент увидел слой и вывел его. Пришлось отдельным правилом записывать: скрытое не рендерим.

Она вывела счётчики на вкладках, которых я тоже скрыл. Тот же баг, тот же корень.

Она полдня не могла победить горизонтальный скролл в модалке. Я в итоге сам открыл девтулзы и нашёл: у скроллбара стоит min-width: 100%, а MUI-шная сетка с отступами рендерится шириной calc(100% + N). Одно упирается в другое, вылезает полоса прокрутки. Агент до этого честно перебрал три неправильные гипотезы.

Она обернула вкладки в свой контейнер с рамкой — а компонент рисует рамку сам. Получилось две полоски.

Ну и половина интерфейса внезапно заговорила по-русски, потому что в Storybook язык по умолчанию оказался не английский.

Это всё реальные косяки, и я их не прячу. Но обратите внимание на одну деталь: каждый из них я увидел за минуты. Не через месяц в продакшене, не от злого пользователя в поддержке. Потому что макет теперь компилируется и запускается.

Когда я отдавал разработчику картинку, у меня не было ни одного способа проверить, что он собрал именно то. Вообще ни одного. Я мог только смотреть глазами и сравнивать с макетом — то есть заниматься тем же угадыванием, только с другой стороны.

Так это про замену людей?

Нет. И вот здесь я, пожалуй, поясню подробнее.

Разработчиков этот пайплайн не заменяет. Он заменяет передачу макета — тот самый момент, где смысл терялся. Разработчик по-прежнему пишет продукт, спорит со мной про UX, чинит то, что я собрал криво, и он же должен внести в код те правки, которые я у себя пометил комментарием «для разработчика».

Кстати, про пометки. У нас правило: если для макета нужно поправить общий компонент — мы этого не делаем. Мы делаем локально, у себя в песочнице, и оставляем комментарий, чтобы разработчик потом починил по-нормальному. Потому что стиль, который я поправлю «только для своей модалки», прилетит во все таблицы приложения, а я об этом даже не узнаю.

Изменилось другое: теперь мы с разработчиком спорим о продукте, а не о том, чей документ считать правдой. Правда одна — код. Figma держит внешний вид, код держит структуру и поведение. Если они разошлись — это видно сразу, а не через полгода.

Кому это не надо

Если у вас лендинг на три экрана — забудьте, вы потратите на настройку больше, чем сэкономите.

Если у вас нет дизайн-системы в коде, а есть только «ну там компоненты какие-то» — сначала компоненты, потом мосты.

Если у вас есть деньги на Enterprise-план Figma — возьмите Code Connect, он делает то же самое, только штатно, и не надо городить манифесты.

А вот если вы, как я, десять лет отдаёте макеты и десять лет получаете «похоже» — попробуйте. Начните с одной кнопки. Откройте её в Figma, откройте её в коде и просто сравните списки свойств.

В стартапах и малом бизнесе нейронки уже успешно заменяют дизайнеров, разработчиков и даже аналитиков. В общем-то, и коперайтеров тоже.

Комментарии

Индекс популярности

Подробнее о том, как считается индекс и что означает каждый параметр, — читайте в справочнике.