Vovó Справка

Действия

Действие — это кусочек HTML, CSS и JavaScript, который показывается в оверлее. Каждое работает само по себе, без сети и без доступа к паролям: то, что ему нужно извне, оно просит у Vovó.

Начало

«Новое действие» создаёт пустое или по примеру: оповещения и чат, что сейчас играет, отсчёт, цель, розыгрыш, счётчик смертей и другие. Пример становится вашей копией, которую можно свободно менять.

В три шага

Только HTML: <template>, который появляется, когда происходит событие, с полями события в фигурных скобках.

<template data-on="follow" data-seconds="5">
    <div class="alert">{user} теперь отслеживает!</div>
</template>

Немного JavaScript: vovo.on("raid", (e) => { ... }) и vovo.show("имя", e). И весь API для остального.

Триггеры

Действие получает только события из своего списка триггеров в редакторе. Кнопка пада — это триггер button.

Условия

Значок ползунков рядом с триггером открывает его условия: триггер срабатывает, только когда выполнены все. Рейд от 50 человек, сообщение, начинающееся с !участвую, нужная награда.

Таймер и горячая клавиша

Триггер Таймер срабатывает время от времени: его условие every говорит, сколько секунд между срабатываниями (без него — раз в минуту). Триггер Горячая клавиша срабатывает на сочетание клавиш, своё условие keys, в том числе когда игра на переднем плане.

Элементы управления

В карточке Управление редактора действие объявляет, что пад может менять, пока оно работает: включено или выключено, выбор между вариантами, счётчик (с целью, если хотите) или текст. Каждый хранится в vovo.state, под ключом, который показывает окно, а каждое изменение приходит как событие control, без всякого триггера. Примеры Оповещения и чат, Цель по фолловерам и Счётчик смертей показывают, как это сделать.

vovo.on("control", () =>
{
    document.getElementById("chat").hidden = !vovo.state.chat;
});

Настроить

Действие может позволить тому, кто им пользуется, менять его, не открывая код: его цвет, размер текста, шрифт, сторону экрана, свою картинку или звук. Палитра рядом с названием его панели или в его строке в списке действий открывает Настроить: строка на каждую настройку, с тем, что в ней, её значением по умолчанию, если оно другое, и путём назад к нему. Изменение видно сразу в сценах, которые показывают действие, без его перезапуска, и каждое — это версия, которую отменяет журнал. Выбирается это только на этом компьютере: телефон или другая Vovó этого никогда не видят. Пакет действия несёт значения по умолчанию, никогда ваш выбор; пакет, который занимает место действия, сохраняет те выборы, для которых в нём ещё есть место.

Автор действия объявляет их в карточке Настроить редактора или в settings в его action.json: у каждой есть тип (цвет, число от минимума до максимума, включено или выключено, выбор, текст, изображение, звук или видео, шрифт), название, ключ и значение по умолчанию. Действие читает их в vovo.settings и слышит событие settings, когда одна меняется; его CSS читает их как var(--vovo-ключ) (число с единицей, например 32px), а включено или выключено или выбор — как атрибут страницы, для селекторов:

.chat
{
    color: var(--vovo-color);
    font-size: var(--vovo-size);
    font-family: var(--vovo-font), sans-serif;
}
html[data-vovo-side="Right"] .chat
{
    right: 40px;
}

Настройкой может быть и камера: тот, кто пользуется действием, выбирает в «Настроить» одну из камер своего компьютера, а действие показывает её там, где размещает (vovo.camera.place, с разрешением camera.show). Действие приходит без камеры и никогда не узнаёт, какая выбрана, и не видит её изображений: vovo.settings говорит только, выбрана ли какая-то, как true или false. Пример «Камера» — это камера в рамке.

Панели

То, что не помещается в кнопку (имена в розыгрыше, цели с их числами, нажатие, которое должно переспросить), идёт в панель действия: panel в его манифесте, показанную в Панелях на боковой панели (её значок у правого края окна, пока хоть у одного действия есть панель). Панель — это список элементов, которые рисует Vovó: heading и note, control по его ключу, button (с confirm она сначала спрашивает «Точно?»), form до четырёх полей и list, читаемый из vovo.state (его key и path внутри), у каждой строки до трёх кнопок.

