SpyBara
Go Premium

plugins/mods/gallery.md 2026-10-21 23:02 UTC to 2026-10-22 22:58 UTC

This page contains 16 additions and 16 deletions.

2026
Fri 2 22:59 Thu 8 22:58 Thu 15 23:58 Fri 16 22:59 Tue 20 23:00 Wed 21 23:02 Thu 22 22:58 Fri 23 22:59 Sat 24 22:59 Mon 26 22:57 Tue 27 22:59

Галерея элементов интерфейса для модов

Посмотрите, какие элементы интерфейса может отрисовывать мод Claude Code: текст, кнопки, поля, Markdown, код и diff, — с примерами кода и снимками экрана терминала.

Мод строит свой интерфейс из элементов: текста, блоков, кнопок, полей и нескольких элементов, которые форматируют содержимое за вас. Примеры на этой странице показывают код, отрисовывающий элемент, и к большинству из них приложен снимок экрана с результатом на панели терминала, поэтому элемент можно выбрать по его внешнему виду.

Чтобы разобраться, как работает отрисовка, начните с раздела Отрисовка в интерфейсе. Основные свойства элементов и приложения, которые отрисовывают каждый из них, описаны в справочнике по элементам. В объявлениях типов перечислены все свойства.

Попробуйте пример

Примеры на этой странице — это фрагменты, а не готовые моды. Каждый из них — код одного элемента и всего, что в него вложено.

Чтобы посмотреть пример в своём терминале, создайте небольшой мод, следуя этим шагам, и вставьте в него пример. Мод добавляет команду /gallery, которая открывает панель и отрисовывает в ней пример. Панель — это боковая область рядом с транскриптом в широком полноэкранном терминале, а в остальных случаях — область в рамке над промптом.

1. Создайте мод

Создайте каталог gallery, а внутри него — каталоги .claude-plugin и hooks. Назначение файлов объясняется в разделе Создание мода.

Сохраните манифест как gallery/.claude-plugin/plugin.json:

{
  "name": "gallery",
  "version": "0.1.0",
  "description": "Opens a pane that draws one sample",
  "author": { "name": "Your Name" }
}

Укажите точку входа в gallery/hooks/hooks.json:

{
  "modules": ["./register.js"]
}

Сохраните код как gallery/hooks/register.js. Он добавляет команду /gallery, которая открывает панель, и отрисовывает в ней Plain text:

// Stands in for your own callback in the samples that take one
const noop = () => {}
// The Select sample keeps its choice here
let picked = 'md'

// The Raster sample packs its cells with this function
const DEFAULT_COLOR = 0x01000000
function cellsOf(rows) {
  const numbers = rows.flat().flatMap(([char, color]) => [char.codePointAt(0), color, DEFAULT_COLOR])
  return new Uint8Array(Uint32Array.from(numbers).buffer).toBase64()
}

export function register(on) {
  on('session.start', async ($, e, next) => {
    await $.command.register({ name: 'gallery', description: 'Open the sample pane' })
    return next(e)
  })

  on('command.run', { command: 'gallery' }, async ($) => {
    await $.ui.open({ id: 'gallery', focus: true, closeOnEscape: true })
    return {}
  })

  on('ui.render', { component: 'Pane' }, async ($, e, next) => {
    if (e.requestId !== 'gallery') return next(e)
    const { Box, Text, Button, Input, Select, Link, Markdown, Code, Raster, Svg } = $.ui.resolve(e)
    // Replace the element after return with a sample
    return Text({ children: ['Plain text'] })
  })
}

2. Запустите мод

В оболочке запустите Claude Code из каталога, содержащего gallery:

claude --plugin-dir ./gallery

В промпте Claude Code выполните /gallery. Откроется панель с текстом Plain text.

3. Подставьте пример

Скопируйте пример с этой страницы. В register.js вставьте его вместо Text({ children: ['Plain text'] }), чтобы он шёл после return, и сохраните файл. Claude Code перезагружает модуль при каждом сохранении, поэтому снова выполните /gallery, чтобы увидеть новый пример.

Выберите элемент

Примеры сгруппированы по тому, что вы хотите вывести на экран:

Вывод текста

Текст на экран выводят три элемента: Text — с вашим собственным оформлением, Markdown — для уже отформатированного содержимого и Link — для URL.

Text

Text отрисовывает строку с заданными вами стилями. В этом примере показаны обычный текст и восемь стилей, каждый на отдельной строке:

Box({
  flexDirection: 'column',
  children: [
    Text({ children: ['Plain text'] }),
    Text({ bold: true, children: ['bold'] }),
    Text({ italic: true, children: ['italic'] }),
    Text({ underline: true, children: ['underline'] }),
    Text({ strikethrough: true, children: ['strikethrough'] }),
    Text({ dimColor: true, children: ['dimColor'] }),
    Text({ inverse: true, children: ['inverse'] }),
    Text({ color: 'red', children: ["color: 'red'"] }),
    Text({ backgroundColor: 'blue', children: ["backgroundColor: 'blue'"] }),
  ],
})

