SpyBara
Go Premium

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

No changes for this document in this history range.

2026

Galerie d'interface pour les mods

Découvrez les éléments d'interface qu'un mod Claude Code peut dessiner, comme du texte, des boutons, des champs, du Markdown, du code et des diffs, avec des exemples de code et des captures d'écran du terminal.

Un mod dessine son interface à partir d'éléments : du texte, des boîtes, des boutons, des champs, et quelques éléments qui mettent en forme le contenu pour vous. Les exemples présentés ici montrent le code qui dessine un élément, et la plupart sont accompagnés d'une capture d'écran du résultat dans un panneau du terminal, afin que vous puissiez choisir un élément selon son apparence.

Pour comprendre le fonctionnement du dessin, commencez par Dessiner dans l'interface. Pour les principales props et les applications qui dessinent chaque élément, consultez la référence des éléments. Les déclarations de types répertorient toutes les props.

Essayer un exemple

Les exemples de cette page sont des extraits, et non des mods complets. Chacun correspond au code d'un élément et de tout ce qui y est imbriqué.

Pour voir un exemple dans votre propre terminal, créez le petit mod décrit dans ces étapes et collez-y l'exemple. Le mod ajoute une commande /gallery qui ouvre un panneau et y dessine l'exemple. Un panneau est une barre latérale à côté de la transcription dans un terminal large en plein écran, ou sinon une zone encadrée au-dessus du prompt.

1. Créer le mod

Créez un répertoire nommé gallery contenant les répertoires .claude-plugin et hooks. Créer un mod explique les fichiers.

Enregistrez le manifeste sous gallery/.claude-plugin/plugin.json :

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

Indiquez votre point d'entrée dans gallery/hooks/hooks.json :

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

Enregistrez le code sous gallery/hooks/register.js. Il ajoute une commande /gallery qui ouvre un panneau, et dessine Plain text dans ce panneau :

// 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. Exécuter le mod

Dans votre shell, démarrez Claude Code depuis le répertoire qui contient gallery :

claude --plugin-dir ./gallery

Dans le prompt de Claude Code, exécutez /gallery. Un panneau s'ouvre et affiche Plain text.

3. Remplacer par un exemple

Copiez un exemple de cette page. Dans register.js, collez-le à la place de Text({ children: ['Plain text'] }), de sorte qu'il suive return, puis enregistrez le fichier. Claude Code recharge le module à chaque enregistrement : exécutez donc à nouveau /gallery pour voir le nouvel exemple.

Choisir un élément

Les exemples sont regroupés selon ce que vous souhaitez afficher à l'écran :

Afficher du texte

Trois éléments affichent des mots à l'écran : Text pour votre propre mise en forme, Markdown pour un contenu déjà formaté, et Link pour une URL.

Text

Text dessine une chaîne avec les styles que vous lui donnez. Cet exemple affiche du texte brut et huit styles, un par ligne :

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'"] }),
  ],
})

Un panneau avec neuf lignes de texte, chacune nommée d'après son style : plain, bold, italic, underline, strikethrough, dimColor en gris, inverse, color red et backgroundColor blue.

dimColor dessine le texte en gris. backgroundColor ne remplit que la largeur du texte.

Markdown

Markdown met en forme le texte de la même manière que les réponses de Claude. Transmettez le contenu dans text, et non dans 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',
})

Un panneau avec un titre en gras, Release notes, puis une phrase contenant un mot en gras et un mot de code en couleur, une liste de deux éléments et une citation en italique avec une barre à sa gauche.

Un titre s'affiche en gras sans ses marques #. Le code en ligne s'affiche en couleur sans ses backticks. Une citation s'affiche en italique avec une barre à sa gauche.

Link dessine un libellé suivi de son URL :

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

Un panneau avec une seule ligne : le libellé Claude Code docs, puis l'URL en gris.

Le terminal dessine l'URL sous forme de texte après le libellé. La possibilité de l'ouvrir d'un clic dépend du terminal de l'utilisateur.

Afficher du code et des modifications

Code dessine du texte source avec les couleurs syntaxiques propres à Claude Code, ou un diff. Dans l'extension VS Code, Code affiche son source en texte brut, sans les couleurs, les numéros de ligne ni l'ombrage de diff visibles sur ces captures d'écran.

Code

Indiquez le language, ou transmettez un path à partir duquel Claude Code le déduira. Avec startLine, les lignes sont numérotées à partir de ce nombre :

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

Un panneau avec deux lignes numérotées de JavaScript en couleurs syntaxiques.

Les couleurs proviennent du thème de l'utilisateur.

Code sous forme de diff

Avec format: 'diff', source contient un ou plusieurs blocs de diff unifié :

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.',
})

Un panneau avec un diff de quatre lignes. La ligne supprimée est ombrée en rouge et la ligne ajoutée en vert, chacune avec son numéro de ligne. Dans la ligne ajoutée, les mots that runs code ont une teinte plus prononcée.

