---
title: "Знакомство с Bubble Tea: интерфейсы в терминале"
description: "Что такое Bubble Tea — TUI go библиотека от Charmbracelet: кто строит на ней терминальные интерфейсы, зачем elm архитектура и как устроены bubbles и lipgloss."
course: "Bubble Tea: TUI-приложения в терминале"
url: "https://golangmaster.ru/courses/bubbletea/lessons/01-znakomstvo-bubbletea/"
published: "2026-09-19"
updated: "2026-10-09"
minutes: 16
---

# Знакомство с Bubble Tea: интерфейсы в терминале

*Курс «Bubble Tea: TUI-приложения в терминале», урок 1 из 25. ~16 минут. Обновлено 09.10.2026. Источник: https://golangmaster.ru/courses/bubbletea/lessons/01-znakomstvo-bubbletea/*

Bubble Tea — библиотека bubbletea go из экосистемы Charmbracelet: на ней сделаны gh-dash, gum и сотни других TUI-приложений. Разберём, зачем терминалу собственные интерфейсы, кто уже строит на этом фреймворке свои инструменты и почему в его сердце лежит elm архитектура, пришедшая из фронтенда.

Половина рабочего дня разработчика проходит в терминале — и всё же самые любимые инструменты там не «печатают строчки», а живут: k9s рисует таблицы подов и отвечает на клавиши, lazygit превращает git в навигацию стрелками, gh-dash показывает pull request'ы как ленту интерфейса, а не плоскую выдачу curl. Разница не в красоте, а в модели: скрипт печатает и умирает, интерфейс держит состояние, ждёт события и перерисовывается. Bubble Tea — способ писать такие программы на Go без борьбы с ANSI-кодами и сырыми потоками ввода. Экраны этого курса можно потрогать в песочнице урока — там вкладка с виртуальным терминалом; полноценные же программы всё равно запускаются локально, потому что настоящему TUI нужен настоящий терминал. Сначала посмотрим на ландшафт: кто, зачем и на чём.

### Bubble Tea — TUI go библиотека: что под капотом

Bubble Tea — фреймворк для терминальных интерфейсов на чистом Go: пакет bubbletea go-проект подключает одной строкой импорта — github.com/charmbracelet/bubbletea. Автор — компания Charmbracelet Кристиана Рочи, фреймворк вышел в 2020 году и с тех пор перерос статус эксперимента: сегодня это де-факто стандартный ответ на вопрос «как сделать TUI-приложение на Go». «Чистый Go» здесь важное слово: без cgo, без зависимости от ncurses, со статическим бинарником на выходе. Программа работает по SSH ровно так же, как локально, — терминал есть терминал. Идею подсмотрели у Elm и Haskell: архитектура Model-Update-View оказалась настолько удачной, что фреймворк прижился далеко за пределами своей ниши. Отрисовка устроена экономно: после каждого события фреймворк сравнивает новый кадр со старым и обновляет только изменившиеся строки — на типичный инструмент это стоит микросекунды. API ядра годами живёт в первой мажорной версии — примеры из туториалов двухлетней давности собираются без правок. Сам фреймворк намеренно мал: он берёт на себя цикл событий, ввод и отрисовку, а компоненты, стили и формы вынесены в соседние библиотеки — до них дойдём ниже.

### Кто строит на Bubble Tea

- gh-dash (dlvhdr/gh-dash) — популярное расширение GitHub CLI: список PR и issues с фильтрами, деталями и ревью прямо в терминале
- gum от Charm — набор готовых бинарников для shell-скриптов: выбор, ввод, подтверждение, спиннеры; внутри каждого — Bubble Tea
- Soft Serve — git-сервер с TUI-панелью управления, тоже из Charmbracelet
- AWS Copilot CLI — интерактивные подсказки и панели деплоя построены на Bubble Tea, Charm публиковал об этом отдельный кейс
- k9s — знаменитая панель Kubernetes на самом деле сделана на tview, не на Bubble Tea; класс задач тот же, а путают их часто
- Сотни утилит в подборках awesome-tui: мониторы, чаты, менеджеры задач, интерактивные генераторы — и внутренние инструменты команд, которых нет в подборках

### TUI против GUI и CLI: где место Bubble Tea

Способов дать пользователю интерфейс три, и у каждого своя ниша. CLI печатает, ждёт ввод и завершается — идеально для пайплайнов и автоматизации. GUI (например, на fyne — у нас есть отдельный курс: [знакомство с Fyne](/courses/fyne/lessons/01-znakomstvo/)) даёт окна и мышь, но требует дисплея, графических библиотек и сборки под каждую платформу. TUI-приложение живёт посередине: оно реагирует на клавиши и мышь, как GUI, но рисуется символами и работает там, куда GUI не доберётся — на сервере без иксов, в docker-контейнере, в SSH-сессии с ноутбука. Моё правило: инструмент для разработчиков, который обязан запускаться на сервере, — почти всегда кандидат на TUI. Нужны курсор, файловый диалог и пиксели — берите GUI и не мучайте терминал, он этого не простит.

