# Pixel Companions для DeepSeek Harness [English](README.md) | [中文](README.zh.md) | Русский | [Tiếng Việt](README.vi.md) | [日本語](README.ja.md) | [한국어](README.ko.md) Я сделал Pixel Companions, потому что хотел, чтобы мои сессии в dsh ощущались менее обезличенными. Это анимированный пиксельный компаньон, который парит **над всем** веб-интерфейсом [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) и повторяет за агентом: печатает, работает, ждёт вашего подтверждения, закончил, спит. Я рендерю его в overlay на весь фрейм, поэтому он виден на каждой странице — в диалоге, настройках, плагинах — и его можно перетащить в любое место окна. Я оставил его обычным опциональным dsh **бандлом**: без форка интерфейса, без правок ядра, без перехвата промптов или ответов. Меня зовут kappyra, и это мой пет-проект для dsh. ![Предпросмотр](demo/preview.webp) Я нарисовал двух персонажей, у каждого — 15 анимированных сцен: - **Lumi** — пиксельная девушка за своим рабочим столом. - **Deepy** — пиксельный кит. **Графика.** Deepy использует матовый пиксельный набор v3, который я выбрал; Whale Girl сохраняет стиль v2 из пака. Все спрайты — 192×128 с прозрачным фоном. Мой компаньон — это браузерная часть официального слота `shell.overlay` на весь фрейм. Скрытый bridge-элемент в `conversation.input.dock` публикует факты сессии в собственное модульное хранилище плагина, а overlay их читает. Кнопка с шестерёнкой открывает небольшую панель настроек, которую я храню в `localStorage` только для этого браузера (см. раздел «Настройки»). ## Возможности - **Парит на каждой странице.** Я положил overlay поверх всех колонок, поэтому компаньон остаётся видимым и в диалоге, и в настройках, и в плагинах — не только рядом с полосой ввода. - **Перетаскивание куда угодно.** Мышь (левая кнопка), касание или перо перемещают компаньона в любое место окна. Я добавил небольшой порог, который отделяет перетаскивание от клика; позиция ограничивается областью просмотра, повторно ограничивается при изменении размера окна и сохраняется между перезагрузками в `kappy.pixel-companions.ui.v1` как `position: {x, y}` (`null` до первого перетаскивания). До этого я автоматически ставлю его в правый нижний угол над областью ввода и следую за изменениями размера окна. - **Следует за работой самой модели.** Я отслеживаю выполняющийся вызов инструмента, поток рассуждений, поток текста ответа или идущий ход без живого потока — но никогда текст промпта и никогда ваш собственный набор. См. [docs/ru/scenes.md](docs/ru/scenes.md). - **Строка ввода при наведении.** Я добавил строку ввода при наведении: наведите курсор на компаньона — или на отчёт о завершении — чтобы набрать и отправить сообщение в текущую сессию; после этого ваш черновик в полосе ввода восстанавливается. Пока отчёт виден, она стоит прямо под ним, а после его закрытия переезжает под компаньона. Для неё нужен открытый диалог; она скрыта во время перетаскивания и когда открыта панель настроек. - **Закреплённый отчёт о завершении.** Я сделал отчёт закрепляемым: после хода первая строка финального ответа и кнопка **«Подробнее»** остаются под компаньоном, пока вы не наведёте на него курсор или не начнётся новый ход. **«Подробнее»** открывает полный ответ как простой текст в прокручиваемой панели; наведение закрывает отчёт, а панель закрывается по ✕, Escape или клику вне её. - **30 анимированных WebP-сцен** (по 15 на персонажа) плюс статичные PNG для режима без анимации; у Deepy есть ещё `roaming` — анимация без стола, пока его перетаскивают. Я отдаю спрайты с собственного маршрута ассетов плагина и загружаю их по сцене, поэтому JS-бандл остаётся небольшим. - **Шесть языков интерфейса.** Я перевёл подписи и названия настроек на English, Русский, 中文, Tiếng Việt, 日本語 и 한국어; первый запуск следует `navigator.language`, иначе выбирается английский. - **Все настройки — в одном месте.** Я держу всё в панели с шестерёнкой у компаньона: персонаж, слайдер **«Размер»** (50–200 % шагом 5 % с кнопками −/+, живым процентом и кнопками-пресетами 50/100/150/200 %), язык, анимация вкл/выкл, показ вкл/выкл, сброс позиции, сетка ручного предпросмотра из 15 сцен, «Авто» и «Закрыть». Тот же элемент размера зарегистрирован и в **«Настройки → Общие → Размер компаньона»**. Я рендерю компаньона в его реальном масштабированном пиксельном размере (152×98 при 100 %), поэтому область клика, подпись/шестерёнка, колонка отчёта/ввода и панель подробностей следуют выбранному размеру. - **Опциональное окно на рабочем столе.** Я также сделал вариант компаньона, который может работать вне браузера — в окне Python без рамки, всегда поверх остальных, на той же машине, получая данные через bridge, доступный только с localhost. Строка настроек показывает его предпросмотр и предупреждает с командой запуска, когда окно не запущено. По умолчанию выключено. См. [docs/ru/desktop.md](docs/ru/desktop.md). - **Безопасно по своей конструкции.** Я сделал слой overlay пропускающим клики; указатель получают только компаньон, его шестерёнка и панель. Плагин не владеет кодом Host, не делает сетевых вызовов, кроме собственного маршрута ассетов и опционального локального bridge для рабочего стола, и читает только публичные props слота. - **Включается по желанию и обратимо.** Отключите мой плагин в «Настройки → Плагины» или удалите бандл — интерфейс вернётся к исходному виду. ## Требования - Профиль dsh Web (`dsh web`) — я нацелен только на официальный веб-клиент. - `pnpm` в `PATH`, потому что `dsh plugin` передаёт операции с пакетами в pnpm. - Node.js 22.6+ нужен только для пересборки из исходников; установленный пакет уже содержит `client.js`. ## Установка Я поставляю пакет готовым бандлом: `client.js` и графика в `assets/` закоммичены, поэтому для установки не нужен шаг сборки. ### Из локальной рабочей копии ```sh git clone https://github.com/kappyra/dsh-pixel-companions.git cd dsh-pixel-companions dsh plugin --profile web add link:"$PWD" ``` `link:` оставляет профиль привязанным к вашей рабочей копии, поэтому последующие изменения в `assets/` или `src/` (после `npm run build`) отдаются сразу. ### Из Git-адреса или tarball ```sh dsh plugin --profile web add github:kappyra/dsh-pixel-companions # or, after `npm pack` in the checkout: dsh plugin --profile web add /path/to/dsh-pixel-companions-0.1.0.tgz ``` Затем **перезагрузите веб-страницу**. Добавление бандла включает его в профиле; компаньон появляется у правого нижнего края на каждой странице — диалог, настройки, плагины — и переживает переходы между страницами. Впрочем, транспорт HMR клиента обычно подменяет бандл за секунду-другую; перезагрузка в любом случае безопасна. Полный сценарий (страница «Плагины», включение, отключение, удаление, диагностика): [docs/ru/installation.md](docs/ru/installation.md). Повседневное использование — перетаскивание, строка ввода при наведении, закреплённый отчёт и его подробности, размер, языки и окно на рабочем столе — я описал в [docs/ru/usage.md](docs/ru/usage.md). ## Настройки Все настройки я держу в панели, которая открывается с компаньона или его кнопкой с шестерёнкой (⚙): | Элемент | Что делает | Где хранится | | --- | --- | --- | | Персонаж | Lumi или Deepy | `kappy.pixel-companions.ui.v1` | | Размер | Слайдер 50–200 % шагом 5 %, с кнопками −/+, живым показанием и пресетами 50/100/150/200 %; спрайт рендерится в реальном пиксельном размере | тот же ключ | | Размер компаньона (Настройки → Общие) | Тот же слайдер, кнопки −/+, показание и пресеты, что и в панели с шестерёнкой; оба меняют общую настройку и остаются синхронными | тот же ключ | | Язык | English, Русский, 中文, Tiếng Việt, 日本語, 한국어 | тот же ключ | | Анимация | Анимированный WebP или статичный PNG | тот же ключ | | Показывать | Показать или скрыть компаньона | тот же ключ | | Окно на рабочем столе | Зеркалировать сцену в опциональное окно на рабочем столе; статус «Выкл.» / «Не запущено» / «Подключено» | тот же ключ | | Сбросить позицию | Вернуть компаньона в автоматическое положение в правом нижнем углу | тот же ключ | | Тестовая сцена | Принудительно показать любую из 15 сцен или вернуться к автоматике (**«Авто»**) | только состояние сессии | | Закрыть | Закрыть панель; **Escape** или клик вне панели тоже закрывают её | — | Я привязываю панель к компаньону, автоматически переворачиваю её над ним или под ним и ограничиваю областью просмотра. Настройки и позиция после перетаскивания хранятся отдельно для каждого браузера и каждого профиля и никогда не записываются в сервис настроек Host; плагин не добавляет отдельную страницу настроек — его строка размера появляется в «Настройки → Общие». ## Окно на рабочем столе (опционально) Я также собрал того же компаньона в виде окна на рабочем столе: он может работать вне браузера — в окне без рамки, всегда поверх остальных, с попиксельной прозрачностью, на той же машине. По умолчанию оно выключено. ```sh sudo apt install python3-gi gir1.2-gtk-3.0 python3-cairo python3 -m pip install --user Pillow python3 desktop/companion.py # or ./desktop/run.sh ``` Отметьте **«Окно на рабочем столе»** в панели с шестерёнкой; строка покажет **«Подключено»**, **«Не запущено»** или **«Выкл.»**. Через bridge на localhost передаются только id сцены, персонаж, масштаб и флаг анимации — никакого текста промпта, черновика, сообщений, id сессий, путей к файлам или вывода модели. См. [docs/ru/desktop.md](docs/ru/desktop.md). ## Сцены | Наблюдаемый сигнал | Сцена | Честный смысл | | --- | --- | --- | | Промпт отправлен (`input.phase` = sending/submitting/adjudicating) | `typing` | Сообщение отправляется | | Выполняется вызов инструмента | `working` | Инструмент работает | | Ассистент стримит рассуждения | `thinking` | Модель рассуждает | | Ассистент стримит текст ответа | `typing` | Модель пишет ответ | | Ход идёт, живого потока нет (запрос в пути) | `thinking` | Ожидание модели | | Идёт > 75 с без живого сигнала | `tired` | Долгая задача, а не усталость модели | | Идёт > 180 с без живого сигнала | `coffee` | Только для вида | | Ожидание подтверждения / вопрос | `waiting` | Ждёт вас | | `promptError`, `lastAgentError` или `openState = error` | `error` | Настоящий сигнал ошибки | | Идёт → остановился без ошибки | `success` (закрепляется) | Держится вместе с отчётом, пока вы не наведёте на компаньона или не начнётся новый ход; может включать отмену | | Нет активности 110 с | `sleeping` | Таймер простоя только для отображения | | Иначе | `idle` | — | Правила я сделал независящими от языка; локализуются только подписи под компаньоном. `thinking` означает, что ассистент рассуждает; набор черновика в полосе ввода ничего не меняет. `planning`, `reading`, `searching`, `debugging` и `offline` доступны **только для ручного предпросмотра**, пока клиент не начнёт отдавать для них типизированные сигналы; плагин никогда не угадывает их по словам промпта. Полные правила: [docs/ru/scenes.md](docs/ru/scenes.md). ## Совместимость Я проверил его на живом профиле dsh `0.2.2-alpha.2` Web: бандл устанавливается, модуль Client загружается через загрузчик модулей Harness, элементы регистрируются в `shell.overlay` (компаньон) и `conversation.input.dock` (скрытый bridge), отдаваемые байты бандла совпадают с репозиторием, а компонент рендерится с настоящими props слота. [docs/ru/compatibility.md](docs/ru/compatibility.md) перечисляет точные API, поток данных bridge → overlay, словари для шести языков и опциональный bridge для рабочего стола. Визуальные проверки (светлая и тёмная тема, ощущение перетаскивания, точное размещение) — за вами. ## Разработка ```sh npm install # esbuild, dev-only npm run build # build the asset manifest, then bundle client.js npm test # unit tests (Node 22.6+) ``` Браузерный код: `src/client/bridge.ts` (хранилище фактов), `Pet.tsx` (overlay, перетаскивание и roaming, скрытый bridge, строка ввода при наведении, отчёт), `state.ts` (правила сцен), `signals.ts` и `asset-url.ts` (чистые помощники и разрешение маршрута ассетов), `text.ts` (шесть языков), `desktop.ts` (опциональный bridge для рабочего стола). Пайплайн, упаковку и структуру я описал в [docs/ru/development.md](docs/ru/development.md). ## Лицензия и материалы - **Код плагина я выпускаю под MIT** — см. [LICENSE](LICENSE). - **Графику маскота** в `assets/`, `source-art/`, `demo/` и в копиях, которые отдаёт плагин, я создал для этого проекта; она поставляется вместе с проектом. На неё не распространяется MIT-лицензия на код, и права на неё остаются за мной. См. [ASSETS_NOTICE.md](ASSETS_NOTICE.md). - DeepSeek и DeepSeek Harness — товарные знаки соответствующих владельцев. Это неофициальный плагин сообщества, не связанный с DeepSeek и не одобренный им. Он использует только публичные API плагинов, документированные Harness. ## Диагностика | Симптом | Что проверить | | --- | --- | | Компаньона нигде нет | «Настройки → Плагины»: бандл включён? Перезагрузите страницу. Открытый диалог не обязателен. | | Компаньон виден, но замер | Возможно, выбран статичный PNG (анимация выключена) или ОС требует уменьшить анимацию. | | Компаньон не двигается при перетаскивании | Сдвиньте на несколько пикселей, прежде чем отпустить (есть порог перетаскивания), и тяните сам спрайт, а не пустой overlay. | | Компаньон ушёл за экран после изменения размера окна или смены монитора | Шестерёнка → **«Сбросить позицию»**; он вернётся в автоматическое положение в правом нижнем углу. | | Спрайт слишком большой или слишком маленький | Нажмите пресет **50/100/150/200 %** или потяните слайдер **«Размер»** (50–200 %) в панели с шестерёнкой либо в «Настройки → Общие → **Размер компаньона**»; сохранённая позиция ограничится заново автоматически, а **«Сбросить позицию»** вернёт автоматическое место в правом нижнем углу. | | Не могу найти элемент размера | Он есть в «**Настройки → Общие → Размер компаньона**» и в панели ⚙ компаньона; оба меняют одну настройку. Если нет ни там, ни там — нужна жёсткая перезагрузка (страница работает на старом клиентском бандле). | | Неправильный язык | Шестерёнка → **«Язык»**. Первый запуск следует языку браузера; иначе — английский. | | Панель настроек обрезается | Панель переворачивается и ограничивается областью просмотра; нажмите **«Сбросить позицию»** и сообщите размер окна. | | Окно на рабочем столе остаётся offline или выглядит непрозрачным прямоугольником | Страница открыта, **«Окно на рабочем столе»** отмечено; для прозрачности установите `python3-cairo`; проверьте `curl http://127.0.0.1:37421/health`. См. [docs/ru/desktop.md](docs/ru/desktop.md). | | Спрайты устарели или отдают 404 после изменения графики | Запустите `npm run build` — хеш содержимого `?v=` входит в URL каждого спрайта — затем перезагрузите страницу. | | `client.js` не загружается | Профиль должен отдавать пакет; снова выполните `dsh plugin --profile web add` и проверьте лог pnpm в `$DSH_HOME/profiles/web/.plugin-manager/logs/`. | Больше — в [docs/ru/troubleshooting.md](docs/ru/troubleshooting.md).