SpyBara
Go Premium

plugins/mods/gallery.md 2026-10-01 23:59 UTC to 2026-10-02 20:57 UTC

This page contains 435 additions and 0 deletions.

2026
Fri 2 22:00

mod용 인터페이스 갤러리

텍스트, 버튼, 필드, Markdown, 코드, diff 등 Claude Code mod가 그릴 수 있는 인터페이스 요소를 샘플 코드 및 터미널 스크린샷과 함께 확인합니다.

mod는 요소로 인터페이스를 그립니다. 요소에는 텍스트, 박스, 버튼, 필드, 그리고 콘텐츠 서식을 대신 지정해 주는 몇 가지 요소가 있습니다. 여기 있는 샘플은 요소를 그리는 코드를 보여 주며, 대부분 터미널 창에 표시된 결과 스크린샷이 함께 제공되므로 모양을 보고 요소를 고를 수 있습니다.

그리기가 작동하는 방식을 알아보려면 인터페이스에 그리기부터 시작하세요. 주요 prop과 각 요소를 그리는 앱은 요소 레퍼런스를 참조하세요. 타입 선언에는 모든 prop이 나열되어 있습니다.

샘플 사용해 보기

이 페이지의 샘플은 완전한 mod가 아니라 코드 조각입니다. 각 샘플은 하나의 요소와 그 안에 중첩된 모든 요소에 대한 코드입니다.

샘플을 직접 터미널에서 확인하려면 다음 단계에 따라 작은 mod를 만들고 샘플을 붙여 넣습니다. 이 mod는 창을 열고 그 안에 샘플을 그리는 /gallery 명령을 추가합니다. 창은 너비가 넓은 전체 화면 터미널에서는 트랜스크립트 옆의 사이드바이며, 그 외의 경우에는 프롬프트 위에 테두리가 있는 영역입니다.

1

mod 만들기

gallery라는 디렉터리를 만들고 그 안에 .claude-plugin 및 hooks 디렉터리를 만듭니다. 각 파일에 대한 설명은 mod 만들기를 참조하십시오.

매니페스트를 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

mod 실행하기

셸에서 gallery가 있는 디렉터리에서 Claude Code를 시작합니다:

claude --plugin-dir ./gallery

Claude Code 프롬프트에서 /gallery를 실행합니다. Plain text가 표시된 창이 열립니다.

3

샘플 교체하기

이 페이지에서 샘플을 복사합니다. register.js에서 Text({ children: ['Plain text'] }) 위에 샘플을 붙여 넣어 return 뒤에 오도록 한 다음 파일을 저장합니다. Claude Code는 파일을 저장할 때마다 모듈을 다시 로드하므로, /gallery를 다시 실행하면 새 샘플을 확인할 수 있습니다.

요소 선택하기

샘플은 화면에 표시하려는 내용에 따라 분류되어 있습니다.

텍스트 표시

화면에 글자를 표시하는 요소는 세 가지입니다. 직접 스타일을 지정하려면 Text를, 이미 서식이 지정된 콘텐츠에는 Markdown을, URL에는 Link를 사용합니다.

`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'"] }),
  ],
})
각 줄이 해당 스타일 이름으로 된 아홉 줄의 텍스트가 있는 창: plain, bold, italic, underline, strikethrough, 회색의 dimColor, inverse, 빨간색 color, 파란색 backgroundColor. 각 줄이 해당 스타일 이름으로 된 아홉 줄의 텍스트가 있는 창: plain, bold, italic, underline, strikethrough, 회색의 dimColor, inverse, 빨간색 color, 파란색 backgroundColor.

dimColor는 텍스트를 회색으로 그립니다. backgroundColor는 텍스트 너비만큼만 채워집니다.

`Markdown`

Markdown은 Claude의 응답과 같은 방식으로 텍스트 서식을 지정합니다. 콘텐츠는 children이 아닌 text에 전달합니다.

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, 굵은 단어 하나와 색상이 적용된 코드 단어 하나가 포함된 문장, 두 항목으로 된 목록, 왼쪽에 막대가 있고 기울임꼴로 표시된 인용문이 있는 창. 굵은 제목 Release notes, 굵은 단어 하나와 색상이 적용된 코드 단어 하나가 포함된 문장, 두 항목으로 된 목록, 왼쪽에 막대가 있고 기울임꼴로 표시된 인용문이 있는 창.

제목은 # 기호 없이 굵게 표시됩니다. 인라인 코드는 백틱 없이 색상으로 표시됩니다. 인용문은 왼쪽에 막대가 있는 기울임꼴로 표시됩니다.

Link는 레이블과 그 뒤에 URL을 표시합니다.

Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })
한 줄이 있는 창: 레이블 Claude Code docs와 그 뒤에 회색으로 표시된 URL. 한 줄이 있는 창: 레이블 Claude Code docs와 그 뒤에 회색으로 표시된 URL.

터미널은 레이블 뒤에 URL을 텍스트로 표시합니다. 클릭으로 URL을 열 수 있는지는 사용자의 터미널에 따라 다릅니다.

코드와 변경 사항 표시하기

Code는 Claude Code 자체의 구문 색상으로 소스 텍스트를 그리거나 diff를 그립니다.

`Code`

language를 지정하거나, Claude Code가 언어를 추론할 수 있도록 path를 전달합니다. startLine을 지정하면 해당 번호부터 줄 번호가 매겨집니다.

Code({
  language: 'javascript',
  startLine: 1,
  source: "const name = 'mods'\nconsole.log('hello ' + name)",
})
구문 색상이 적용된 JavaScript 두 줄에 줄 번호가 매겨진 창. 구문 색상이 적용된 JavaScript 두 줄에 줄 번호가 매겨진 창.

색상은 사용자의 테마에서 가져옵니다.

diff로 표시하는 `Code`

format: 'diff'를 지정하면 source는 하나 이상의 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라는 단어는 더 진한 음영으로 표시됩니다. 네 줄짜리 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에 포커스가 있을 때 해당 Input에 전달되므로, 창이 열리자마자 입력을 받아야 하는 필드에는 autoFocus: true를 추가합니다.

`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이 색상으로 표시된 n: Next, 회색으로 대괄호에 둘러싸인 Skip. 한 줄에 하나씩 버튼 세 개가 있는 창: 대괄호로 둘러싸인 Save, 대괄호 없이 n이 색상으로 표시된 n: Next, 회색으로 대괄호에 둘러싸인 Skip.

