Oberflächengalerie für Mods
Sehen Sie sich die Oberflächenelemente an, die ein Claude Code-Mod zeichnen kann, etwa Text, Schaltflächen, Felder, Markdown, Code und Diffs, mit Beispielcode und Terminal-Screenshots.
Ein Mod zeichnet seine Oberfläche aus Elementen: Text, Boxen, Schaltflächen, Felder und einige Elemente, die Inhalte für Sie formatieren. Die Beispiele hier zeigen den Code, der ein Element zeichnet, und die meisten enthalten einen Screenshot des Ergebnisses in einem Terminal-Bereich, sodass Sie ein Element anhand seines Aussehens auswählen können.
Um zu erfahren, wie das Zeichnen funktioniert, beginnen Sie mit In der Oberfläche zeichnen. Die wichtigsten Props und welche Apps die einzelnen Elemente zeichnen, finden Sie in der Elementreferenz. Die Typdeklarationen führen alle Props auf.
Ein Beispiel ausprobieren
Die Beispiele auf dieser Seite sind Codeausschnitte, keine vollständigen Mods. Jedes Beispiel enthält den Code für ein Element und alles, was darin verschachtelt ist.
Um ein Beispiel in Ihrem eigenen Terminal zu sehen, erstellen Sie mit den folgenden Schritten den kleinen Mod und fügen das Beispiel darin ein. Der Mod fügt einen Befehl /gallery hinzu, der einen Bereich öffnet und das Beispiel dort zeichnet. Ein Bereich ist in einem breiten Vollbild-Terminal eine Seitenleiste neben dem Transkript, andernfalls ein umrahmter Bereich oberhalb des Prompts.
Den Mod erstellen
Erstellen Sie ein Verzeichnis namens gallery mit den Verzeichnissen .claude-plugin und hooks darin. Einen Mod erstellen erläutert die Dateien.
Speichern Sie das Manifest als gallery/.claude-plugin/plugin.json:
{
"name": "gallery",
"version": "0.1.0",
"description": "Opens a pane that draws one sample",
"author": { "name": "Your Name" }
}
Geben Sie Ihren Einstiegspunkt in gallery/hooks/hooks.json an:
{
"modules": ["./register.js"]
}
Speichern Sie den Code als gallery/hooks/register.js. Er fügt einen Befehl /gallery hinzu, der einen Bereich öffnet, und zeichnet Plain text in diesem Bereich:
// 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'] })
})
}
Den Mod ausführen
Starten Sie Claude Code in Ihrer Shell aus dem Verzeichnis, das gallery enthält:
claude --plugin-dir ./gallery
Führen Sie am Prompt von Claude Code /gallery aus. Ein Bereich mit Plain text darin öffnet sich.
Ein Beispiel einsetzen
Kopieren Sie ein Beispiel von dieser Seite. Fügen Sie es in register.js anstelle von Text({ children: ['Plain text'] }) ein, sodass es auf return folgt, und speichern Sie die Datei. Claude Code lädt das Modul bei jedem Speichern neu. Führen Sie daher /gallery erneut aus, um das neue Beispiel zu sehen.
Ein Element auswählen
Die Beispiele sind danach gruppiert, was Sie auf dem Bildschirm darstellen möchten:
- Text anzeigen:
Text,MarkdownundLink - Code und Änderungen anzeigen:
Code - Elemente anordnen:
Box - Eingaben entgegennehmen:
Button,InputundSelect - Bilder zeichnen:
Raster,Svg,ImageundClient
Text anzeigen
Drei Elemente bringen Wörter auf den Bildschirm: Text für Ihre eigene Formatierung, Markdown für Inhalte, die bereits formatiert sind, und Link für eine URL.
`Text`
Text zeichnet eine Zeichenkette mit den Stilen, die Sie angeben. Dieses Beispiel zeigt eine Zeile für jeden Stil:
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'"] }),
],
})
dimColor zeichnet den Text in Grau. backgroundColor füllt nur so weit, wie der Text breit ist.
`Markdown`
Markdown formatiert Text so, wie die Antworten von Claude formatiert werden. Übergeben Sie den Inhalt in text, nicht in 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',
})
Eine Überschrift wird fett ohne ihre #-Zeichen gezeichnet. Inline-Code wird farbig ohne seine Backticks gezeichnet. Ein Zitat wird kursiv mit einem Balken auf der linken Seite gezeichnet.
`Link`
Link zeichnet eine Beschriftung, gefolgt von ihrer URL:
Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })
Das Terminal zeichnet die URL als Text nach der Beschriftung. Ob ein Klick sie öffnet, hängt vom Terminal des Benutzers ab.
Code und Änderungen anzeigen
Code stellt Quelltext mit den eigenen Syntaxfarben von Claude Code dar oder zeigt einen Diff an.
`Code`
Geben Sie die language an oder übergeben Sie einen path, aus dem Claude Code sie ableitet. Mit startLine werden die Zeilen ab dieser Zahl nummeriert:
Code({
language: 'javascript',
startLine: 1,
source: "const name = 'mods'\nconsole.log('hello ' + name)",
})
Die Farben stammen aus dem Theme des Benutzers.
`Code` als Diff
Mit format: 'diff' besteht source aus einem oder mehreren Unified-Diff-Hunks:
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.',
})
Claude Code zeigt anstelle der @@-Zeile Zeilennummern an. Wo sich eine entfernte und eine hinzugefügte Zeile ähneln, werden die geänderten Wörter stärker hervorgehoben.
Elemente anordnen
`Box`
Box ordnet seinen Inhalt in einer Zeile oder einer Spalte an und kann einen Rahmen zeichnen. Dieses Beispiel platziert eine Reihe von Wörtern über einer umrandeten 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'"] })],
}),
],
})
Der Rahmen erstreckt sich über die Breite des Bereichs.
Eingaben entgegennehmen
Button, Input und Select sind Steuerelemente: Der Benutzer wechselt mit Tab zwischen ihnen und bedient dasjenige, das den Fokus hat. Unter Tastaturfokus und Hotkeys erfahren Sie, welche Tasten sie erreichen.
Wenn Sie einen Bereich mit focus: true öffnen, erhält der Bereich den Tastaturfokus. Eingegebene Buchstaben erreichen ein Input, sobald es den Fokus hat. Fügen Sie daher autoFocus: true zu einem Feld hinzu, das Eingaben entgegennehmen soll, sobald sich der Bereich öffnet.
`Button`
Ein Button führt onPress aus. Dieses Beispiel zeigt die Standardform, einen plain-Button mit einem Hotkey und einen abgeblendeten Button:
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 }),
],
})
Ein Button, der den Fokus hat, wird invertiert dargestellt. Hier hat der Benutzer zweimal Tab gedrückt:
`Input`
Ein Input ist ein einzeiliges Textfeld, das onSubmit ausführt, wenn der Benutzer die Eingabetaste drückt:
Input({
key: 'title',
label: 'Title',
placeholder: 'Type a title and press Enter',
value: '',
submitLabel: 'save',
onSubmit: noop,
})
Ohne Fokus zeigt das Feld seine Beschriftung und seinen Platzhalter:
Mit Fokus wird die Beschriftung fett dargestellt, ein Cursor erscheint und das submitLabel wird nach ⏎ angezeigt:
Durch Tippen wird der Platzhalter ersetzt:
`Select`
Mit einem Select kann der Benutzer eine von mehreren Optionen auswählen; es führt onSelect mit dem value der Option aus:
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
},
})
Geschlossen zeigt es seine Beschriftung und die aktuelle Option:
Geöffnet listet es seine Optionen auf und markiert eine davon:
Nachdem der Benutzer eine Option ausgewählt hat, schließt sich die Liste:
Bilder zeichnen
`Raster`
Ein Raster ist ein Gitter aus farbigen Zeichenzellen, etwa für eine Heatmap, eine Sparkline oder ein Spielbrett. Das Terminal zeichnet es. Dieses Beispiel verwendet die Funktion cellsOf im Startermodul, die die Zellen in den String packt, den ein Raster erwartet. Ein Gitter aus farbigen Zellen zeichnen erklärt sie:
Raster({
key: 'grid',
columns: 3,
rows: 2,
cells: cellsOf([
[['█', 0x2e7d32], ['█', 0xf9a825], ['█', 0xc62828]],
[['█', 0x2e7d32], ['█', 0x2e7d32], ['█', 0xf9a825]],
]),
})
Ein Raster rundet jede Farbe auf eine kleinere Palette, sodass 0x2e7d32 als #337733 gezeichnet wird.
`Svg`
Ein Svg zeichnet ein SVG-Dokument in der Desktop-App:
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>',
})
Im Terminal wird ein Bereich, der nur ein Svg zurückgibt, leer geöffnet. Um dort etwas anderes zu zeichnen, prüfen Sie e.surface und geben Sie einen anderen Baum zurück.
`Image` und `Client`
Zwei weitere Elemente haben hier kein Beispiel. Image zeichnet ein PNG oder Rohpixel im Terminal. Client ist ein Bereich, den eine zweite Datei von Ihnen zeichnet, für Animationen und Zeigereingaben. Die Elementreferenz listet ihre Props auf.
Sofern Claude Code nicht erkennt, dass das Terminal Bilder des kitty-Grafikprotokolls mit Unicode-Platzhaltern zeichnet, sieht der Benutzer anstelle des Bildes den alt-Text eines Image abgeblendet. Schreiben Sie alt-Text, der für sich allein verständlich ist. Die Erkennung läuft beim Start: Sie gelingt in kitty 0.28 oder höher und in Ghostty, sobald das Terminal auf die Grafikabfrage von Claude Code antwortet, und schlägt in diesen Fällen fehl:
- Andere Terminals: jedes Terminal, das keines dieser beiden ist oder nicht auf die Abfrage antwortet.
- tmux und screen: eine Sitzung, die innerhalb von tmux oder screen läuft, in jedem Terminal, kitty und Ghostty eingeschlossen.
- Hintergrundsitzungen: jede Hintergrundsitzung, unabhängig davon, von welchem Terminal aus sie verbunden ist.
Wenn die Benutzer Ihres Mods den abgeblendeten Text in einem Terminal sehen, das diese Platzhalterbilder tatsächlich zeichnet, können sie CLAUDE_CODE_FORCE_TERMINAL_IMAGES auf 1 setzen, wodurch die Erkennung übersprungen wird. Innerhalb von tmux oder screen hilft das nicht: Der alt-Text verschwindet, und Claude Code sendet das Bild, ohne es für das Passthrough von tmux oder screen zu verpacken.
Sehen, wo ein Mod zeichnen kann
Die Beispiele zeichnen alle in einem Bereich. Ein Mod kann auch an anderen Stellen zeichnen und Claude Code aufrufen, damit es etwas für ihn anzeigt:
- Bereich und Band: Auswählen, wo gezeichnet wird
- Die eigenen Zeilen von Claude Code, etwa der Spinner: Ändern, was Claude Code bereits zeichnet
- Toast, Statuszeile und Log-Zeile: Etwas anzeigen, ohne einen Turn zu starten
- Fragedialog: Einen Tool-Aufruf zurückhalten, bis der Benutzer entscheidet
Nächste Schritte
- In der Oberfläche zeichnen: Erstellen Sie Schritt für Schritt einen Bereich mit Tabs
- Eine Zeichnung testen: Drücken Sie Ihre Schaltflächen aus einem Test heraus
- Referenz der Elemente: die wichtigsten Props jedes Elements und die Apps, die es zeichnen