### Зачем elm архитектура в терминале

Классический GUI-фреймворк предлагает колбэки: кнопка нажата — вызовись сюда, таймер тикнул — сюда. На форме из трёх полей это терпимо. На панели с десятью экранами колбэки начинают менять состояние кто попало и в каком попало порядке, а отладка превращается в археологию: кто именно испортил поле модели, ищется часами. Elm-архитектура (та самая, из языка Elm; Redux — её младший родственник) разрешает проблему жёстко. Всё состояние приложения живёт в одном значении — модели. Каждое событие — обычное значение-сообщение. Единственная функция Update получает сообщение и возвращает новую модель. Единственная функция View рисует модель в строку. Никаких скрытых мутаций из четырёх углов программы: поток «событие → Update → View» один, и он помещается в голову целиком. Для терминала это совпадение особенно удачно — событий много, и все они асинхронные: клавиши, мышь, resize окна, ответы сети, таймеры.

### Первый взгляд: программа целиком

```go
package main

import (
        "fmt"
        "os"

        "github.com/charmbracelet/bubbletea"
)

type model struct {
        count int
}

func (m model) Init() tea.Cmd {
        return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
        switch msg := msg.(type) {
        case tea.KeyMsg:
                switch msg.String() {
                case "up":
                        m.count++
                case "down":
                        m.count--
                case "q", "ctrl+c":
                        return m, tea.Quit
                }
        }
        return m, nil
}

func (m model) View() string {
        return fmt.Sprintf(
                "Счёт: %d\n\n↑ больше, ↓ меньше, q — выход\n",
                m.count,
        )
}

func main() {
        if _, err := tea.NewProgram(model{}).Run(); err != nil {
                fmt.Println("Ошибка:", err)
                os.Exit(1)
        }
}
```

Вся программа — три метода и одна строка запуска. Init() объявляет, что нужно сделать при старте (здесь — ничего), Update получает любое событие и переключается по его типу, View рисует модель в строку, а фреймворк сам печатает её и перерисовывает при изменениях. Ветки q и ctrl+c возвращают tea.Quit — команду завершить цикл. tea.NewProgram создаёт программу, Run блокирует main до выхода. В песочнице сайта этот код не запустится: Bubble Tea требует настоящий терминал. Локально — go mod init, go get github.com/charmbracelet/bubbletea, go run main.go.

### Экосистема Charm: bubbles, lipgloss и компания

Bubble Tea — не одинокая библиотека, а центр целой экосистемы. bubbles — официальный набор компонентов: список с фильтрацией, текстовые поля, таблицы, спиннеры, прогресс-бары. Всё это тоже модели, встраиваемые в вашу, — в курсе им посвящено несколько уроков, включая готовые списки. Lip Gloss — стилизация: цвета, рамки, отступы, выравнивание; верстка терминального интерфейса, предсказуемая как CSS с жёсткими правилами — основы разберём в отдельном уроке. Дальше по списку: glamour рендерит markdown в терминале, huh собирает формы, gum предлагает готовые команды для скриптов, vhs записывает демо-гифки. Практический вывод: прежде чем писать список задач своими руками, проверьте bubbles; прежде чем собирать ANSI-коды цветов конкатенацией, откройте Lip Gloss. Обе проблемы давно решены, и решены лучше, чем получится с первого раза у вас.

### Карта экосистемы Charm

| Пакет или проект | Что делает | Когда пригождается |
| --- | --- | --- |
| bubbletea | ядро: цикл событий, Model, Update, View, ввод | каркас любого TUI-приложения |
| bubbles | готовые компоненты: list, textinput, table, spinner, progress | чтобы не писать список задач самому |
| lipgloss | цвета, рамки, отступы, выравнивание | любой интерфейс сложнее одной строки |
| glamour | рендер markdown в терминале | просмотр README, справки, changelog |
| huh | формы: поля, выбор, подтверждения | мастера настройки, ввод данных |
| vhs | запись GIF из сценария терминала | демо для README проекта |

### Терминал как платформа: что он умеет