Действие, которому есть что предложить, делит это двумя способами. { "kind": "panel", "label": "Розыгрыш", "icon": "gift" } начинает ещё одну панель: свой пункт в Панелях, со своим названием и значком (один из значков Vovó по имени или эмодзи; без него — значок первой кнопки пада этого действия). Элементы после неё, до следующей, принадлежат ей, а те, что до первой, показываются вверху каждой. Внутри панели tab начинает раздел (до двенадцати): элементы после него, до следующей вкладки, видны, пока он выбран, а те, что до первой вкладки, видны во всех. Так розыгрыш — это одна панель с разделом для розыгрыша, другим для участников и третьим для победителей, а не одна длинная страница. Действие, которое не объявляет ни одного { "kind": "panel" }, имеет одну панель, названную по нему.

Заголовок Панелей называет ту, что впереди; нажатие на него показывает список всех, у каждой сказано, показывает ли её открытая сцена и чья она, с поиском, когда их больше восьми. Разделы показываются вкладками под заголовком: те, что помещаются, а остальные — под «Ещё». Заголовок открывает группу: элементы после него делят одну карточку, идущие подряд кнопки делят строку, список — отдельная карточка со счётчиком, а заметка стоит между карточками. Форма из одного поля заполняется прямо в панели, Enter отправляет её, как и текстовый элемент управления; форма из нескольких полей открывает маленькое окно. Счётчик с целью (max) показывает, сколько пройдено.

В списке могут быть тысячи строк. У списка длиннее восьми есть свой поиск, который остаётся на виду, пока список прокручивается. Если он последний элемент своего раздела, он показывается целиком; если после него есть элементы, он показывает первые восемь строк и путь ко всем, поэтому длинный список ставьте в конец или в отдельный раздел.

То, что там делается, приходит как событие panel, без всякого триггера: его name, values формы, а также item и index строки. Имена принадлежат действию, какая бы панель их ни показывала. Действие слышит свою панель, только пока его показывает открытая сцена, в OBS или в окне предпросмотра: если ни одной нет, панель говорит об этом, её кнопки ждут приглушёнными, а «Открыть предпросмотр» открывает предпросмотр сцены; её элементы управления и списки по-прежнему видны, потому что Vovó их хранит. Пользуется ею только тот, кто ведёт стрим, здесь или на устройстве, которому вы разрешили панели, и во время паники до действия ничего не доходит.

Писать в чат

С разрешением chat.send vovo.chat.send("...") пишет в чат стрима от вашего имени. Vovó держит темп (20 строк за 30 секунд) и пишет один раз то, о чём просят две страницы, показывающие действие; два нажатия кнопки — две строки. Пример Напоминание в чате показывает, как это сделать. С { as: "persona" } строка идёт через собственный аккаунт персоны в Twitch (Интеграции, под Twitch): то, что персона говорит не в ответ, например строка, которую кто-то набрал для неё. Пока этот аккаунт не подключён, ничего не пишется, и от вашего имени вместо неё тоже.

Vovó отличает вызов одной страницы от вызова другой по событию, которое действие обрабатывало, когда вызвало. Вызов, сделанный позже, после await или в таймере, говорит, на какое событие он отвечает, с помощью { event: e }, где e — то, что получила ваша функция: vovo.chat.send("Добро пожаловать!", { event: e }). То же касается vovo.emit, vovo.pad.play, vovo.webhook.send, vovo.draw, vovo.media.play и вызовов OBS. Без этого две страницы написали бы строку дважды, а ссылка модератора ждала бы в колокольчике.

Микрофон, экран и то, как вы двигаетесь

