- Обложка генерируется из названия и категории события за один вызов, около 10 секунд
- Промпт собирается по осям A.O.C. поверх фиксированного стилевого префикса листинга
- Невидимый суффикс держит композицию full-bleed, а белую обводку срезает авто-кроп
Задача
В zdes.events события приходят двумя потоками: организаторы создают их руками, а агрегатор подтягивает публичные анонсы из открытых афиш и каналов организаторов. У большой части нет картинки вообще, у остальных она случайная: скриншот афиши, фото с телефона, чужой постер с текстом. Листинг из таких карточек выглядит как доска объявлений, а не как продукт с собственным лицом.
Обычный путь — шаблонный конструктор обложек с селекторами фона и шрифта — я попробовал первым и выбросил. Он давал одинаково унылые карточки, тяжело грузил страницу создания и всё равно требовал от организатора решений, которых тот принимать не хочет. Нужен был способ получить картинку из того, что уже есть: названия, описания и категории, причём так, чтобы тысяча обложек читалась как одна серия.
Приём
Обложка собирается в два слоя. Первый — стилевой префикс листинга: одна фиксированная строка про технику и палитру, общая для всех обложек раздела. Для блога и подборок — это двухцветная ризография в фирменных цветах на крем-бумаге; для событий, созданных руками, — банк из примерно 14 курируемых арт-направлений, из которого случайно берётся одно. Стиль перестаёт быть решением на каждую картинку и становится константой, как описано в архитектуре стилевого префикса.
flowchart LR
L{Листинг} -->|блог, подборки| R[Ризография<br/>в фирменных цветах]
L -->|события руками| B[Случайное из ~14<br/>арт-направлений]Второй слой — содержательный промпт — пишет языковая модель по мета-промпту арт-директора, построенному на осях A.O.C.: что в кадре (одна ситуативная виньетка из темы события), как скомпоновано (фокус-субъект и негатив-спейс), как освещено (физический свет и ограниченная палитра, mood-слова вроде «moody» и «epic» запрещены). Мета-промпт получает локаль страницы и пишет промпт на её языке; статический фолбэк на случай недоступности модели тоже двуязычный.
[стилевой префикс листинга]
ANCHOR: одна ситуативная виньетка из темы события
COMPOSITION: один фокус-субъект, негатив-спейс
CHEMISTRY: физический свет, ограниченная палитра, без mood-слов
STYLE: в духе {направление из банка}
[невидимый суффикс: the image IS the artwork, bleeds to all four
edges, not a photo of a poster, no mockup / frame / margin,
no text, no logos, no watermarks]
Невидимый суффикс приклеивается к каждому промпту на сервере и пользователю не показывается. Его история показательна. Первая версия содержала слово «poster», и модель честно рисовала постер: лист на серой стене с тенью. Убрал слово, добавил прямое «это изображение и есть работа, заливка до всех четырёх краёв, не фото плаката» и запрет на рамки, мокапы и поля. Туда же ушёл запрет клише «силуэт на закате» и защита от текста и лишних рук.
flowchart TB
subgraph before[Первая версия суффикса]
direction LR
V1[Слово poster<br/>в промпте] --> R1[Лист на серой<br/>стене с тенью]
end
subgraph after[Рабочая версия]
direction LR
V2[Изображение и есть<br/>работа, до краёв] --> R2[Арт на весь кадр,<br/>без рамок и мокапов]
end
before ~~~ after
classDef key stroke:#FF3600,stroke-width:2px
class R1 keyГенерация one-shot: нажал кнопку, через ~10 секунд обложка стоит на форме, диалог закрылся. Превью, «Заново» и «Использовать» убраны намеренно: цикл выбора из вариантов превращает быстрый инструмент в редактор, а если результат не нравится, проще нажать ещё раз. Из той же логики и бюджет: 5 генераций в месяц на пользователя, слот возвращается, если вызов упал. Модель, Nano Banana 2, выбрана после замера: предыдущий кандидат отдавал картинку примерно за 45 секунд — это в четыре с лишним раза дольше.
flowchart LR
K[Кнопка] --> G[Nano Banana 2:<br/>~10 секунд]
G --> O[Обложка на форме,<br/>диалог закрыт]
O -. не нравится .-> K
G -. вызов упал .-> S[Слот из 5<br/>возвращается]Последний узел — автоматический кроп. Модель, несмотря на запрет в промпте, периодически добавляет тонкую кремовую «печатную» рамку по периметру. Усиление промпта («zero print margin, no keyline») помогало ненадёжно, поэтому кроп сделан в браузере на шаге конвертации. Каждая сторона проверяется на near-white (яркий пиксель с низкой насыщенностью, чтобы закатное небо не считалось рамкой); если хотя бы две стороны согласны, срезается максимальная найденная ширина плюс 2 пикселя равномерно со всех четырёх сторон. Первая версия усредняла цвет четырёх углов и на частичной рамке получала грязный референс, ничего не кропала; абсолютный порог решил это. На контрольном примере 928×1152 с рамкой стало 872×1096 с артом до краёв.
flowchart LR
S[Каждая сторона:<br/>near-white?] --> Q{Согласны<br/>хотя бы две?}
Q -->|да| C[Срез: макс. ширина<br/>+2 px со всех сторон]
Q -->|нет| N[Без кропа]
C --> R[928×1152 стало<br/>872×1096]
classDef key stroke:#FF3600,stroke-width:2px
class C keyОтдельный урок пришёл от обложек подборок. Три версии промпта дрейфовали по культуре: первая рисовала западный город по умолчанию, вторая перекорректировалась в советскую открытку, третья с чек-листом «современной России» давала перегруженные панорамы с текстом. Рабочей оказалась четвёртая: одна виньетка из темы плюс единственный негативный гард на фон. Культурные якоря в image-промптах работают только как запреты, никогда — как списки атрибутов.
flowchart LR
V1[Западный город<br/>по умолчанию] --> V2[Советская<br/>открытка]
V2 --> V3[Перегруженные<br/>панорамы с текстом]
V3 --> V4[Одна виньетка +<br/>негативный гард]
classDef key stroke:#FF3600,stroke-width:2px
class V4 keyГде ломается
- Текст в картинке. Запрет в суффиксе снижает частоту, но не исключает буквы и псевдонадписи, особенно когда название события само похоже на вывеску. Фильтра на выходе нет — ловит глаз организатора.
- Повторяемость. Фиксированный префикс даёт единый язык, но при одинаковой категории модель тянется к одним и тем же сюжетам. В подборках обложки несколько раз подряд показывали одно животное, потому что сюжет брался из заголовка выпуска; пришлось строить его по разбросу историй и банить маскотов.
- Стоимость и бюджет. Генерация заметно дороже классификации текстом, отсюда лимит на пользователя и доступ только авторизованным. Для тысяч агрегированных событий это означает выбор между обложкой и её отсутствием, а не между вариантами.
- Кроп по эвристике. Порог 50% и требование двух согласных сторон настроены на конкретную модель. Светлый арт с белыми краями может потерять пару пикселей, а рамка нестандартного цвета пройдёт.
Обновление, сентябрь 2026. В zdes.media тот же приём — фиксированная ризография плюс сюжет по разбросу историй — в сентябре отступил на роль запасного. Сгенерированная обложка дороже подбора, а единый стиль делает ленту однотипной: выпуски на взгляд перестают отличаться. Теперь обложкой становится фото из материалов источника, со ссылкой на первоисточник, а ризография рисуется, только если в источнике ничего не нашлось. Генерация закрывает дыру там, где картинки нет вообще, но не заменяет настоящую.
Итог
- Обложка из названия и категории закрывает главную дыру листинга: событие без картинки.
- Стиль вынесен в префикс, содержание — в A.O.C.-промпт; их можно менять независимо.
- Модель нарушает «no border» и «no poster» достаточно часто, чтобы страховать их кодом, а не только промптом.
- Один вызов без выбора из вариантов быстрее и честнее для быстрого инструмента, чем галерея превью.
© Александр Никулин. Цитирование — с указанием автора и ссылкой · Версия для LLM