포커스가 있는 버튼은 반전 색상으로 그려집니다. 다음은 사용자가 Tab 키를 두 번 누른 상태입니다.

같은 버튼 세 개 중 두 번째 버튼인 n: Next가 반전 색상으로 그려진 모습. 같은 버튼 세 개 중 두 번째 버튼인 n: Next가 반전 색상으로 그려진 모습.

`Input`

Input은 한 줄짜리 텍스트 필드로, 사용자가 Enter 키를 누르면 onSubmit을 실행합니다.

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

포커스가 없을 때 필드는 레이블과 플레이스홀더를 표시합니다.

한 줄로 된 창: 레이블 Title 다음에 회색 플레이스홀더 Type a title and press Enter가 표시됨. 한 줄로 된 창: 레이블 Title 다음에 회색 플레이스홀더 Type a title and press Enter가 표시됨.

포커스가 있으면 레이블이 굵게 바뀌고, 커서가 나타나며, ⏎ 뒤에 submitLabel이 표시됩니다.

레이블이 굵게 표시되고, 플레이스홀더의 첫 글자에 블록 커서가 있으며, 리턴 기호 뒤에 save라는 단어가 있는 같은 필드. 레이블이 굵게 표시되고, 플레이스홀더의 첫 글자에 블록 커서가 있으며, 리턴 기호 뒤에 save라는 단어가 있는 같은 필드.

입력하면 플레이스홀더가 입력한 내용으로 대체됩니다.

입력한 글자 Rel이 들어 있고, 그 뒤에 리턴 기호와 save라는 단어가 있는 같은 필드. 입력한 글자 Rel이 들어 있고, 그 뒤에 리턴 기호와 save라는 단어가 있는 같은 필드.

`Select`

Select를 사용하면 사용자가 여러 옵션 중 하나를 고를 수 있으며, 선택한 옵션의 value로 onSelect를 실행합니다.

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, 작은 아래쪽 화살표. 한 줄로 된 창: 레이블 Format, 현재 옵션 Markdown, 작은 아래쪽 화살표.

열려 있을 때는 옵션 목록을 표시하고 그중 하나를 표시합니다.

선택기가 열려 레이블 아래에 옵션 세 개가 나열된 모습. 두 번째 옵션인 HTML이 반전 색상으로 그려져 있음. 선택기가 열려 레이블 아래에 옵션 세 개가 나열된 모습. 두 번째 옵션인 HTML이 반전 색상으로 그려져 있음.

사용자가 옵션을 고르면 목록이 닫힙니다.

선택기가 다시 닫히고, 이제 현재 옵션으로 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는 Desktop 앱에서 SVG 문서를 그립니다:

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는 사용자의 두 번째 파일이 그리는 영역으로, 애니메이션과 포인터 입력에 사용합니다. 요소 참조에 해당 요소의 prop이 나열되어 있습니다.

mod가 그릴 수 있는 위치 확인하기

샘플은 모두 창에 그립니다. mod는 다른 위치에도 그릴 수 있으며, Claude Code를 호출하여 대신 무언가를 표시하게 할 수도 있습니다:

다음 단계