Действие может следить за громкостью вашего микрофона (audio.level), цветом экрана (screen.color) и тем, как вы двигаетесь в игре (input.move): на сколько повернулась камера, куда вы идёте и прыгаете ли, с мыши, W, A, S и D или стрелок и контроллера, чтобы сцена покачивалась вместе с камерой. Примеры «Свечение экрана» и «Покачивание камеры» показывают, как это сделать. Vovó читает каждое, только пока открытый оверлей показывает действие, которое этого ждёт, а строка состояния показывает его значок в своей середине, пока это происходит, с названиями действий во всплывающей подсказке. С клавиатуры она читает только клавиши движения, как направление, никогда какую клавишу, и не тогда, когда окно Vovó на переднем плане, где набираемый текст раскачивал бы сцену; мышь и контроллер тогда всё равно двигают её, если не включено «Приостанавливать движение, когда Vovó на переднем плане» (Настройки, Общие). Звук никогда не покидает компьютер, только его громкость.

Клипы и видео

С разрешением media.play vovo.media.play(ссылка) показывает клип Twitch, видео Twitch или видео YouTube в его официальном плеере, там, куда его поместил vovo.media.place(элемент), со звуком. Действие, которое запускает только оператор, играет его сразу; любое другое, которое мог запустить кто-то из чата, ждёт в колокольчике, пока вы (или устройство с правом одобрять) его не пропустите. Плеер не знает, когда клип закончится: укажите { seconds: 60 } или вызовите vovo.media.stop(). Пример Клипы на телевизоре принимает !clip и ссылку от модераторов.

Ваши модераторы — это люди, которым вы доверяете чат: в Интеграциях, у Twitch, «Ссылки модераторов воспроизводятся сразу» позволяет ссылке, которую вставил один из них (или вы), выйти в эфир без ожидания, когда действие показывает её из-за его сообщения. Выключено, пока вы не включите; ссылки всех остальных по-прежнему ждут.

Голосовые звонки

С разрешением call действие может соединить вас по телефону с ИИ-моделью, в эфире: вы говорите в микрофон, она отвечает вслух, и стрим слышит обоих. vovo.call.start({ instructions, voice }) открывает звонок с вашим ключом OpenAI (Интеграции, ИИ); instructions — это кто модель и как она говорит. Звонок открывается в тишине, чтобы действие могло сначала позвонить телефоном; vovo.call.answer() открывает микрофон и даёт модели заговорить первой, vovo.call.tell() говорит ей что-то во время звонка, а vovo.call.end() кладёт трубку. call.started, call.answered, call.text (сказанное, записанное текстом) и call.ended говорят, что происходит.

То, что говорит модель, слышно сразу, и никто это заранее не читает, поэтому звонок начинается только с того, что вы сделали своими руками: кнопки пада, горячей клавиши, элемента управления или панели действия. Чат, награды и вебхуки звонков не начинают. OpenAI берёт плату посекундно с момента открытия, поэтому у каждого звонка есть потолок (не больше пяти минут). Пока звонок идёт, в строке состояния виден красный телефон: нажмите его или панику, чтобы сразу положить трубку. Пользуйтесь наушниками, иначе модель услышит саму себя из ваших колонок.

Вебхуки

С разрешением webhook vovo.webhook.send("имя", { ... }) просит Vovó отправить JSON на вебхук, настроенный в Настройках, Вебхуки: канала Discord, автоматизации, инструмента в вашей сети. Адрес остаётся в хранилище этого компьютера, вне резервных копий и пакетов, а действие знает только имя. Пример Объявление в Discord показывает, как это сделать.

Входящие вебхуки

В обратную сторону сервис в интернете сообщает Vovó: в Настройках, Вебхуки, создайте входящий вебхук, скопируйте его адрес и вставьте в сервис (страницу пожертвований, магазин, скрипт). Каждый вызов доходит до действий как событие webhook, с hook (имя) и data (то, что прислали). Используйте триггер webhook с условием, что hook — это имя. У каждого вебхука свой адрес: давайте его только тому сервису, который его вызывает. Ретранслятор хранит вызов запечатанным для этого компьютера не больше суток, так что вызов, сделанный при закрытой Vovó, придёт, когда она откроется. То, что приходит, — чужой текст: действия показывают его только как текст.