Панель с девятью строками текста, каждая из которых названа по своему стилю: обычный, bold, italic, underline, strikethrough, dimColor серым цветом, inverse, color red и backgroundColor blue.

dimColor отрисовывает текст серым цветом. backgroundColor заливает фон только по ширине текста.

Markdown

Markdown форматирует текст так же, как форматируются ответы Claude. Передавайте содержимое в text, а не в children:

Markdown({
  text: '## Release notes\n\nThis build has **two** fixes and one `flag`:\n\n- Faster start\n- Fewer prompts\n\n> Quoted text',
})

Панель с жирным заголовком Release notes, затем предложение с одним жирным словом и одним цветным словом кода, список из двух пунктов и цитата курсивом с чертой слева.

Заголовок отрисовывается жирным шрифтом без знаков #. Встроенный код отрисовывается цветом без обратных кавычек. Цитата отрисовывается курсивом с чертой слева.

Link отрисовывает подпись, а за ней — её URL:

Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })

Панель с одной строкой: подпись Claude Code docs, а затем URL серым цветом.

Терминал отрисовывает URL как текст после подписи. Откроется ли он по щелчку, зависит от терминала пользователя.

Вывод кода и изменений

Code отрисовывает исходный текст с подсветкой синтаксиса в цветах самого Claude Code или diff. В расширении VS Code Code показывает свой source как обычный текст, без цветов, номеров строк и подсветки diff, которые видны на этих снимках экрана.

Code

Укажите язык в language или передайте path, чтобы Claude Code определил язык по нему. С startLine строки нумеруются начиная с этого числа:

Code({
  language: 'javascript',
  startLine: 1,
  source: "const name = 'mods'\nconsole.log('hello ' + name)",
})

Панель с двумя пронумерованными строками JavaScript с подсветкой синтаксиса.

Цвета берутся из темы пользователя.

Code в виде diff

С format: 'diff' в source передаются один или несколько фрагментов (hunks) в формате unified diff:

Code({
  format: 'diff',
  source: '@@ -1,3 +1,3 @@\n # Mods\n-A mod is a plugin.\n+A mod is a plugin that runs code.\n Read on.',
})

Панель с diff из четырёх строк. Удалённая строка подсвечена красным, добавленная — зелёным, у каждой указан номер строки. В добавленной строке слова that runs code подсвечены ярче.

Вместо строки @@ Claude Code отрисовывает номера строк. Если удалённая и добавленная строки похожи, изменившиеся слова подсвечиваются ярче.

Компоновка элементов

Box

Box располагает своё содержимое в строку или в столбец и может отрисовывать рамку. В этом примере над блоком в рамке размещается строка слов:

Box({
  flexDirection: 'column',
  gap: 1,
  children: [
    Box({
      flexDirection: 'row',
      columnGap: 4,
      children: [Text({ children: ['a row'] }), Text({ children: ['of three'] }), Text({ children: ['items'] })],
    }),
    Box({
      borderStyle: 'round',
      paddingX: 1,
      children: [Text({ children: ["borderStyle: 'round'"] })],
    }),
  ],
})

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

Рамка растягивается на всю ширину панели.

Ввод данных

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

Откройте панель с focus: true, чтобы она попыталась получить фокус клавиатуры. Вводимые буквы попадают в Input, как только на нём оказывается фокус. Как выбрать поле, которое получит фокус при открытии панели, описано в разделе Горячая клавиша и первый фокус.

Button

Кнопка вызывает onPress. В этом примере показаны кнопка по умолчанию, кнопка plain с горячей клавишей и приглушённая кнопка:

Box({
  flexDirection: 'column',
  children: [
    Button({ key: 'save', label: 'Save', onPress: noop }),
    Button({ key: 'next', label: 'Next', hotkey: 'n', plain: true, onPress: noop }),
    Button({ key: 'skip', label: 'Skip', dimColor: true, onPress: noop }),
  ],
})

Панель с тремя кнопками, по одной в строке: Save в скобках, n: Next без скобок с цветной буквой n и Skip в скобках серым цветом.

Кнопка с фокусом отрисовывается в инверсных цветах. Здесь пользователь дважды нажал Tab:

Те же три кнопки, вторая из которых, n: Next, отрисована в инверсных цветах.

Input

Input — это однострочное текстовое поле, которое вызывает onSubmit, когда пользователь нажимает Enter:

Input({
  key: 'title',
  label: 'Title',
  placeholder: 'Type a title and press Enter',
  value: '',
  submitLabel: 'save',
  onSubmit: noop,
})

Без фокуса поле показывает подпись и текст-заполнитель:

Панель с одной строкой: подпись Title, затем текст-заполнитель Type a title and press Enter серым цветом.

