e687303c57
Warm and show the NPC window sooner, lazy-load ReactFlow/TipTap, overlay save progress like materials, and fix the undefined controlStyles crash after creating an NPC. Co-authored-by: Cursor <cursoragent@cursor.com>
1204 lines
114 KiB
TypeScript
1204 lines
114 KiB
TypeScript
export type EditorLocale = 'ru' | 'en';
|
||
|
||
export const EDITOR_LOCALE_STORAGE_KEY = 'dnd_editor_locale';
|
||
|
||
function primaryLanguageTag(lang: string): string {
|
||
const trimmed = lang.trim().toLowerCase();
|
||
if (!trimmed) return '';
|
||
const sep = trimmed.search(/[-_]/);
|
||
return sep === -1 ? trimmed : trimmed.slice(0, sep);
|
||
}
|
||
|
||
/**
|
||
* Выбор `ru` / `en` по языку ОС/браузера, если пользователь ещё не сохранил язык в `localStorage`.
|
||
* В Electron совпадает с локалью системы (Chromium подставляет `navigator.languages`).
|
||
*/
|
||
export function inferEditorLocaleFromSystem(languages?: readonly string[]): EditorLocale {
|
||
let list: string[];
|
||
if (languages !== undefined) {
|
||
list = [...languages];
|
||
} else if (typeof navigator !== 'undefined') {
|
||
list = [...navigator.languages];
|
||
if (navigator.language) {
|
||
list.push(navigator.language);
|
||
}
|
||
list = list.filter((x) => x.trim() !== '');
|
||
} else {
|
||
list = [];
|
||
}
|
||
for (const lang of list) {
|
||
const tag = primaryLanguageTag(lang);
|
||
if (tag === 'en') return 'en';
|
||
if (tag === 'ru') return 'ru';
|
||
}
|
||
return 'ru';
|
||
}
|
||
|
||
export function normalizeEditorLocale(raw: string | null | undefined): EditorLocale {
|
||
if (raw == null) {
|
||
return inferEditorLocaleFromSystem();
|
||
}
|
||
const trimmed = raw.trim();
|
||
if (trimmed === '') {
|
||
return inferEditorLocaleFromSystem();
|
||
}
|
||
const s = trimmed.toLowerCase();
|
||
if (s === 'en') return 'en';
|
||
if (s === 'ru') return 'ru';
|
||
return inferEditorLocaleFromSystem();
|
||
}
|
||
|
||
/** Flat message table; `{name}` placeholders supported in `translate`. */
|
||
export const EDITOR_MESSAGES: Record<EditorLocale, Record<string, string>> = {
|
||
ru: {
|
||
'common.close': 'Закрыть',
|
||
'common.cancel': 'Отмена',
|
||
'common.save': 'Сохранить',
|
||
'common.saving': 'Сохранение…',
|
||
'common.edit': 'Редактировать',
|
||
'common.understood': 'Понятно',
|
||
'common.message': 'Сообщение',
|
||
'common.error': 'Ошибка',
|
||
'common.delete': 'Удалить',
|
||
'common.closeMenu': 'Закрыть меню',
|
||
|
||
'app.brandTitle': 'НРИ Плеер',
|
||
|
||
'notice.campaignAudioEmpty': 'Аудио не добавлено. Проверьте формат файла.',
|
||
|
||
'license.checkingTitle': 'Проверка лицензии…',
|
||
'license.checkingWait': 'Подождите.',
|
||
'license.requiredTitle': 'Требуется лицензия',
|
||
'license.requiredHint':
|
||
'Укажите ключ в меню «Настройки» → «Указать ключ». До активации доступно только меню «Настройки».',
|
||
'license.tokenTitle': 'Указать ключ',
|
||
'license.tokenKey': 'КЛЮЧ',
|
||
'license.tokenPlaceholder': 'Продуктовый ключ TTRPG-... или DND-...',
|
||
'license.tokenSaving': 'Сохранение…',
|
||
'license.eulaTitle': 'Лицензионное соглашение',
|
||
'license.eulaReject': 'Не принимаю',
|
||
'license.eulaAccept': 'Принимаю условия',
|
||
'license.eulaNoteEn':
|
||
'The binding legal text below is in Russian. If you need an English summary, contact support.',
|
||
'license.aboutTitle': 'О лицензии',
|
||
'license.aboutDevSkip': 'Режим разработки: проверка лицензии отключена (DND_SKIP_LICENSE).',
|
||
'license.aboutStatus': 'СТАТУС',
|
||
'license.aboutProduct': 'ПРОДУКТ',
|
||
'license.aboutLicenseId': 'ID ЛИЦЕНЗИИ',
|
||
'license.aboutExpiry': 'ОКОНЧАНИЕ',
|
||
'license.aboutDevice': 'УСТРОЙСТВО',
|
||
'license.aboutNoData': 'Нет данных лицензии.',
|
||
'license.reason.ok': 'Активна',
|
||
'license.reason.none': 'Ключ не указан',
|
||
'license.reason.expired': 'Срок действия истёк',
|
||
'license.reason.bad_signature': 'Недействительная подпись',
|
||
'license.reason.bad_payload': 'Неверный формат токена',
|
||
'license.reason.malformed': 'Повреждённый токен',
|
||
'license.reason.not_yet_valid': 'Ещё не действует',
|
||
'license.reason.wrong_device': 'Другой привязанный компьютер',
|
||
'license.reason.revoked_remote': 'Отозвана на сервере',
|
||
|
||
'presentation.overlay': 'Презентация запущена',
|
||
'presentation.title': 'Презентация запущена',
|
||
'presentation.body':
|
||
'Редактор заблокирован. Закройте окна «Презентация» и «Панель управления», чтобы продолжить.',
|
||
|
||
'zip.progress': 'Прогресс операции',
|
||
'zip.importTitle': 'Импорт проекта',
|
||
'zip.exportTitle': 'Экспорт проекта',
|
||
|
||
'top.settings': 'Настройки',
|
||
'top.project': 'Проект',
|
||
'top.file': 'Файл',
|
||
'top.backToProjects': 'К списку проектов',
|
||
'top.appVersion': 'Версия приложения',
|
||
'top.run': 'Запустить',
|
||
'top.launching': 'Запуск…',
|
||
'top.afterLicense': 'Доступно после активации лицензии',
|
||
'top.setStartScene': 'Назначьте начальную сцену на графе (ПКМ по узлу)',
|
||
'top.runHelpAria': 'Как разблокировать кнопку «Запустить»',
|
||
|
||
'menu.enterKey': 'Указать ключ',
|
||
'menu.aboutLicense': 'О лицензии',
|
||
'menu.checkUpdates': 'Проверить обновления',
|
||
'menu.language': 'Язык',
|
||
'menu.langRu': 'Русский',
|
||
'menu.langEn': 'English',
|
||
'menu.aboutProgram': 'О программе',
|
||
'menu.instructions': 'Инструкция',
|
||
|
||
'top.aboutApp': 'О приложении',
|
||
|
||
'app.about.title': 'О программе',
|
||
'app.about.tagline': 'Редактор кампаний и пульт мастера для настольных ролевых игр',
|
||
'app.about.description':
|
||
'TTRPG Player (НРИ Плеер) — настольное приложение для мастера: вы собираете кампанию как граф сцен с картами, музыкой и ветвлениями, а во время сессии управляете атмосферой с пульта. Игроки видят только презентацию на втором экране — без панелей редактора.',
|
||
'app.about.versionLabel': 'ВЕРСИЯ',
|
||
'app.about.developerLabel': 'РАЗРАБОТЧИК',
|
||
'app.about.developer':
|
||
'Независимая разработка. По вопросам лицензии, покупки и поддержки — электронная почта ниже.',
|
||
'app.about.supportLabel': 'ПОДДЕРЖКА',
|
||
'app.about.supportEmail': 'player.ttrpg@gmail.com',
|
||
'app.about.websiteLabel': 'САЙТ И ОБНОВЛЕНИЯ',
|
||
'app.about.websiteUrl': 'https://ttrpgplayer.ru/',
|
||
|
||
'help.title': 'Инструкция',
|
||
'help.navAria': 'Разделы инструкции',
|
||
|
||
'help.section.overview.title': 'Обзор приложения',
|
||
'help.section.overview.body':
|
||
'При запуске вы попадаете в Редактор — здесь готовите кампанию: сцены, картинки, музыку и связи между эпизодами. Когда придёт время играть, нажмите «Запустить» — откроются «Презентация» для игроков и «Пульт управления» для вас.\n\nВ редакторе слева — список сцен, по центру — карта связей, справа — настройки игры и выбранной сцены.\n\nПока идёт показ, редактор временно нельзя менять — это нормально. Закройте презентацию и пульт, чтобы снова редактировать кампанию.\n\nИнтернет нужен только для активации лицензии и проверки обновлений. Все проекты и файлы хранятся на вашем компьютере.',
|
||
|
||
'help.section.license.title': 'Лицензия и первый запуск',
|
||
'help.section.license.body':
|
||
'Перед работой с проектами один раз активируйте лицензию.\n\n1) Откройте «Настройки» → «Указать ключ».\n\n2) Если появится лицензионное соглашение — прочитайте и примите его.\n\n3) Вставьте ключ из письма (формат TTRPG-… или старый DND-…) и нажмите «Сохранить».\n\nДо активации доступны только настройки. После успешного сохранения ключа откроются проекты, сцены и запуск сессии.\n\nСтатус, срок действия и привязка к компьютеру — в «Настройки» → «О лицензии». Ключ привязан к этому ПК; на другом компьютере понадобится отдельная активация по условиям покупки.',
|
||
|
||
'help.section.projects.title': 'Проекты',
|
||
'help.section.projects.body':
|
||
'Проект — вся кампания целиком: сцены, медиа и связи между ними.\n\nСоздать новую кампанию:\n\n1) На начальном экране введите название в поле слева.\n\n2) Нажмите «Создать проект».\n\nОткрыть существующую — кликните по названию в списке. Вернуться к списку: «Проект» → «Начальный экран» или клик по названию приложения в шапке.\n\nПеренести кампанию на другой компьютер:\n\n1) «Проект» → «Экспорт» — сохраните копию как .ttrpg.zip.\n\n2) На другом ПК — «Проект» → «Импорт» и выберите этот файл.\n\nПереименовать открытый проект: «Файл» → «Переименовать проект» (минимум 3 символа; в имени файла нельзя использовать <>:"/\\|?*).\n\nУдалить проект с диска:\n\n1) На карточке проекта нажмите «⋮».\n\n2) В меню выберите «Удалить».\n\n3) Подтвердите удаление в диалоге.\n\nПосле этого файл проекта и кэш будут стёрты без восстановления. Если кампания может понадобиться снова — сначала сделайте экспорт.',
|
||
|
||
'help.section.scenes.title': 'Сцены',
|
||
'help.section.scenes.body':
|
||
'Сцена — отдельный эпизод: локация, кадр истории, диалог. У неё есть название, картинка или видео для игроков, описание для мастера и своя музыка.\n\nДобавить сцену:\n\n1) В левой колонке нажмите «+ Новая сцена».\n\n2) Задайте название и настройте свойства справа (см. «Свойства сцены»).\n\n«Поиск сцен…» помогает быстро найти нужную. Клик по карточке выделяет сцену — она же подсветится на карте связей.\n\nУдалить: правый клик по карточке в списке → «Удалить». Сцена исчезнет из списка и с карты вместе со связями.\n\nПеретащите сцену из списка на карту — так она появится как узел (подробнее в «Граф сцен»).',
|
||
|
||
'help.section.graph.title': 'Граф сцен',
|
||
'help.section.graph.body':
|
||
'Карта в центре показывает, как эпизоды связаны. Каждый прямоугольник — место на схеме; одна сцена может встретиться несколько раз (например, игроки снова возвращаются в таверну).\n\nДобавить сцену на карту:\n\n1) Возьмите сцену в левом списке.\n\n2) Перетащите на свободное место на карте.\n\nСделать переход между сценами:\n\n1) Наведите на нижнюю точку первой карточки.\n\n2) Потяните линию к верхней точке второй и отпустите — появится стрелка.\n\nИз одной сцены может выходить несколько стрелок — так вы делаете ветвление сюжета. Вторую стрелку к той же паре сцен провести нельзя.\n\nУдалить стрелку: правый клик по линии → «Удалить». Обычный клик по линии ничего не делает.\n\nС чего начинается игра: правый клик по карточке → «Начальная сцена» (появится метка «НАЧАЛО»), затем «Запустить» в шапке. Можно начать с любой карточки основного сюжета: ПКМ → «Запустить с этой сцены» — откроются презентация и пульт с выбранного места (метку «НАЧАЛО» ставить не обязательно). Для карточек побочных линий этот пункт недоступен.\n\nУбрать карточку с карты, не удаляя сцену из списка: ПКМ → «Удалить».\n\nМасштаб — кнопки внизу или колёсико мыши. «Показать всё» вместит всю схему на экран.',
|
||
|
||
'help.section.sideStorylines.title': 'Побочные сюжетные линии',
|
||
'help.section.sideStorylines.body':
|
||
'Побочная линия — отдельная ветка сюжета, не связанная с основным сюжетом. Она нужна для ответвлений, флешбэков, побочных квестов и сцен «вне основного пути».\n\nСоздать побочную линию в редакторе:\n\n1) Добавьте сцены на карту и соедините их стрелками в отдельной группе — она не должна касаться основного сюжета (фиолетовые связи) и других побочных линий.\n\n2) Правый клик по стартовой карточке побочной ветки → «Начальная сцена побочной линии». Появится синяя метка «ПОБОЧНАЯ».\n\n3) В свойствах сцены задайте «Название побочной линии» — оно будет видно на пульте.\n\nПункт «Начальная сцена побочной линии» скрыт, если карточка уже связана с основным сюжетом (где есть фиолетовое «НАЧАЛО») или с другой побочной линией (где есть синее «ПОБОЧНАЯ»).\n\nСвязи внутри побочной линии и выделение её карточек — синего цвета (#0078d4). Между основным и побочным сюжетом, а также между разными побочными линиями, стрелки провести нельзя.\n\nСнять метку: ПКМ → «Снять метку «Начальная сцена побочной линии»». Название очистится, плитка исчезнет с пульта.\n\nУдалить стартовую карточку: если есть следующая сцена по стрелке — метка переносится на неё; если нет — вся побочная линия удаляется с карты.\n\nВо время игры на пульте под блоком «Музыка» появляется «Побочные сюжетные линии» — плитки с превью и названием. Клик переносит партию на первую сцену линии. Программа запоминает, с какой сцены основного сюжета вы ушли.\n\nПока идёт побочная линия, в «Варианты ветвления» первой опцией всегда «Вернуться в основной сюжет» — возврат на запомненную сцену. История «Сюжетная линия» продолжает записывать все шаги, включая побочную ветку.\n\nЗапустить побочную линию из редактора нельзя — только с пульта во время сессии.',
|
||
|
||
'help.section.sceneProps.title': 'Свойства сцены',
|
||
'help.section.sceneProps.body':
|
||
'Выберите сцену в списке слева — справа откроются её свойства.\n\n«Название сцены» — для мастера. «Описание» — заметки мастера с форматированием: рядом с подписью нажмите карандаш, откроется редактор (жирный, курсив, заголовки, списки, ссылки). Под подписью видно фрагмент текста или «описание отсутствует», если поле пустое. Во время сессии описание открывается с пульта в отдельном окне (см. «Пульт управления»), а не в блоке «Сюжетная линия».\n\nЕсли у сцены на карте есть карточка с синей меткой «ПОБОЧНАЯ», появится поле «Название побочной линии».\n\nКартинка или видео для игроков:\n\n1) В «Превью сцены» нажмите «Загрузить» или «Изменить».\n\n2) Выберите файл (PNG, JPG, WebP, GIF и др.).\n\n3) Для картинки можно «Повернуть» (шаг 90°). «Очистить» — убрать превью.\n\n4) Для картинки можно включить «Затемнить сцену»: при показе игроки сначала увидят карту в полной темноте, а вы снимете её с пульта «Кистью Открытия» (см. «Эффекты»).\n\n5) Для картинки доступна кнопка «Редактор сцены» — сетка, ловушки и неигровые токены на карте (см. «Редактор сцены», «Генератор сетки», «Ловушки», «Неигровые токены»).\n\nДля видео включите «Автостарт», если ролик должен сам начаться на экране игроков. На видео-сценах эффекты кистью и редактор сцены недоступны.\n\n«Аудио сцены» — музыка и звуки этого эпизода. «Загрузить» добавляет файлы. У каждого трека: «Авто» (играть при входе в сцену) и «Цикл». Корзина удаляет трек.\n\nСвязи между сценами задаются на карте, а не здесь — см. «Граф сцен».',
|
||
|
||
'help.section.sceneEditor.title': 'Редактор сцены',
|
||
'help.section.sceneEditor.body':
|
||
'«Редактор сцены» — отдельное окно для подготовки карты: сетка боя, ловушки и неигровые токены. Доступен только для сцен с изображением (не с видео).\n\nОткрыть:\n\n1) Выберите сцену в списке слева.\n\n2) В «Свойствах сцены» загрузите картинку, если её ещё нет.\n\n3) Нажмите «Редактор сцены».\n\nСлева — аккордеоны «Сетка», «Неигровые токены» и «Ловушки»; справа — карта сцены.\n\nНавигация по карте: колесо мыши — зум; средняя кнопка мыши или Space+ЛКМ — сдвиг вида. Delete / Backspace убирает выделенный маркер на карте.\n\nПод аккордеонами кнопка «Очистить сцену» убирает с текущей карты все ловушки и токены (пул токенов приложения не трогает).\n\nПодробнее: разделы «Генератор сетки», «Ловушки» и «Неигровые токены».',
|
||
|
||
'help.section.grid.title': 'Генератор сетки',
|
||
'help.section.grid.body':
|
||
'Генератор сетки накладывает на картинку сцены боевую сетку — квадратную или гексагональную. Сетка помогает ориентироваться по клеткам во время боя и видна и вам на пульте, и игрокам на презентации.\n\nНастроить:\n\n1) Откройте «Редактор сцены» для сцены с изображением (см. «Редактор сцены»).\n\n2) Раскройте аккордеон «Сетка» слева.\n\n3) Включите «Наложить сетку» — линии появятся поверх карты.\n\n4) «Тип» — «Квадратная» или «Гексогональная».\n\n5) «Цвет» — оттенок линий (удобно подобрать контраст к карте).\n\n6) «Размер» — ползунок ячейки: чем больше значение, тем крупнее клетки.\n\nПока сетка выключена, тип, цвет и размер недоступны для изменения, но запомненные значения сохраняются и вернутся при повторном включении.\n\nНастройки сетки хранятся в проекте вместе со сценой. На видео-сценах генератор недоступен — только на картинках. Сетка рисуется под маркерами ловушек и токенов и не мешает их расставлять.',
|
||
|
||
'help.section.traps.title': 'Ловушки',
|
||
'help.section.traps.body':
|
||
'Ловушки — маркеры на карте сцены для скрытых угроз и сюрпризов. Расстановка хранится в проекте вместе со сценой; во время игры вы решаете, когда их показать игрокам.\n\nВ редакторе сцены:\n\n1) Откройте «Редактор сцены» для сцены с картинкой (см. «Редактор сцены»).\n\n2) Раскройте аккордеон «Ловушки» слева.\n\n3) Перетащите тип из палитры на нужное место карты.\n\n4) Перетащите маркер, чтобы сдвинуть его; потяните за уголок выделенного маркера — изменить размер.\n\n5) Delete / Backspace — убрать выделенную ловушку. «Очистить сцену» снимает все маркеры сразу.\n\nТипы: Мимик, Взрыв, Яд, Пропасть, Стрела, Лазер и Метка (универсальный маркер без особого эффекта).\n\nВо время сессии:\n\n1) На пульте в «Предпросмотр экрана» видны все ловушки текущей сцены. Пока они скрыты от игроков, маркеры у вас слегка приглушены.\n\n2) На презентации маркеры появляются только после проявления или срабатывания.\n\n3) Правый клик по маркеру на пульте:\n• «Проявить» — показать игрокам без срабатывания.\n• «Активировать» — проявить и запустить эффект: у Мимика, Пропасти, Стрелы и Лазера — анимация и звук; у Яда и Взрыва — как соответствующие эффекты с пульта (облако яда / взрыв); у Метки — короткая вспышка.\n• «Обезвредить» — показать как обезвреженную.\n\nСостояние ловушек (проявлены / сработали / обезврежены) сбрасывается при новом запуске сессии. Сами маркеры на карте остаются.',
|
||
|
||
'help.section.tokens.title': 'Неигровые токены',
|
||
'help.section.tokens.body':
|
||
'Неигровые токены — картинки существ, предметов и маркеров, которые вы ставите на карту сцены. Библиотека токенов хранится в приложении на этом компьютере (не внутри файла проекта). На сцене сохраняется только расстановка: какой токен, где стоит, размер и поворот.\n\nВ редакторе сцены:\n\n1) Откройте «Редактор сцены» для сцены с картинкой (см. «Редактор сцены»).\n\n2) Раскройте «Неигровые токены».\n\n3) «Добавить» — задайте уникальное название и изображение (кнопка выбора или перетаскивание файла).\n\n4) В поиске можно быстро найти токен по имени.\n\n5) Меню «⋮» у плитки — «Изменить» или «Удалить» (с подтверждением). Удаление из пула также убирает этот токен с текущей сцены.\n\n6) Перетащите плитку на карту, чтобы поставить токен. Выделите маркер: перетаскивание — сдвиг, уголок — размер, ручка поворота — угол. Delete / Backspace или ПКМ по маркеру — убрать с карты. «Очистить сцену» снимает все токены и ловушки со сцены.\n\nВо время сессии:\n\n1) На пульте в «Предпросмотр экрана» токены видны сразу (в отличие от ловушек их не нужно проявлять).\n\n2) Перетаскивайте токены левой кнопкой — новая позиция запоминается до конца текущей сессии, в том числе если вы возвращаетесь к сцене через «Сюжетную линию». При новом «Запустить» позиции снова берутся из редактора.\n\n3) На экране презентации токены только отображаются: клики и перетаскивание для игроков недоступны.\n\nПри экспорте и импорте сюжетных линий нужные файлы токенов упаковываются вместе с линией, чтобы на другом компьютере расстановка не «теряла» картинки.',
|
||
|
||
'help.section.campaignAudio.title': 'Аудио игры',
|
||
'help.section.campaignAudio.body':
|
||
'«Аудио игры» в блоке «Свойства игры» — музыка всей кампании: тема, фон, атмосфера. Она не привязана к одной сцене.\n\n1) Нажмите «Загрузить» и выберите файлы.\n\n2) Для каждого трека отметьте «Авто» и «Цикл» по желанию.\n\n3) Удалить трек — иконка корзины.\n\nНа пульте музыка сцены важнее общей: пока играет трек сцены, кампанийная музыка приглушается. Когда у сцены нет своего звука или вы переключитесь вручную — общая музыка снова может играть.',
|
||
|
||
'help.section.materials.title': 'Материалы',
|
||
'help.section.materials.body':
|
||
'Материалы — изображения кампании (карты, записки, чертежи), которые можно показать игрокам поверх сцены во время игры. Они общие для проекта и не привязаны к одной сцене.\n\nВ редакторе:\n\n1) В блоке «Свойства игры» нажмите «Материалы».\n\n2) «Добавить» — укажите уникальное название и изображение (PNG, JPG или WebP): кнопка выбора или перетаскивание файла.\n\n3) В списке можно искать, менять порядок перетаскиванием, править или удалять через меню «⋮» (перед удалением будет подтверждение).\n\n4) Под большим превью — «Повернуть»: поворот на 90° (учитывается и в плитке, и при показе на экране).\n\nВо время сессии:\n\n1) На пульте в «Инструменты» нажмите кнопку материалов (иконка карты сокровищ) — откроется отдельное окно со списком.\n\n2) Клик по плитке показывает материал поверх сцены на пульте и на презентации; повторный клик по той же плитке скрывает его.\n\n3) На предпросмотре пульта материал можно перетаскивать и менять размер за углы; крестик закрывает показ.\n\n4) В окне материалов лупы «+» / «−» — инструменты масштаба: выберите лупу, затем кликните по материалу в предпросмотре пульта.\n\nПри смене сцены показ материала сбрасывается. Описание сцены и эффекты поля с материалами не связаны.',
|
||
|
||
'help.section.npcs.title': 'НПС',
|
||
'help.section.npcs.body':
|
||
'НПС — персонажи кампании с аватаром, описанием и однонаправленными связями между собой. Они общие для проекта и не привязаны к одной сцене.\n\nВ редакторе:\n\n1) В блоке «Свойства игры» нажмите «НПС» — откроется отдельное окно редактора персонажей.\n\n2) «Добавить» — укажите уникальное имя и обязательный аватар (PNG, JPG или WebP): кнопка выбора или перетаскивание файла. При необходимости сразу заполните описание.\n\n3) Слева — список персонажей: поиск, порядок перетаскиванием; меню «⋮» — только удаление (с подтверждением; все связи с этим персонажем тоже удаляются).\n\n4) В центре — граф связей: протяните стрелку от одного персонажа к другому и укажите обязательное название связи. Связь однонаправленная (А → Б и Б → А — разные). Несколько связей в одном направлении рисуются параллельными дугами. Клик по связи или её подписи выбирает исходного персонажа и подсвечивает его исходящие связи.\n\n5) Справа — карточка выбранного персонажа: аватар, имя, описание (форматированный текст) и список «Отношения» — только исходящие связи («название» + имя цели).\n\n6) Правый клик по связи на графе — «Редактировать» название или «Удалить» (с подтверждением).\n\nВо время сессии:\n\n1) На пульте в «Инструменты» рядом с материалами нажмите кнопку НПС (цветная иконка человека) — откроется отдельное окно.\n\n2) Справа — список персонажей; клик по плитке показывает аватар поверх сцены на пульте и на презентации; повторный клик по той же плитке скрывает его. Слева — описание и исходящие отношения выбранного персонажа (их видите только вы).\n\n3) На предпросмотре пульта аватар можно перетаскивать и менять размер за углы; крестик закрывает показ.\n\n4) В окне НПС лупы «+» / «−» — инструменты масштаба: выберите лупу, затем кликните по аватару в предпросмотре пульта.\n\nПри смене сцены показ НПС сбрасывается. Игроки на презентации видят только аватар.',
|
||
|
||
'help.section.session.title': 'Запуск сессии',
|
||
'help.section.session.body':
|
||
'Когда кампания готова, можно начать игру.\n\nОбычный запуск:\n\n1) На карте связей щёлкните правой кнопкой по карточке старта → «Начальная сцена».\n\n2) Нажмите «Запустить» в шапке редактора.\n\nБыстрый запуск с любой карточки: правый клик по нужной карточке на карте → «Запустить с этой сцены». Презентация и пульт откроются сразу с выбранного места.\n\nОткроются «Презентация» (для игроков) и «Пульт управления» (для вас). Редактор на время показа затемняется — так и должно быть.\n\nВернуться к подготовке:\n\n1) На пульте нажмите «Выключить демонстрацию» или «Завершить показ» (если дальше некуда переходить).\n\n2) Дождитесь закрытия обоих окон.\n\nОкно «Презентация» перенесите на второй монитор, проектор или ТВ и разверните на весь экран (F11). Игроки увидят только картинку, видео и эффекты — без ваших кнопок.',
|
||
|
||
'help.section.controlPanel.title': 'Пульт управления',
|
||
'help.section.controlPanel.body':
|
||
'Пульт — ваш стол во время игры. Игроки смотрят на презентацию, вы управляете всем отсюда.\n\nСлева сверху — «Инструменты», затем эффекты и ход сюжета; справа — мини-копия экрана игроков, варианты переходов и музыка.\n\nВ «Инструменты» кнопка с книгой открывает отдельное окно с оформленным описанием текущей сцены. Если описания нет, кнопка неактивна — при наведении подсказка «Описание отсутствует». Кнопка материалов (иконка карты) открывает окно со списком материалов кампании — подробнее в разделе «Материалы». Кнопка НПС (цветная иконка человека) открывает окно персонажей — см. раздел «НПС».\n\n«Предпросмотр экрана» показывает то же, что видят игроки. На сценах с картинкой здесь же рисуют эффекты — они сразу появляются на большом экране. Если на сцене расставлены ловушки, они видны на предпросмотре: правый клик по маркеру — проявить, активировать или обезвредить (см. «Ловушки»). Неигровые токены тоже видны на предпросмотре и их можно двигать до конца сессии (см. «Неигровые токены»).\n\n«Сюжетная линия» — цепочка пройденных эпизодов. Текущая сцена помечена «ТЕКУЩАЯ СЦЕНА». Клик по прошлому шагу переносит партию к тому месту на карте и добавляет новый шаг в историю.\n\n«Выключить демонстрацию» — закончить показ и вернуться в редактор.',
|
||
|
||
'help.section.transitions.title': 'Переходы между сценами',
|
||
'help.section.transitions.body':
|
||
'Куда можно пойти дальше — видно на пульте в «Варианты ветвления». Это исходящие стрелки с текущей карточки на карте.\n\n1) Посмотрите карточки «ОПЦИЯ 1», «ОПЦИЯ 2» — там названия целевых сцен.\n\n2) Нажмите «Переключить» у нужного варианта.\n\n3) На презентации сменятся картинка и музыка, в сюжетной линии появится новый шаг.\n\nЕсли вариантов нет (конец ветки) — «Нет вариантов перехода». Нажмите «Завершить показ», чтобы закрыть окна.\n\nВарианты появляются только там, где вы провели стрелки на карте в редакторе.',
|
||
|
||
'help.section.music.title': 'Музыка на пульте',
|
||
'help.section.music.body':
|
||
'Блок «Музыка» повторяет треки из редактора — отдельно «Музыка сцены» и «Музыка игры».\n\n▶ — воспроизвести, ⏸ — пауза, ⏹ — остановить. «Авто»/«Ручн.» и «Цикл»/«Один раз» показывают, как трек настроен в редакторе.\n\nКлик по полоске прогресса — перемотка (если известна длина). Стрелки ← → на полоске (когда она в фокусе) — на 5 секунд назад или вперёд.\n\nЕсли музыка не стартует сама — один раз нажмите ▶: после вашего действия звук обычно разрешается. Не играет файл — проверьте формат (MP3, WAV и т.п.).',
|
||
|
||
'help.section.effects.title': 'Эффекты поля и действий',
|
||
'help.section.effects.body':
|
||
'Эффекты работают на сценах с картинкой, не на видео. Рисуйте в «Предпросмотр экрана» — игроки увидят то же на презентации.\n\nВыберите инструмент слева:\n• Эффекты поля (туман, дождь, огонь, вода) — зажмите левую кнопку и ведите по карте.\n• Эффекты действий (молния, луч света, заморозка, тьма, облако яда, взрыв) — короткий клик или штрих; у некоторых есть звук.\n\nЕсли у сцены в свойствах включено «Затемнить сцену», появится блок «Управление затемнением» с «Кистью Открытия» 🔦. Водите по предпросмотру — тьма снимается на обоих экранах сразу. У игроков нераскрытое остаётся чёрным, у вас на пульте — полузатемнённым. Уже открытые участки сохраняются, пока идёт показ и вы снова попадаете на ту же карточку сцены на карте. Это не то же самое, что эффект «Тьма» 🌑 в блоке действий.\n\nЛастик 🧹 — для эффектов поля (туман, дождь, огонь, вода) водите кистью, как «Кистью Открытия» для затемнения: стирается только пройденный участок. Эффекты действий (молния, луч и т.д.) убираются целиком при клике или проведении по ним. «Очистить эффекты» — снять всё сразу.\n\n«Радиус кисти» под панелью — чем больше число, тем шире мазок.',
|
||
|
||
'help.section.presentation.title': 'Экран презентации',
|
||
'help.section.presentation.body':
|
||
'«Презентация» — то, что видят игроки: картинка сцены (с учётом поворота из редактора) или видео по вашим настройкам.\n\nЭффекты с пульта накладываются поверх. Меню и кнопки мастера здесь не показываются — клики по карте, ловушкам и токенам для игроков недоступны.\n\nЕсли у сцены включено «Затемнить сцену», игроки сначала видят полностью чёрный экран. Мастер открывает карту «Кистью Открытия» на пульте.\n\nПри смене сцены с пульта картинка обновляется сама. Перенесите окно на экран для игроков и при необходимости спрячьте панель задач.\n\nПустой или тёмный экран — скорее всего, у сцены нет превью. Добавьте картинку в свойствах сцены в редакторе.',
|
||
|
||
'help.section.importExport.title': 'Импорт и экспорт',
|
||
'help.section.importExport.body':
|
||
'Проект хранится как файл .ttrpg.zip — внутри уже все картинки, звуки и настройки.\n\nРезервная копия или перенос на другой ПК:\n\n1) «Проект» → «Экспорт».\n\n2) Выберите проект и куда сохранить.\n\n3) Скопируйте .ttrpg.zip на флешку, в облако или на другой компьютер.\n\nЗагрузить бэкап:\n\n1) «Проект» → «Импорт».\n\n2) Выберите .ttrpg.zip.\n\n3) Проект появится в списке на начальном экране.\n\nПри больших архивах показывается прогресс. Картинки и музыку отдельно переносить не нужно — всё внутри архива.',
|
||
|
||
'help.section.settings.title': 'Настройки, язык и обновления',
|
||
'help.section.settings.body':
|
||
'«Настройки» → «Указать ключ» — ввести или сменить лицензию. «О лицензии» — проверить статус и срок.\n\n«Проверить обновления» (в установленной версии при активной лицензии) — если есть новая версия, можно скачать и перезапустить программу.\n\n«Язык» → «Русский» или «English» — меняет язык интерфейса. Выбор сохраняется между запусками.\n\nНомер версии — в шапке справа от меню. «О приложении» → «О программе» — о продукте и контактах поддержки.',
|
||
|
||
'updates.dialogTitle': 'Обновления',
|
||
'updates.checking': 'Проверка наличия обновлений…',
|
||
'updates.available': 'Доступна новая версия {version}.',
|
||
'updates.current': 'У вас установлена актуальная версия ({version}).',
|
||
'updates.error': 'Не удалось проверить обновления: {message}',
|
||
'updates.notPackaged': 'Проверка доступна только в установленной версии приложения.',
|
||
'updates.noLicense': 'Нужна активная лицензия.',
|
||
'updates.download': 'Обновить',
|
||
'updates.downloading': 'Загрузка…',
|
||
'updates.stageLine': 'Этап: {stage}',
|
||
'updates.stage.checking': 'проверка обновлений',
|
||
'updates.stage.available': 'доступна версия {version}',
|
||
'updates.stage.not-available': 'актуальная версия',
|
||
'updates.stage.downloading': 'загрузка{percent}',
|
||
'updates.stage.installing': 'установка и перезапуск',
|
||
'updates.stage.error': 'ошибка',
|
||
'updates.stagePercent': ' ({percent}%)',
|
||
|
||
'projectMenu.home': 'Начальный экран',
|
||
'projectMenu.import': 'Импорт',
|
||
'projectMenu.importFoundry': 'Импорт из Foundry',
|
||
'projectMenu.export': 'Экспорт',
|
||
'projectMenu.noProjects': 'Нет сохранённых проектов',
|
||
|
||
'foundryImport.title': 'Импорт из Foundry',
|
||
'foundryImport.hint':
|
||
'Выберите папку или архив мира (.world) либо модуля Foundry VTT (версии 11+). Будет создан новый проект.',
|
||
'foundryImport.sourceType': 'ТИП ИСТОЧНИКА',
|
||
'foundryImport.folder': 'Папка',
|
||
'foundryImport.archive': 'Архив (.zip / .fvtt)',
|
||
'foundryImport.source': 'ИСТОЧНИК',
|
||
'foundryImport.chooseFolder': 'Выбрать папку',
|
||
'foundryImport.chooseArchive': 'Выбрать архив',
|
||
'foundryImport.noSourceSelected': 'Не выбрано',
|
||
'foundryImport.import': 'Импортировать',
|
||
|
||
'fileMenu.rename': 'Переименовать проект',
|
||
|
||
'scenes.search': 'Поиск сцен…',
|
||
'scenes.new': '+ Новая сцена',
|
||
'scenes.dropHint': 'Перетащите изображения или видео',
|
||
'scenes.batchTitle': 'Создание сцен',
|
||
'scenes.batchProgress': 'Сцена {current} из {total}',
|
||
'scenes.dropSkippedTitle': 'Часть файлов не добавлена',
|
||
'scenes.dropSkippedIntro': 'Эти файлы пропущены:',
|
||
'scenes.dropSkippedUnsupported': 'неподдерживаемый формат',
|
||
'scenes.dropSkippedNoPath': 'не удалось получить путь к файлу',
|
||
'scenes.inspectorGame': 'Свойства игры',
|
||
'scenes.inspectorScene': 'Свойства сцены',
|
||
'scenes.selectHint': 'Выберите сцену слева, чтобы редактировать её свойства.',
|
||
'scenes.openProjectHint': 'Откройте проект, чтобы редактировать кампанию и сцены.',
|
||
|
||
'rename.title': 'Переименовать проект',
|
||
'rename.projectName': 'НАЗВАНИЕ ПРОЕКТА',
|
||
'rename.projectPlaceholder': 'Название проекта…',
|
||
'rename.projectMin': 'Минимум 3 символа.',
|
||
'rename.projectDup': 'Проект с таким названием уже существует.',
|
||
'rename.fileName': 'НАЗВАНИЕ ФАЙЛА ПРОЕКТА',
|
||
'rename.fileInvalid': 'Минимум 3 символа, без символов <>:"/\\|?*',
|
||
'rename.fileDup': 'Файл проекта с таким названием уже существует.',
|
||
'rename.saving': 'Сохранение…',
|
||
|
||
'export.title': 'Экспорт проекта',
|
||
'export.project': 'ПРОЕКТ',
|
||
'export.hint':
|
||
'Выберите сюжетные линии для экспорта. В архив попадут только выбранные линии, их сцены и материалы. Далее откроется окно сохранения .ttrpg.zip.',
|
||
'export.exporting': 'Экспорт…',
|
||
'export.saveAs': 'Сохранить как…',
|
||
|
||
'storyline.section': 'СЮЖЕТНАЯ ЛИНИЯ',
|
||
'storyline.main': 'Основная линия',
|
||
'storyline.loading': 'Загрузка линий…',
|
||
'storyline.empty': 'В проекте нет сюжетных линий с метками «НАЧАЛО» или «ПОБОЧНАЯ».',
|
||
'storyline.mainExistsHint': 'в проекте уже есть основная линия',
|
||
|
||
'importSource.title': 'Импорт',
|
||
'importSource.type': 'ТИП ИМПОРТА',
|
||
'importSource.fromProject': 'Из проекта',
|
||
'importSource.fromFile': 'Из файла',
|
||
'importSource.project': 'ПРОЕКТ',
|
||
'importSource.file': 'ФАЙЛ',
|
||
'importSource.chooseFile': 'Выбрать файл',
|
||
'importSource.noFileSelected': 'Файл не выбран',
|
||
'importSource.noOtherProjects': 'Нет других проектов для импорта.',
|
||
'importSource.fileOnlyHint': 'Выберите файл проекта (.ttrpg.zip) для полного импорта.',
|
||
|
||
'importStoryline.title': 'Импорт сюжетных линий',
|
||
'importStoryline.source': 'ИСТОЧНИК',
|
||
'importStoryline.continue': 'Далее',
|
||
'importStoryline.import': 'Импортировать',
|
||
'importStoryline.conflictsTitle': 'Совпадение названий сцен',
|
||
'importStoryline.conflictsHint':
|
||
'В импортируемых линиях есть сцены с такими же названиями, как в текущем проекте. Выберите действие для каждой.',
|
||
'importStoryline.createNewScene': 'Создать новую сцену',
|
||
'importStoryline.useExistingScene': 'Использовать «{title}»',
|
||
'importStoryline.reportTitle': 'Импорт завершён',
|
||
'importStoryline.reportLines': 'Импортировано линий: {count}',
|
||
'importStoryline.reportScenesCreated': 'Создано новых сцен: {count}',
|
||
'importStoryline.reportScenesReused': 'Использовано существующих сцен: {count}',
|
||
'importStoryline.reportNpcsCreated': 'Создано новых НПС: {count}',
|
||
'importStoryline.reportNpcsReused': 'Использовано существующих НПС: {count}',
|
||
'importStoryline.reportNodes': 'Добавлено карточек на граф: {count}',
|
||
'importStoryline.reportEdges': 'Добавлено связей: {count}',
|
||
'importStoryline.reportAssetsCopied': 'Скопировано файлов материалов: {count}',
|
||
'importStoryline.reportAssetsReused': 'Повторно использовано материалов: {count}',
|
||
'importStoryline.reportRenamedSides': 'Переименованы побочные линии: {names}',
|
||
'importStoryline.npcConflictsTitle': 'Совпадение имён НПС',
|
||
'importStoryline.npcConflictsHint':
|
||
'В импортируемых линиях есть НПС с такими же именами, как в текущем проекте. Выберите действие для каждого.',
|
||
'importStoryline.createNewNpc': 'Создать нового НПС',
|
||
'importStoryline.useExistingNpc': 'Использовать «{name}»',
|
||
|
||
'confirmDelete.title': 'Удаление проекта',
|
||
'confirmDelete.body': 'Удалить проект «{name}» безвозвратно? Файл и кэш будут стёрты с диска.',
|
||
'confirmDelete.failedTitle': 'Не удалось удалить',
|
||
|
||
'confirmDeleteScene.title': 'Удаление сцены',
|
||
'confirmDeleteScene.body': 'Удалить сцену «{name}»? Её нельзя будет восстановить.',
|
||
|
||
'picker.title': 'Проекты',
|
||
'picker.newPlaceholder': 'Название нового проекта…',
|
||
'picker.create': 'Создать проект',
|
||
'picker.search': 'Поиск кампаний…',
|
||
'picker.searchEmpty': 'Ничего не найдено.',
|
||
'picker.existing': 'СУЩЕСТВУЮЩИЕ',
|
||
'picker.lockedHint':
|
||
'Открытие и создание — после активации лицензии. Список показывает файлы в папке приложения.',
|
||
'picker.empty': 'Пока нет проектов.',
|
||
'picker.projectMenu': 'Меню проекта',
|
||
'picker.openDisabled': 'Открытие проекта — после активации лицензии',
|
||
'picker.opening': 'Открытие…',
|
||
'picker.defaultName': 'Моя кампания',
|
||
|
||
'campaign.label': 'АУДИО ИГРЫ',
|
||
'campaign.noFiles': 'Файлов пока нет. Добавьте аудио.',
|
||
'campaign.auto': 'Авто',
|
||
'campaign.loop': 'Цикл',
|
||
'campaign.removeTitle': 'Убрать из кампании',
|
||
'campaign.upload': 'Загрузить',
|
||
'drop.hintAudio': 'Перетащите аудиофайлы сюда',
|
||
'drop.hintPreview': 'Перетащите изображение или видео',
|
||
|
||
'materials.open': 'Материалы',
|
||
'materials.managerTitle': 'Материалы',
|
||
'materials.add': 'Добавить',
|
||
'materials.addTitle': 'Новый материал',
|
||
'materials.editTitle': 'Изменить материал',
|
||
'materials.savingTitle': 'Сохранение материала',
|
||
'materials.savingWait': 'Подождите…',
|
||
'materials.savingProgress': 'Прогресс сохранения материала',
|
||
'materials.edit': 'Изменить',
|
||
'materials.search': 'Поиск материалов…',
|
||
'materials.searchEmpty': 'Ничего не найдено.',
|
||
'materials.empty': 'Материалов пока нет.',
|
||
'materials.addPrompt': 'Добавьте материал',
|
||
'materials.name': 'НАЗВАНИЕ',
|
||
'materials.namePlaceholder': 'Название материала…',
|
||
'materials.nameRequired': 'Укажите название.',
|
||
'materials.nameDup': 'Материал с таким названием уже есть.',
|
||
'materials.image': 'ИЗОБРАЖЕНИЕ',
|
||
'materials.imageEmpty': 'Изображение не выбрано',
|
||
'materials.imageRequired': 'Выберите изображение.',
|
||
'materials.chooseImage': 'Выбрать изображение',
|
||
'materials.dropHint': 'Перетащите изображение (PNG, JPG, WebP)',
|
||
'materials.tileMenu': 'Меню материала',
|
||
'materials.windowEmpty': 'Добавьте материалы в редакторе.',
|
||
'materials.closeOverlay': 'Закрыть материал',
|
||
'materials.rotateOverlay': 'Повернуть',
|
||
'materials.deleteTitle': 'Удаление материала',
|
||
'materials.deleteConfirm': 'Вы уверены, что хотите удалить материал «{name}»?',
|
||
'materials.zoomIn': 'Увеличить',
|
||
'materials.zoomOut': 'Уменьшить',
|
||
'materials.zoomInHint': 'Кликните по материалу в предпросмотре пульта, чтобы увеличить.',
|
||
'materials.zoomOutHint': 'Кликните по материалу в предпросмотре пульта, чтобы уменьшить.',
|
||
'materials.zoomIdleHint': 'Выберите лупу, затем кликните по материалу в предпросмотре пульта.',
|
||
|
||
'npcs.open': 'НПС',
|
||
'npcs.editorTitle': 'НПС',
|
||
'npcs.add': 'Добавить',
|
||
'npcs.addTitle': 'Новый НПС',
|
||
'npcs.editTitle': 'Изменить НПС',
|
||
'npcs.savingTitle': 'Сохранение НПС',
|
||
'npcs.savingWait': 'Подождите…',
|
||
'npcs.savingProgress': 'Прогресс сохранения НПС',
|
||
'npcs.graphLoading': 'Загрузка графа…',
|
||
'npcs.edit': 'Изменить',
|
||
'npcs.tileMenu': 'Меню НПС',
|
||
'npcs.search': 'Поиск НПС…',
|
||
'npcs.searchEmpty': 'Ничего не найдено.',
|
||
'npcs.empty': 'НПС пока нет.',
|
||
'npcs.selectPrompt': 'Выберите НПС в списке или на графе.',
|
||
'npcs.name': 'ИМЯ',
|
||
'npcs.namePlaceholder': 'Имя персонажа…',
|
||
'npcs.nameRequired': 'Укажите имя.',
|
||
'npcs.nameDup': 'НПС с таким именем уже есть.',
|
||
'npcs.avatar': 'АВАТАР',
|
||
'npcs.avatarEmpty': 'Аватар не выбран',
|
||
'npcs.avatarRequired': 'Выберите аватар.',
|
||
'npcs.chooseAvatar': 'Выбрать аватар',
|
||
'npcs.dropHint': 'Перетащите изображение (PNG, JPG, WebP)',
|
||
'npcs.description': 'ОПИСАНИЕ',
|
||
'npcs.descriptionPlaceholder': 'Описание персонажа…',
|
||
'npcs.descriptionEmpty': 'Описание отсутствует',
|
||
'npcs.relations': 'Отношения',
|
||
'npcs.untitled': 'Без имени',
|
||
'npcs.deleteTitle': 'Удаление НПС',
|
||
'npcs.deleteConfirm': 'Вы уверены, что хотите удалить НПС «{name}»? Все связи с ним будут удалены.',
|
||
'npcs.relationCreateTitle': 'Название связи',
|
||
'npcs.relationEditTitle': 'Название связи',
|
||
'npcs.relationLabel': 'НАЗВАНИЕ',
|
||
'npcs.relationLabelPlaceholder': 'Например: друзья, враги…',
|
||
'npcs.relationLabelRequired': 'Укажите название связи.',
|
||
'npcs.relationEdit': 'Редактировать',
|
||
'npcs.relationDelete': 'Удалить',
|
||
'npcs.relationDeleteTitle': 'Удаление связи',
|
||
'npcs.relationDeleteConfirm': 'Удалить связь «{name}»?',
|
||
'npcs.graphZoomBar': 'Масштаб графа',
|
||
'npcs.graphZoomIn': 'Увеличить',
|
||
'npcs.graphZoomOut': 'Уменьшить',
|
||
'npcs.graphFitAll': 'Показать всё',
|
||
'npcs.windowEmpty': 'Добавьте НПС в редакторе.',
|
||
'npcs.selectToShow': 'Выберите персонажа в списке — он появится на экране.',
|
||
'npcs.closeOverlay': 'Закрыть всех',
|
||
'npcs.rotateOverlay': 'Повернуть',
|
||
'npcs.zoomIn': 'Увеличить',
|
||
'npcs.zoomOut': 'Уменьшить',
|
||
'npcs.zoomInHint': 'Кликните по аватару в предпросмотре пульта, чтобы увеличить.',
|
||
'npcs.zoomOutHint': 'Кликните по аватару в предпросмотре пульта, чтобы уменьшить.',
|
||
'npcs.zoomIdleHint': 'Выберите лупу, затем кликните по аватару в предпросмотре пульта.',
|
||
'npcs.ungrouped': 'Без группы',
|
||
'npcs.addGroup': 'Новая группа',
|
||
'npcs.editGroup': 'Изменить группу',
|
||
'npcs.deleteGroup': 'Удалить группу',
|
||
'npcs.groupName': 'Название группы',
|
||
'npcs.groupColor': 'Цвет',
|
||
'npcs.groupNameRequired': 'Укажите название группы.',
|
||
'npcs.groupNameDup': 'Группа с таким названием уже есть.',
|
||
'npcs.deleteGroupTitle': 'Удаление группы',
|
||
'npcs.deleteGroupConfirm':
|
||
'Удалить группу «{name}»? НПС станут без группы, вложенные группы будут подняты на уровень выше.',
|
||
'npcs.addSubgroup': 'Добавить подгруппу',
|
||
'npcs.group': 'ГРУППА',
|
||
'npcs.bindingEnable': 'Привязать…',
|
||
'npcs.bindingKind': 'ТИП ПРИВЯЗКИ',
|
||
'npcs.bindingStoryline': 'Сюжетная линия',
|
||
'npcs.bindingScene': 'Сцена',
|
||
'npcs.bindingMain': 'Основная линия',
|
||
'npcs.bindingSelect': 'ОБЪЕКТ',
|
||
'npcs.graphFilterAll': 'Все',
|
||
'npcs.graphFilterUngrouped': 'Без группы',
|
||
'npcs.graphFilter': 'Фильтр графа',
|
||
|
||
'scene.title': 'НАЗВАНИЕ СЦЕНЫ',
|
||
'scene.description': 'ОПИСАНИЕ',
|
||
'scene.descriptionEmpty': 'описание отсутствует',
|
||
'scene.descriptionModalTitle': 'Описание сцены',
|
||
'scene.descriptionPlaceholder': 'Введите описание сцены…',
|
||
'scene.descriptionToolbar': 'Форматирование',
|
||
'scene.descriptionBold': 'Жирный',
|
||
'scene.descriptionItalic': 'Курсив',
|
||
'scene.descriptionUnderline': 'Подчёркнутый',
|
||
'scene.descriptionHeading2': 'Заголовок',
|
||
'scene.descriptionHeading3': 'Подзаголовок',
|
||
'scene.descriptionQuote': 'Цитата',
|
||
'scene.descriptionBulletList': 'Маркированный список',
|
||
'scene.descriptionOrderedList': 'Нумерованный список',
|
||
'scene.descriptionLink': 'Ссылка',
|
||
'scene.descriptionLinkPrompt': 'URL ссылки',
|
||
'scene.preview': 'ПРЕВЬЮ СЦЕНЫ',
|
||
'scene.previewHint': 'Файл изображения (PNG, JPG, WebP, GIF и т.д.).',
|
||
'scene.previewEmpty': 'Превью не задано',
|
||
'scene.previewBusy': 'Загрузка и оптимизация изображения…',
|
||
'scene.previewBusySelecting': 'Выберите файл…',
|
||
'scene.previewOptimizing': 'Превью уже доступно. Оптимизируем в фоне…',
|
||
'scene.previewReady': 'Превью готово',
|
||
'scene.previewFailed': 'Превью добавлено, но оптимизация не удалась',
|
||
'scene.change': 'Изменить',
|
||
'scene.clear': 'Очистить',
|
||
'scene.autostart': 'Автостарт',
|
||
'scene.darkenScene': 'Затемнить сцену',
|
||
'scene.rotate': 'Повернуть',
|
||
'scene.audio': 'АУДИО СЦЕНЫ',
|
||
'scene.removeTitle': 'Убрать из сцены',
|
||
'scene.branching': 'ВЕТВЛЕНИЯ',
|
||
'scene.branchingHint':
|
||
'Перетащите сцену из списка на граф. С одной карточки можно задать несколько вариантов — по одной связи на каждую целевую сцену. Повторно к той же сцене (включая вторую карточку той же сцены на графе) подключить нельзя.',
|
||
|
||
'sceneCard.current': 'ТЕКУЩАЯ',
|
||
'sceneCard.menu': 'Меню сцены',
|
||
|
||
'graph.badgeStart': 'НАЧАЛО',
|
||
'graph.badgeSideStory': 'ПОБОЧНАЯ',
|
||
'graph.untitled': 'Без названия',
|
||
'graph.videoBadge': 'Видео',
|
||
'graph.audioBadge': 'Аудио',
|
||
'graph.loop': 'Цикл',
|
||
'graph.autoplay': 'Автостарт',
|
||
'graph.previewAutostart': 'Авто превью',
|
||
'graph.videoLoop': 'Цикл видео',
|
||
'graph.zoomBar': 'Масштаб графа',
|
||
'graph.zoomIn': 'Увеличить',
|
||
'graph.zoomOut': 'Уменьшить',
|
||
'graph.fitAll': 'Показать всё',
|
||
'graph.startScene': 'Начальная сцена',
|
||
'graph.unsetStartScene': 'Снять метку «Начальная сцена»',
|
||
'graph.sideStoryStartScene': 'Начальная сцена побочной линии',
|
||
'graph.unsetSideStoryStartScene': 'Снять метку «Начальная сцена побочной линии»',
|
||
'graph.runFromScene': 'Запустить с этой сцены',
|
||
|
||
'scene.sideStoryLineTitle': 'Название побочной линии',
|
||
|
||
'control.remoteTitle': 'ПУЛЬТ УПРАВЛЕНИЯ',
|
||
'control.instruments': 'ИНСТРУМЕНТЫ',
|
||
'control.descriptionTool': 'Описание',
|
||
'control.materialsTool': 'Материалы',
|
||
'control.npcsTool': 'НПС',
|
||
'control.descriptionMissing': 'Описание отсутствует',
|
||
'control.effects': 'ЭФФЕКТЫ',
|
||
'control.tools': 'Очистка',
|
||
'control.fieldEffects': 'Эффекты поля',
|
||
'control.actionEffects': 'Эффекты действий',
|
||
'control.eraser': 'Ластик',
|
||
'control.clearEffects': 'Очистить эффекты',
|
||
'control.fog': 'Туман',
|
||
'control.rain': 'Дождь',
|
||
'control.fire': 'Огонь',
|
||
'control.water': 'Вода',
|
||
'control.darkness': 'Тьма',
|
||
'control.darknessControl': 'Управление затемнением',
|
||
'control.explorerBrush': 'Кисть Открытия',
|
||
'control.lightning': 'Молния',
|
||
'control.sunbeam': 'Луч света',
|
||
'control.freeze': 'Заморозка',
|
||
'control.poisonCloud': 'Облако яда',
|
||
'control.explosion': 'Взрыв',
|
||
'control.brushRadius': 'Радиус кисти',
|
||
'control.effectsSound': 'Звук эффектов',
|
||
'control.storyLine': 'СЮЖЕТНАЯ ЛИНИЯ',
|
||
'control.gotoScene': 'Перейти к этой сцене',
|
||
'control.currentSceneBadge': 'ТЕКУЩАЯ СЦЕНА',
|
||
'control.passed': 'Пройдено',
|
||
'control.noActiveScene': 'Нет активной сцены.',
|
||
'control.screenPreview': 'Предпросмотр экрана',
|
||
'control.stopPresentation': 'Выключить демонстрацию',
|
||
'control.videoBrushHint':
|
||
'Видео-превью: кисть эффектов отключена (как на экране демонстрации — оверлей только для изображения).',
|
||
'control.branches': 'Варианты ветвления',
|
||
'control.returnToMainStory': 'Вернуться в основной сюжет',
|
||
'control.sideStoryLines': 'Побочные сюжетные линии',
|
||
'control.option': 'ОПЦИЯ {n}',
|
||
'control.unnamed': 'Без названия',
|
||
'control.switchScene': 'Переключить',
|
||
'control.noBranches': 'Нет вариантов перехода.',
|
||
'control.endPresentation': 'Завершить показ',
|
||
'control.music': 'Музыка',
|
||
'control.sceneMusic': 'МУЗЫКА СЦЕНЫ',
|
||
'control.gameMusic': 'МУЗЫКА ИГРЫ',
|
||
'control.noSceneAudio': 'В текущей сцене нет аудио.',
|
||
'control.noGameAudio': 'В игре нет аудио.',
|
||
'control.modeAuto': 'Авто',
|
||
'control.modeManual': 'Ручн.',
|
||
'control.once': 'Один раз',
|
||
'control.loop': 'Цикл',
|
||
'control.scrubSeek': 'Клик — перемотка',
|
||
'control.durationUnknown': 'Длительность неизвестна',
|
||
'control.pauseSceneMusic': 'Пауза (сцена)',
|
||
'control.pauseSceneMusicTitle': 'В сцене есть музыка',
|
||
'control.pauseCampaignTitle': 'Пауза: в сцене есть музыка',
|
||
'control.playFailed': 'Не удалось запустить.',
|
||
'control.audioAutoplayBlocked':
|
||
'Автозапуск заблокирован (нужно действие пользователя) или ошибка воспроизведения.',
|
||
'control.audioNoUrl': 'URL не получен',
|
||
'control.audioNoUrlDetail': 'Не удалось получить dnd://asset URL для аудио.',
|
||
'control.audioBlocked': 'Ошибка/блок',
|
||
'control.audioError': 'Ошибка',
|
||
'control.audioMediaError': 'MediaError code={code} (1=ABORTED, 2=NETWORK, 3=DECODE, 4=SRC_NOT_SUPPORTED)',
|
||
'control.audioLoading': 'Загрузка…',
|
||
'control.audioPlaying': 'Играет',
|
||
'control.audioPaused': 'Пауза',
|
||
'control.audioStopped': 'Остановлено',
|
||
'control.previewTrackLabel': 'Превью без субтитров',
|
||
'control.transportPlay': 'Воспроизведение',
|
||
'control.transportPause': 'Пауза',
|
||
'control.transportStop': 'Стоп',
|
||
'control.volume': 'Громкость',
|
||
},
|
||
en: {
|
||
'common.close': 'Close',
|
||
'common.cancel': 'Cancel',
|
||
'common.save': 'Save',
|
||
'common.saving': 'Saving…',
|
||
'common.edit': 'Edit',
|
||
'common.understood': 'OK',
|
||
'common.message': 'Message',
|
||
'common.error': 'Error',
|
||
'common.delete': 'Delete',
|
||
'common.closeMenu': 'Close menu',
|
||
|
||
'app.brandTitle': 'TTRPG Player',
|
||
|
||
'notice.campaignAudioEmpty': 'No audio was added. Check the file format.',
|
||
|
||
'license.checkingTitle': 'Checking license…',
|
||
'license.checkingWait': 'Please wait.',
|
||
'license.requiredTitle': 'License required',
|
||
'license.requiredHint':
|
||
'Enter your key via Settings → Enter license key. Until activation, only Settings is available.',
|
||
'license.tokenTitle': 'Enter license key',
|
||
'license.tokenKey': 'KEY',
|
||
'license.tokenPlaceholder': 'TTRPG- or DND- product key…',
|
||
'license.tokenSaving': 'Saving…',
|
||
'license.eulaTitle': 'End User License Agreement',
|
||
'license.eulaReject': 'Decline',
|
||
'license.eulaAccept': 'I accept the terms',
|
||
'license.eulaNoteEn':
|
||
'The binding legal text below is in Russian. If you need an English summary, contact support.',
|
||
'license.aboutTitle': 'About license',
|
||
'license.aboutDevSkip': 'Development mode: license checks are disabled (DND_SKIP_LICENSE).',
|
||
'license.aboutStatus': 'STATUS',
|
||
'license.aboutProduct': 'PRODUCT',
|
||
'license.aboutLicenseId': 'LICENSE ID',
|
||
'license.aboutExpiry': 'EXPIRES',
|
||
'license.aboutDevice': 'DEVICE',
|
||
'license.aboutNoData': 'No license data.',
|
||
'license.reason.ok': 'Active',
|
||
'license.reason.none': 'No key provided',
|
||
'license.reason.expired': 'Expired',
|
||
'license.reason.bad_signature': 'Invalid signature',
|
||
'license.reason.bad_payload': 'Invalid token format',
|
||
'license.reason.malformed': 'Malformed token',
|
||
'license.reason.not_yet_valid': 'Not yet valid',
|
||
'license.reason.wrong_device': 'Wrong bound device',
|
||
'license.reason.revoked_remote': 'Revoked on server',
|
||
|
||
'presentation.overlay': 'Presentation running',
|
||
'presentation.title': 'Presentation running',
|
||
'presentation.body': 'The editor is locked. Close the Presentation and Control windows to continue.',
|
||
|
||
'zip.progress': 'Operation progress',
|
||
'zip.importTitle': 'Import project',
|
||
'zip.exportTitle': 'Export project',
|
||
|
||
'top.settings': 'Settings',
|
||
'top.project': 'Project',
|
||
'top.file': 'File',
|
||
'top.backToProjects': 'Back to projects',
|
||
'top.appVersion': 'App version',
|
||
'top.run': 'Run',
|
||
'top.launching': 'Starting…',
|
||
'top.afterLicense': 'Available after license activation',
|
||
'top.setStartScene': 'Set a start scene on the graph (right‑click a node)',
|
||
'top.runHelpAria': 'How to enable the Run button',
|
||
|
||
'menu.enterKey': 'Enter license key',
|
||
'menu.aboutLicense': 'About license',
|
||
'menu.checkUpdates': 'Check for updates',
|
||
'menu.language': 'Language',
|
||
'menu.langRu': 'Русский',
|
||
'menu.langEn': 'English',
|
||
'menu.aboutProgram': 'About',
|
||
'menu.instructions': 'Instructions',
|
||
|
||
'top.aboutApp': 'About',
|
||
|
||
'app.about.title': 'About',
|
||
'app.about.tagline': 'Campaign editor and GM control panel for tabletop RPGs',
|
||
'app.about.description':
|
||
'TTRPG Player is a desktop app for game masters: build your campaign as a scene graph with maps, music and branching paths, then run the session from the control panel. Players see only the presentation on a second screen — no editor panels.',
|
||
'app.about.versionLabel': 'VERSION',
|
||
'app.about.developerLabel': 'DEVELOPER',
|
||
'app.about.developer':
|
||
'Independent development. For licensing, purchase and support questions, use the email below.',
|
||
'app.about.supportLabel': 'SUPPORT',
|
||
'app.about.supportEmail': 'player.ttrpg@gmail.com',
|
||
'app.about.websiteLabel': 'WEBSITE & UPDATES',
|
||
'app.about.websiteUrl': 'https://ttrpgplayer.ru/',
|
||
|
||
'help.title': 'Instructions',
|
||
'help.navAria': 'Instruction sections',
|
||
|
||
'help.section.overview.title': 'App overview',
|
||
'help.section.overview.body':
|
||
'When you launch the app, you land in the Editor — where you prepare your campaign: scenes, images, music, and how episodes connect. When it is time to play, click Run. That opens Presentation for your players and the Control panel for you.\n\nIn the editor, the left column lists scenes, the center shows the story map, and the right column holds game and scene settings.\n\nWhile a session is running, the editor is temporarily locked — that is normal. Close presentation and the control panel to edit again.\n\nInternet is only needed for license activation and update checks. All projects and files stay on your computer.',
|
||
|
||
'help.section.license.title': 'License and first launch',
|
||
'help.section.license.body':
|
||
'Before you can work with projects, activate your license once.\n\n1) Open Settings → Enter license key.\n\n2) If you see the license agreement, read and accept it.\n\n3) Paste the key from your email (TTRPG-… or legacy DND-…) and click Save.\n\nUntil activation succeeds, only Settings is available. After that, projects, scenes, and running a session unlock.\n\nStatus, expiry, and device binding are under Settings → About license. The key is tied to this PC; another computer may need a separate activation per your purchase terms.',
|
||
|
||
'help.section.projects.title': 'Projects',
|
||
'help.section.projects.body':
|
||
'A project is your whole campaign: scenes, media, and connections between them.\n\nCreate a new campaign:\n\n1) On the home screen, type a name in the field on the left.\n\n2) Click Create project.\n\nOpen an existing one — click its name in the list. Return to the list: Project → Home, or click the app title in the header.\n\nMove a campaign to another computer:\n\n1) Project → Export — save a copy as .ttrpg.zip.\n\n2) On the other PC — Project → Import and pick that file.\n\nRename an open project: File → Rename project (at least 3 characters; file names cannot contain <>:"/\\|?*).\n\nTo delete a project from disk:\n\n1) On the project card, click ⋮.\n\n2) In the menu, choose Delete.\n\n3) Confirm deletion in the dialog.\n\nThe project file and cache are then removed permanently. If you might need the campaign again, export a backup first.',
|
||
|
||
'help.section.scenes.title': 'Scenes',
|
||
'help.section.scenes.body':
|
||
'A scene is one episode: a location, story beat, or dialogue. It has a title, an image or video for players, notes for the GM, and its own music.\n\nAdd a scene:\n\n1) In the left column, click + New scene.\n\n2) Set the title and adjust properties on the right (see Scene properties).\n\nSearch scenes… helps you find one quickly. Click a card to select it — it will also highlight on the story map.\n\nDelete: right-click a list card → Delete. The scene disappears from the list and map, including all links.\n\nDrag a scene from the list onto the map to place it as a node (see Scene graph).',
|
||
|
||
'help.section.graph.title': 'Scene graph',
|
||
'help.section.graph.body':
|
||
'The map in the center shows how episodes connect. Each box is a spot on your story; the same scene can appear more than once (for example, players return to the tavern).\n\nPlace a scene on the map:\n\n1) Grab a scene in the left list.\n\n2) Drag it onto empty space on the map.\n\nConnect two scenes:\n\n1) Point at the bottom dot on the first card.\n\n2) Drag a line to the top dot on the second and release — an arrow appears.\n\nOne scene can have several outgoing arrows — that is how you branch the story. You cannot draw a second arrow between the same pair.\n\nRemove an arrow: right-click the line → Delete. A normal click on the line does nothing.\n\nSet where the game starts: right-click a card → Start scene (a START badge appears), then click Run in the header. You can also start from any main-story card: right-click → Start from this scene — presentation and the control panel open at that spot (no START badge required). Side-story cards do not offer this menu item.\n\nRemove a card from the map without deleting the scene from the list: right-click → Delete.\n\nZoom with the buttons at the bottom or the mouse wheel. Fit view shows the whole map.',
|
||
|
||
'help.section.sideStorylines.title': 'Side storylines',
|
||
'help.section.sideStorylines.body':
|
||
'A side storyline is a separate branch not connected to the main plot — for detours, flashbacks, side quests, and scenes off the main path.\n\nCreate one in the editor:\n\n1) Place scenes on the map and link them in an isolated group — it must not touch the main story (purple links) or other side storylines.\n\n2) Right-click the starting card → Side storyline start scene. A blue SIDE badge appears.\n\n3) In scene properties, set Side storyline title — it appears on the control panel.\n\nThe menu item is hidden if the card is already linked to the main story (purple START anywhere in the group) or another side storyline (blue SIDE in the group).\n\nLinks inside a side storyline and card selection use blue (#0078d4). You cannot link main to side, or one side storyline to another.\n\nClear the mark: right-click → Clear side storyline start mark. The title is cleared and the tile disappears from the control panel.\n\nDeleting the start card: if there is a next scene along an arrow, the mark moves to it; otherwise the whole side storyline is removed from the map.\n\nDuring play, Side storylines appears under Music on the control panel — tiles with preview and title. Clicking jumps to the first scene. The app remembers which main-story scene you left from.\n\nWhile in a side storyline, Branch options always lists Return to main story first — back to the remembered scene. Storyline history keeps recording all steps, including inside side branches.\n\nYou cannot launch a side storyline from the editor — only from the control panel during a session.',
|
||
|
||
'help.section.sceneProps.title': 'Scene properties',
|
||
'help.section.sceneProps.body':
|
||
'Select a scene in the left list — its properties open on the right.\n\nScene title is for the GM. Description is GM notes with formatting: click the pencil next to the label to open the editor (bold, italic, headings, lists, links). Below the label you see a text preview, or “no description” when empty. During a session, open the description from the control panel in a separate window (see Control panel) — it is not shown inside the Storyline list.\n\nIf the scene has a graph card with a blue SIDE badge, a Side storyline title field appears.\n\nImage or video for players:\n\n1) Under Scene preview, click Upload or Change.\n\n2) Pick a file (PNG, JPG, WebP, GIF, etc.).\n\n3) For images, use Rotate (90° steps). Clear removes the preview.\n\n4) For images, enable Darken scene so players start in full darkness and you reveal the map with the Opening brush on the control panel (see Effects).\n\n5) For images, Scene editor opens the battle grid, traps, and non-player tokens on the map (see Scene editor, Grid generator, Traps, and Non-player tokens).\n\nFor video, enable Autostart if the clip should start on its own on the player screen. Brush effects and the scene editor are not available on video scenes.\n\nScene audio — music and sounds for this episode. Upload adds files. Per track: Auto (play when entering the scene) and Loop. The trash icon removes a track.\n\nLinks between scenes are drawn on the map, not here — see Scene graph.',
|
||
|
||
'help.section.sceneEditor.title': 'Scene editor',
|
||
'help.section.sceneEditor.body':
|
||
'Scene editor is a separate window for preparing the map: battle grid, traps, and non-player tokens. It is available only for image scenes (not video).\n\nOpen it:\n\n1) Select a scene in the left list.\n\n2) In Scene properties, upload an image if the scene has none yet.\n\n3) Click Scene editor.\n\nOn the left are the Grid, Non-player tokens, and Traps accordions; on the right is the scene map.\n\nMap navigation: mouse wheel zooms; middle mouse button or Space+left-drag pans the view. Delete / Backspace removes the selected marker on the map.\n\nUnder the accordions, Clear scene removes every trap and token from the current map (it does not delete tokens from the app library).\n\nFor details, see Grid generator, Traps, and Non-player tokens.',
|
||
|
||
'help.section.grid.title': 'Grid generator',
|
||
'help.section.grid.body':
|
||
'The grid generator overlays a battle grid on the scene image — square or hexagonal. It helps track cells in combat and is visible both on your control panel and on the players’ presentation.\n\nSet it up:\n\n1) Open Scene editor for an image scene (see Scene editor).\n\n2) Expand the Grid accordion on the left.\n\n3) Enable Overlay grid — lines appear over the map.\n\n4) Type — Square or Hexagonal.\n\n5) Color — line tint (pick contrast that suits the map).\n\n6) Size — cell size slider: higher values mean larger cells.\n\nWhile the grid is off, type, color, and size stay disabled, but the saved values return when you turn it back on.\n\nGrid settings are stored with the scene in the project. The generator is not available on video scenes — only on images. The grid draws under trap and token markers and does not block placing them.',
|
||
|
||
'help.section.traps.title': 'Traps',
|
||
'help.section.traps.body':
|
||
'Traps are markers on the scene map for hidden threats and surprises. Placement is stored with the scene in the project; during play you decide when players see them.\n\nIn the scene editor:\n\n1) Open Scene editor for an image scene (see Scene editor).\n\n2) Expand the Traps accordion on the left.\n\n3) Drag a type from the palette onto the map.\n\n4) Drag a marker to move it; drag the corner handle of the selected marker to resize.\n\n5) Delete / Backspace removes the selected trap. Clear scene removes all markers at once.\n\nTypes: Mimic, Explosion, Poison, Pit, Arrow, Laser, and Marker (a generic marker without a special effect).\n\nDuring a session:\n\n1) On the control panel Screen preview you see every trap on the current scene. While still hidden from players, markers look slightly muted on your side.\n\n2) On presentation, markers appear only after reveal or activation.\n\n3) Right-click a marker on the control panel:\n• Reveal — show it to players without triggering.\n• Activate — reveal and play the effect: Mimic, Pit, Arrow, and Laser play animation and sound; Poison and Explosion use the matching control-panel effects (poison cloud / explosion); Marker shows a short flash.\n• Disarm — show it as disarmed.\n\nTrap runtime state (revealed / triggered / disarmed) resets when you start a new session. Markers placed on the map remain.',
|
||
|
||
'help.section.tokens.title': 'Non-player tokens',
|
||
'help.section.tokens.body':
|
||
'Non-player tokens are images of creatures, props, and markers you place on the scene map. The token library lives in the app on this computer (not inside the project file). The scene only stores placements: which token, where it stands, size, and rotation.\n\nIn the scene editor:\n\n1) Open Scene editor for an image scene (see Scene editor).\n\n2) Expand Non-player tokens.\n\n3) Add — enter a unique name and an image (choose file or drop one).\n\n4) Use search to find a token by name.\n\n5) The ⋮ menu on a tile opens Edit or Delete (with confirmation). Deleting from the library also removes that token from the current scene.\n\n6) Drag a tile onto the map to place it. Select a marker: drag to move, corner handle to resize, rotate handle to turn. Delete / Backspace or right-click the marker removes it from the map. Clear scene removes all tokens and traps from the scene.\n\nDuring a session:\n\n1) On the control panel Screen preview, tokens are visible right away (unlike traps, they do not need revealing).\n\n2) Drag tokens with the left button — the new position is kept until the current session ends, including when you return to the scene via Storyline. A new Run resets positions to what you set in the editor.\n\n3) On the presentation screen tokens are display-only: players cannot click or drag them.\n\nWhen you export or import storylines, the needed token files are packed with the line so placements keep their images on another computer.',
|
||
|
||
'help.section.campaignAudio.title': 'Game audio',
|
||
'help.section.campaignAudio.body':
|
||
'Game audio under Game properties is music for the whole campaign: theme, ambience, background. It is not tied to one scene.\n\n1) Click Upload and choose files.\n\n2) Set Auto and Loop per track as you like.\n\n3) Remove a track with the trash icon.\n\nOn the control panel, scene music comes first: while a scene track plays, campaign music pauses. When the scene has no track or you take manual control, campaign music can play again.',
|
||
|
||
'help.section.materials.title': 'Materials',
|
||
'help.section.materials.body':
|
||
'Materials are campaign images (maps, notes, sketches) you can show players on top of the scene during play. They belong to the project and are not tied to one scene.\n\nIn the editor:\n\n1) Under Game properties, click Materials.\n\n2) Add — enter a unique name and an image (PNG, JPG, or WebP) via Choose image or by dropping a file.\n\n3) In the list you can search, reorder by drag-and-drop, and edit or delete via the ⋮ menu (delete asks for confirmation).\n\n4) Under the large preview, Rotate turns the image by 90° (applied in the tile and when shown on screen).\n\nDuring a session:\n\n1) On the control panel under Tools, click the materials button (treasure-map icon) to open a separate window with the list.\n\n2) Click a tile to show the material over the scene on the control preview and presentation; click the same tile again to hide it.\n\n3) On the control preview you can drag the material and resize it from the corners; the × button closes the overlay.\n\n4) In the materials window, the + / − magnifiers are zoom tools: pick one, then click the material on the control preview.\n\nChanging scenes clears the material overlay. Scene description and field effects are separate from materials.',
|
||
|
||
'help.section.npcs.title': 'NPCs',
|
||
'help.section.npcs.body':
|
||
'NPCs are campaign characters with an avatar, description, and one-way relations between them. They belong to the project and are not tied to one scene.\n\nIn the editor:\n\n1) Under Game properties, click NPCs — a separate character editor window opens.\n\n2) Add — enter a unique name and a required avatar (PNG, JPG, or WebP) via Choose avatar or by dropping a file. You can fill in the description right away if you want.\n\n3) Left: character list with search and drag reorder; the ⋮ menu is delete only (with confirmation; all relations involving that character are removed too).\n\n4) Center: relationship graph — drag an arrow from one character to another and enter a required relation name. Relations are one-way (A → B and B → A are different). Multiple relations in the same direction are drawn as parallel curves. Click a relation or its label to select the source character and highlight their outgoing links.\n\n5) Right: the selected character’s card — avatar, name, description (rich text), and a Relations list of outgoing links only (“name” + target name).\n\n6) Right-click a relation on the graph to Edit the name or Delete (with confirmation).\n\nDuring a session:\n\n1) On the control panel under Tools, next to materials, click the NPCs button (colored person icon) to open a separate window.\n\n2) Right: character list; click a tile to show the avatar over the scene on the control preview and presentation; click the same tile again to hide it. Left: description and outgoing relations for the selected character (visible only to you).\n\n3) On the control preview you can drag the avatar and resize it from the corners; the × button closes the overlay.\n\n4) In the NPCs window, the + / − magnifiers are zoom tools: pick one, then click the avatar on the control preview.\n\nChanging scenes clears the NPC overlay. Players on presentation see only the avatar.',
|
||
|
||
'help.section.session.title': 'Starting a session',
|
||
'help.section.session.body':
|
||
'When your campaign is ready, you can start playing.\n\nStandard start:\n\n1) On the story map, right-click the starting card → Start scene.\n\n2) Click Run in the editor header.\n\nQuick start from any card: right-click the card on the map → Start from this scene. Presentation and the control panel open at that spot right away.\n\nPresentation (for players) and the Control panel (for you) open. The editor dims while the show runs — that is expected.\n\nReturn to prep:\n\n1) On the control panel, click Stop presentation or End presentation (when there is nowhere left to go).\n\n2) Wait until both windows close.\n\nMove the Presentation window to a second monitor, projector, or TV and go fullscreen (F11). Players see only the image, video, and effects — not your buttons.',
|
||
|
||
'help.section.controlPanel.title': 'Control panel',
|
||
'help.section.controlPanel.body':
|
||
'The control panel is your desk during play. Players watch presentation; you run everything from here.\n\nTop-left: Tools, then effects and storyline. On the right: a mini copy of the player screen, branch options, and music.\n\nUnder Tools, the book button opens a separate window with the current scene’s formatted description. If there is no description, the button is disabled — the tooltip reads “No description”. The materials button (map icon) opens a window with the campaign materials list — see the Materials section for details. The NPCs button (colored person icon) opens the characters window — see the NPCs section.\n\nScreen preview shows what players see. On image scenes, paint effects here — they appear on the big screen right away. If the scene has traps, they appear on the preview: right-click a marker to reveal, activate, or disarm (see Traps). Non-player tokens are also visible on the preview and can be moved until the session ends (see Non-player tokens).\n\nStoryline lists episodes you have visited. The current scene is marked CURRENT SCENE. Click an earlier step to move the party back to that spot and add a new history entry.\n\nStop presentation ends the show and unlocks the editor.',
|
||
|
||
'help.section.transitions.title': 'Scene transitions',
|
||
'help.section.transitions.body':
|
||
'Where you can go next appears under Branch options on the control panel. These are outgoing arrows from the current card on the map.\n\n1) Read the OPTION 1, OPTION 2 cards — they show target scene names.\n\n2) Click Switch on the choice you want.\n\n3) Presentation updates image and music; storyline adds a new step.\n\nIf there are no options (end of a branch), you will see No transitions available. Click End presentation to close the show windows.\n\nOptions only exist where you drew arrows on the map in the editor.',
|
||
|
||
'help.section.music.title': 'Music on the control panel',
|
||
'help.section.music.body':
|
||
'The Music section mirrors what you set in the editor — Scene music and Game music separately.\n\n▶ play, ⏸ pause, ⏹ stop. Auto/Manual and Loop/Once show how each track was configured in the editor.\n\nClick the progress bar to seek (when duration is known). ← → on the bar (when focused) skip 5 seconds back or forward.\n\nIf music does not start on its own, press ▶ once — after your click, sound is usually allowed. If a file still will not play, check the format (MP3, WAV, etc.).',
|
||
|
||
'help.section.effects.title': 'Field and action effects',
|
||
'help.section.effects.body':
|
||
'Effects work on image scenes, not video. Paint in Screen preview — players see the same on presentation.\n\nPick a tool on the left:\n• Field effects (fog, rain, fire, water) — hold the left button and brush on the map.\n• Action effects (lightning, sunbeam, freeze, darkness, poison cloud, explosion) — click or short stroke; some include sound.\n\nIf Darken scene is enabled in scene properties, a Darkness control section appears with the Opening brush 🔦. Brush on the preview to clear darkness on both screens at once. Unrevealed areas stay fully black for players and half-dark on your preview. Revealed areas are remembered while the show runs and you return to the same graph card. This is not the same as the Darkness 🌑 action effect.\n\nEraser 🧹 — for field effects (fog, rain, fire, water), brush like the Opening brush for darkness: only the stroke area is erased. Action effects (lightning, sunbeam, etc.) are removed whole when you click or drag over them. Clear effects removes everything at once.\n\nBrush radius under the panel — higher values mean a wider stroke.',
|
||
|
||
'help.section.presentation.title': 'Presentation screen',
|
||
'help.section.presentation.body':
|
||
'Presentation is what players see: the scene image (with rotation from the editor) or video according to your settings.\n\nEffects from the control panel draw on top. There are no GM menus or buttons here — players cannot click the map, traps, or tokens.\n\nIf Darken scene is enabled, players first see a fully black screen. The GM reveals the map with the Opening brush on the control panel.\n\nWhen you switch scenes from the control panel, the image updates automatically. Move the window to the display players watch and hide the taskbar if needed.\n\nA blank or dark screen usually means the scene has no preview — add one in scene properties in the editor.',
|
||
|
||
'help.section.importExport.title': 'Import and export',
|
||
'help.section.importExport.body':
|
||
'A project is stored as a .ttrpg.zip file — images, sounds, and settings are already inside.\n\nBackup or move to another PC:\n\n1) Project → Export.\n\n2) Choose the project and where to save.\n\n3) Copy the .ttrpg.zip to a USB drive, cloud, or another computer.\n\nLoad a backup:\n\n1) Project → Import.\n\n2) Select the .ttrpg.zip.\n\n3) The project appears on the home screen.\n\nLarge archives show a progress bar. You do not need to move images and music separately — everything is in the archive.',
|
||
|
||
'help.section.settings.title': 'Settings, language and updates',
|
||
'help.section.settings.body':
|
||
'Settings → Enter license key — add or change your license. About license — check status and expiry.\n\nCheck for updates (installed app with active license) — if a new version exists, you can download and restart.\n\nLanguage → Русский or English changes the interface. Your choice is saved between launches.\n\nThe version number is in the header, right of the menus. About → About opens product info and support contacts.',
|
||
|
||
'updates.dialogTitle': 'Updates',
|
||
'updates.checking': 'Checking for updates…',
|
||
'updates.available': 'A new version is available: {version}.',
|
||
'updates.current': 'You have the latest version ({version}).',
|
||
'updates.error': 'Could not check for updates: {message}',
|
||
'updates.notPackaged': 'Updates can only be checked in the installed application.',
|
||
'updates.noLicense': 'An active license is required.',
|
||
'updates.download': 'Update',
|
||
'updates.downloading': 'Downloading…',
|
||
'updates.stageLine': 'Stage: {stage}',
|
||
'updates.stage.checking': 'checking for updates',
|
||
'updates.stage.available': 'version {version} available',
|
||
'updates.stage.not-available': 'up to date',
|
||
'updates.stage.downloading': 'downloading{percent}',
|
||
'updates.stage.installing': 'installing and restarting',
|
||
'updates.stage.error': 'error',
|
||
'updates.stagePercent': ' ({percent}%)',
|
||
|
||
'projectMenu.home': 'Home',
|
||
'projectMenu.import': 'Import',
|
||
'projectMenu.importFoundry': 'Import from Foundry',
|
||
'projectMenu.export': 'Export',
|
||
'projectMenu.noProjects': 'No saved projects',
|
||
|
||
'foundryImport.title': 'Import from Foundry',
|
||
'foundryImport.hint':
|
||
'Choose a Foundry VTT world or module folder or archive (version 11+). A new project will be created.',
|
||
'foundryImport.sourceType': 'SOURCE TYPE',
|
||
'foundryImport.folder': 'Folder',
|
||
'foundryImport.archive': 'Archive (.zip / .fvtt)',
|
||
'foundryImport.source': 'SOURCE',
|
||
'foundryImport.chooseFolder': 'Choose folder',
|
||
'foundryImport.chooseArchive': 'Choose archive',
|
||
'foundryImport.noSourceSelected': 'Nothing selected',
|
||
'foundryImport.import': 'Import',
|
||
|
||
'fileMenu.rename': 'Rename project',
|
||
|
||
'scenes.search': 'Search scenes…',
|
||
'scenes.new': '+ New scene',
|
||
'scenes.dropHint': 'Drop images or videos',
|
||
'scenes.batchTitle': 'Creating scenes',
|
||
'scenes.batchProgress': 'Scene {current} of {total}',
|
||
'scenes.dropSkippedTitle': 'Some files were not added',
|
||
'scenes.dropSkippedIntro': 'These files were skipped:',
|
||
'scenes.dropSkippedUnsupported': 'unsupported format',
|
||
'scenes.dropSkippedNoPath': 'could not resolve file path',
|
||
'scenes.inspectorGame': 'Game properties',
|
||
'scenes.inspectorScene': 'Scene properties',
|
||
'scenes.selectHint': 'Select a scene on the left to edit its properties.',
|
||
'scenes.openProjectHint': 'Open a project to edit the campaign and scenes.',
|
||
|
||
'rename.title': 'Rename project',
|
||
'rename.projectName': 'PROJECT NAME',
|
||
'rename.projectPlaceholder': 'Project name…',
|
||
'rename.projectMin': 'At least 3 characters.',
|
||
'rename.projectDup': 'A project with this name already exists.',
|
||
'rename.fileName': 'PROJECT FILE NAME',
|
||
'rename.fileInvalid': 'At least 3 characters; forbidden characters <>:"/\\|?*',
|
||
'rename.fileDup': 'A project file with this name already exists.',
|
||
'rename.saving': 'Saving…',
|
||
|
||
'export.title': 'Export project',
|
||
'export.project': 'PROJECT',
|
||
'export.hint':
|
||
'Select storylines to export. The archive will include only the chosen lines, their scenes, and assets. Then choose where to save the .ttrpg.zip file.',
|
||
'export.exporting': 'Exporting…',
|
||
'export.saveAs': 'Save as…',
|
||
|
||
'storyline.section': 'STORYLINE',
|
||
'storyline.main': 'Main storyline',
|
||
'storyline.loading': 'Loading storylines…',
|
||
'storyline.empty': 'This project has no storylines marked with START or SIDE badges.',
|
||
'storyline.mainExistsHint': 'main storyline already exists in this project',
|
||
|
||
'importSource.title': 'Import',
|
||
'importSource.type': 'IMPORT TYPE',
|
||
'importSource.fromProject': 'From project',
|
||
'importSource.fromFile': 'From file',
|
||
'importSource.project': 'PROJECT',
|
||
'importSource.file': 'FILE',
|
||
'importSource.chooseFile': 'Choose file',
|
||
'importSource.noFileSelected': 'No file selected',
|
||
'importSource.noOtherProjects': 'No other projects available to import from.',
|
||
'importSource.fileOnlyHint': 'Choose a project file (.ttrpg.zip) for a full import.',
|
||
|
||
'importStoryline.title': 'Import storylines',
|
||
'importStoryline.source': 'SOURCE',
|
||
'importStoryline.continue': 'Continue',
|
||
'importStoryline.import': 'Import',
|
||
'importStoryline.conflictsTitle': 'Duplicate scene titles',
|
||
'importStoryline.conflictsHint':
|
||
'Imported storylines contain scenes with the same titles as in the current project. Choose what to do for each.',
|
||
'importStoryline.createNewScene': 'Create new scene',
|
||
'importStoryline.useExistingScene': 'Use existing «{title}»',
|
||
'importStoryline.reportTitle': 'Import complete',
|
||
'importStoryline.reportLines': 'Storylines imported: {count}',
|
||
'importStoryline.reportScenesCreated': 'New scenes created: {count}',
|
||
'importStoryline.reportScenesReused': 'Existing scenes reused: {count}',
|
||
'importStoryline.reportNpcsCreated': 'New NPCs created: {count}',
|
||
'importStoryline.reportNpcsReused': 'Existing NPCs reused: {count}',
|
||
'importStoryline.reportNodes': 'Graph cards added: {count}',
|
||
'importStoryline.reportEdges': 'Connections added: {count}',
|
||
'importStoryline.reportAssetsCopied': 'Asset files copied: {count}',
|
||
'importStoryline.reportAssetsReused': 'Assets reused: {count}',
|
||
'importStoryline.reportRenamedSides': 'Renamed side storylines: {names}',
|
||
'importStoryline.npcConflictsTitle': 'Duplicate NPC names',
|
||
'importStoryline.npcConflictsHint':
|
||
'Imported storylines contain NPCs with the same names as in the current project. Choose what to do for each.',
|
||
'importStoryline.createNewNpc': 'Create new NPC',
|
||
'importStoryline.useExistingNpc': 'Use existing «{name}»',
|
||
|
||
'confirmDelete.title': 'Delete project',
|
||
'confirmDelete.body':
|
||
'Permanently delete project “{name}”? The file and cache will be removed from disk.',
|
||
'confirmDelete.failedTitle': 'Could not delete',
|
||
|
||
'confirmDeleteScene.title': 'Delete scene',
|
||
'confirmDeleteScene.body': 'Delete scene “{name}”? This cannot be undone.',
|
||
|
||
'picker.title': 'Projects',
|
||
'picker.newPlaceholder': 'New project name…',
|
||
'picker.create': 'Create project',
|
||
'picker.search': 'Search campaigns…',
|
||
'picker.searchEmpty': 'No matches.',
|
||
'picker.existing': 'EXISTING',
|
||
'picker.lockedHint':
|
||
'Opening and creating projects require an active license. The list still shows files in the app folder.',
|
||
'picker.empty': 'No projects yet.',
|
||
'picker.projectMenu': 'Project menu',
|
||
'picker.openDisabled': 'Open project — after license activation',
|
||
'picker.opening': 'Opening…',
|
||
'picker.defaultName': 'My campaign',
|
||
|
||
'campaign.label': 'GAME AUDIO',
|
||
'campaign.noFiles': 'No files yet. Add audio.',
|
||
'campaign.auto': 'Auto',
|
||
'campaign.loop': 'Loop',
|
||
'campaign.removeTitle': 'Remove from campaign',
|
||
'campaign.upload': 'Upload',
|
||
'drop.hintAudio': 'Drop audio files here',
|
||
'drop.hintPreview': 'Drop an image or video',
|
||
|
||
'materials.open': 'Materials',
|
||
'materials.managerTitle': 'Materials',
|
||
'materials.add': 'Add',
|
||
'materials.addTitle': 'New material',
|
||
'materials.editTitle': 'Edit material',
|
||
'materials.savingTitle': 'Saving material',
|
||
'materials.savingWait': 'Please wait…',
|
||
'materials.savingProgress': 'Material save progress',
|
||
'materials.edit': 'Edit',
|
||
'materials.search': 'Search materials…',
|
||
'materials.searchEmpty': 'No matches.',
|
||
'materials.empty': 'No materials yet.',
|
||
'materials.addPrompt': 'Add a material',
|
||
'materials.name': 'NAME',
|
||
'materials.namePlaceholder': 'Material name…',
|
||
'materials.nameRequired': 'Name is required.',
|
||
'materials.nameDup': 'A material with this name already exists.',
|
||
'materials.image': 'IMAGE',
|
||
'materials.imageEmpty': 'No image selected',
|
||
'materials.imageRequired': 'Choose an image.',
|
||
'materials.chooseImage': 'Choose image',
|
||
'materials.dropHint': 'Drop an image (PNG, JPG, WebP)',
|
||
'materials.tileMenu': 'Material menu',
|
||
'materials.windowEmpty': 'Add materials in the editor.',
|
||
'materials.closeOverlay': 'Close material',
|
||
'materials.rotateOverlay': 'Rotate',
|
||
'materials.deleteTitle': 'Delete material',
|
||
'materials.deleteConfirm': 'Are you sure you want to delete material “{name}”?',
|
||
'materials.zoomIn': 'Zoom in',
|
||
'materials.zoomOut': 'Zoom out',
|
||
'materials.zoomInHint': 'Click the material on the control preview to zoom in.',
|
||
'materials.zoomOutHint': 'Click the material on the control preview to zoom out.',
|
||
'materials.zoomIdleHint': 'Pick a magnifier, then click the material on the control preview.',
|
||
|
||
'npcs.open': 'NPCs',
|
||
'npcs.editorTitle': 'NPCs',
|
||
'npcs.add': 'Add',
|
||
'npcs.addTitle': 'New NPC',
|
||
'npcs.editTitle': 'Edit NPC',
|
||
'npcs.savingTitle': 'Saving NPC',
|
||
'npcs.savingWait': 'Please wait…',
|
||
'npcs.savingProgress': 'NPC save progress',
|
||
'npcs.graphLoading': 'Loading graph…',
|
||
'npcs.edit': 'Edit',
|
||
'npcs.tileMenu': 'NPC menu',
|
||
'npcs.search': 'Search NPCs…',
|
||
'npcs.searchEmpty': 'No matches.',
|
||
'npcs.empty': 'No NPCs yet.',
|
||
'npcs.selectPrompt': 'Select an NPC in the list or on the graph.',
|
||
'npcs.name': 'NAME',
|
||
'npcs.namePlaceholder': 'Character name…',
|
||
'npcs.nameRequired': 'Name is required.',
|
||
'npcs.nameDup': 'An NPC with this name already exists.',
|
||
'npcs.avatar': 'AVATAR',
|
||
'npcs.avatarEmpty': 'No avatar selected',
|
||
'npcs.avatarRequired': 'Choose an avatar.',
|
||
'npcs.chooseAvatar': 'Choose avatar',
|
||
'npcs.dropHint': 'Drop an image (PNG, JPG, WebP)',
|
||
'npcs.description': 'DESCRIPTION',
|
||
'npcs.descriptionPlaceholder': 'Character description…',
|
||
'npcs.descriptionEmpty': 'No description',
|
||
'npcs.relations': 'Relations',
|
||
'npcs.untitled': 'Untitled',
|
||
'npcs.deleteTitle': 'Delete NPC',
|
||
'npcs.deleteConfirm': 'Are you sure you want to delete NPC “{name}”? All of their relations will be removed.',
|
||
'npcs.relationCreateTitle': 'Relation name',
|
||
'npcs.relationEditTitle': 'Relation name',
|
||
'npcs.relationLabel': 'NAME',
|
||
'npcs.relationLabelPlaceholder': 'e.g. friends, rivals…',
|
||
'npcs.relationLabelRequired': 'Relation name is required.',
|
||
'npcs.relationEdit': 'Edit',
|
||
'npcs.relationDelete': 'Delete',
|
||
'npcs.relationDeleteTitle': 'Delete relation',
|
||
'npcs.relationDeleteConfirm': 'Delete relation “{name}”?',
|
||
'npcs.graphZoomBar': 'Graph zoom',
|
||
'npcs.graphZoomIn': 'Zoom in',
|
||
'npcs.graphZoomOut': 'Zoom out',
|
||
'npcs.graphFitAll': 'Fit view',
|
||
'npcs.windowEmpty': 'Add NPCs in the editor.',
|
||
'npcs.selectToShow': 'Select a character in the list — they will appear on screen.',
|
||
'npcs.closeOverlay': 'Close all',
|
||
'npcs.rotateOverlay': 'Rotate',
|
||
'npcs.zoomIn': 'Zoom in',
|
||
'npcs.zoomOut': 'Zoom out',
|
||
'npcs.zoomInHint': 'Click the avatar on the control preview to zoom in.',
|
||
'npcs.zoomOutHint': 'Click the avatar on the control preview to zoom out.',
|
||
'npcs.zoomIdleHint': 'Pick a magnifier, then click the avatar on the control preview.',
|
||
'npcs.ungrouped': 'Ungrouped',
|
||
'npcs.addGroup': 'New group',
|
||
'npcs.editGroup': 'Edit group',
|
||
'npcs.deleteGroup': 'Delete group',
|
||
'npcs.groupName': 'Group name',
|
||
'npcs.groupColor': 'Color',
|
||
'npcs.groupNameRequired': 'Group name is required.',
|
||
'npcs.groupNameDup': 'A group with this name already exists.',
|
||
'npcs.deleteGroupTitle': 'Delete group',
|
||
'npcs.deleteGroupConfirm':
|
||
'Delete group “{name}”? NPCs will become ungrouped; child groups will move up one level.',
|
||
'npcs.addSubgroup': 'Add subgroup',
|
||
'npcs.group': 'GROUP',
|
||
'npcs.bindingEnable': 'Bind…',
|
||
'npcs.bindingKind': 'BINDING TYPE',
|
||
'npcs.bindingStoryline': 'Storyline',
|
||
'npcs.bindingScene': 'Scene',
|
||
'npcs.bindingMain': 'Main storyline',
|
||
'npcs.bindingSelect': 'TARGET',
|
||
'npcs.graphFilterAll': 'All',
|
||
'npcs.graphFilterUngrouped': 'Ungrouped',
|
||
'npcs.graphFilter': 'Graph filter',
|
||
|
||
'scene.title': 'SCENE TITLE',
|
||
'scene.description': 'DESCRIPTION',
|
||
'scene.descriptionEmpty': 'no description',
|
||
'scene.descriptionModalTitle': 'Scene description',
|
||
'scene.descriptionPlaceholder': 'Enter scene description…',
|
||
'scene.descriptionToolbar': 'Formatting',
|
||
'scene.descriptionBold': 'Bold',
|
||
'scene.descriptionItalic': 'Italic',
|
||
'scene.descriptionUnderline': 'Underline',
|
||
'scene.descriptionHeading2': 'Heading',
|
||
'scene.descriptionHeading3': 'Subheading',
|
||
'scene.descriptionQuote': 'Quote',
|
||
'scene.descriptionBulletList': 'Bullet list',
|
||
'scene.descriptionOrderedList': 'Numbered list',
|
||
'scene.descriptionLink': 'Link',
|
||
'scene.descriptionLinkPrompt': 'Link URL',
|
||
'scene.preview': 'SCENE PREVIEW',
|
||
'scene.previewHint': 'Image file (PNG, JPG, WebP, GIF, etc.).',
|
||
'scene.previewEmpty': 'No preview',
|
||
'scene.previewBusy': 'Loading and optimizing image…',
|
||
'scene.previewBusySelecting': 'Choose a file…',
|
||
'scene.previewOptimizing': 'Preview is ready. Optimizing in the background…',
|
||
'scene.previewReady': 'Preview is ready',
|
||
'scene.previewFailed': 'Preview was added, but optimization failed',
|
||
'scene.change': 'Change',
|
||
'scene.clear': 'Clear',
|
||
'scene.autostart': 'Autostart',
|
||
'scene.darkenScene': 'Darken scene',
|
||
'scene.rotate': 'Rotate',
|
||
'scene.audio': 'SCENE AUDIO',
|
||
'scene.sideStoryLineTitle': 'Side storyline title',
|
||
'scene.removeTitle': 'Remove from scene',
|
||
'scene.branching': 'BRANCHING',
|
||
'scene.branchingHint':
|
||
'Drag a scene from the list onto the graph. One card can branch to several targets — one link per target scene. You cannot link twice to the same target (including a second card of the same scene).',
|
||
|
||
'sceneCard.current': 'CURRENT',
|
||
'sceneCard.menu': 'Scene menu',
|
||
|
||
'graph.badgeStart': 'START',
|
||
'graph.badgeSideStory': 'SIDE',
|
||
'graph.untitled': 'Untitled',
|
||
'graph.videoBadge': 'Video',
|
||
'graph.audioBadge': 'Audio',
|
||
'graph.loop': 'Loop',
|
||
'graph.autoplay': 'Autoplay',
|
||
'graph.previewAutostart': 'Preview autostart',
|
||
'graph.videoLoop': 'Video loop',
|
||
'graph.zoomBar': 'Graph zoom',
|
||
'graph.zoomIn': 'Zoom in',
|
||
'graph.zoomOut': 'Zoom out',
|
||
'graph.fitAll': 'Fit view',
|
||
'graph.startScene': 'Start scene',
|
||
'graph.unsetStartScene': 'Clear start scene mark',
|
||
'graph.sideStoryStartScene': 'Side storyline start scene',
|
||
'graph.unsetSideStoryStartScene': 'Clear side storyline start mark',
|
||
'graph.runFromScene': 'Start from this scene',
|
||
|
||
'control.remoteTitle': 'CONTROL PANEL',
|
||
'control.instruments': 'TOOLS',
|
||
'control.descriptionTool': 'Description',
|
||
'control.materialsTool': 'Materials',
|
||
'control.npcsTool': 'NPCs',
|
||
'control.descriptionMissing': 'No description',
|
||
'control.effects': 'EFFECTS',
|
||
'control.tools': 'Cleanup',
|
||
'control.fieldEffects': 'Field effects',
|
||
'control.actionEffects': 'Action effects',
|
||
'control.eraser': 'Eraser',
|
||
'control.clearEffects': 'Clear effects',
|
||
'control.fog': 'Fog',
|
||
'control.rain': 'Rain',
|
||
'control.fire': 'Fire',
|
||
'control.water': 'Water',
|
||
'control.darkness': 'Darkness',
|
||
'control.darknessControl': 'Darkness control',
|
||
'control.explorerBrush': 'Opening brush',
|
||
'control.lightning': 'Lightning',
|
||
'control.sunbeam': 'Sunbeam',
|
||
'control.freeze': 'Freeze',
|
||
'control.poisonCloud': 'Poison cloud',
|
||
'control.explosion': 'Explosion',
|
||
'control.brushRadius': 'Brush radius',
|
||
'control.effectsSound': 'Effects sound',
|
||
'control.storyLine': 'STORYLINE',
|
||
'control.gotoScene': 'Go to this scene',
|
||
'control.currentSceneBadge': 'CURRENT SCENE',
|
||
'control.passed': 'Visited',
|
||
'control.noActiveScene': 'No active scene.',
|
||
'control.screenPreview': 'Screen preview',
|
||
'control.stopPresentation': 'Stop presentation',
|
||
'control.videoBrushHint':
|
||
'Video preview: effect brush is disabled (like on the presentation screen — overlay is for images only).',
|
||
'control.branches': 'Branch options',
|
||
'control.returnToMainStory': 'Return to main story',
|
||
'control.sideStoryLines': 'Side storylines',
|
||
'control.option': 'OPTION {n}',
|
||
'control.unnamed': 'Untitled',
|
||
'control.switchScene': 'Switch',
|
||
'control.noBranches': 'No transitions available.',
|
||
'control.endPresentation': 'End presentation',
|
||
'control.music': 'Music',
|
||
'control.sceneMusic': 'SCENE MUSIC',
|
||
'control.gameMusic': 'GAME MUSIC',
|
||
'control.noSceneAudio': 'No audio in the current scene.',
|
||
'control.noGameAudio': 'No game audio.',
|
||
'control.modeAuto': 'Auto',
|
||
'control.modeManual': 'Manual',
|
||
'control.once': 'Once',
|
||
'control.loop': 'Loop',
|
||
'control.scrubSeek': 'Click to seek',
|
||
'control.durationUnknown': 'Duration unknown',
|
||
'control.pauseSceneMusic': 'Paused (scene)',
|
||
'control.pauseSceneMusicTitle': 'Scene has music',
|
||
'control.pauseCampaignTitle': 'Paused: scene has music',
|
||
'control.playFailed': 'Could not start playback.',
|
||
'control.audioAutoplayBlocked': 'Autoplay was blocked (user gesture required) or playback failed.',
|
||
'control.audioNoUrl': 'No URL',
|
||
'control.audioNoUrlDetail': 'Could not get dnd://asset URL for audio.',
|
||
'control.audioBlocked': 'Error / blocked',
|
||
'control.audioError': 'Error',
|
||
'control.audioMediaError': 'MediaError code={code} (1=ABORTED, 2=NETWORK, 3=DECODE, 4=SRC_NOT_SUPPORTED)',
|
||
'control.audioLoading': 'Loading…',
|
||
'control.audioPlaying': 'Playing',
|
||
'control.audioPaused': 'Paused',
|
||
'control.audioStopped': 'Stopped',
|
||
'control.previewTrackLabel': 'Preview (no captions)',
|
||
'control.transportPlay': 'Play',
|
||
'control.transportPause': 'Pause',
|
||
'control.transportStop': 'Stop',
|
||
'control.volume': 'Volume',
|
||
},
|
||
};
|
||
|
||
export function translateEditorMessage(
|
||
locale: EditorLocale,
|
||
key: string,
|
||
vars?: Record<string, string | number>,
|
||
): string {
|
||
let s = EDITOR_MESSAGES[locale][key] ?? EDITOR_MESSAGES.ru[key] ?? key;
|
||
if (vars) {
|
||
for (const [k, v] of Object.entries(vars)) {
|
||
s = s.split(`{${k}}`).join(String(v));
|
||
}
|
||
}
|
||
return s;
|
||
}
|