Дизайн-система для Vue 3

Мельче части — прочнее система.

Интерфейсы собираются из компонентов, основ и утилит. В сборку уезжает ровно то, что вы импортировали, — и ничего сверх.

Vue 3.5 · TypeScript · 84 компонентов · 0 runtime-зависимостей

Две оси, а не одна
КомпонентCSSJS
GrCard+ 235 B2 779 B
GrDialog+ 670 B9 989 B
GrDataTable+ 2 911 B36 431 B
GrSelect+ 3 037 B23 216 B

GrDataTable и GrSelect стоят почти одинаково по стилям, а по коду расходятся в полтора с лишним раза. Одна цифра не предсказывает другую.

Сжато, только пакет: фреймворк ваш, и в этих числах его нет.

Не картинка

Работающий экран, собранный из тех же компонентов.

Store overview

Revenue
€21 480
Рост+12.4% vs previous
Orders
486
Рост+6.1% vs previous
Conversion
3,4%
Падение−0.3 pp vs previous
Average basket
€44,20
Без измененийNo change

Daily revenue

Thousands of euros

То же демо, что стоит на странице GrStatistic: ради главной ничего не написано во второй раз.

Гранулярность

149 путей экспорта. Берёте компонент, composable или одну директиву — граф зависимостей на этом заканчивается.

Согласованность

Цвет, отступ и радиус — это роль, а не значение. Обе темы равноправны, и контраст проверяется в обеих.

Своя тема

Ребрендинг — это смена значений токенов. Исходники компонентов при этом не трогаются.

Для разработчика

Типы, авто-импорт, метаданные для IDE. Контракт доступности проверяется гейтом, а не декларируется.

Одна цена, четыре разреза

Одну цифру напечатать было бы проще.

Каждое число снято со сборки и сжато. Фреймворк в них не входит: он ваш, а не мой. Какой из разрезов важен, зависит от того, что вас ограничивает, — поэтому здесь все четыре.

Во что обойдётся начать

13 214B, дальше почти ничего

base + GrButton13 214 B
+ GrCard+ 235 B
+ GrDialog+ 670 B
+ GrDataTable+ 2 911 B
+ GrSelect+ 3 037 B

Первый компонент несёт токены, обе темы и базовый слой. Следующие четыре вместе стоят всё ещё меньше, чем он один.

Все ли компоненты лёгкие

13.6×разброс по набору

GrBadge2 680 B
GrCard2 779 B
GrAlert3 728 B
GrButton4 746 B
GrTabs5 674 B
GrDialog9 989 B
GrSelect23 216 B
GrDataTable36 431 B

Нет. Разброс — от GrBadge до GrDataTable, а насколько, сказано числом выше. Если библиотека говорит, что все её компоненты лёгкие, — она их не мерила.

Что вы берёте на себя

0runtime-зависимостей

149 путей экспорта

Под узлом ничего нет. Ваш lock-файл, ваша поверхность аудита и ваш путь обновления остаются вашими, а 149 путей экспорта означают, что граф останавливается там же, где вы.

Во что обходится вторая тема

1563B, при любом размере

1 · 11 651 B
2 · 13 214 B

Число почти не меняется между одним компонентом и всеми 84. Отказ от тёмной темы — не то место, где экономят вес.

Замерено 2026-10-16 · core 1.1.1 · granum 2.1.0 · gzip

Модель

Четыре слоя, каждый собран из предыдущего. Имя продукта и есть его архитектура.

01

Tokens

Цвет, отступы, радиусы, движение и слои — именованными ролями.

02

Components

84 в ядре, плюс пакеты-спутники вокруг. Каждый берётся отдельно от прочих.

03

Patterns

Композиции под задачу: формы, поиск, настройки, оверлеи.

04

Interfaces

Целые экраны. Компонент полезен. Система ценна.

Основы

Токен — это роль, а не hex-код.

Цвет, отступ, радиус, движение и слои — именованные роли, прочитанные из пакета. Меняются значения — компоненты следуют за ними в обеих темах.

токенов
198
темы
2
разделов основ
10

Смотреть основы →

РольСветлаяТёмная
--gr-bg#f8fafc#0f172a
--gr-card#ffffff#1e293b
--gr-fg#0f172a#f8fafc
--gr-muted-fg#556275#aab6c7
--gr-primary#4f46e5#9d8bfa
--gr-accent#eef2ff#1e1b4b
Одна разметка, две темы: карточка нарисована только ролями, и разница между ними — один атрибут темы.

От пустого проекта до кнопки

Четыре шага и ни одного генератора.

Весь путь быстрого старта: пакеты, конфиг granum, два импорта CSS и первый компонент. Ни одну строку за вас не пишет генератор.

Шаги

В приложение

npm i @feugene/granularity vue @floating-ui/dom @unocss/reset
pnpm add @feugene/granularity vue @floating-ui/dom @unocss/reset
yarn add @feugene/granularity vue @floating-ui/dom @unocss/reset
bun add @feugene/granularity vue @floating-ui/dom @unocss/reset

В сборку

npm i -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc
pnpm add -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc
yarn add -D vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc
bun add -d vite @vitejs/plugin-vue @feugene/granum @feugene/granum-engine-wind typescript vue-tsc
granum.config.mjs
import { windEngine } from '@feugene/granum-engine-wind'
import { defineGranumConfig } from '@feugene/granum/vite'

export default defineGranumConfig({
  engine: windEngine(),
  providers: ['@feugene/granularity'],
  components: [{ provider: '@feugene/granularity', names: ['GrButton'] }],
  themes: { names: ['light', 'dark'] },
  appSources: { dirs: ['src'] },
})
vite.config.ts
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
import { granum } from '@feugene/granum/vite'
import granumConfig from './granum.config.mjs'

export default defineConfig({ plugins: [Vue(), granum(granumConfig)] })
src/main.ts
import './reset.css'
import 'virtual:granum.css'

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')
src/reset.css
@import '@unocss/reset/tailwind-compat.css' layer(reset);
src/App.vue
<script setup lang="ts">
import { GrButton } from '@feugene/granularity/components/GrButton'
</script>

<template>
  <GrButton tone="primary">Save</GrButton>
</template>

Быстрый стартПопробовать в песочнице

Открытая разработка

Всё здесь проверяемо.

Цифры на сайте приходят из сборки, а не из текста. Каждая ведёт на страницу, где видно, откуда она взялась.

Начните собирать на Granularity.

Самая короткая полезная страница — быстрый старт. Остальная документация подождёт, пока не понадобится.

Быстрый стартОткрыть песочницу

Установка

npm i @feugene/granularity vue @floating-ui/dom @unocss/reset
pnpm add @feugene/granularity vue @floating-ui/dom @unocss/reset
yarn add @feugene/granularity vue @floating-ui/dom @unocss/reset
bun add @feugene/granularity vue @floating-ui/dom @unocss/reset

Почему список именно такой