
Страница логина и ЕСТЬ демо
GeekBye v1.7.5 добавил скриншот продукта на страницу логина и удалил его в тот же день — пересобрав вместо него демо из настоящих компонентов. Плюс: пользователь, который оказался быстрее OCR, и как на самом деле выглядят 25 стилевых коммитов за один день.
GeekBye v1.7.5 — недельный релиз с раздвоением личности: 37 коммитов, из которых 28 — редизайн страницы логина, а 25 из них — микроправки style(login), все приземлившиеся за один день. Это же релиз, который починил одну из самых поучительных гонок в кодовой базе. Обе истории стоит рассказать, и сходятся они в одной идее: страница логина — первое, что видит неавторизованный пользователь, так что пусть она лучше будет продуктом, а не его картинкой.
Скриншот — часов на пять
Редизайн начался конвенционально. Перестроить на две колонки, вход слева, продукт справа — картинкой. Позднеутренние коммиты делают ровно это: в 11:57 в репозиторий приземляется настоящий превью-скриншот, PNG на 114 KB, и через шесть минут его один раз обновляют.
В 17:04 его уже не было. Коммит-разворот заменяет статичную картинку 344 строками настоящих компонентов — панелью LoginDemo, собранной из восьми маленьких кусочков, воспроизводящих реальный UI оверлея: пилюля записи в навбаре с пульсирующими столбиками эквалайзера и кнопкой «стоп», панель чата с вкладками Chat/Transcript, отрендеренный ответ ассистента (объясняющий React-овский useEffect — как символично), быстрые действия "Tell me more / Simplify / Show example" (расскажи подробнее / упрости / покажи пример), ряд живых подсказок и поле Assist с ⌘⏎.
Давайте будем точны со словом «демо», потому что тут легко переобещать: у кнопок настоящие hover-состояния — свечения, шиммеры, переходы, — но ничего не подключено к клику, а поле ввода только для чтения. Это не песочница. Это — реальный UI-словарь продукта, отрендеренный вживую: тот же ассет логотипа, те же градиентные рамки и backdrop-blur, тот же импорт productName, которым пользуется white-label-система, — так что демо автоматически ребрендируется для каждого продукта, собираемого из этой кодовой базы. Скриншот ничего из этого не умеет. Скриншот устаревает в день съёмки, размывается на неправильном дисплее и навсегда забрендирован тем продуктом, который ты случайно запечатлел. Компоненты чёткие при любом DPI, всегда актуальны и корректны для каждого бренда — потому что они не фотография дизайн-системы, они и есть дизайн-система.
Удалённый PNG, кстати, всё ещё лежит в репозитории на теге релиза — осиротевший, ни на что не ссылающийся. Каждая кодовая база носит в себе пару окаменелостей проигравшего подхода.
Как выглядят 25 стилевых коммитов за один день
Лог коммитов того единственного дня — это блокнот дизайнера, сохранённый с необычной честностью. Соотношение колонок пошло 40/60, потом 45/55. Лейбл "Works with" (работает с) над логотипами платформ добавили в полдень, передвинули и убрали — он прожил примерно полдня. Сам ряд логотипов платформ (Google Meet, Teams, Zoom, Slack, Webex), добавленный в 10:59 утра, был целиком удалён в 22:08 той же ночью. А футер пережил сагу выравнивания в четыре подхода: один контейнер-обёртка, потом удаление центрирующих классов, потом центрирование флексбоксом, потом просто придвинуть его ближе к низу.
Легко прочитать это как суету. Мы читаем это как настоящую форму дизайнерской работы: ты сходишься к решению, рендеря, глядя и подправляя — а делать это в 25 маленьких коммитах вместо одного сквошнутого «redesign login page» значит, что сам поиск оказывается записан. Когда кто-то спросит «а мы разве не пробовали ряд логотипов?», ответ лежит в истории, с таймстемпами.
Пользователь, который был быстрее OCR
Инженерная история релиза случилась пятью днями раньше, в цепочке из трёх фикс-коммитов. Начиная с v1.5.12 нажатие Cmd+H ставит скриншот в очередь с мгновенной обратной связью: миниатюра появляется в очереди сразу, а извлечение текста — локальный OCR Apple Vision, примерно ~1-2 секунды — крутится в фоне. Событие очереди буквально уходит с ocrText: '' и комментарием, обещающим, что текст заполнится позже.
Это хорошая оптимизация — и она отчеканила гонку. Быстрый пользователь жмёт Cmd+H и тут же отправляет вопрос. Текстовое поле скриншота всё ещё пустое. Запрос уходит без содержимого экрана, и модель отвечает — правдиво и бесяще — "I cannot see images" (я не вижу изображений). Наивный путь не упал с ошибкой; он упал правильным ответом на неправильный вопрос — самый запутывающий способ, которым может ломаться софт.
Фикс блокирует путь отправки на той асинхронной работе, которую оптимизация отложила: если у любого скриншота в очереди текст OCR всё ещё пуст, запрос паркуется, а UI показывает индикатор "Reading screen..." (читаю экран); useEffect срабатывает в момент, когда текст приземляется, и отправляет запрос с полным извлечённым содержимым. Две React-специфичные детали в диффе стоит украсть: очередь скриншотов зеркалится в ref, синхронизируемый во время рендера, потому что цепочка замыканий обработчиков событий захватывала устаревшее состояние; и запаркованный запрос отправляется напрямую, а не через общий хук очереди запросов — по той же причине stale closure.
И прямо в сообщении коммита записана честная морщинка: трассировочные логи, добавленные, чтобы выследить эту гонку, вскрыли второй баг на бэкенде — сборка промпта в одном из путей кода полностью теряла текст скриншота. Один симптом, два бага, найденные инструментированием всей цепочки и наблюдением, где текст исчезает. Цепочка закончилась продуктовым решением, через девять минут после фикса гонки: Cmd+H ставит скриншоты в очередь для пакетного анализа, а Cmd+Enter всегда делает свежий снимок текущего экрана — два разных воркфлоу вместо одного двусмысленного. (Что на самом деле делает Assist по Cmd+Enter — тема отдельного поста: мгновенная помощь AI по тому, на что ты смотришь.)
Маленькая кода той же недели для читателей главы про white-label: User-Agent Product/version (platform) получил фикс для dev-режима, потому что app.getVersion() в незапакованном Electron возвращает версию Electron, а не продукта. Строки идентичности, как всегда, протекают в сантехнике.
Три вещи, которым нас научил этот релиз
- Рендери продукт, а не фотографируй его. Демо страницы логина, собранное из настоящих компонентов, само ребрендируется, переживает любую плотность экрана и не может устареть. Подход со скриншотом попробовали и удалили в пределах одного рабочего дня — дешёвый эксперимент, ясный вердикт.
- Каждой асинхронной оптимизации нужен шлагбаум в точке использования. «Мгновенная обратная связь с пустым текстом OCR» была правильным UX-решением, но пути отправки пришлось научиться ждать то, что оптимизация отложила. Если откладываешь работу — найди каждого потребителя её результата и научи его разнице между «пусто» и «ещё не готово».
- Инструментируй цепочку, а не подозреваемого. Трассировочные логи следили за текстом скриншота от конца до конца — от обработчика шортката через IPC до API-клиента — и именно поэтому одно расследование закрыло два бага, один из которых был по ту сторону сети.
Про предыдущую главу истории v1 — встречи, которые снова можно найти (v1.7.3); а про весь путь — анатомию доведения софта до совершенства.