Лендинг конференции за один день: Next.js + Dokploy

Иногда проект начинается с одного сообщения в чат. «Мне надо сделать сайт моего мероприятия» — и понеслось. Именно так появился 18ai.pashavin.ru — лендинг для конференции «Навстречу к AI», которую мы провели вживую, с реальными спикерами, площадкой «Калибр» и всеми радостями офлайн-ивента, включая техничку, которая подвела прямо перед стартом.
В этой статье расскажу, как за одну сессию разработки мы получили полноценный продакшн-сайт: с анимациями, галереей, секцией дресс-кода с реальными референсами, мобильной вёрсткой и автодеплоем через Dokploy. По пути решили несколько нетривиальных задач — от горизонтального скролла на мобилке до построения CI/CD-пайплайна через webhook.
Контекст: зачем вообще делать сайт после ивента
Конференция «Навстречу к AI» уже прошла. Спикеры отстрелялись, гости разошлись, площадка освободилась. Казалось бы — зачем сайт? Но у постфактум-лендингов есть своя ценность:
- SEO и органика. Люди гуглят «AI конференция [город]» — и находят тебя, узнают о следующем событии.
- Социальное доказательство. Фотогалерея, спикеры, программа — всё это работает как портфолио организатора.
- База для следующего ивента. Шаблон уже готов, следующий раз — просто обновить контент.
- Дресс-код и атмосфера. Люди хотят знать, как одеваться. Хороший лендинг снимает этот вопрос заранее.
Так что сайт — это не «запоздалый пиар», а инструмент с долгосрочной отдачей.
Стек и архитектурные решения
Выбор стека был очевиден — он диктуется общим дизайн-системой pashavin.ru:
- Next.js 14 — App Router, статическая генерация, оптимизация изображений из коробки
- Tailwind CSS — утилитарные классы, нет необходимости изобретать велосипед
- GSAP — анимации заголовка, плавные появления секций
- Dokploy — собственная PaaS-платформа для деплоя через Docker
- GitHub Webhook — автодеплой при пуше в
master
Дизайн строго выдержан в фирменном стиле: тёмный фон, оранжевый акцент #FF4F00, шрифт Syne. Никаких Bootstrap, никаких готовых UI-китов — всё кастомное.
Hero-секция: GSAP и посимвольная анимация
Главный заголовок «НАВСТРЕЧУ К AI» анимируется посимвольно при загрузке страницы. Каждая буква появляется с небольшой задержкой, создавая эффект «набора текста» в обратном направлении.
useEffect(() => {
if (!titleRef.current) return;
const chars = titleRef.current.querySelectorAll('.char');
gsap.fromTo(
chars,
{ opacity: 0, y: 40 },
{
opacity: 1,
y: 0,
duration: 0.6,
stagger: 0.05,
ease: 'power3.out',
}
);
}, []);Первая проблема возникла на мобилке: заголовок не помещался в одну строку и переносился. Решение — clamp() с меньшим минимальным значением:
/* До */
font-size: clamp(2.5rem, 12vw, 10rem);
/* После */
font-size: clamp(1.8rem, 9vw, 10rem);Простая правка, но она кардинально меняет восприятие на экранах шириной 375–430px.
Секция дресс-кода: от идеи до референсов
Одна из самых интересных задач — секция дресс-кода. Изначально стиль назывался «Фестивальный», но в процессе итераций его переименовали в Smart Casual — более точное определение того, что ожидается от гостей.
Требования к фото были чёткими: качественные, дорогие на вид, соответствующие тёмному дизайну сайта. Первая попытка — Unsplash. Результат не устроил: фото были слишком generic, не передавали нужную атмосферу.
Вторая итерация — Pinterest. Организатор сам подобрал референсы и прислал прямые ссылки. Это оказалось правильным решением: человек, который организует мероприятие, лучше понимает нужную атмосферу, чем алгоритм поиска стоков.
const menPhotos = [
'https://i.pinimg.com/736x/be/07/78/be077825a1f8fd206bb3d7b8d57a829c.jpg',
'https://i.pinimg.com/736x/78/af/5d/78af5ddc996ed1df4c318cd4e64b2a82.jpg',
'https://i.pinimg.com/736x/f2/9e/6c/f29e6ccde7b26bc5537ac9200303bc46.jpg',
];
const womenPhotos = [
'https://i.pinimg.com/736x/bd/93/46/bd934626fc87ff67274a1b5defa96040.jpg',
'https://i.pinimg.com/1200x/e6/4c/e2/e64ce2ff92006fdb85e7e98c05668194.jpg',
// ...
];Тексты тоже переработали под новый стиль:
До (Фестивальный стиль):
Пиджак с рубашкой, галстук по желанию. Нарядный, но не официальный — фестивальный дух.
После (Smart Casual):
Чиносы или брюки, рубашка или поло, пиджак по желанию. Аккуратно, но без галстука — расслабленная элегантность.
Мелочь? Нет. Дресс-код — это первое, что многие читают перед ивентом. Точность формулировок напрямую влияет на то, как выглядит зал.
Мобильная вёрстка: горизонтальный скролл вместо стопки
Первая версия мобильной адаптации была предсказуемой: всё в одну колонку, огромные отступы, бесконечный скролл вниз. Это работает, но скучно и неэффективно по использованию экрана.
Решение — горизонтальный скролл со scroll-snap для всех фото-секций. Паттерн выглядит так:
{/* Мобилка — горизонтальный скролл */}
<div className="flex md:hidden gap-4 overflow-x-auto pb-4 photo-scroll">
{photos.map((src, i) => (
<div key={i} className="flex-none w-[70vw] h-[280px] relative rounded-xl overflow-hidden">
<Image src={src} alt="" fill className="object-cover" />
</div>
))}
</div>
{/* Десктоп — грид */}
<div className="hidden md:grid grid-cols-3 gap-6">
{/* ... */}
</div>.photo-scroll {
scroll-snap-type: x mandatory;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.photo-scroll > * {
scroll-snap-align: start;
}
.photo-scroll::-webkit-scrollbar {
display: none;
}То же самое применили к карточкам спикеров (80vw на карточку) и галерее мероприятия (65vw). Результат — мобильная версия ощущается как нативное приложение, а не как мобильная web-страница.
Проблема с воздухом на десктопе решилась просто — уменьшили вертикальные отступы:
// До
<section className="py-32">
// После
<section className="py-20">py-32 — это 128px сверху и снизу. Для десктопа с большим монитором это выглядело как пустота между блоками. py-20 (80px) — более плотная и профессиональная вёрстка.
Галерея без лайтбокса: осознанное решение
Лайтбокс — стандартная фича для фотогалерей. Кликаешь на фото — оно открывается на весь экран. Но в этом проекте от него отказались сознательно и дважды.
Первый раз лайтбокс убрали по дизайнерским соображениям. Потом он вернулся при рефакторинге — и его убрали снова, уже окончательно. Причина простая: галерея служит настроению, а не просмотру. Гостям не нужно разглядывать каждое фото в деталях — им нужно поймать атмосферу. Горизонтальный свайп справляется с этим лучше, чем модальное окно.
Технически это означало полное удаление:
- State для активного фото (
selectedPhoto,isOpen) - Обработчиков событий (
onClick,onClose) - Компонента модального окна
- Счётчика в лайтбоксе
Очистка кода — тоже разработка.
Деплой: Dokploy + GitHub Webhook
Пожалуй, самая интересная часть с технической точки зрения. Вместо ручного деплоя настроили полноценный CI/CD через Dokploy — собственную PaaS-платформу на VPS.
Схема работы:
- Пуш в
masterна GitHub - GitHub отправляет webhook на Dokploy API
- Dokploy клонирует репозиторий, собирает Docker-образ
- Контейнер поднимается, Let's Encrypt выдаёт HTTPS-сертификат
- Сайт доступен по домену
Dockerfile для Next.js приложения:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]Первый деплой споткнулся о приватный репозиторий — Dokploy не имел SSH-ключа с доступом. Решение: репо сделали публичным (лендинг не содержит секретов, всё в .env файлах).
Вторая проблема — Dokploy не мог найти Dockerfile, потому что искал его в code/Dockerfile вместо корня. Решилось указанием правильного dockerfilePath через API.
После этих двух правок — всё заработало. Wildcard DNS уже был настроен (*.pashavin.ru → VPS IP), поэтому поддомен 18ai.pashavin.ru поднялся сразу.
Автоматизация: скилл и агент для Dokploy
После десятка задеплоенных проектов на одной и той же платформе стало понятно: паттерны повторяются. Создание проекта в Dokploy, настройка git-источника, добавление домена, запуск деплоя — это одна и та же последовательность API-вызовов.
Решение — создать скилл dokploy-deploy и агента dokploy-deployer для Claude Code:
~/.claude/skills/dokploy-deploy/SKILL.md # документация паттернов
~/.claude/agents/dokploy-deployer.md # автономный агент
Скилл содержит:
- Полный референс API endpoints и их параметры
- Типичные pitfalls и их решения (таблицей)
- Шаблон Dockerfile для Next.js
- Quick reference с ключевыми константами
Агент работает по 9-шаговому workflow:
- Анализ проекта (определение стека, порта, переменных)
- Инициализация git-репозитория
- Создание проекта в Dokploy
- Создание приложения с buildType=dockerfile
- Настройка git-источника и домена
- Добавление webhook на GitHub
- Добавление проекта в git-auto-sync
- Первый пуш и запуск деплоя
- Мониторинг и диагностика
Это TDD применённый к процессной документации: сначала описываешь что должно работать, потом запускаешь и видишь где ломается, потом дорабатываешь документацию. Следующий проект деплоится быстрее, потому что агент уже знает все подводные камни.
Результат
За одну сессию разработки получили:
- Продакшн-сайт на
https://18ai.pashavin.ruс HTTPS - 7 полноценных секций: Hero, Marquee, О мероприятии, Спикеры, Программа, Дресс-код, Фотогалерея
- Мобильная вёрстка с горизонтальным скроллом на всех фото-блоках
- GSAP-анимации на заголовке и при появлении секций
- Автодеплой — пуш в git автоматически обновляет сайт
- Скилл и агент для ускорения следующих деплоев
Время от «мне надо сделать сайт» до работающего продакшна — несколько часов.
Выводы
Первый и главный урок: контентные решения важнее технических. Мы поменяли «Фестивальный стиль» на «Smart Casual», переписали два абзаца текста, заменили стоковые фото на Pinterest-референсы. Это не код — но это то, что гость запомнит и на что будет ориентироваться при выборе одежды. Технологии доставляют контент; контент создаёт опыт.
Второй урок: итеративность быстрее перфекционизма. Лайтбокс убирали дважды. Фото дресс-кода меняли трижды. Мобильная вёрстка прошла через несколько итераций. Каждый раз это было быстрое изменение → деплой → фидбек → следующая итерация. Такой подход даёт результат быстрее, чем попытка сделать всё идеально с первого раза.
Третий урок: горизонтальный скролл недооценён. На мобилках мы привыкли к бесконечному вертикальному скроллу. Но для галерей и карточек горизонтальный свайп со scroll-snap — это качественно другой UX. Он компактнее, интерактивнее и ощущается как нативное приложение. Стоит добавить в арсенал и использовать осознанно.
Четвёртый урок: документируй паттерны, пока они свежие. Скилл для Dokploy появился после десятого проекта на этой платформе. Стоило сделать это после третьего. Каждый раз, когда решаешь одну и ту же проблему во второй раз — это сигнал: пора написать документацию или создать инструмент. Время, вложенное в автоматизацию рутины, возвращается с процентами уже на следующем проекте.
Пятый урок: постфактум-лендинги имеют смысл. Мероприятие прошло, но сайт продолжает работать. Он собирает органический трафик, рассказывает историю события, служит портфолио и готовит базу для следующей конференции. Если провёл ивент — сделай страницу. Это несколько часов работы с долгосрочной отдачей.
«Навстречу к AI» получилась мясной и крутой — по словам самого организатора. Техничка подвела, онлайн-трансляция пошла в брак, но контент был живым. Лендинг теперь сохраняет эту историю в сети.

AI-инженер, предприниматель, маркетолог. Основатель feberra.com и x10seo.ru. 13 лет в перфоманс-маркетинге, 3 года в системной интеграции AI в бизнес.
Связанный проект
AI Content Aggregator →