feat: страница /ai-dev/ — AI-разработка и проекты, карточка в Активности

This commit is contained in:
Nikolay Mamadaev committed 2026-10-07 12:52:10 +02:00
1 parent 39dad71bd1
commit 52485a17c4
10 files changed
+1089 -4

No files matched your search

+653
View File
@@ -0,0 +1,653 @@
<!DOCTYPE html>
<html lang="ru" data-theme="dark" data-radius="medium">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta
name="description"
content="Николай Мамадаев, AI-разработчик. Делаю целые продукты: Telegram-боты, MCP-серверы, плагины для Figma и Obsidian, desktop-утилиты."
/>
<title>AI-разработка · Николай Мамадаев</title>
<script>
(function () {
var FONT_CSS = {
merriweather: "/assets/fonts/merriweather.css",
geologica: "/assets/fonts/geologica.css",
mono: "/assets/fonts/mono.css",
};
try {
var t = JSON.parse(localStorage.getItem("siteThemeV1") || "{}");
var d = document.documentElement;
var m = t.mode;
if (m !== "light" && m !== "dark" && m !== "system") m = "system";
var eff =
m === "system"
? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
: m;
d.dataset.theme = eff;
var DEF = { h: 210, s: 90, l: 40 };
function pickAccent(o) {
if (!o) return null;
var h = typeof o.h === "number" ? o.h : typeof o.hue === "number" ? o.hue : null;
var s = typeof o.s === "number" ? o.s : typeof o.sat === "number" ? o.sat : null;
var l = typeof o.l === "number" ? o.l : typeof o.light === "number" ? o.light : null;
if (h === null && s === null && l === null) return null;
return {
h: h === null ? DEF.h : h,
s: s === null ? DEF.s : Math.min(100, Math.max(30, s)),
l: l === null ? DEF.l : Math.min(70, Math.max(20, l)),
};
}
// Текущий формат: отдельный акцент для светлой и тёмной темы ({light, dark}).
// Старый плоский формат ({h, s, l}) остаётся совместимым.
var acc =
pickAccent(eff === "dark" ? t.dark : t.light) ||
pickAccent(eff === "dark" ? t.light : t.dark) ||
pickAccent(t) ||
DEF;
d.style.setProperty("--theme-h", String(acc.h));
d.style.setProperty("--theme-s", String(acc.s));
d.style.setProperty("--theme-l", String(acc.l));
var H = (((acc.h % 360) + 360) % 360) / 360;
var S = Math.min(100, Math.max(0, acc.s)) / 100;
var Lv = Math.min(100, Math.max(0, acc.l)) / 100;
var r, g, b;
if (S === 0) { r = g = b = Lv; }
else {
var q = Lv < 0.5 ? Lv * (1 + S) : Lv + S - Lv * S;
var p = 2 * Lv - q;
var hue2rgb = function(p, q, t) {
if (t < 0) t += 1; if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
r = hue2rgb(p, q, H + 1/3);
g = hue2rgb(p, q, H);
b = hue2rgb(p, q, H - 1/3);
}
var lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
d.style.setProperty("--on-accent", lum > 0.58 ? "hsl(220 14% 12%)" : "hsl(0 0% 98%)");
var rad = t.radius;
if (rad === "soft" || rad === "medium" || rad === "strong") {
d.dataset.radius = rad;
} else {
d.dataset.radius = "medium";
}
var f = t.font;
if (f === "onest") f = "geologica";
if (f === "anonymous") f = "mono";
if (f !== "merriweather" && f !== "mono" && f !== "geologica") f = "geologica";
d.dataset.font = f;
var mb = t.meshBg;
if (mb === "off") {
d.dataset.meshBg = "off";
} else {
d.dataset.meshBg = "on";
}
var href = FONT_CSS[f];
if (href && !document.querySelector('link[data-theme-font="' + f + '"]')) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = href;
link.setAttribute("data-theme-font", f);
document.head.appendChild(link);
}
} catch (e) {}
})();
</script>
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="/assets/favicon/site.webmanifest" />
<link rel="preload" href="/assets/fonts/merriweather.css" as="style" />
<link rel="preload" href="/css/main.css" as="style" />
<link rel="preload" href="/js/skill-connectors.js" as="script" />
<link rel="modulepreload" href="/js/main.js" />
<link rel="modulepreload" href="/js/modules/ui/page-mesh-shader.js" />
<link rel="stylesheet" href="/css/main.css" />
<link rel="canonical" href="https://mamadaevv.site/ai-dev/" />
<link rel="alternate" hreflang="ru" href="https://mamadaevv.site/ai-dev/" />
<link rel="alternate" hreflang="en" href="https://mamadaevv.site/ai-dev/" />
<link rel="alternate" hreflang="x-default" href="https://mamadaevv.site/ai-dev/" />
<meta name="author" content="Николай Мамадаев" />
<meta name="robots" content="index, follow" />
<meta name="theme-color" content="#0f1115" />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Николай Мамадаев — продуктовый дизайнер" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:locale:alternate" content="en_US" />
<meta property="og:title" content="AI-разработка · Николай Мамадаев" />
<meta property="og:description" content="Николай Мамадаев, AI-разработчик. Делаю целые продукты: Telegram-боты, MCP-серверы, плагины для Figma и Obsidian, desktop-утилиты." />
<meta property="og:url" content="https://mamadaevv.site/ai-dev/" />
<meta property="og:image" content="https://mamadaevv.site/assets/og/og-default.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="AI-разработка · Николай Мамадаев" />
<!-- Twitter / X -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="AI-разработка · Николай Мамадаев" />
<meta name="twitter:description" content="Николай Мамадаев, AI-разработчик. Делаю целые продукты: Telegram-боты, MCP-серверы, плагины для Figma и Obsidian, desktop-утилиты." />
<meta name="twitter:image" content="https://mamadaevv.site/assets/og/og-default.png" />
<meta name="twitter:image:alt" content="AI-разработка · Николай Мамадаев" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://mamadaevv.site/#person",
"name": "Николай Мамадаев",
"url": "https://mamadaevv.site",
"jobTitle": "Продуктовый дизайнер",
"description": "Продуктовый дизайнер с опытом более 10 лет. Проектирую цифровые продукты, интерфейсы и дизайн-системы.",
"knowsAbout": [
"UX/UI-дизайн",
"продуктовый дизайн",
"дизайн-системы",
"прототипирование",
"Figma",
"no-code"
],
"sameAs": [
"https://t.me/mamadaevv",
"https://vk.com/mamadaevv",
"https://github.com/mamadaevv"
]
},
{
"@type": "WebSite",
"@id": "https://mamadaevv.site/#website",
"url": "https://mamadaevv.site/",
"name": "Николай Мамадаев — продуктовый дизайнер",
"inLanguage": "ru",
"author": {
"@id": "https://mamadaevv.site/#person"
},
"publisher": {
"@id": "https://mamadaevv.site/#person"
}
},
{
"@type": "WebPage",
"@id": "https://mamadaevv.site/ai-dev/#page",
"url": "https://mamadaevv.site/ai-dev/",
"name": "AI-разработка · Николай Мамадаев",
"description": "Николай Мамадаев, AI-разработчик. Делаю целые продукты: Telegram-боты, MCP-серверы, плагины для Figma и Obsidian, desktop-утилиты.",
"isPartOf": {
"@id": "https://mamadaevv.site/#website"
},
"author": {
"@id": "https://mamadaevv.site/#person"
},
"inLanguage": "ru"
},
{
"@type": "BreadcrumbList",
"@id": "https://mamadaevv.site/ai-dev/#breadcrumbs",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Николай Мамадаев — продуктовый дизайнер",
"item": "https://mamadaevv.site/"
},
{
"@type": "ListItem",
"position": 2,
"name": "AI-разработка · Николай Мамадаев",
"item": "https://mamadaevv.site/ai-dev/"
}
]
}
]
}
</script>
<script src="/js/skill-connectors.js" defer></script>
<script type="module" src="/js/main.js"></script>
<link rel="stylesheet" href="/vendor/plyr/plyr.css" />
<style>
.ai-page {
max-width: 52rem;
margin: 0 auto;
}
.ai-page h2 {
margin: 2.25rem 0 0.85rem;
font-size: clamp(1.15rem, 2vw, 1.35rem);
font-weight: 700;
color: var(--text);
}
.ai-page .section__prose {
margin-bottom: 0.75rem;
color: var(--text);
}
.ai-page a:not(.btn) {
color: var(--accent);
}
/* Сетка карточек проектов: 2 колонки, схлопывается в одну на мобильном */
.ai-projects {
list-style: none;
margin: 1.25rem 0 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
gap: 1rem;
}
.ai-projects > li {
margin: 0;
}
.ai-projects__media {
border-radius: var(--radius-md);
overflow: hidden;
border: 1px solid var(--line);
margin-bottom: 0.7rem;
background: var(--surface);
}
.ai-projects__media img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 16 / 10;
object-fit: cover;
}
.ai-projects__head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 0.75rem;
}
.ai-projects__title {
margin: 0;
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
}
.ai-projects__stack {
margin: 0.3rem 0 0;
font-family: var(--font-mono, ui-monospace, monospace);
font-size: 0.78rem;
color: var(--text-muted);
}
.ai-projects__desc {
margin: 0.45rem 0 0;
font-size: 0.95rem;
color: var(--text);
}
.ai-projects__links {
list-style: none;
margin: 0.6rem 0 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: 0.4rem 0.9rem;
font-size: 0.85rem;
}
/* Навыки — компактные чипы переиспользуют стили тегов карточек активности */
.ai-stack-list {
list-style: none;
margin: 1rem 0 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: 0.45rem;
}
.ai-stack-list li {
margin: 0;
padding: 0.3rem 0.7rem;
border: 1px solid var(--line);
border-radius: 999px;
font-family: var(--font-mono, ui-monospace, monospace);
font-size: 0.8rem;
color: var(--text-muted);
}
</style>
</head>
<body>
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Разделы страницы">
<a href="#contact">Контакты</a>
</nav>
</div>
</div>
</header>
<div class="fab-stack" aria-label="Быстрые действия">
<div class="theme-panel-fab-wrap">
<button type="button" class="fab fab--secondary glass-neutral" data-theme-panel-btn aria-expanded="false" aria-controls="theme-panel" aria-label="Настройки стиля">
<span class="theme-panel-fab__icon theme-panel-fab__icon--open-hide" aria-hidden="true"></span>
<svg class="theme-panel-fab__icon theme-panel-fab__icon--close" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M6 6L18 18M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
</button>
<div id="theme-panel" class="theme-picker__panel glass-neutral" role="dialog" aria-label="Тема и оформление" hidden data-theme-panel>
<div class="theme-picker__stack">
<section class="theme-picker__section" aria-labelledby="theme-accent-title">
<h3 id="theme-accent-title" class="theme-picker__section-title">Акцентный цвет</h3>
<div class="colorpicker" data-colorpicker>
<div class="colorpicker__plane-box">
<canvas class="colorpicker__plane" width="320" height="180" data-sl-canvas aria-label="Насыщенность и светлость акцента"></canvas>
<div class="colorpicker__knob" data-sl-knob></div>
</div>
<div class="colorpicker__hue-wrap">
<label class="colorpicker__hue-sr" for="theme-hue-slider">Оттенок акцента</label>
<input id="theme-hue-slider" class="colorpicker__hue" type="range" min="0" max="360" value="210" data-hue-slider aria-valuemin="0" aria-valuemax="360" />
</div>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-mode-title">
<h3 id="theme-mode-title" class="theme-picker__section-title">Тема</h3>
<div class="radius-seg theme-mode-seg" role="radiogroup" aria-labelledby="theme-mode-title">
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="system" aria-label="Как в системе"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--system"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="light" aria-label="Светлая тема"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--light"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="dark" aria-label="Тёмная тема"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--dark"></span></span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-radius-title">
<h3 id="theme-radius-title" class="theme-picker__section-title">Скругление углов</h3>
<div class="radius-seg" role="radiogroup" aria-labelledby="theme-radius-title">
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="soft" aria-label="Слабое скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--soft"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="medium" aria-label="Среднее скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--medium"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="strong" aria-label="Сильное скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--strong"></span></span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-typography-title">
<h3 id="theme-typography-title" class="theme-picker__section-title">Типографика</h3>
<div class="radius-seg" role="radiogroup" aria-labelledby="theme-typography-title">
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="geologica" aria-label="Sans"><span class="theme-font-seg__label">Sans</span></button>
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="merriweather" aria-label="Sans Serif"><span class="theme-font-seg__label">Sans Serif</span></button>
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="mono" aria-label="Mono"><span class="theme-font-seg__label">Mono</span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-mesh-bg-title">
<h3 id="theme-mesh-bg-title" class="theme-picker__section-title">Фон страницы</h3>
<div class="radius-seg radius-seg--two" role="radiogroup" aria-labelledby="theme-mesh-bg-title">
<button type="button" class="radius-seg__btn theme-mesh-bg-seg__btn" role="radio" aria-checked="false" data-mesh-bg-option="on" aria-label="Показать фоновый градиент"><span class="theme-mesh-bg-seg__label">Вкл</span></button>
<button type="button" class="radius-seg__btn theme-mesh-bg-seg__btn" role="radio" aria-checked="false" data-mesh-bg-option="off" aria-label="Скрыть фоновый градиент"><span class="theme-mesh-bg-seg__label">Выкл</span></button>
</div>
</section>
</div>
</div>
</div>
<a class="fab fab--primary" href="#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
<div class="content-edit-fab-stack" aria-label="Правки контента" data-content-edit-ui>
<button
type="button"
class="fab fab--secondary glass-neutral content-edit-fab"
data-content-edit-mode-toggle
hidden
aria-pressed="false"
aria-label="Режим правок контента"
title="Режим правок"
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 20h4l10.5-10.5a2.12 2.12 0 0 0 0-3L16.5 4.5a2.12 2.12 0 0 0-3 0L3 15v5z"
stroke="currentColor"
stroke-width="1.75"
stroke-linejoin="round"
/>
</svg>
<span class="content-edit-fab__badge" hidden aria-hidden="true">0</span>
</button>
</div>
<main id="case-main" class="section section--tight">
<div class="section__inner ai-page">
<p class="hero__eyebrow">AI-разработка · идея, код, деплой</p>
<h1 class="case-page__h1">Делаю целые продукты</h1>
<p class="case-page__sub">Telegram-боты, MCP-серверы, плагины и утилиты. Схема, код, деплой</p>
<p class="section__prose">
Больше десяти лет я проектировал интерфейсы. Теперь довожу идеи до работающего
кода: бэкенд, база данных, деплой. Инфраструктура тоже моя часть работы.
В большинстве проектов код пишет ИИ-агент. Я задаю архитектуру, проверяю
результат и отвечаю за то, что продукт вообще работает.
</p>
<h2 id="roles">Что я делаю</h2>
<ul class="section__prose ai-stack-list">
<li>Продуктовая логика и API</li>
<li>Telegram-боты на aiogram 3</li>
<li>MCP-серверы</li>
<li>Плагины Figma и Obsidian</li>
<li>Автоматизация и агентные пайплайны</li>
</ul>
<h2 id="projects">Проекты</h2>
<ol class="ai-projects">
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-01.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Personal Assistant</h3>
</div>
<p class="ai-projects__stack">Python · aiogram 3 · PostgreSQL</p>
<p class="ai-projects__desc">
Личный ассистент в Telegram: напоминания, планирование дел и работа с LLM
в одном диалоге.
</p>
<ul class="ai-projects__links">
<li><a href="../cases/ai-platform-primo-rpa/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-02.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Image Gen Bot</h3>
</div>
<p class="ai-projects__stack">Python · aiogram 3 · Redis · PostgreSQL</p>
<p class="ai-projects__desc">
Бот для генерации изображений: баланс, реферальная программа, админ-логи
в отдельные топики супергруппы.
</p>
<ul class="ai-projects__links">
<li><a href="../cases/ai-platform-primo-rpa/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-03.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">MCP Image Server</h3>
</div>
<p class="ai-projects__stack">JavaScript · MCP · OpenRouter</p>
<p class="ai-projects__desc">
Собственный MCP-сервер для генерации картинок. Подключается к агентам
как инструмент.
</p>
<ul class="ai-projects__links">
<li><a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin/mcp-img-gen" target="_blank" rel="noopener noreferrer">Код</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-01.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">AI assistant</h3>
</div>
<p class="ai-projects__stack">TypeScript · Figma Plugin API</p>
<p class="ai-projects__desc">
Плагин для Figma, который исполняет скрипты прямо в редакторе.
ИИ-ассистент для любого тарифа.
</p>
<ul class="ai-projects__links">
<li><a href="../cases/ai-assistant-figma/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-02.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Card Columns</h3>
</div>
<p class="ai-projects__stack">TypeScript · Obsidian API</p>
<p class="ai-projects__desc">
Вью для заметок в стиле канбан-доски: группировка по колонкам с фильтрами
по тегам.
</p>
<ul class="ai-projects__links">
<li><a href="../cases/card-columns-obsidian/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-03.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Hermes Desktop Plugins</h3>
</div>
<p class="ai-projects__stack">JavaScript · TypeScript · Electron</p>
<p class="ai-projects__desc">
Плагины для рабочего стола Hermes: чип баланса API, звук завершения задачи
и контроль трат.
</p>
<ul class="ai-projects__links">
<li><a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin/unorouter-balance" target="_blank" rel="noopener noreferrer">Код</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-01.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Social Post Writer</h3>
</div>
<p class="ai-projects__stack">Python · aiogram 3 · SQLite</p>
<p class="ai-projects__desc">
Бот, который превращает тезисы в готовый пост под нужную площадку и тон,
учитывая голос автора.
</p>
<ul class="ai-projects__links">
<li><a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin/social-post-writer-bot" rel="noopener noreferrer">Код</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="../assets/ai-dev/placeholder-02.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">AI Design Assistant</h3>
</div>
<p class="ai-projects__stack">HTML · CSS · GLSL · WebGL</p>
<p class="ai-projects__desc">
Этот сайт целиком: структура, дизайн-система, шейдеры, CI/CD.
Весь цикл создания вместе с ИИ-агентом.
</p>
<ul class="ai-projects__links">
<li><a href="../cases/site-portfolio/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
</ol>
<h2 id="stack">Стек</h2>
<ul class="section__prose ai-stack-list">
<li>Python</li>
<li>TypeScript</li>
<li>JavaScript</li>
<li>Go</li>
<li>HTML/CSS</li>
<li>GLSL</li>
<li>aiogram 3</li>
<li>FastAPI</li>
<li>PostgreSQL</li>
<li>Redis</li>
<li>SQLite</li>
<li>Docker</li>
<li>Coolify</li>
<li>Gitea</li>
<li>MCP</li>
</ul>
<h2 id="links">Где я это выкладываю</h2>
<p class="section__prose">
Код открыт: <a href="https://github.com/mamadaevv" target="_blank" rel="noopener noreferrer">GitHub</a>
и <a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin" target="_blank" rel="noopener noreferrer">Gitea</a>.
Сервисы, которые работают прямо сейчас, живут на
<a href="https://secrets-4-me.dynv6.net" target="_blank" rel="noopener noreferrer">secrets-4-me</a>.
</p>
</div>
</main>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