С фокусом подпись становится жирной, появляется курсор, а после ⏎ отображается submitLabel:

То же поле с жирной подписью, блочным курсором на первой букве текста-заполнителя и знаком возврата, за которым следует слово save.

Ввод заменяет текст-заполнитель:

То же поле с введёнными буквами Rel, за которыми следуют знак возврата и слово save.

Select

Select позволяет пользователю выбрать один из нескольких вариантов и вызывает onSelect со значением value выбранного варианта:

Select({
  key: 'format',
  label: 'Format',
  value: picked,
  options: [
    { value: 'md', label: 'Markdown' },
    { value: 'html', label: 'HTML' },
    { value: 'txt', label: 'Plain text' },
  ],
  onSelect: (value) => {
    picked = value
  },
})

В закрытом состоянии он показывает подпись и текущий вариант:

Панель с одной строкой: подпись Format, текущий вариант Markdown и маленькая стрелка вниз.

В открытом состоянии он показывает список вариантов и выделяет один из них:

Открытый список выбора с тремя вариантами под подписью. Второй вариант, HTML, отрисован в инверсных цветах.

После того как пользователь выберет вариант, список закрывается:

Список выбора снова закрыт, и текущим вариантом теперь показан HTML.

Рисование изображений

Raster

Raster — это сетка цветных символьных ячеек для тепловой карты, спарклайна или игрового поля. Его отрисовывает терминал. В этом примере используется функция cellsOf из начального модуля, которая упаковывает ячейки в строку, принимаемую Raster. Подробнее см. в разделе Отрисовка сетки цветных ячеек:

Raster({
  key: 'grid',
  columns: 3,
  rows: 2,
  cells: cellsOf([
    [['█', 0x2e7d32], ['█', 0xf9a825], ['█', 0xc62828]],
    [['█', 0x2e7d32], ['█', 0x2e7d32], ['█', 0xf9a825]],
  ]),
})

Панель с небольшой сеткой цветных блоков в две строки по три: зелёный, янтарный и красный, затем зелёный, зелёный и янтарный.

Raster округляет каждый цвет до более ограниченной палитры, поэтому 0x2e7d32 отрисовывается как #337733.

Svg

Svg отрисовывает SVG-документ в приложении Desktop и расширении VS Code:

Svg({
  alt: 'Three bars of rising height',
  width: 120,
  height: 60,
  source:
    '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 60"><rect x="10" y="40" width="20" height="20" fill="#2e7d32"/><rect x="50" y="25" width="20" height="35" fill="#f9a825"/><rect x="90" y="5" width="20" height="55" fill="#c62828"/></svg>',
})

В терминале панель, которая возвращает только Svg, открывается пустой. Чтобы отрисовать там что-то другое, проверьте e.surface и верните другое дерево.

Image и Client

Для ещё двух элементов примеров здесь нет. Image отрисовывает PNG или необработанные пиксели в терминале. Client — это область, которую отрисовывает ваш второй файл, для анимации и ввода указателем. Их свойства перечислены в справочнике по элементам.

Image отрисовывается как картинка в следующих терминалах:

  • kitty 0.28 или новее
  • Ghostty
  • iTerm2 3.5 или новее. Для отрисовки в iTerm2 требуется Claude Code v2.1.305 или новее.

В любом другом терминале пользователь увидит вместо картинки приглушённый текст alt элемента Image. Пишите текст alt, который понятен сам по себе, поскольку он также отображается, помимо прочего, в следующих случаях:

  • tmux и screen: сессия, запущенная внутри tmux или screen, в любом терминале.
  • Фоновые сессии: любая фоновая сессия, из какого бы терминала к ней ни подключались.
  • iTerm2 без полноэкранной отрисовки: в iTerm2 картинка отрисовывается только при полноэкранной отрисовке и не отрисовывается, если для CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT установлено значение 1. Чтобы увидеть картинку, выполните /tui fullscreen в промпте Claude Code и не устанавливайте эту переменную.
  • Путь к файлу в качестве источника в iTerm2: iTerm2 отрисовывает Image, у которого проп source содержит байты png или rgba, и показывает текст alt для элемента, у которого source указывает file. Если у вашего мода есть пользователи iTerm2, передавайте картинку в base64 в source.png или source.rgba, а не как путь в source.file.

Если пользователи вашего мода видят приглушённый текст в терминале, который отрисовывает изображения протокола графики kitty с плейсхолдерами Unicode, они могут установить для CLAUDE_CODE_FORCE_TERMINAL_IMAGES значение 1. Внутри tmux или screen это не помогает: текст alt пропадает, а Claude Code отправляет изображение, не оборачивая его для сквозной передачи через tmux или screen.

Где ещё может отрисовывать мод

Все примеры отрисовываются на панели. Мод также может отрисовывать в других местах и вызывать Claude Code, чтобы тот что-то показал за него:

Дальнейшие шаги