Из программы на этом компьютере

Программа на этом компьютере может сказать действию, что ей известно: скрипт, читающий лог игры, инструмент, ведущий счёт турнира, макрос. Действие слушает событие со своим именем, среди триггеров в своём action.json (как в папке, за которой следит vovo dev):

"triggers": ["score"]

и слышит его, как любое другое:

vovo.on("score", (e) =>
{
    document.getElementById("home").textContent = e.home;
    document.getElementById("away").textContent = e.away;
});

Программа сообщает его через vovo emit, имя и поля:

vovo emit score home=2 away=1

Число, true и false приходят как есть, всё остальное — как текст. Списки и объекты передаются целиком в JSON, и так программа это вызывает:

import json, subprocess
subprocess.run(["vovo", "emit", "score", "--fields", json.dumps({"home": 2, "away": 1})])

Команда говорит, какие действия его услышали, и завершается с ошибкой (код выхода 1, с причиной), когда никто бы не услышал: ни у одного действия нет этого имени среди триггеров, их условия не выполнены или ни одна открытая страница их не показывает. Событие идёт туда же, куда пошёл бы собственный vovo.emit действия, никогда во время паники, не больше 30 за 10 секунд, а журнал говорит, что его запустила командная строка. Действие только для оператора его не слышит. То, что присылает программа, — текст этой программы: действие показывает его только как текст. Чтобы сделать вид, что произошло событие API, например отслеживание, используйте vovo simulate.

Предпросмотр и Имитировать

Редактор показывает действие вживую, пока вы печатаете, а кнопки Имитировать запускают триггеры, не дожидаясь настоящего события, и двигают элементы управления так, как сделала бы кнопка пада. Ничего из предпросмотра не попадает на стрим. Значок в углу кода или предпросмотра отдаёт ему всё окно; тот же значок или Esc возвращает его рядом с другим.

Программы чтения с экрана

Программы чтения с экрана не умеют читать редактор кода. Кнопка Простой текст над кодом ставит на его место текстовое поле, которое Экранный диктор, NVDA и JAWS читают целиком, по строкам, словам и символам. Она включена с самого начала, если Windows сообщает, что работает программа чтения с экрана; Tab переходит дальше, поэтому делайте отступы пробелами.

Файлы

Во вкладке Файлы редактора добавьте изображения, звуки, видео и шрифты. Действие использует их по имени: <img src="logo.png">. Чтобы пропустить один из своих звуков или видео через Web Audio (компрессор, индикатор уровня), запросите его с crossOrigin = "anonymous", прежде чем указать имя: действие работает отдельно от всего, и для него даже собственные файлы приходят извне, а Web Audio иначе слышит это как тишину.

Разрешения

То, что действие может просить у Vovó, находится в разделе Поведение: писать в чат, вызывать вебхук, показывать общий экран, показывать камеру, показывать источники и включать фильтры в OBS. Если это выключено, действие не может этого делать.

OBS из действия

С разрешением obs.toggle vovo.obs.source("Сцена", "Источник", true) показывает источник в сцене OBS (false скрывает; без значения переключает), а vovo.obs.filter("Источник", "Фильтр", true) делает то же с фильтром. Имена — как в OBS, без учёта регистра и диакритики; имя, которого в OBS нет, называется в Консоли вместе с тем, которое имелось в виду. Это всё, до чего действие достаёт в OBS: оно не может остановить трансляцию или прочитать её ключ.

Только для оператора

В разделе Поведение «Только для того, кто ведёт стрим» делает так, что действие запускают только пад, горячие клавиши, таймеры и его элементы управления: никогда зрители, чат, награды, вебхуки или событие другого действия. Используйте это для того, что никто из смотрящих не должен уметь делать, например очищать чат или переключать сцены.

Версии

Каждое сохранение хранит версию. «История» возвращает любую из них.

Пакеты