Недооценённый факт: современный терминал — платформа с возможностями, о которых GUI-разработчик даже не задумывается. Он умеет цвета и стили — 256 цветов и truecolor почти везде, юникодную графику для рамок, события resize окна, а с включённым режимом — даже мышь: клики, движение, колесо. Bubble Tea берёт всё это на себя: фреймворк переводит терминал в нужные режимы, читает сырые байты ввода, собирает их в понятные сообщения и перерисовывает только изменившиеся строки. Вам остаются три метода и здравый смысл. Обратная сторона: у терминала есть причуды. Одни и те же комбинации клавиш в разных эмуляторах приходят по-разному, поддержка мыши зависит от самого эмулятора, а что-то не различается в принципе. Это не баг фреймворка, а природа платформы: вы пишете не под операционную систему, а под сотню эмуляторов от macOS Terminal до Windows Terminal. Капризы клавиатуры подробно разберём в четвёртом уроке курса. Здесь же отметим только приятное: всё это богатство доступно без единой строчки кода настройки — вы подключаете пакет и сразу работаете с сообщениями, а не с байтами и ioctl.

### Почему не ncurses и не tview

Выбор у Go-разработчика шире, и честнее обсудить альтернативы сразу. ncurses — C-библиотека возрастом в десятилетия: мощная, но с cgo, ручным управлением окнами и чуждым Go циклом жизни. tview — зрелый виджетный фреймворк, на нём сделан k9s: таблицы, деревья и формы доступны из коробки, модель событий ближе к классическим GUI. Bubble Tea берёт другим: крошечное ядро, View — просто строка, вся логика — чистые функции над состоянием. Спорный момент скажу честно: перерисовывать весь View после каждого события выглядит расточительно, и я долго относился к этому скептически, ожидая мерцания и тормозов. Практика умерила пыл в обе стороны. Перерисовка на деле дешевле, чем кажется, — фреймворк обновляет только изменившиеся строки. Но для гигантских таблиц на десятки тысяч строк разница достижима: замеряйте, прежде чем строить монолит на одном экране. Для типичного инструмента — панели, чата, меню — запас прочности огромный.

> **Про версии.** Курс написан по актуальной версии v1.x пакета github.com/charmbracelet/bubbletea — именно её поставит go get по умолчанию. API ядра — Model, Update, View, Program — стабилен годами: код из ранних туториалов собирается без переделок.

> **Как проходить этот курс.** Интерактивы уроков — тесты, «заполни пропуск», «собери программу» — засчитывают XP и проверяют понимание даже без запуска кода. Но TUI нельзя выучить глазами: копируйте примеры в локальный проект, запускайте и ломайте их намеренно. Стартовый набор: свежий Go, любой терминал, пять минут на go mod init и go get github.com/charmbracelet/bubbletea. Дальше только практика: понажимайте клавиши, измените строки, сломайте ветку Update и посмотрите, что случится.

### Проверка: кто есть кто

**Вопрос:** Какой из этих инструментов построен на Bubble Tea?

- k9s — панель Kubernetes
- htop — монитор процессов
- ✅ gum — набор компонентов для shell-скриптов от Charm
- tmux — мультиплексор терминала

gum — проект Charmbracelet, написан на Bubble Tea. k9s сделан на tview, htop — на ncurses, tmux — вообще на чистом C. Путаница с k9s частая: класс задач тот же, стек другой.

### Проверка: специфика TUI

**Вопрос:** Чем TUI-приложение принципиально отличается от GUI?

- TUI не умеет реагировать на мышь
- TUI-приложения нельзя собрать в один бинарник
- TUI работает только на Linux
- ✅ TUI рисуется символами в терминале и работает по SSH без дисплея и графического стека

TUI рисуется символами: ему не нужны дисплей и графические библиотеки, поэтому он живёт на серверах и в SSH-сессиях. Мышь Bubble Tea тоже поддерживает — в уроке про мышь это разберём. И Linux тут ни при чём: тот же бинарник работает в macOS и Windows Terminal.

### Что нарисует View?

```go
type model struct{ count int }

func initialModel() model { return model{count: 1} }

func (m model) View() string {
        return fmt.Sprintf("Счёт: %d\n", m.count)
}

// Пользователь нажал: ↑, ↓, ↑, ↑
```

**Что выведет программа?**

- Счёт: 1
- Счёт: 2
- ✅ Счёт: 3
- Счёт: 4

Стартовое значение 1; каждое ↑ увеличивает его, ↓ уменьшает: 1 → 2 → 1 → 2 → 3. View всегда отражает текущую модель — это и есть суть однонаправленного потока данных.

### Восстановите каркас программы

Впишите недостающие детали: имя пакета, путь импорта, метод старта и команду выхода.

```go
package ___

import (
        "fmt"

        "github.com/___/bubbletea"
)

func (m model) ___() tea.Cmd {
        return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
        // ... обработка событий ...
        case "q":
                return m, tea.___
}
```

