11 KiB
Дизайн-система KT AI — по ней собирается весь UI
В папке проекта лежит design-system/ — это дизайн-система KT AI
(источник: github.com/erjan-A/kt-ai-design-system, MIT, версия в design-system/VERSION).
Весь визуал берётся оттуда: цвета, шрифт, отступы, кнопки, карточки, секции лендинга.
Не выдумывай свой стиль и не тащи чужие фреймворки. Твоя работа — собрать страницу из готовых классов ДС и наполнить её содержанием юзера.
Если папки design-system/ в проекте нет (старый проект) — принеси её один раз:
cp -r /srv/opencode/design-system/kt-ai design-system
🔒 Три правила, которые нельзя нарушать
- Цвета и размеры — только токенами
var(--kt-ai-…). Сырой hex (#0F1218,#fff) в вёрстке запрещён: он ломает светлую/тёмную тему. - Никакого Bootstrap / Tailwind / Material / Font Awesome / Google Fonts. Шрифт (Inter) уже внутри ДС и работает офлайн. Всё, что нужно лендингу, в ДС уже есть.
- Свой
<style>— только на мелочи, которых нет в ДС (позиционирование, картинка-фон). Не переопределяй кнопки, карточки и типографику.
Старт: index.html
Это рабочий каркас лендинга. Копируй его целиком и меняй содержание.
<!DOCTYPE html>
<html lang="ru" data-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Название проекта</title>
<link rel="stylesheet" href="design-system/kt-ai-fonts.css">
<link rel="stylesheet" href="design-system/kt-ai-tokens.css">
<link rel="stylesheet" href="design-system/kt-ai-components.css">
<link rel="stylesheet" href="design-system/kt-ai-page.css">
<style>
/* ДС рисует кнопки для <button>; у ссылки-кнопки браузер добавляет подчёркивание */
a.kt-ai-btn { text-decoration: none; }
</style>
</head>
<body>
<header class="kt-ai-pagehead">
<div class="kt-ai-wrap kt-ai-pagehead-in">
<strong>Название</strong>
<span class="kt-ai-spacer"></span>
<a class="kt-ai-btn" data-variant="ghost" href="#about">О нас</a>
<a class="kt-ai-btn" data-variant="primary" href="#contacts">Оставить заявку</a>
</div>
</header>
<section class="kt-ai-hero" data-align="center">
<div class="kt-ai-wrap">
<h1>Главное обещание в одну строку</h1>
<p class="kt-ai-hero-sub">Подзаголовок: кому это и почему стоит остаться.</p>
<div class="kt-ai-hero-actions">
<a class="kt-ai-btn" data-variant="primary" data-size="lg" href="#contacts">Оставить заявку</a>
<a class="kt-ai-btn" data-size="lg" href="#about">Подробнее</a>
</div>
</div>
</section>
<section id="about" class="kt-ai-section" data-divider="true">
<div class="kt-ai-wrap">
<div class="kt-ai-section-head">
<h2>Что вы получите</h2>
<p>Одно-два предложения пояснения к секции.</p>
</div>
<div class="kt-ai-grid" style="margin-top:var(--kt-ai-space-9)">
<article class="kt-ai-tile"><h3>Пункт первый</h3><p>Коротко и по делу.</p></article>
<article class="kt-ai-tile"><h3>Пункт второй</h3><p>Коротко и по делу.</p></article>
<article class="kt-ai-tile"><h3>Пункт третий</h3><p>Коротко и по делу.</p></article>
</div>
</div>
</section>
<section id="contacts" class="kt-ai-cta">
<div class="kt-ai-wrap">
<h2>Призыв к действию</h2>
<p>Город, адрес, часы работы — то, что нужно, чтобы дойти.</p>
<a class="kt-ai-btn" data-variant="primary" data-size="lg" href="#">Написать</a>
</div>
</section>
<footer class="kt-ai-wrap kt-ai-pagefoot">
<span>© 2026 Название</span>
<span class="kt-ai-spacer"></span>
<span>Контакты</span>
</footer>
</body>
</html>
Блоки страницы (kt-ai-page.css)
| Класс | Что это |
|---|---|
.kt-ai-wrap |
контейнер по центру (1080px). data-width="narrow" — 720px, "wide" — 1200px |
.kt-ai-pagehead + .kt-ai-pagehead-in |
липкая шапка страницы |
.kt-ai-hero, .kt-ai-hero-sub, .kt-ai-hero-actions |
первый экран. data-align="center" — по центру |
.kt-ai-section + .kt-ai-section-head (h2 + p) |
обычная секция. data-divider="true" — линия сверху |
.kt-ai-grid + .kt-ai-tile (h3 + p) |
сетка плиток «возможности». data-cols="2"/"4", у плитки data-span="2"/"full" |
.kt-ai-tile-icon |
иконка над заголовком плитки (спрайт — design-system/icons/) |
.kt-ai-cta |
финальный блок с призывом |
.kt-ai-pagefoot |
подвал |
.kt-ai-spacer |
распорка внутри шапки/подвала (толкает остальное вправо) |
.kt-ai-centered |
одна карточка по центру экрана — для страницы входа и 404 |
Отступы между секциями ДС ставит сама. Адаптив (3→2→1 колонка) — тоже, @media писать не нужно.
Элементы (kt-ai-components.css)
| Класс | Как применять |
|---|---|
.kt-ai-btn |
кнопка / ссылка-кнопка. data-variant="primary" — главная, "ghost" — прозрачная, "danger" — опасная. data-size="sm"/"lg" |
.kt-ai-card |
карточка контента |
.kt-ai-chip |
статус-пилюля / тег |
.kt-ai-link |
текстовая ссылка |
.kt-ai-field + .kt-ai-input / .kt-ai-textarea / .kt-ai-select |
поле формы с подписью |
Один primary на экран. Остальные кнопки — обычные или ghost.
Токены (kt-ai-tokens.css)
Цвет: --kt-ai-bg, --kt-ai-bg-soft, --kt-ai-fg, --kt-ai-fg-muted, --kt-ai-fg-faint,
--kt-ai-border, --kt-ai-divider, --kt-ai-card-bg, --kt-ai-card-border,
--kt-ai-primary, --kt-ai-link, --kt-ai-danger.
Отступы: --kt-ai-space-1…12 (2px → 64px). Скругления: --kt-ai-radius-md/lg/xl/2xl/3xl/full.
Текст: --kt-ai-text-xs…3xl. Вес: --kt-ai-weight-regular/medium/semibold/bold.
Шрифты: --kt-ai-font-sans (Inter), --kt-ai-font-mono.
Тема — атрибут на <html>: data-theme="auto" (по системной, ставь его по умолчанию),
"light", "dark". Проверь страницу в обеих темах — с токенами это бесплатно.
Не лендинг, а приложение (дашборд, таблица, очередь заявок, чат)
Тогда экран собирается не вёрсткой руками, а конфигом:
- Возьми
design-system/templates/kt-ai-app-shell.html— самодостаточный HTML-каркас приложения (без React и npm). - Опиши экран JSON-конфигом по
design-system/docs/PRODUCT_CONTRACT.mdи положи его в тег<script id="kt-app-config" type="application/json">…</script>внутри каркаса — он сам отрисует таблицу, KPI, фильтры, drawer и темы. - Проверь конфиг:
python3 design-system/scripts/validate_product.py config.json --strict→ нужен0/0.
Полные правила для сложных экранов — design-system/AGENTS.md, список компонентов —
design-system/COMPONENTS.md, приёмка — design-system/CHECKLIST.md. Читай их, когда лендинга
уже мало.
📦 Готовые рецепты
Фото без ключей
- Одно и то же слово → одна и та же картинка:
https://picsum.photos/seed/coffee/800/600 - По теме:
https://loremflickr.com/800/600/coffee(тег прямо в URL)
Вставляй с рамкой ДС: <img src="…" alt="…" style="width:100%;border-radius:var(--kt-ai-radius-3xl)">
Кнопка WhatsApp
<a class="kt-ai-btn" data-variant="primary" data-size="lg"
href="https://wa.me/7XXXXXXXXXX?text=Здравствуйте!">Написать в WhatsApp</a>
7XXXXXXXXXX — номер в международном формате без +.
Форма заявки без бэкенда
<form action="https://formsubmit.co/EMAIL" method="POST" style="max-width:420px">
<div class="kt-ai-field"><label>Имя</label><input class="kt-ai-input" name="name" required></div>
<div class="kt-ai-field"><label>Телефон</label><input class="kt-ai-input" name="phone" required></div>
<button class="kt-ai-btn" data-variant="primary" type="submit">Отправить</button>
</form>
Скажи юзеру: замени EMAIL на свою почту — заявки будут приходить туда (первая заявка активирует форму).
Favicon-эмодзи (без файла)
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>☕</text></svg>">
Карта
На maps.google.com: место → «Поделиться» → «Встроить карту» → вставь iframe как есть:
<iframe src="https://www.google.com/maps/embed?pb=..." width="100%" height="320"
style="border:0;border-radius:var(--kt-ai-radius-3xl)" loading="lazy"></iframe>
Плавные появления при скролле
<style>
.reveal{opacity:0;transform:translateY(20px);transition:opacity .6s ease,transform .6s ease}
.reveal.in{opacity:1;transform:none}
</style>
<script>
var io=new IntersectionObserver(function(entries){
entries.forEach(function(e){ if(e.isIntersecting) e.target.classList.add('in'); });
},{threshold:.15});
document.querySelectorAll('.reveal').forEach(function(el){ io.observe(el); });
</script>
Перед тем как сказать «готово»
- Подключены все четыре CSS из
design-system/, папка лежит в проекте (не забудь закоммитить её). - В вёрстке нет сырых hex-цветов и чужих шрифтов.
- Страница нормально выглядит в светлой и тёмной теме и на телефоне (узкое окно).
- Один
data-variant="primary"на экран, тексты — про юзера, а не «Lorem ipsum».