+16
View File
@@ -838,6 +838,22 @@
</div> </div>
</div> </div>
<ol id="mini-projects-list" class="mini-projects-grid" data-mini-projects-list> <ol id="mini-projects-list" class="mini-projects-grid" data-mini-projects-list>
<li class="mini-projects-grid__item" data-mp-cells="2">
<a
class="mp-card mp-card--link mp-card--compact"
href="ai-dev/"
data-glass="false"
aria-label="AI-разработка — открыть страницу"
>
<div class="mp-card__body">
<h3 class="mp-card__title">AI-разработка</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">Боты · MCP · плагины</li>
</ul>
<p class="mp-card__desc">Не только дизайн, а целые продукты: от API до деплоя</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2"> <li class="mini-projects-grid__item" data-mp-cells="2">
<a <a
class="mp-card mp-card--link mp-card--compact" class="mp-card mp-card--link mp-card--compact"
+6
View File
@@ -1,6 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml"> xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://mamadaevv.site/ai-dev/</loc>
<lastmod>2026-10-07</lastmod>
<xhtml:link rel="alternate" hreflang="x-default" href="https://mamadaevv.site/ai-dev/" />
<xhtml:link rel="alternate" hreflang="ru" href="https://mamadaevv.site/ai-dev/" />
</url>
<url> <url>
<loc>https://mamadaevv.site/cases/ai-assistant-figma/</loc> <loc>https://mamadaevv.site/cases/ai-assistant-figma/</loc>
<lastmod>2026-09-26</lastmod> <lastmod>2026-09-26</lastmod>
+15 -4
View File
@@ -28,7 +28,7 @@ const NOINDEX_PAGES = new Set([
// Страницы, у которых пока нет перевода: собираются только в дефолтную локаль, // Страницы, у которых пока нет перевода: собираются только в дефолтную локаль,
// чтобы /en/ не отдавал русскоязычный дубль и не попадал в sitemap. // чтобы /en/ не отдавал русскоязычный дубль и не попадал в sitemap.
const DEFAULT_LOCALE_ONLY_PAGES = new Set(); const DEFAULT_LOCALE_ONLY_PAGES = new Set(["ai-dev"]);
// Своя og-картинка для страницы основного AI Server-кейса. // Своя og-картинка для страницы основного AI Server-кейса.
const PER_PAGE_OG_IMAGE = { const PER_PAGE_OG_IMAGE = {
@@ -65,8 +65,9 @@ function sitePath(relNorm, loc) {
const norm = relNorm.startsWith("cases/") const norm = relNorm.startsWith("cases/")
? `cases/${path.basename(relNorm, ".html")}/` ? `cases/${path.basename(relNorm, ".html")}/`
: base === "resume" ? "resume/" : base === "resume" ? "resume/"
: base === "cookie-policy" ? "cookie-policy/" : base === "cookie-policy" ? "cookie-policy/"
: base === "" || base === "/" ? "" : base === "ai-dev" ? "ai-dev/"
: base === "" || base === "/" ? ""
: `${base.replace(/\/$/, "")}/`; : `${base.replace(/\/$/, "")}/`;
return loc === DEFAULT_LOCALE ? norm : `${loc}/${norm}`; return loc === DEFAULT_LOCALE ? norm : `${loc}/${norm}`;
} }
@@ -321,6 +322,9 @@ function baseVars(relNorm, depth) {
if (relNorm === "cookie-policy.html") { if (relNorm === "cookie-policy.html") {
return { assetPrefix: "../", casesPrefix: "" }; return { assetPrefix: "../", casesPrefix: "" };
} }
if (relNorm === "ai-dev.html") {
return { assetPrefix: "../", casesPrefix: "../cases/" };
}
return { return {
assetPrefix: depth === 0 ? "" : "../".repeat(depth), assetPrefix: depth === 0 ? "" : "../".repeat(depth),
casesPrefix: depth === 0 ? "cases/" : "", casesPrefix: depth === 0 ? "cases/" : "",
@@ -342,6 +346,7 @@ function build() {
const isCase = relNorm.startsWith("cases/"); const isCase = relNorm.startsWith("cases/");
const isResume = relNorm === "resume.html"; const isResume = relNorm === "resume.html";
const isCookiePolicy = relNorm === "cookie-policy.html"; const isCookiePolicy = relNorm === "cookie-policy.html";
const isAiDev = relNorm === "ai-dev.html";
const omitFile = isCase ? path.basename(pagePath) : null; const omitFile = isCase ? path.basename(pagePath) : null;
const noSlug = relNorm.replace(/\.html$/, ""); const noSlug = relNorm.replace(/\.html$/, "");
@@ -370,7 +375,11 @@ function build() {
const vars = baseVars(relNorm, depth); const vars = baseVars(relNorm, depth);
vars.canonicalUrl = canonicalUrl; vars.canonicalUrl = canonicalUrl;
vars.canonicalRu = canonicalFor(relNorm, "ru"); vars.canonicalRu = canonicalFor(relNorm, "ru");
vars.canonicalEn = canonicalFor(relNorm, "en"); // Для ru-only страниц en-альтернаты не существует — отдаём ru,
// иначе hreflang указывает на несуществующий /en/... URL.
vars.canonicalEn = DEFAULT_LOCALE_ONLY_PAGES.has(noSlug)
? vars.canonicalRu
: canonicalFor(relNorm, "en");
vars.authorName = isDefault ? AUTHOR_NAME_RU : AUTHOR_NAME_EN; vars.authorName = isDefault ? AUTHOR_NAME_RU : AUTHOR_NAME_EN;
vars.siteName = isDefault ? SITE_NAME_RU : SITE_NAME_EN; vars.siteName = isDefault ? SITE_NAME_RU : SITE_NAME_EN;
vars.metaRobots = isNoindex ? "noindex, nofollow" : "index, follow"; vars.metaRobots = isNoindex ? "noindex, nofollow" : "index, follow";
@@ -403,6 +412,8 @@ function build() {
outPath = path.join(outDir, langPrefix, "resume", "index.html"); outPath = path.join(outDir, langPrefix, "resume", "index.html");
} else if (isCookiePolicy) { } else if (isCookiePolicy) {
outPath = path.join(outDir, langPrefix, "cookie-policy", "index.html"); outPath = path.join(outDir, langPrefix, "cookie-policy", "index.html");
} else if (isAiDev) {
outPath = path.join(outDir, langPrefix, "ai-dev", "index.html");
} else { } else {
outPath = path.join(outDir, langPrefix, rel); outPath = path.join(outDir, langPrefix, rel);
} }
+32
View File
@@ -0,0 +1,32 @@
// Генерация серых заглушек (16:10) для страницы ai-dev.
// Заглушки — намеренно нейтральный серый, без текста и градиентов.
import fs from "node:fs";
import path from "node:path";
import sharp from "sharp";
const outDir = path.join(process.cwd(), "public", "assets", "ai-dev");
fs.mkdirSync(outDir, { recursive: true });
const W = 640;
const H = 400;
// Разные оттенки серого, чтобы карточки не выглядели одинаковыми при загрузке.
const shades = [
{ fill: "#2a2d31", label: "01" },
{ fill: "#31353a", label: "02" },
{ fill: "#25282c", label: "03" },
];
const tiles = await Promise.all(
shades.map(async ({ fill, label }) => {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H}">
<rect width="${W}" height="${H}" fill="${fill}" />
</svg>`;
const file = path.join(outDir, `placeholder-${label}.webp`);
await sharp(Buffer.from(svg)).webp({ quality: 72 }).toFile(file);
return file;
}),
);
console.log(`Generated ${tiles.length} placeholders in ${outDir}`);
for (const f of tiles) console.log(" ", path.basename(f), fs.statSync(f).size, "bytes");
+351
View File
@@ -0,0 +1,351 @@
<!DOCTYPE html>
<html lang="ru" data-theme="dark" data-radius="medium">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta
name="description"
content="Николай Мамадаев, AI-разработчик. Делаю целые продукты: Telegram-боты, MCP-серверы, плагины для Figma и Obsidian, desktop-утилиты."
/>
<title>AI-разработка · Николай Мамадаев</title>
{{> head-links}}
{{> head-plyr}}
<style>
.ai-page {
max-width: 52rem;
margin: 0 auto;
}
.ai-page h2 {
margin: 2.25rem 0 0.85rem;
font-size: clamp(1.15rem, 2vw, 1.35rem);
font-weight: 700;
color: var(--text);
}
.ai-page .section__prose {
margin-bottom: 0.75rem;
color: var(--text);
}
.ai-page a:not(.btn) {
color: var(--accent);
}
/* Сетка карточек проектов: 2 колонки, схлопывается в одну на мобильном */
.ai-projects {
list-style: none;
margin: 1.25rem 0 0;
padding: 0;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
gap: 1rem;
}
.ai-projects > li {
margin: 0;
}
.ai-projects__media {
border-radius: var(--radius-md);
overflow: hidden;
border: 1px solid var(--line);
margin-bottom: 0.7rem;
background: var(--surface);
}
.ai-projects__media img {
display: block;
width: 100%;
height: auto;
aspect-ratio: 16 / 10;
object-fit: cover;
}
.ai-projects__head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 0.75rem;
}
.ai-projects__title {
margin: 0;
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
}
.ai-projects__stack {
margin: 0.3rem 0 0;
font-family: var(--font-mono, ui-monospace, monospace);
font-size: 0.78rem;
color: var(--text-muted);
}
.ai-projects__desc {
margin: 0.45rem 0 0;
font-size: 0.95rem;
color: var(--text);
}
.ai-projects__links {
list-style: none;
margin: 0.6rem 0 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: 0.4rem 0.9rem;
font-size: 0.85rem;
}
/* Навыки — компактные чипы переиспользуют стили тегов карточек активности */
.ai-stack-list {
list-style: none;
margin: 1rem 0 0;
padding: 0;
display: flex;
flex-wrap: wrap;
gap: 0.45rem;
}
.ai-stack-list li {
margin: 0;
padding: 0.3rem 0.7rem;
border: 1px solid var(--line);
border-radius: 999px;
font-family: var(--font-mono, ui-monospace, monospace);
font-size: 0.8rem;
color: var(--text-muted);
}
</style>
</head>
<body>
{{> header-case}}
{{> fab-stack}}
<main id="case-main" class="section section--tight">
<div class="section__inner ai-page">
<p class="hero__eyebrow">AI-разработка · идея, код, деплой</p>
<h1 class="case-page__h1">Делаю целые продукты</h1>
<p class="case-page__sub">Telegram-боты, MCP-серверы, плагины и утилиты. Схема, код, деплой</p>
<p class="section__prose">
Больше десяти лет я проектировал интерфейсы. Теперь довожу идеи до работающего
кода: бэкенд, база данных, деплой. Инфраструктура тоже моя часть работы.
В большинстве проектов код пишет ИИ-агент. Я задаю архитектуру, проверяю
результат и отвечаю за то, что продукт вообще работает.
</p>
<h2 id="roles">Что я делаю</h2>
<ul class="section__prose ai-stack-list">
<li>Продуктовая логика и API</li>
<li>Telegram-боты на aiogram 3</li>
<li>MCP-серверы</li>
<li>Плагины Figma и Obsidian</li>
<li>Автоматизация и агентные пайплайны</li>
</ul>
<h2 id="projects">Проекты</h2>
<ol class="ai-projects">
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-01.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Personal Assistant</h3>
</div>
<p class="ai-projects__stack">Python · aiogram 3 · PostgreSQL</p>
<p class="ai-projects__desc">
Личный ассистент в Telegram: напоминания, планирование дел и работа с LLM
в одном диалоге.
</p>
<ul class="ai-projects__links">
<li><a href="{{casesPrefix}}ai-platform-primo-rpa/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-02.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Image Gen Bot</h3>
</div>
<p class="ai-projects__stack">Python · aiogram 3 · Redis · PostgreSQL</p>
<p class="ai-projects__desc">
Бот для генерации изображений: баланс, реферальная программа, админ-логи
в отдельные топики супергруппы.
</p>
<ul class="ai-projects__links">
<li><a href="{{casesPrefix}}ai-platform-primo-rpa/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-03.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">MCP Image Server</h3>
</div>
<p class="ai-projects__stack">JavaScript · MCP · OpenRouter</p>
<p class="ai-projects__desc">
Собственный MCP-сервер для генерации картинок. Подключается к агентам
как инструмент.
</p>
<ul class="ai-projects__links">
<li><a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin/mcp-img-gen" target="_blank" rel="noopener noreferrer">Код</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-01.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">AI assistant</h3>
</div>
<p class="ai-projects__stack">TypeScript · Figma Plugin API</p>
<p class="ai-projects__desc">
Плагин для Figma, который исполняет скрипты прямо в редакторе.
ИИ-ассистент для любого тарифа.
</p>
<ul class="ai-projects__links">
<li><a href="{{casesPrefix}}ai-assistant-figma/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-02.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Card Columns</h3>
</div>
<p class="ai-projects__stack">TypeScript · Obsidian API</p>
<p class="ai-projects__desc">
Вью для заметок в стиле канбан-доски: группировка по колонкам с фильтрами
по тегам.
</p>
<ul class="ai-projects__links">
<li><a href="{{casesPrefix}}card-columns-obsidian/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-03.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Hermes Desktop Plugins</h3>
</div>
<p class="ai-projects__stack">JavaScript · TypeScript · Electron</p>
<p class="ai-projects__desc">
Плагины для рабочего стола Hermes: чип баланса API, звук завершения задачи
и контроль трат.
</p>
<ul class="ai-projects__links">
<li><a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin/unorouter-balance" target="_blank" rel="noopener noreferrer">Код</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-01.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">Social Post Writer</h3>
</div>
<p class="ai-projects__stack">Python · aiogram 3 · SQLite</p>
<p class="ai-projects__desc">
Бот, который превращает тезисы в готовый пост под нужную площадку и тон,
учитывая голос автора.
</p>
<ul class="ai-projects__links">
<li><a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin/social-post-writer-bot" rel="noopener noreferrer">Код</a></li>
</ul>
</li>
<li>
<div class="ai-projects__media">
<img
src="{{assetPrefix}}assets/ai-dev/placeholder-02.webp"
alt=""
width="640"
height="400"
loading="lazy"
decoding="async"
/>
</div>
<div class="ai-projects__head">
<h3 class="ai-projects__title">AI Design Assistant</h3>
</div>
<p class="ai-projects__stack">HTML · CSS · GLSL · WebGL</p>
<p class="ai-projects__desc">
Этот сайт целиком: структура, дизайн-система, шейдеры, CI/CD.
Весь цикл создания вместе с ИИ-агентом.
</p>
<ul class="ai-projects__links">
<li><a href="{{casesPrefix}}site-portfolio/" target="_blank" rel="noopener noreferrer">Кейс</a></li>
</ul>
</li>
</ol>
<h2 id="stack">Стек</h2>
<ul class="section__prose ai-stack-list">
<li>Python</li>
<li>TypeScript</li>
<li>JavaScript</li>
<li>Go</li>
<li>HTML/CSS</li>
<li>GLSL</li>
<li>aiogram 3</li>
<li>FastAPI</li>
<li>PostgreSQL</li>
<li>Redis</li>
<li>SQLite</li>
<li>Docker</li>
<li>Coolify</li>
<li>Gitea</li>
<li>MCP</li>
</ul>
<h2 id="links">Где я это выкладываю</h2>
<p class="section__prose">
Код открыт: <a href="https://github.com/mamadaevv" target="_blank" rel="noopener noreferrer">GitHub</a>
и <a href="http://x1qnvk08zec2u5cx6yh5iexh.155.212.186.39.sslip.io/admin" target="_blank" rel="noopener noreferrer">Gitea</a>.
Сервисы, которые работают прямо сейчас, живут на
<a href="https://secrets-4-me.dynv6.net" target="_blank" rel="noopener noreferrer">secrets-4-me</a>.
</p>
</div>
</main>
</body>
</html>
+16
View File
@@ -18,6 +18,22 @@
</div> </div>
</div> </div>
<ol id="mini-projects-list" class="mini-projects-grid" data-mini-projects-list> <ol id="mini-projects-list" class="mini-projects-grid" data-mini-projects-list>
<li class="mini-projects-grid__item" data-mp-cells="2">
<a
class="mp-card mp-card--link mp-card--compact"
href="ai-dev/"
data-glass="false"
aria-label="AI-разработка — открыть страницу"
>
<div class="mp-card__body">
<h3 class="mp-card__title">AI-разработка</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">Боты · MCP · плагины</li>
</ul>
<p class="mp-card__desc">Не только дизайн, а целые продукты: от API до деплоя</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2"> <li class="mini-projects-grid__item" data-mp-cells="2">
<a <a
class="mp-card mp-card--link mp-card--compact" class="mp-card mp-card--link mp-card--compact"