Подсказка: Имя пакета — main; организация в пути импорта — charmbracelet; метод, который вызывают при старте, называется Init; выйти из программы помогает команда tea.Quit.

Правильные ответы в пропусках: `main`, `charmbracelet`, `Init`, `Quit`

### Соберите минимальный каркас

Расставьте строки каркаса Bubble Tea в правильном порядке — от объявления пакета до запуска. Метод View не случайно отсутствует: его добавим во втором уроке, а пока просто восстановите порядок остальных частей.

Правильный порядок строк:

1. `package main`
2. `import "github.com/charmbracelet/bubbletea"`
3. `type hello struct{}`
4. `func (h hello) Init() tea.Cmd { return nil }`
5. `func (h hello) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return h, nil }`
6. `func main() { tea.NewProgram(hello{}).Run() }`

### Карточки: словарь Bubble Tea

- **Bubble Tea** — Фреймворк терминальных интерфейсов от Charmbracelet (Go, 2020): цикл событий, Model, Update, View — и ничего лишнего.
- **Elm-архитектура** — Паттерн: всё состояние в модели, события — значения-сообщения, Update возвращает новую модель, View рисует строку. Пришёл из языка Elm.
- **bubbles** — Официальный набор компонентов Charm: list, textinput, table, spinner, progress. Каждый — тоже модель, встраивается в вашу.
- **Lip Gloss** — Библиотека стилей той же экосистемы: цвета, рамки, отступы, выравнивание для терминальной вёрстки.
- **TUI** — Text User Interface — интерфейс, нарисованный символами внутри терминала: клавиши, мышь и события есть, графического стека нет.
- **charmbracelet** — Компания и организация на GitHub: поддерживает bubbletea, bubbles, lipgloss, gum и десятки других терминальных инструментов.

### Что дальше по курсу

Дальше — практика. [Второй урок](/courses/bubbletea/lessons/02-model-update-view/) собирает счётчик целиком: каждая строка Model, Update и View с разбором и типичными ошибками новичка. [Третий](/courses/bubbletea/lessons/03-tea-program/) — про tea.Program: полный экран, мышь, отправка сообщений снаружи и то, как программа завершается. Потом придут команды tea.Cmd для асинхронных операций и компоненты bubbles. Полная программа — 25 уроков от «Hello, TUI» до итоговой панели задач — лежит на странице [курса Bubble Tea](/courses/bubbletea/). И напомню про запуск: примеры рассчитаны на локальный Go и настоящий терминал. Установить зависимость и собрать программу занимает минут пять, а ощущение живого интерфейса на собственном экране не заменит ни один скринкаст.

## Коротко: что запомнить

- Bubble Tea — фреймворк TUI от Charmbracelet (Go, 2020): цикл событий, Model, Update, View и ничего лишнего.
- Elm-архитектура: всё состояние в модели, события — сообщения, Update возвращает новую модель, View рисует строку.
- На Bubble Tea сделаны gh-dash, gum, Soft Serve и AWS Copilot CLI; k9s — сосед на tview, класс задач тот же.
- TUI занимает нишу между CLI и GUI: интерактивность как у GUI, но работает по SSH без дисплея.
- Экосистема: bubbles — компоненты, Lip Gloss — стили; рядом glamour, huh, gum, vhs.
- Перерисовка всего View после каждого события дешевле, чем кажется; для гигантских таблиц — замеряйте.
- Примеры курса запускаются локально: нужен настоящий терминал, песочница показывает логику на виртуальном.

## Домашнее задание

Установите Bubble Tea локально: mkdir tui-lab, затем go mod init tui-lab и go get github.com/charmbracelet/bubbletea. Соберите программу из урока, запустите и понажимайте стрелки. Потом сломайте её нарочно: уберите ветку ctrl+c и попробуйте выйти. Опишите словами, что происходит и почему — этот вывод понадобится в четвёртом уроке.

## Вопросы и ответы по уроку

### Что такое Bubble Tea простыми словами?

Библиотека для Go, которая превращает терминал в платформу для интерфейсов: собирает клавиши и события в понятные сообщения, а вам оставляет три метода — модель состояния, обновление и отрисовку строки.

### Чем Bubble Tea отличается от tview?

tview — виджетный фреймворк, близкий к классическим GUI: таблицы и формы из коробки, модель событий с колбэками. Bubble Tea — Elm-архитектура с чистыми функциями над состоянием: меньше готовых виджетов, больше дисциплины состояния, проще тесты и предсказуемый поток данных.

### Можно ли запускать Bubble Tea программы по SSH?

Да, это одна из главных причин брать TUI: программа рисуется символами и требует только терминал. Соберите статический бинарник, положите на сервер — интерфейс работает в SSH-сессии без установки зависимостей.
