Bots and Bones design system · v1
{{ s.num }}{{ s.title }}
{{ g.name }} {{ g.count }}
Bots and Bones · инструкция · v2 Как подключить дизайн-систему к nodex.html Девять шагов: от копирования файлов до проверки. Можно идти по порядку и выкатывать после каждого шага — интерфейс не ломается, а постепенно переходит на токены.
1–4 · подключение, ~30 мин 5–8 · перевод стилей, по частям 9 · проверка
01Скопировать файлы на сервер
Из этого проекта нужна только папка токенов, иконки и логотип. Компоненты (components/) — это образцы, их не подключают, по ним сверяются.
/ds/
  styles.css            ← точка входа, только @import
  tokens/
    fonts.css           ← заменить на локальный (шаг 2)
    colors.css          ← 2 темы: light, night
    typography.css
    spacing.css         ← радиусы, кольца, тени
    motion.css          ← @keyframes bnb-*
    base.css
  assets/
    glyphs.json         ← все иконки
    bnb-logo.png
/fonts/                 ← уже есть, добавить Plex и JetBrains
02Шрифты — только локально
Важно В nodex стоит CSP font-src 'self' — Google Fonts из tokens/fonts.css заблокируются, и весь текст молча упадёт в системный шрифт.
Скачайте woff2 с кириллицей (Google Fonts или пакеты fontsource): IBM Plex Sans 400/500, IBM Plex Mono 400/500, JetBrains Mono 400. Положите в /fonts/ и замените содержимое /ds/tokens/fonts.css:
@font-face { font-family: 'IBM Plex Sans'; font-weight: 400; font-display: swap;
  src: url('/fonts/ibm-plex-sans-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Sans'; font-weight: 500; font-display: swap;
  src: url('/fonts/ibm-plex-sans-500.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 400; font-display: swap;
  src: url('/fonts/ibm-plex-mono-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 500; font-display: swap;
  src: url('/fonts/ibm-plex-mono-500.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-weight: 400; font-display: swap;
  src: url('/fonts/jetbrains-mono-400.woff2') format('woff2'); }
Если решите оставить Golos / Noto Sans Mono / Geologica — не трогайте fonts.css, а в мосте (шаг 4) переопределите --font-sans, --font-mono, --font-label.
03Подключить в <head> и выставить тему
Скрипт темы — до стилей, чтобы не было вспышки светлой темы. Ссылка на styles.css — до собственного <style> nodex, тогда стили nodex сильнее и ничего не съедет.
<link href="/fonts/fonts.css" rel="stylesheet">
<script>
  (function(){
    var t = "night";
    try { t = localStorage.getItem("rvre_theme") || t; } catch(e){}
    document.documentElement.setAttribute("data-theme", t);
  })();
</script>
<link href="/ds/styles.css" rel="stylesheet">   ← новое
<style>
  :root{ … }                                    ← существующие стили nodex
Переключатель темы (например, в меню профиля):
function setTheme(t){
  document.documentElement.setAttribute("data-theme", t);
  try { localStorage.setItem("rvre_theme", t); } catch(e){}
}
nightпо умолчанию — ближе всего к текущему чёрному
lightсветлая нейтральная, она же — без атрибута
04Мост: старые переменные → токены
Замените блок :root{ … } в начале стилей nodex целиком. После этого весь код, который уже пишет var(--fg), var(--node) и т.д., сразу берёт цвета из темы.
Конфликт имён --muted и --accent есть и в nodex, и в системе. Старые значения нужно удалить — иначе они перебьют тему. В мосте ниже их нет намеренно.
:root, [data-theme]{
  /* поверхности */
  --bg:        var(--canvas);
  --grid:      var(--dot);
  --panel:     var(--ash);
  --node:      var(--card);
  --node-head: var(--ash);
  --line:      var(--hairline);
  /* текст */
  --fg:        var(--ink);
  --dim:       var(--muted);      /* --muted уже из системы */
  /* акценты и статусы */
  --accent2:   var(--fern);       /* --accent уже = var(--moss) */
  --err:       var(--error);
  --ok:        var(--emerald);
  /* форма */
  --r:         var(--radius-md);  /* было 28px → 12px */
  --r-sm:      var(--radius-sm);  /* было 16px → 4px  */
  /* шрифты */
  --sans:      var(--font-sans);
  --mono:      var(--font-mono);
  --display:   var(--font-sans);
  /* сокеты = цвета типов данных */
  --sock-text:  var(--t-text);
  --sock-image: var(--t-image);
  --sock-vid:   var(--t-video);
  --sock-aud:   var(--t-audio);
  --sock-num:   var(--t-any);
  --sock-3d:    var(--t-any);
}
Селектор [data-theme] нужен, чтобы алиасы пересчитывались при смене темы. Для num и 3D в системе отдельных цветов нет — пока --t-any; если нужны свои, добавьте их в каждую тему в colors.css.
05Убрать захардкоженные цвета
В nodex много цветов прямо в правилах — мост их не видит. Поиск-замена по файлу:
БылоСталоГде
#000000 #070707var(--canvas)фон, холст
#0d0d0d #0e0e0e rgba(9,10,12,.99)var(--ash)палитра, меню, поля, кнопки
#1a1a1a (фон)var(--card)ноды
#161616 #1a1a1a (hover) rgba(255,255,255,.06)var(--shade)ховеры
#232323 #3a3a3a #3d3d3avar(--hairline)скроллбары, разделители
#5a5a57var(--muted)заголовки категорий
color:#000 #0a0a0a на кнопках/бейджахvar(--on-accent).tbtn.prim, .pbadge
#ffb3b3 #ff6b6bvar(--error)danger, «не сохранено»
#5bbf7avar(--emerald)«сохранено»
--pcat-c (#f8a5a5, #fde047 …)var(--t-*)категории палитры — по типу данных
Быстрая проверка, что ничего не осталось: поиск по регулярке #[0-9a-f]{3,6}\b внутри <style>. Допустимы только цвета в SVG-логотипах моделей.
06Радиусы, рамки, тени
Радиусыкнопки, поля, чипы → 4px
меню, контекст → 6px
ноды, карточки, CTA → 12px
модалки → 18px
999px — только профиль
Рамкиborder: 1px solid … → border: none
+ box-shadow: var(--ring-hairline)
выделено → var(--ring-selected)
запуск → var(--ring-running)
ошибка → var(--ring-error)
Тенив покое — нет
выделено → var(--shadow-lift)
перетаскивание → var(--shadow-drag)
меню → 0 12px 24px -14px rgba(0,0,0,.2)
Пример — кнопка тулбара до и после:
/* было */
.tbtn{ border:1px solid var(--line); background:#0d0d0d; border-radius:999px; … }
.tbtn.prim{ background:var(--fg); color:#000; font-weight:700; }

/* стало */
.tbtn{ border:none; background:var(--ash); box-shadow:var(--ring-hairline);
  border-radius:var(--radius-sm); font-family:var(--font-mono); font-size:12px;
  padding:7px 12px; transition:background var(--dur-fast) var(--ease); }
.tbtn:hover{ background:var(--shade); }
.tbtn:focus-visible{ outline:none; box-shadow:var(--ring-selected); }
.tbtn:disabled{ opacity:.4; }
.tbtn.prim{ background:var(--moss); color:var(--on-accent); box-shadow:none;
  font-weight:500; border-radius:var(--radius-md); }
.tbtn.prim:hover{ filter:brightness(1.04); }
.tbtn.prim:active{ filter:brightness(.96); }
Жирность: в системе только 400 и 500. Все font-weight:700 и 600 → 500.
07Иконки из glyphs.json
Все пути — на сетке 20×20, только обводка. Не перерисовывать: брать путь из файла и красить через currentColor.
var GLYPHS = {};
fetch("/ds/assets/glyphs.json").then(function(r){ return r.json(); })
  .then(function(j){ GLYPHS = j; document.dispatchEvent(new Event("glyphs:ready")); });

function glyph(d, size){
  return '<svg viewBox="0 0 20 20" width="' + (size||20) + '" height="' + (size||20) + '" '
    + 'fill="none" stroke="currentColor" stroke-width="1.3" '
    + 'stroke-linecap="round" stroke-linejoin="round"><path d="' + d + '"/></svg>';
}
Структуру ключей смотрите в самом файле. Цвет иконки типа данных — color: var(--t-image) и т.д. Логотипы моделей остаются как есть; где логотипа нет — 3-буквенный mono-бейдж (FLX, KLG).
08Анимации состояний
Keyframes уже приходят из motion.css. Повесить на существующие классы nodex:
.node.is-new      { animation: bnb-in var(--dur-in) var(--ease); }
.node.is-running  { box-shadow: var(--ring-running); }
.node.is-running .status-ico { animation: var(--pulse); }
.node.is-error    { animation: bnb-err .6s ease 2; }
.node .result.is-ready { animation: bnb-reveal .4s var(--ease); }
#wires path.is-flowing { stroke-dasharray: 6 5; animation: var(--flow); }
#ctxmenu.on, #proj-menu.on { animation: bnb-pop .16s var(--ease); }
Имена классов-состояний подставьте свои — в nodex они могут называться иначе. Без пружин и отскоков.
09Проверка перед выкаткой
{{ progress }}
[ Bots and Bones ] Design system Tokens, components and every node state of the canvas editor. Switch the theme on the left — every card re-renders with the same token names. Buttons, chips, checkboxes and nodes in the cards are clickable.
{{ s.name }} {{ s.intro }}
{{ r.mark }} {{ r.text }}
{{ c.name }} open ↗
{{ c.sub }}