Merge branch 'dev'
No files matched your search
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: AI assistant — плагин для Figma с AI-функциями."
|
||||
content="Кейс о плагине для Figma, который получает скрипты из Cursor и запускает их."
|
||||
/>
|
||||
<title>AI assistant — Плагин для Figma — кейс</title>
|
||||
<title>AI assistant: плагин-мост между Cursor и Figma</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -112,20 +112,20 @@
|
||||
<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 assistant — Плагин для Figma — кейс" />
|
||||
<meta property="og:description" content="Кейс: AI assistant — плагин для Figma с AI-функциями." />
|
||||
<meta property="og:title" content="AI assistant: плагин-мост между Cursor и Figma" />
|
||||
<meta property="og:description" content="Кейс о плагине для Figma, который получает скрипты из Cursor и запускает их." />
|
||||
<meta property="og:url" content="https://mamadaevv.site/cases/ai-assistant-figma/" />
|
||||
<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 assistant — Плагин для Figma — кейс" />
|
||||
<meta property="og:image:alt" content="AI assistant: плагин-мост между Cursor и Figma" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="AI assistant — Плагин для Figma — кейс" />
|
||||
<meta name="twitter:description" content="Кейс: AI assistant — плагин для Figma с AI-функциями." />
|
||||
<meta name="twitter:title" content="AI assistant: плагин-мост между Cursor и Figma" />
|
||||
<meta name="twitter:description" content="Кейс о плагине для Figma, который получает скрипты из Cursor и запускает их." />
|
||||
<meta name="twitter:image" content="https://mamadaevv.site/assets/og/og-default.png" />
|
||||
<meta name="twitter:image:alt" content="AI assistant — Плагин для Figma — кейс" />
|
||||
<meta name="twitter:image:alt" content="AI assistant: плагин-мост между Cursor и Figma" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -169,8 +169,8 @@
|
||||
"@type": "CreativeWork",
|
||||
"@id": "https://mamadaevv.site/cases/ai-assistant-figma/#page",
|
||||
"url": "https://mamadaevv.site/cases/ai-assistant-figma/",
|
||||
"name": "AI assistant — Плагин для Figma — кейс",
|
||||
"description": "Кейс: AI assistant — плагин для Figma с AI-функциями.",
|
||||
"name": "AI assistant: плагин-мост между Cursor и Figma",
|
||||
"description": "Кейс о плагине для Figma, который получает скрипты из Cursor и запускает их.",
|
||||
"isPartOf": {
|
||||
"@id": "https://mamadaevv.site/#website"
|
||||
},
|
||||
@@ -181,7 +181,7 @@
|
||||
"creator": {
|
||||
"@id": "https://mamadaevv.site/#person"
|
||||
},
|
||||
"datePublished": "2026-09-24",
|
||||
"datePublished": "2026-09-26",
|
||||
"about": "UX/UI-дизайн и проектирование интерфейсов"
|
||||
},
|
||||
{
|
||||
@@ -203,7 +203,7 @@
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 3,
|
||||
"name": "AI assistant — Плагин для Figma — кейс",
|
||||
"name": "AI assistant: плагин-мост между Cursor и Figma",
|
||||
"item": "https://mamadaevv.site/cases/ai-assistant-figma/"
|
||||
}
|
||||
]
|
||||
@@ -241,6 +241,21 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
/* Реальный размер картинки: натуральная ширина в пикселях, ограниченная колонкой */
|
||||
.case-media--real {
|
||||
width: auto;
|
||||
margin-inline: auto;
|
||||
margin-left: auto;
|
||||
transform: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.case-media--real img {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
margin-inline: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function () {
|
||||
@@ -398,34 +413,165 @@
|
||||
|
||||
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<div class="section__inner case-article" data-case-sequential-images>
|
||||
<p class="hero__eyebrow">Figma · Plugin</p>
|
||||
<h1 class="case-page__h1">AI assistant</h1>
|
||||
<p class="case-page__sub">Плагин для Figma с AI-функциями</p>
|
||||
<p class="case-page__sub">Мост между Cursor IDE и Figma для создания и запуска скриптов</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
Рабочие будни проходили в Figma: проектировал сайты и приложения, использовал плагины, а когда готовых решений не хватало, делал свои. Со временем заметил, сколько времени уходит на повторяющиеся действия. Рутину вроде организации слоёв хотелось отдать скриптам, а задачи, которые вручную казались неподъёмными, так и оставались в списке на потом.
|
||||
</p>
|
||||
|
||||
<h2 id="context">Контекст</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
Плагин я делал для себя. LLM уже помогали создавать скрипты для Figma. Код готовил в Cursor, а для запуска переносил в Figma вручную. Навыков самостоятельного написания кода плагинов и скриптов не хватало, поэтому по ходу работы изучал документацию и API плагинов Figma, а правила генерации скриптов в Cursor постоянно уточнял.
|
||||
</p>
|
||||
|
||||
<h2 id="task">Задача</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
Задача состояла в том, чтобы убрать ручной перенос кода и запускать скрипты прямо из Figma. Плагину предстояло связать Cursor с Figma, дать возможность повторно запускать сценарии и быстро копировать для LLM контекст выбранного объекта или страницы.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>Каталог позволял добавлять скрипты под разные задачи и запускать их прямо в Figma.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Каталог пользовательских скриптов плагина"
|
||||
data-src="../../assets/ai-assistant-figma/Scripts%20List.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Каталог сценариев с поиском, сортировкой и быстрым запуском.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="solution">Решение</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
Локальный сервер и WebSocket связали Cursor с плагином. Когда скрипт был готов, достаточно было открыть плагин и нажать «Выполнить». Код автоматически передавался в Figma.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Редактор скрипта в плагине Figma"
|
||||
data-src="../../assets/ai-assistant-figma/Script%20Edit.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Экран скрипта перед запуском в Figma.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Готовые сценарии запускал чаще, чем создавал новые. Из каталога их можно было запускать и без Cursor.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Меню дополнительных действий со скриптом"
|
||||
data-src="../../assets/ai-assistant-figma/Menu%20More.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Меню дополнительных действий со скриптом.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Для более точных ответов модели плагин копировал данные о выбранной ноде или целой странице. Этот контекст можно было передать LLM вместе с запросом.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Панель плагина с переключателем Live"
|
||||
data-src="../../assets/ai-assistant-figma/Live%20Mode.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Панель управления скриптом с переключателем Live.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Логи выполнения мог читать LLM-бот в Cursor. Логические ошибки разбирал по шагам: делил сценарий на части и запускал их по очереди. Сначала проверял скрипт в отдельном файле, а после успешного теста пробовал в рабочем макете.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Редактор скрипта с панелью логов"
|
||||
data-src="../../assets/ai-assistant-figma/Script%20Edit%20Log%20View.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Редактор и панель логов выполнения.</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../assets/ai-assistant-figma/video/20250904-1414-49.4157894.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="../../assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm" type="video/webm" />
|
||||
<source src="../../assets/ai-assistant-figma/video/20250904-1414-49.4157894.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Доработка скрипта в Cursor и проверка результата в Figma.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="result">Результат</h2>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>На ручное выполнение отдельной задачи уходило от 1 до 30 минут. Это оценка, отдельную статистику не собирал. Теперь скрипт запускался одним нажатием.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Индикатор выполнения скрипта"
|
||||
data-src="../../assets/ai-assistant-figma/Script%20is%20Working.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Индикатор активного выполнения скрипта.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
Высвободившееся время позволяло браться за более сложные рабочие сценарии. В рабочих файлах часто запускал скрипт, который сводил векторные иконки через flatten для корректного отображения в продакшене. Другой превращал фрейм в компонент, создавал его инстанс и переносил мастер-компонент в заданное место на странице компонентов. Скрипты также помогали обновлять цветовые токены после ручных изменений и собирать структуру файла дизайн-системы с множеством страниц.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Были и другие задачи: добавлял варианты компонентов, сохранял набор токенов из JSON в текстовом слое или собирал прототип с переходами по клавиатуре. Подсветку кода в макете тоже автоматизировал скриптом, чтобы нагляднее показать идею и подобрать цвета синтаксиса. Вручную за такую работу не взялся бы.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../assets/ai-assistant-figma/video/20250913-0936-57.5977819.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="../../assets/ai-assistant-figma/video/20250913-0936-57.5977819.webm" type="video/webm" />
|
||||
<source src="../../assets/ai-assistant-figma/video/20250913-0936-57.5977819.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Сборка формы из компонентов дизайн-системы по референсу с помощью скрипта.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
За время работы лучше разобрался в Figma Plugin API. Теперь при планировании заранее учитываю, какие действия можно скриптовать, чтобы не тратить время на рутину.
|
||||
</p>
|
||||
|
||||
<h2 id="next-steps">Планы</h2>
|
||||
<p class="section__prose">
|
||||
Дальше планирую убрать Cursor из рабочего процесса и общаться с LLM-агентами прямо в Figma. В зависимости от задачи агент сможет подготовить переиспользуемый скрипт или выполнить действие по текстовой команде.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Сейчас готово только окно интерфейса. Работа с агентами и запуск действий пока не реализованы.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../assets/ai-assistant-figma/video/20260916-132035.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="../../assets/ai-assistant-figma/video/20260916-132035.webm" type="video/webm" />
|
||||
<source src="../../assets/ai-assistant-figma/video/20260916-132035.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Макет интерфейса планируемой работы с LLM-агентами в Figma.</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -689,7 +689,7 @@ a:visited:not(.btn):not(.fab):not(.logo):not(.skip-link):hover {
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-end;
|
||||
gap: 0.65rem 0.95rem;
|
||||
font-size: 0.9rem;
|
||||
font-size: 1.2rem;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
@@ -698,7 +698,7 @@ a:visited:not(.btn):not(.fab):not(.logo):not(.skip-link):hover {
|
||||
.nav a {
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.02em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -781,7 +781,7 @@ a:visited:not(.btn):not(.fab):not(.logo):not(.skip-link):hover {
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.nav-more__dock a:hover,
|
||||
@@ -5139,7 +5139,7 @@ html {
|
||||
|
||||
.nav {
|
||||
gap: 0.65rem 1.2rem;
|
||||
font-size: 0.925rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.hero {
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Case Study: AI Assistant—a Figma plugin with AI features."
|
||||
content="Case study of a Figma plugin that retrieves and runs scripts from Cursor."
|
||||
/>
|
||||
<title>AI Assistant — Figma Plugin — Case Study</title>
|
||||
<title>AI assistant: a script bridge between Cursor and Figma</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -112,20 +112,20 @@
|
||||
<meta property="og:site_name" content="Nikolai Mamadaev — Product Designer" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:locale:alternate" content="ru_RU" />
|
||||
<meta property="og:title" content="AI Assistant — Figma Plugin — Case Study" />
|
||||
<meta property="og:description" content="Case Study: AI Assistant—a Figma plugin with AI features." />
|
||||
<meta property="og:title" content="AI assistant: a script bridge between Cursor and Figma" />
|
||||
<meta property="og:description" content="Case study of a Figma plugin that retrieves and runs scripts from Cursor." />
|
||||
<meta property="og:url" content="https://mamadaevv.site/en/cases/ai-assistant-figma/" />
|
||||
<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 Assistant — Figma Plugin — Case Study" />
|
||||
<meta property="og:image:alt" content="AI assistant: a script bridge between Cursor and Figma" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="AI Assistant — Figma Plugin — Case Study" />
|
||||
<meta name="twitter:description" content="Case Study: AI Assistant—a Figma plugin with AI features." />
|
||||
<meta name="twitter:title" content="AI assistant: a script bridge between Cursor and Figma" />
|
||||
<meta name="twitter:description" content="Case study of a Figma plugin that retrieves and runs scripts from Cursor." />
|
||||
<meta name="twitter:image" content="https://mamadaevv.site/assets/og/og-default.png" />
|
||||
<meta name="twitter:image:alt" content="AI Assistant — Figma Plugin — Case Study" />
|
||||
<meta name="twitter:image:alt" content="AI assistant: a script bridge between Cursor and Figma" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -169,8 +169,8 @@
|
||||
"@type": "CreativeWork",
|
||||
"@id": "https://mamadaevv.site/en/cases/ai-assistant-figma/#page",
|
||||
"url": "https://mamadaevv.site/en/cases/ai-assistant-figma/",
|
||||
"name": "AI Assistant — Figma Plugin — Case Study",
|
||||
"description": "Case Study: AI Assistant—a Figma plugin with AI features.",
|
||||
"name": "AI assistant: a script bridge between Cursor and Figma",
|
||||
"description": "Case study of a Figma plugin that retrieves and runs scripts from Cursor.",
|
||||
"isPartOf": {
|
||||
"@id": "https://mamadaevv.site/#website"
|
||||
},
|
||||
@@ -181,7 +181,7 @@
|
||||
"creator": {
|
||||
"@id": "https://mamadaevv.site/#person"
|
||||
},
|
||||
"datePublished": "2026-09-24",
|
||||
"datePublished": "2026-09-26",
|
||||
"about": "UX/UI design and interface design"
|
||||
},
|
||||
{
|
||||
@@ -203,7 +203,7 @@
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": 3,
|
||||
"name": "AI Assistant — Figma Plugin — Case Study",
|
||||
"name": "AI assistant: a script bridge between Cursor and Figma",
|
||||
"item": "https://mamadaevv.site/cases/ai-assistant-figma/"
|
||||
}
|
||||
]
|
||||
@@ -241,6 +241,21 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
/* Реальный размер картинки: натуральная ширина в пикселях, ограниченная колонкой */
|
||||
.case-media--real {
|
||||
width: auto;
|
||||
margin-inline: auto;
|
||||
margin-left: auto;
|
||||
transform: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.case-media--real img {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
margin-inline: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function () {
|
||||
@@ -398,34 +413,166 @@
|
||||
|
||||
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<div class="section__inner case-article" data-case-sequential-images>
|
||||
<p class="hero__eyebrow">Figma · Plugin</p>
|
||||
<h1 class="case-page__h1">AI Assistant</h1>
|
||||
<p class="case-page__sub">A Figma plugin with AI features</p>
|
||||
<p class="case-page__sub">A bridge between Cursor IDE and Figma for creating and running scripts</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
I worked in Figma every day, designing software, apps and websites. I used plenty of plugins and made a few of my own when I could not find what I needed. The same manual steps kept coming back. Organizing layers was tedious, and some tasks felt unrealistic to do by hand, so I kept putting them off.
|
||||
</p>
|
||||
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
I built the plugin for myself. I was already using LLMs for different tasks and asking them to help write Figma scripts. I created the code in Cursor, then had to move it into Figma manually to run it. I did not know how to write plugin or script code myself, so I learned from Figma's documentation and plugin API as I went, while refining my script-generation rules in Cursor.
|
||||
</p>
|
||||
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
I wanted to remove the manual code handoff and run scripts directly in Figma. The plugin had to connect Cursor and Figma, let me reuse existing scripts, and make it easy to copy context about a selected node or an entire page for the LLM.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>I could add scripts for different tasks to the catalog and run them directly in Figma.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Catalog of custom plugin scripts"
|
||||
data-src="../../../assets/ai-assistant-figma/Scripts%20List.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script catalog with search, sorting, and quick launch.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
A local server and WebSocket connected Cursor to the plugin. Once a script was ready, I opened the plugin and clicked Run. The code was sent to Figma automatically.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Script editor in the Figma plugin"
|
||||
data-src="../../../assets/ai-assistant-figma/Script%20Edit.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script screen before running it in Figma.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Saved scripts could be launched from the catalog without Cursor. I ran existing scripts more often than I created new ones.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Menu of additional script actions"
|
||||
data-src="../../../assets/ai-assistant-figma/Menu%20More.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Menu of additional actions for a script.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
To give the LLM better context, the plugin could copy information about a selected node or an entire page. I used that data in my conversation with the model.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Plugin toolbar with the Live toggle"
|
||||
data-src="../../../assets/ai-assistant-figma/Live%20Mode.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script controls with the Live toggle.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The LLM in Cursor could read the execution logs. If the issue was with the script's logic rather than a bug, I split it into small steps and ran them one by one. I tested each script in a separate Figma file first, then tried it in a working file when it behaved as expected.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Script editor with an execution log panel"
|
||||
data-src="../../../assets/ai-assistant-figma/Script%20Edit%20Log%20View.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script editor and execution log panel.</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../../assets/ai-assistant-figma/video/20250904-1414-49.4157894.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="../../../assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm" type="video/webm" />
|
||||
<source src="../../../assets/ai-assistant-figma/video/20250904-1414-49.4157894.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Editing a script in Cursor and checking the result in Figma.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="result">Result</h2>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>I estimated that a task could take 1 to 30 minutes by hand. Launching its script then took one click.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Script execution indicator"
|
||||
data-src="../../../assets/ai-assistant-figma/Script%20is%20Working.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Indicator that a script is running.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
The time saved let me try more complex workflows. In working files, I often ran a script to flatten vector icons so they displayed correctly in production. Another turned a frame into a component, created an instance, and moved the master component to a designated place on the components page. Scripts also updated color tokens after manual changes and helped build a design-system file with many pages.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Other tasks included adding component variants, saving a set of tokens from JSON stored in a text layer, and building a prototype with keyboard-driven transitions. I also automated code syntax highlighting in a mockup to present an idea and tune the syntax colors. I would not have colored code by hand.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../../assets/ai-assistant-figma/video/20250913-0936-57.5977819.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="../../../assets/ai-assistant-figma/video/20250913-0936-57.5977819.webm" type="video/webm" />
|
||||
<source src="../../../assets/ai-assistant-figma/video/20250913-0936-57.5977819.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>A script assembles a form from design-system components using a reference.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
I learned more about the Figma Plugin API. Now I plan work with scriptable actions in mind, so I spend less time on repetitive steps.
|
||||
</p>
|
||||
|
||||
<h2 id="next-steps">Plans</h2>
|
||||
<p class="section__prose">
|
||||
Next, I want to remove Cursor from the workflow and talk to LLM agents directly in Figma. Depending on the task, an agent could create a reusable script or carry out an action from a text command.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
For now, only the interface window exists. Agent conversations and actions are not implemented yet.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../../assets/ai-assistant-figma/video/20260916-132035.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="../../../assets/ai-assistant-figma/video/20260916-132035.webm" type="video/webm" />
|
||||
<source src="../../../assets/ai-assistant-figma/video/20260916-132035.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Interface concept for the planned LLM agent workflow in Figma.</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -811,6 +811,194 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="activity" class="section section--surface" aria-labelledby="mini-projects-title" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 id="mini-projects-title" class="section__title">Activity</h2>
|
||||
<div
|
||||
class="skills-intro skills-intro--chat section__prose"
|
||||
data-skills-intro
|
||||
role="region"
|
||||
aria-labelledby="mini-projects-title"
|
||||
>
|
||||
<div class="skills-msg" data-skills-msg>
|
||||
<div class="skills-msg__body">
|
||||
<p class="skills-msg__author">Nikolay M:</p>
|
||||
<p class="skills-msg__text">
|
||||
I enjoy building small side projects and sharing something useful with the world.
|
||||
</p>
|
||||
<time class="skills-msg__time" datetime="" data-skills-msg-time></time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">An AI assistant for any editor plan</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Obsidian plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Shows note cards in a kanban-board style</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="This site — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">This site</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Built with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">The whole site-building cycle with AI</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://www.figma.com/@mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Figma Community — open profile"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/figma_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Figma Community
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
I publish useful files and plugins for the community
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://dribbble.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Dribbble — open profile"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/dribbble_logo.webp"
|
||||
alt=""
|
||||
width="1024"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Dribbble
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Nice visuals with UI elements
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://t.me/designnotpizza"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Design is not pizza — open Telegram channel"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/tg-channel-logo-design_not_pizza.webp"
|
||||
alt=""
|
||||
width="640"
|
||||
height="640"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Design is not pizza
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
My channel about design. Posts on product design and useful links
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://github.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="GitHub — open profile"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/github_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
GitHub
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
My projects and code experiments
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="experience" class="section section--surface" aria-labelledby="experience-title" data-reveal>
|
||||
@@ -1266,196 +1454,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="activity" class="section section--surface" aria-labelledby="mini-projects-title" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 id="mini-projects-title" class="section__title">Activity</h2>
|
||||
<div
|
||||
class="skills-intro skills-intro--chat section__prose"
|
||||
data-skills-intro
|
||||
role="region"
|
||||
aria-labelledby="mini-projects-title"
|
||||
>
|
||||
<div class="skills-msg" data-skills-msg>
|
||||
<div class="skills-msg__body">
|
||||
<p class="skills-msg__author">Nikolay M:</p>
|
||||
<p class="skills-msg__text">
|
||||
I enjoy building small side projects and sharing something useful with the world.
|
||||
</p>
|
||||
<time class="skills-msg__time" datetime="" data-skills-msg-time></time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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--horizontal mp-card--hor-image"
|
||||
href="https://www.figma.com/@mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Figma Community — open profile"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/figma_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Figma Community
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
I publish useful files and plugins for the community
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://dribbble.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Dribbble — open profile"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/dribbble_logo.webp"
|
||||
alt=""
|
||||
width="1024"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Dribbble
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Nice visuals with UI elements
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://t.me/designnotpizza"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Design is not pizza — open Telegram channel"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/tg-channel-logo-design_not_pizza.webp"
|
||||
alt=""
|
||||
width="640"
|
||||
height="640"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Design is not pizza
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
My channel about design. Posts on product design and useful links
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://github.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="GitHub — open profile"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/misc/github_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
GitHub
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
My projects and code experiments
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">An AI assistant for any editor plan</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Obsidian plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Shows note cards in a kanban-board style</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="This site — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">This site</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Built with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">The whole site-building cycle with AI</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="contact" class="section section--surface section--footerish" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Contact</h2>
|
||||
|
||||
@@ -818,6 +818,194 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="activity" class="section section--surface" aria-labelledby="mini-projects-title" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 id="mini-projects-title" class="section__title">Активность</h2>
|
||||
<div
|
||||
class="skills-intro skills-intro--chat section__prose"
|
||||
data-skills-intro
|
||||
role="region"
|
||||
aria-labelledby="mini-projects-title"
|
||||
>
|
||||
<div class="skills-msg" data-skills-msg>
|
||||
<div class="skills-msg__body">
|
||||
<p class="skills-msg__author">Николай М:</p>
|
||||
<p class="skills-msg__text">
|
||||
Люблю делать разные мини-проекты или делиться чем-то полезным с миром.
|
||||
</p>
|
||||
<time class="skills-msg__time" datetime="" data-skills-msg-time></time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Figma</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">ИИ помощник для любого тарифа редактора</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Obsidian</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Отображение карточек с заметками в стиле канбан доски</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="Этот сайт — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Этот сайт</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Разработка с AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Весь цикл создания сайта при помощи ИИ</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://www.figma.com/@mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Figma Community — открыть профиль"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/figma_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Figma Community
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Выкладываю полезные файлы и плагины для сообщества
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://dribbble.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Dribbble — открыть профиль"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/dribbble_logo.webp"
|
||||
alt=""
|
||||
width="1024"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Dribbble
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Красивые картинки с элементами интерфейсов
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://t.me/designnotpizza"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Дизайн не пицца — открыть канал в Telegram"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/tg-channel-logo-design_not_pizza.webp"
|
||||
alt=""
|
||||
width="640"
|
||||
height="640"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Дизайн не пицца
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Мой канал про дизайн. Посты на тему продуктового дизайна и полезные ссылки
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://github.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="GitHub — открыть профиль"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/github_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
GitHub
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Мои проекты и эксперименты с кодом
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="experience" class="section section--surface" aria-labelledby="experience-title" data-reveal>
|
||||
@@ -1288,196 +1476,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="activity" class="section section--surface" aria-labelledby="mini-projects-title" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 id="mini-projects-title" class="section__title">Активность</h2>
|
||||
<div
|
||||
class="skills-intro skills-intro--chat section__prose"
|
||||
data-skills-intro
|
||||
role="region"
|
||||
aria-labelledby="mini-projects-title"
|
||||
>
|
||||
<div class="skills-msg" data-skills-msg>
|
||||
<div class="skills-msg__body">
|
||||
<p class="skills-msg__author">Николай М:</p>
|
||||
<p class="skills-msg__text">
|
||||
Люблю делать разные мини-проекты или делиться чем-то полезным с миром.
|
||||
</p>
|
||||
<time class="skills-msg__time" datetime="" data-skills-msg-time></time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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--horizontal mp-card--hor-image"
|
||||
href="https://www.figma.com/@mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Figma Community — открыть профиль"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/figma_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Figma Community
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Выкладываю полезные файлы и плагины для сообщества
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://dribbble.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Dribbble — открыть профиль"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/dribbble_logo.webp"
|
||||
alt=""
|
||||
width="1024"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Dribbble
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Красивые картинки с элементами интерфейсов
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://t.me/designnotpizza"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Дизайн не пицца — открыть канал в Telegram"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/tg-channel-logo-design_not_pizza.webp"
|
||||
alt=""
|
||||
width="640"
|
||||
height="640"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Дизайн не пицца
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Мой канал про дизайн. Посты на тему продуктового дизайна и полезные ссылки
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
href="https://github.com/mamadaevv"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="GitHub — открыть профиль"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="assets/misc/github_logo.webp"
|
||||
alt=""
|
||||
width="800"
|
||||
height="800"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
GitHub
|
||||
<span class="mp-card__ext" aria-hidden="true"></span>
|
||||
</h3>
|
||||
<p class="mp-card__desc">
|
||||
Мои проекты и эксперименты с кодом
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Figma</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">ИИ помощник для любого тарифа редактора</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Obsidian</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Отображение карточек с заметками в стиле канбан доски</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="Этот сайт — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Этот сайт</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Разработка с AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Весь цикл создания сайта при помощи ИИ</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="contact" class="section section--surface section--footerish" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Контакты</h2>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<url>
|
||||
<loc>https://mamadaevv.site/cases/ai-assistant-figma/</loc>
|
||||
<lastmod>2026-09-24</lastmod>
|
||||
<lastmod>2026-09-26</lastmod>
|
||||
<xhtml:link rel="alternate" hreflang="x-default" href="https://mamadaevv.site/cases/ai-assistant-figma/" />
|
||||
<xhtml:link rel="alternate" hreflang="ru" href="https://mamadaevv.site/cases/ai-assistant-figma/" />
|
||||
<xhtml:link rel="alternate" hreflang="en" href="https://mamadaevv.site/en/cases/ai-assistant-figma/" />
|
||||
@@ -101,7 +101,7 @@
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://mamadaevv.site/</loc>
|
||||
<lastmod>2026-09-24</lastmod>
|
||||
<lastmod>2026-09-26</lastmod>
|
||||
<xhtml:link rel="alternate" hreflang="x-default" href="https://mamadaevv.site/" />
|
||||
<xhtml:link rel="alternate" hreflang="ru" href="https://mamadaevv.site/" />
|
||||
<xhtml:link rel="alternate" hreflang="en" href="https://mamadaevv.site/en/" />
|
||||
|
||||
@@ -190,6 +190,9 @@ async function toWebm(inputPath, outPath, statusCtx) {
|
||||
} else {
|
||||
a.push("-an");
|
||||
}
|
||||
// Резервируем место под Cues в начале файла, чтобы браузер мог перематывать
|
||||
// (иначе Cues пишутся в конец и duration=N/A, seek не работает).
|
||||
a.push("-reserve_index_space", "50000");
|
||||
a.push(outPath);
|
||||
const d = getDurationSec(inputPath);
|
||||
await runFfmpegProgress(a, {
|
||||
|
||||
@@ -237,11 +237,37 @@ function serveStatic(req, res) {
|
||||
}
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const mime = MIME[ext] || "application/octet-stream";
|
||||
fs.readFile(filePath, (e2, data) => {
|
||||
if (e2) { res.writeHead(500); res.end("Error"); return; }
|
||||
res.writeHead(200, { "Content-Type": mime });
|
||||
res.end(data);
|
||||
const total = stat.size;
|
||||
const range = req.headers.range;
|
||||
|
||||
// Поддержка Range-запросов — нужна браузеру для перемотки видео/аудио
|
||||
if (range) {
|
||||
const m = /^bytes=(\d*)-(\d*)$/.exec(range);
|
||||
if (m) {
|
||||
let start = m[1] ? parseInt(m[1], 10) : 0;
|
||||
let end = m[2] ? parseInt(m[2], 10) : total - 1;
|
||||
if (isNaN(start) || isNaN(end) || start > end || end >= total) {
|
||||
res.writeHead(416, { "Content-Range": `bytes */${total}` });
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
res.writeHead(206, {
|
||||
"Content-Type": mime,
|
||||
"Content-Range": `bytes ${start}-${end}/${total}`,
|
||||
"Accept-Ranges": "bytes",
|
||||
"Content-Length": end - start + 1,
|
||||
});
|
||||
fs.createReadStream(filePath, { start, end }).pipe(res);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
res.writeHead(200, {
|
||||
"Content-Type": mime,
|
||||
"Accept-Ranges": "bytes",
|
||||
"Content-Length": total,
|
||||
});
|
||||
fs.createReadStream(filePath).pipe(res);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Case Study: AI Assistant—a Figma plugin with AI features."
|
||||
content="Case study of a Figma plugin that retrieves and runs scripts from Cursor."
|
||||
/>
|
||||
<title>AI Assistant — Figma Plugin — Case Study</title>
|
||||
<title>AI assistant: a script bridge between Cursor and Figma</title>
|
||||
{{> head-links}}
|
||||
{{> head-plyr}}
|
||||
<style>
|
||||
@@ -33,6 +33,21 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
/* Реальный размер картинки: натуральная ширина в пикселях, ограниченная колонкой */
|
||||
.case-media--real {
|
||||
width: auto;
|
||||
margin-inline: auto;
|
||||
margin-left: auto;
|
||||
transform: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.case-media--real img {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
margin-inline: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function () {
|
||||
@@ -85,34 +100,166 @@
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<div class="section__inner case-article" data-case-sequential-images>
|
||||
<p class="hero__eyebrow">Figma · Plugin</p>
|
||||
<h1 class="case-page__h1">AI Assistant</h1>
|
||||
<p class="case-page__sub">A Figma plugin with AI features</p>
|
||||
<p class="case-page__sub">A bridge between Cursor IDE and Figma for creating and running scripts</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
I worked in Figma every day, designing software, apps and websites. I used plenty of plugins and made a few of my own when I could not find what I needed. The same manual steps kept coming back. Organizing layers was tedious, and some tasks felt unrealistic to do by hand, so I kept putting them off.
|
||||
</p>
|
||||
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
I built the plugin for myself. I was already using LLMs for different tasks and asking them to help write Figma scripts. I created the code in Cursor, then had to move it into Figma manually to run it. I did not know how to write plugin or script code myself, so I learned from Figma's documentation and plugin API as I went, while refining my script-generation rules in Cursor.
|
||||
</p>
|
||||
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
I wanted to remove the manual code handoff and run scripts directly in Figma. The plugin had to connect Cursor and Figma, let me reuse existing scripts, and make it easy to copy context about a selected node or an entire page for the LLM.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>I could add scripts for different tasks to the catalog and run them directly in Figma.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Catalog of custom plugin scripts"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Scripts%20List.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script catalog with search, sorting, and quick launch.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
A local server and WebSocket connected Cursor to the plugin. Once a script was ready, I opened the plugin and clicked Run. The code was sent to Figma automatically.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Script editor in the Figma plugin"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Script%20Edit.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script screen before running it in Figma.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Saved scripts could be launched from the catalog without Cursor. I ran existing scripts more often than I created new ones.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Menu of additional script actions"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Menu%20More.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Menu of additional actions for a script.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
To give the LLM better context, the plugin could copy information about a selected node or an entire page. I used that data in my conversation with the model.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Plugin toolbar with the Live toggle"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Live%20Mode.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script controls with the Live toggle.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The LLM in Cursor could read the execution logs. If the issue was with the script's logic rather than a bug, I split it into small steps and ran them one by one. I tested each script in a separate Figma file first, then tried it in a working file when it behaved as expected.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Script editor with an execution log panel"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Script%20Edit%20Log%20View.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Script editor and execution log panel.</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/ai-assistant-figma/video/20250904-1414-49.4157894.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250904-1414-49.4157894.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Editing a script in Cursor and checking the result in Figma.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="result">Result</h2>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>I estimated that a task could take 1 to 30 minutes by hand. Launching its script then took one click.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Script execution indicator"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Script%20is%20Working.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Indicator that a script is running.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
The time saved let me try more complex workflows. In working files, I often ran a script to flatten vector icons so they displayed correctly in production. Another turned a frame into a component, created an instance, and moved the master component to a designated place on the components page. Scripts also updated color tokens after manual changes and helped build a design-system file with many pages.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Other tasks included adding component variants, saving a set of tokens from JSON stored in a text layer, and building a prototype with keyboard-driven transitions. I also automated code syntax highlighting in a mockup to present an idea and tune the syntax colors. I would not have colored code by hand.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/ai-assistant-figma/video/20250913-0936-57.5977819.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250913-0936-57.5977819.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250913-0936-57.5977819.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>A script assembles a form from design-system components using a reference.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
I learned more about the Figma Plugin API. Now I plan work with scriptable actions in mind, so I spend less time on repetitive steps.
|
||||
</p>
|
||||
|
||||
<h2 id="next-steps">Plans</h2>
|
||||
<p class="section__prose">
|
||||
Next, I want to remove Cursor from the workflow and talk to LLM agents directly in Figma. Depending on the task, an agent could create a reusable script or carry out an action from a text command.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
For now, only the interface window exists. Agent conversations and actions are not implemented yet.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/ai-assistant-figma/video/20260916-132035.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20260916-132035.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20260916-132035.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Interface concept for the planned LLM agent workflow in Figma.</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: AI assistant — плагин для Figma с AI-функциями."
|
||||
content="Кейс о плагине для Figma, который получает скрипты из Cursor и запускает их."
|
||||
/>
|
||||
<title>AI assistant — Плагин для Figma — кейс</title>
|
||||
<title>AI assistant: плагин-мост между Cursor и Figma</title>
|
||||
{{> head-links}}
|
||||
{{> head-plyr}}
|
||||
<style>
|
||||
@@ -33,6 +33,21 @@
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
/* Реальный размер картинки: натуральная ширина в пикселях, ограниченная колонкой */
|
||||
.case-media--real {
|
||||
width: auto;
|
||||
margin-inline: auto;
|
||||
margin-left: auto;
|
||||
transform: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.case-media--real img {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
margin-inline: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function () {
|
||||
@@ -85,34 +100,165 @@
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<div class="section__inner case-article" data-case-sequential-images>
|
||||
<p class="hero__eyebrow">Figma · Plugin</p>
|
||||
<h1 class="case-page__h1">AI assistant</h1>
|
||||
<p class="case-page__sub">Плагин для Figma с AI-функциями</p>
|
||||
<p class="case-page__sub">Мост между Cursor IDE и Figma для создания и запуска скриптов</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
Рабочие будни проходили в Figma: проектировал сайты и приложения, использовал плагины, а когда готовых решений не хватало, делал свои. Со временем заметил, сколько времени уходит на повторяющиеся действия. Рутину вроде организации слоёв хотелось отдать скриптам, а задачи, которые вручную казались неподъёмными, так и оставались в списке на потом.
|
||||
</p>
|
||||
|
||||
<h2 id="context">Контекст</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
Плагин я делал для себя. LLM уже помогали создавать скрипты для Figma. Код готовил в Cursor, а для запуска переносил в Figma вручную. Навыков самостоятельного написания кода плагинов и скриптов не хватало, поэтому по ходу работы изучал документацию и API плагинов Figma, а правила генерации скриптов в Cursor постоянно уточнял.
|
||||
</p>
|
||||
|
||||
<h2 id="task">Задача</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
Задача состояла в том, чтобы убрать ручной перенос кода и запускать скрипты прямо из Figma. Плагину предстояло связать Cursor с Figma, дать возможность повторно запускать сценарии и быстро копировать для LLM контекст выбранного объекта или страницы.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>Каталог позволял добавлять скрипты под разные задачи и запускать их прямо в Figma.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Каталог пользовательских скриптов плагина"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Scripts%20List.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Каталог сценариев с поиском, сортировкой и быстрым запуском.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="solution">Решение</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
Локальный сервер и WebSocket связали Cursor с плагином. Когда скрипт был готов, достаточно было открыть плагин и нажать «Выполнить». Код автоматически передавался в Figma.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Редактор скрипта в плагине Figma"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Script%20Edit.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Экран скрипта перед запуском в Figma.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Готовые сценарии запускал чаще, чем создавал новые. Из каталога их можно было запускать и без Cursor.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Меню дополнительных действий со скриптом"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Menu%20More.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Меню дополнительных действий со скриптом.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Для более точных ответов модели плагин копировал данные о выбранной ноде или целой странице. Этот контекст можно было передать LLM вместе с запросом.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Панель плагина с переключателем Live"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Live%20Mode.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Панель управления скриптом с переключателем Live.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Логи выполнения мог читать LLM-бот в Cursor. Логические ошибки разбирал по шагам: делил сценарий на части и запускал их по очереди. Сначала проверял скрипт в отдельном файле, а после успешного теста пробовал в рабочем макете.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Редактор скрипта с панелью логов"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Script%20Edit%20Log%20View.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Редактор и панель логов выполнения.</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/ai-assistant-figma/video/20250904-1414-49.4157894.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250904-1414-49.4157894.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250904-1414-49.4157894.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Доработка скрипта в Cursor и проверка результата в Figma.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="result">Результат</h2>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">✅</span>
|
||||
<div class="case-callout__content">
|
||||
<p>На ручное выполнение отдельной задачи уходило от 1 до 30 минут. Это оценка, отдельную статистику не собирал. Теперь скрипт запускался одним нажатием.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--real">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Индикатор выполнения скрипта"
|
||||
data-src="{{assetPrefix}}assets/ai-assistant-figma/Script%20is%20Working.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Индикатор активного выполнения скрипта.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
Высвободившееся время позволяло браться за более сложные рабочие сценарии. В рабочих файлах часто запускал скрипт, который сводил векторные иконки через flatten для корректного отображения в продакшене. Другой превращал фрейм в компонент, создавал его инстанс и переносил мастер-компонент в заданное место на странице компонентов. Скрипты также помогали обновлять цветовые токены после ручных изменений и собирать структуру файла дизайн-системы с множеством страниц.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Были и другие задачи: добавлял варианты компонентов, сохранял набор токенов из JSON в текстовом слое или собирал прототип с переходами по клавиатуре. Подсветку кода в макете тоже автоматизировал скриптом, чтобы нагляднее показать идею и подобрать цвета синтаксиса. Вручную за такую работу не взялся бы.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/ai-assistant-figma/video/20250913-0936-57.5977819.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250913-0936-57.5977819.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20250913-0936-57.5977819.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Сборка формы из компонентов дизайн-системы по референсу с помощью скрипта.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
За время работы лучше разобрался в Figma Plugin API. Теперь при планировании заранее учитываю, какие действия можно скриптовать, чтобы не тратить время на рутину.
|
||||
</p>
|
||||
|
||||
<h2 id="next-steps">Планы</h2>
|
||||
<p class="section__prose">
|
||||
Дальше планирую убрать Cursor из рабочего процесса и общаться с LLM-агентами прямо в Figma. В зависимости от задачи агент сможет подготовить переиспользуемый скрипт или выполнить действие по текстовой команде.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Сейчас готово только окно интерфейса. Работа с агентами и запуск действий пока не реализованы.
|
||||
</p>
|
||||
<figure class="case-media case-media--real">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/ai-assistant-figma/video/20260916-132035.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20260916-132035.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-assistant-figma/video/20260916-132035.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Макет интерфейса планируемой работы с LLM-агентами в Figma.</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{> projects-section-mp}}{{> projects-section}}
|
||||
{{> projects-section-mp}}{{> projects-section}}{{> mini-projects-section}}
|
||||
|
||||
<section id="experience" class="section section--surface" aria-labelledby="experience-title" data-reveal>
|
||||
<div class="section__inner">
|
||||
@@ -545,8 +545,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{> mini-projects-section}}
|
||||
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{> projects-section-mp}}{{> projects-section}}
|
||||
{{> projects-section-mp}}{{> projects-section}}{{> mini-projects-section}}
|
||||
|
||||
<section id="experience" class="section section--surface" aria-labelledby="experience-title" data-reveal>
|
||||
<div class="section__inner">
|
||||
@@ -560,8 +560,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{> mini-projects-section}}
|
||||
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
|
||||
@@ -18,6 +18,51 @@
|
||||
</div>
|
||||
</div>
|
||||
<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="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">An AI assistant for any editor plan</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Obsidian plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Shows note cards in a kanban-board style</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="This site — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">This site</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Built with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">The whole site-building cycle with AI</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
@@ -138,51 +183,6 @@
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">An AI assistant for any editor plan</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Obsidian plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Shows note cards in a kanban-board style</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="This site — open case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">This site</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project type">
|
||||
<li class="mp-card__tag">Built with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">The whole site-building cycle with AI</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
@@ -18,6 +18,51 @@
|
||||
</div>
|
||||
</div>
|
||||
<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="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Figma</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">ИИ помощник для любого тарифа редактора</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Obsidian</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Отображение карточек с заметками в стиле канбан доски</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="Этот сайт — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Этот сайт</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Разработка с AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Весь цикл создания сайта при помощи ИИ</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal mp-card--hor-image"
|
||||
@@ -138,51 +183,6 @@
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/ai-assistant-figma/"
|
||||
aria-label="AI assistant — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Figma</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">ИИ помощник для любого тарифа редактора</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/card-columns-obsidian/"
|
||||
aria-label="Card Columns — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Obsidian</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Отображение карточек с заметками в стиле канбан доски</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="cases/site-with-ai-ide/"
|
||||
aria-label="Этот сайт — открыть кейс"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Этот сайт</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Разработка с AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Весь цикл создания сайта при помощи ИИ</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||