Claude Code dessine des numéros de ligne à la place de la ligne @@. Lorsqu'une ligne supprimée et une ligne ajoutée se ressemblent, les mots modifiés reçoivent une teinte plus prononcée.

Disposer des éléments

Box

Box dispose son contenu en ligne ou en colonne, et peut dessiner une bordure. Cet exemple place une ligne de mots au-dessus d'une boîte avec bordure :

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'"] })],
    }),
  ],
})

Un panneau avec trois mots sur une ligne, espacés de quatre colonnes, puis une ligne vide, puis une bordure arrondie autour d'une ligne de texte. La bordure s'étend sur toute la largeur du panneau.

La bordure s'étend sur toute la largeur du panneau.

Recevoir des saisies

Button, Input et Select sont des contrôles : l'utilisateur passe de l'un à l'autre avec Tab et utilise celui qui a le focus. Focus clavier et raccourcis clavier indique quelles touches leur parviennent.

Ouvrez un panneau avec focus: true pour demander le focus clavier pour celui-ci. Les lettres saisies parviennent à un Input dès qu'il a le focus. Pour choisir quel champ a le focus à l'ouverture du panneau, consultez Définir un raccourci clavier et le premier focus.

Button

Un bouton exécute onPress. Cet exemple montre la forme par défaut, un bouton plain avec un raccourci clavier, et un bouton atténué :

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 }),
  ],
})

Un panneau avec trois boutons, un par ligne : Save entre crochets, n: Next sans crochets et avec le n en couleur, et Skip entre crochets en gris.

Un bouton qui a le focus s'affiche en vidéo inverse. Ici, l'utilisateur a appuyé deux fois sur Tab :

Les trois mêmes boutons, le deuxième, n: Next, affiché en vidéo inverse.

Input

Un Input est un champ de texte qui contient une ligne par défaut et exécute onSubmit lorsque l'utilisateur appuie sur Enter :

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

Sans le focus, le champ affiche son libellé et son texte indicatif :

Un panneau avec une ligne : le libellé Title, puis le texte indicatif Type a title and press Enter en gris.

Avec le focus, le libellé passe en gras, un curseur apparaît et le submitLabel s'affiche après ⏎ :

Le même champ avec son libellé en gras, un curseur bloc sur la première lettre du texte indicatif, et un symbole de retour suivi du mot save.

La saisie remplace le texte indicatif :

Le même champ contenant les lettres saisies Rel, suivies du symbole de retour et du mot save.

Définissez rows sur 2 ou plus pour un champ qui contient plusieurs lignes, comme une note ou un message de commit :

Input({
  key: 'note',
  label: 'Note',
  placeholder: 'Write a note',
  rows: 4,
  onSubmit: noop,
})

Le terminal et l'application Desktop affichent les lignes. Dans l'extension VS Code, le champ contient une seule ligne. rows nécessite Claude Code v2.1.301 ou une version ultérieure. Sur les versions antérieures, le champ contient une seule ligne.

Le champ occupe le nombre de lignes que vous définissez, même lorsqu'il est vide, dans la limite de la hauteur du panneau ou de la bande dans laquelle il est affiché. Tant que le champ a le focus, un texte plus long défile à l'intérieur.

  • Dans le terminal, Enter soumet toujours. L'utilisateur y commence une nouvelle ligne en tapant une barre oblique inverse puis en appuyant sur Enter, ou en appuyant sur Shift+Enter lorsque l'émulateur de terminal le prend en charge. Ce sont les mêmes touches que dans le prompt.
  • Dans le terminal, les flèches Haut et Bas permettent de passer d'une ligne à l'autre du champ. Depuis sa première et sa dernière ligne, elles passent au contrôle précédent ou suivant.
  • onSubmit et onInput reçoivent l'intégralité du texte, avec ses lignes jointes par \n.

Select

Un Select permet à l'utilisateur de choisir une option parmi plusieurs, et exécute onSelect avec la value de l'option :

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
  },
})

Fermé, il affiche son libellé et l'option actuelle :

Un panneau avec une ligne : le libellé Format, l'option actuelle Markdown et une petite flèche vers le bas.

Ouvert, il liste ses options et en met une en évidence :

Le sélecteur ouvert, avec ses trois options listées sous le libellé. La deuxième option, HTML, est affichée en vidéo inverse.

Une fois que l'utilisateur a choisi une option, la liste se ferme :

Le sélecteur de nouveau fermé, affichant désormais HTML comme option actuelle.

Dessiner des images

Raster

Un Raster est une grille de cellules de caractères colorées, pour une carte de chaleur, une sparkline ou un plateau de jeu. Le terminal la dessine. Cet exemple utilise la fonction cellsOf du module de départ, qui regroupe les cellules dans la chaîne attendue par un Raster. Dessiner une grille de cellules colorées l'explique :

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