Значок экспорта в списке действий записывает действие в .zip с его кодом и файлами, чтобы передать кому-нибудь. В разделе Поведение его автор, сайт и строка о том, что оно делает, идут вместе с ним, чтобы тот, кто его импортирует, знал, что это и откуда. «Импортировать действие» показывает, что приносит пакет и о чём просит, прежде чем его сохранить, и открывает действие в редакторе: прочитайте его перед использованием. Пакет с именем действия, которое у вас есть, — скорее всего, это действие в более новой версии, поэтому он предлагает занять его место: действие сохраняет свои сцены, кнопки и состояние, а прежняя версия остаётся в его истории. В терминале то же делают vovo export и vovo import, а vovo import --replace занимает место действия с тем же именем. Пакет, сделанный для других, может указать id в разделе Поведение: имя автора и имя действия через точку (example.raffle). Тогда его следующая версия находит действие, которое обновляет, даже после того как вы его переименовали, а два действия с одним именем от разных авторов никогда не занимают место друг друга; vovo import --replace тоже опирается на него. В любом случае импорт говорит, какая версия занимает место какой, и отмечает, если файл той же версии или старее, а выбранное в «Настроить» остаётся везде, где в новой версии ещё есть эта настройка. Пакет может сказать, по какой лицензии он передаётся: название лицензии или своя строка в разделе Поведение и полный текст лицензии, выбранный там из файла или лежащий как LICENSE рядом с action.json в папке. Тот, кто импортирует действие, видит строку и читает текст в окне импорта до того, как действие будет принято. Vovó сообщает то, что вы написали, и никого ни к чему не обязывает: она не проверяет ни ключа, ни учётной записи, ни покупки, а продажа действия происходит вне Vovó. Значок копирования рядом создаёт копию действия и открывает её в редакторе, чтобы начать вариант с того, что работает: его код, файлы и триггеры переходят в копию; состояние, сцены и кнопки — нет, а триггер горячей клавиши приходит без сочетания, чтобы одна клавиша не запускала оба.

В своём редакторе

Действие можно писать в любимом редакторе или собственной сборкой: держите его части в папке так, как их держит пакет (action.json, index.html, style.css, script.js и files/), и в терминале запустите vovo dev с этой папкой. Vovó откроет свой редактор на действии с этим именем, создав его из папки, если в профиле такого нет, и сразу покажет в предпросмотре каждое изменение, сохранённое в папке; Имитировать работает как всегда. Как и изменение, набранное здесь, оно попадает на стрим, только когда вы Сохраните. vovo dev stop или Перестать следить вверху редактора отпускает папку.

vovo new <папка> создаёт эту папку за вас, пустую или из одного из примеров (vovo new --list их перечисляет, а --from goal берёт один), а vovo check <папка> сразу говорит всё, что не так в папке или пакете, ничего не создавая и не открывая: каждую проблему с её файлом и то, что Vovó приняла бы и пропустила, например ключ, который ей не нужен. Обе команды отвечают и при закрытой Vovó. vovo export <действие> <папка> записывает в виде такой папки действие, которое у вас уже есть.

vovo dev также записывает в папку vovo.d.ts, API в том виде, в каком он у этой Vovó, и jsconfig.json, если его нет, чтобы редактор вроде VS Code дополнял vovo., названия событий в vovo.on(" и поля каждого события. Ни один из них не входит в действие, и пакет никогда их не несёт; в системе контроля версий храните их или игнорируйте, как удобно. Чтобы ошибочное поле подчёркивалось, добавьте "checkJs": true в compilerOptions jsconfig.

Туда же он записывает action.schema.json, который тоже не входит в действие: с "$schema": "./action.schema.json" в начале action.json редактор подсказывает его ключи, предлагает события и разрешения по имени и подчёркивает то, что Vovó отклонила бы.

Предпросмотр открывается и в вашем браузере, по адресу, который печатает vovo dev, или стрелкой в углу предпросмотра: тот же черновик, выполняемый тем же vovo, что в эфире, перезагружаемый при каждом изменении, доступный для Имитировать, с инструментами разработчика самого браузера (его консолью, точками останова, элементами).

Чтобы показать его на стриме

Действие должно быть в сцене, а сцена — в OBS.