Un panneau avec une petite grille de blocs colorés, deux lignes de trois : vert, ambre et rouge, puis vert, vert et ambre.

Un Raster arrondit chaque couleur à une palette plus restreinte : 0x2e7d32 s'affiche donc en #337733.

Svg

Un Svg dessine un document SVG dans l'application Desktop et l'extension 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>',
})

Dans le terminal, un panneau qui ne renvoie qu'un Svg s'ouvre vide. Pour y dessiner autre chose, vérifiez e.surface et renvoyez une arborescence différente.

Image et Client

Deux autres éléments n'ont pas d'exemple ici. Image dessine un PNG ou des pixels bruts dans le terminal. Client est une zone dessinée par un second fichier de votre part, pour l'animation et la saisie au pointeur. La référence des éléments répertorie leurs props.

Une Image s'affiche sous forme d'image dans ces terminaux :

  • kitty 0.28 ou ultérieur
  • Ghostty
  • iTerm2 3.5 ou ultérieur. L'affichage dans iTerm2 nécessite Claude Code v2.1.305 ou ultérieur.

Dans tout autre terminal, l'utilisateur voit le texte alt de l'Image, atténué, à la place de l'image. Rédigez un texte alt qui se suffit à lui-même, car il s'affiche aussi dans les cas suivants, entre autres :

  • GNU screen : une session exécutée dans screen, dans n'importe quel terminal.
  • tmux : une session exécutée dans tmux qui ne remplit pas une condition requise pour dessiner dans tmux.
  • Sessions en arrière-plan : toute session en arrière-plan, quel que soit le terminal depuis lequel elle est rattachée.
  • iTerm2 hors rendu plein écran : dans iTerm2, l'image ne s'affiche qu'avec le rendu plein écran, et pas lorsque CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT est défini sur 1. Pour voir l'image, exécutez /tui fullscreen dans le prompt de Claude Code et laissez cette variable non définie.
  • Une source par chemin de fichier dans iTerm2 ou tmux : dans iTerm2 et dans tmux, une Image dont la source désigne un file affiche le texte alt au lieu de l'image. Si votre mod a des utilisateurs d'iTerm2 ou de tmux, transmettez l'image en base64 dans source.png ou source.rgba plutôt que sous forme de chemin dans source.file.

Si les utilisateurs de votre mod voient le texte atténué dans un terminal qui affiche les images du protocole graphique kitty avec des espaces réservés Unicode, ils peuvent définir CLAUDE_CODE_FORCE_TERMINAL_IMAGES sur 1. Ils ne doivent pas la définir dans GNU screen, dans une version de tmux antérieure à 3.3, dans une popup tmux, ni lorsque l'option allow-passthrough de tmux est désactivée. Dans ces cas, ils ne voient aucune image, et une case remplace le texte alt.

Dessiner une Image dans tmux

Si une Image affiche son texte alt dans tmux, vérifiez ces conditions ainsi que les autres cas d'affichage du texte alt, comme une session en arrière-plan :

  • Claude Code v2.1.310 ou ultérieur
  • tmux 3.3 ou ultérieur
  • Claude Code s'exécute dans un panneau tmux, et non dans une popup tmux
  • tmux s'exécute dans kitty 0.28 ou ultérieur, Ghostty, ou iTerm2 3.5 ou ultérieur
  • Les options tmux focus-events et allow-passthrough sont sur on. Dans kitty ou Ghostty, allow-passthrough peut aussi valoir all.
  • Dans iTerm2, tmux s'exécute sans -CC, le rendu plein écran est activé et CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT n'est pas définie.
  • Dans iTerm2, la fenêtre tmux n'est pas plus grande que la fenêtre iTerm2. Pour le vérifier, exécutez tmux display-message -p '#{window_bigger}' dans cette fenêtre tmux. Si la commande affiche 1, ajustez la taille de la fenêtre tmux, puis redémarrez Claude Code.
  • L'auteur du mod transmet l'image sous forme d'octets png ou rgba, et non sous forme de chemin file. Si vous utilisez un mod que vous n'avez pas écrit et que les autres conditions sont remplies, demandez à son auteur de vérifier ce point.

Pour chaque option tmux qui n'est pas déjà définie comme requis, exécutez sa commande dans votre shell :

tmux set -g allow-passthrough on
tmux set -g focus-events on

Détachez-vous ensuite de tmux, rattachez-vous et redémarrez Claude Code. Redémarrez-le à nouveau chaque fois que vous rattachez tmux depuis un autre terminal. Pour conserver les deux options après un redémarrage du serveur tmux, ajoutez aussi les deux lignes à ~/.tmux.conf.

Voir où un mod peut dessiner

Tous les exemples dessinent dans un panneau. Un mod peut aussi dessiner à d'autres endroits, et appeler Claude Code pour afficher quelque chose à sa place :

Étapes suivantes