Документация Nyxtale

Платформа NyxtaleЯзык Nyx

Синтаксис

Полная грамматика .nsx: заголовок, реплики, выборы, метки, ветвления, директивы.

.nsx — построчный формат. Одна строка — одна мысль; вложенность задаётся отступом. Пустые строки игнорируются.

Строк всего четыре вида, и каждый узнаётся по первому символу:

Сигил Что это Пример
@ инструкция движку @bg forest_night
(нет) реплика — то, что читают Марк: Кто здесь?
* опция выбора * choice "Войти"
-> переход -> inside

Сигилов четыре, а не один, чтобы сцена листалась как рукопись, а не разбиралась как конфиг. Реплика — самая частая строка в истории — не носит никакого сигила вообще: проза выглядит прозой.

Заголовок

@nsx_version 1
@scene doorway
@render horror + creepypasta
движок принял

Реплики

narrator: Тишина стояла такая, что было слышно лампу.
Марк: Кто здесь?
{hero}: Я вернулся.
движок принял line×3

Говорящий — это отображаемый текст, а не идентификатор: Марк, Смотритель, любые буквы любого алфавита. narrator — обычное имя говорящего, просто читатель рисует его без плашки.

{hero} — подстановка флага в имя: имя персонажа подставится на лету. То же работает и в тексте реплики.

Эмоцию можно указать в скобках — читатель получает её отдельным полем:

mark (fear): Здесь кто-то был.
движок принял line

Идентификатор эмоции — только латиницей. Марк (страх): сейчас не разбирается, хотя имя говорящего кириллицей работает. Это ограничение парсера, а не решение формата.

Комментарии

// в начале строки или после директивы — комментарий до конца строки; /* … */ — блочный, можно на несколько строк. Внутри реплики оба знака литеральны: проза есть проза, и движок не имеет права съесть половину предложения за то, что автор поставил в нём слэш.

// заметка себе: здесь потом добавить звук
@bg hall_night // фон выбран нарочно тусклым
/* этот кусок пока отложен —
   вернуться к нему после главы 3 */
narrator: Он ушёл; она осталась стоять.
движок принял lineeffect

Точка с запятой комментарием не является — это была ранняя версия языка, и её сняли ровно потому, что ; слишком часто встречается в живой фразе.

Выбор

* choice "Войти" @if has_key == 1
    @set trespassed = 1
    narrator: Дверь поддалась.
    -> inside
* choice "Постучать" @timer 8
    -> knock
* choice "Заплатить сторожу" @cost 5 candles
    -> bribe
движок принял linesetchoicejump×3

Слово choice обязательно, текст — в кавычках. Идущие подряд * choice на одном отступе — один узел выбора с несколькими опциями. Тело опции — её отступ.

Модификаторы в шапке опции:

Модификатор Что делает
@if <выражение> опция видна, только если выражение истинно
@cost <N> <валюта> опция платная
@timer <секунды> на выбор ставится таймер

@timer считает секунды, не миллисекунды.

Выборы вкладываются: тело опции может содержать свой * choice.

Переходы и метки

@label inside
narrator: Внутри было теплее, чем снаружи. Это и пугало.
-> hall
движок принял linejump

@label <имя> — адрес. -> <цель> или @jump <цель> — переход к нему. Метки не видны читателю.

Условия

Строкой — когда нужно просто увести:

@if fear > 5 -> panic
@unless has_key == 1 -> locked_out
движок принял branch×2jump×2

Блоком — когда под условием несколько действий:

@if fear > 5
    @heartbeat 110
    narrator: Руки не слушались.
    -> panic
движок принял lineeffectbranchjump

@unless — то же самое с отрицанием.

Флаги

@set fear = 0
@set fear += 2
@set fear -= 1
@set name = 0
движок принял set×4

Операторы — =, +=, -=. Флаг нужно задать до того, как его прочитают: если найдётся путь, на котором чтение случается раньше записи, валидатор скажет об этом кодом NSX_READ_BEFORE_WRITE.

Выражения

Приоритет от низкого к высокому:

or  <  and  <  not  <  сравнения (== != < <= > >=)  <  + -  <  * / %  <  унарный -  <  primary

and, or, not пишутся и как &&, ||, ! — одно и то же.

Primary — целое число, true / false, флаг, скобки или функция: rand, min, max, clamp, abs.

@set roll = 0
@set roll = rand(1, 6)
@set roll = clamp(roll, 1, 5)
@if roll > 3 and fear < 10 -> steady
движок принял branchset×3jump

Арифметика только целочисленная. Деление отбрасывает дробь в сторону нуля, деление на ноль даёт 0. Это не упрощение: превью в браузере, движок на телефоне и повтор по сохранению обязаны сойтись бит в бит, иначе превью ведёт автора в одну концовку, а игрока — в другую.

rand() детерминирован: он ходит от rng_seed, который лежит в состоянии и в сохранении. Одно и то же прохождение всегда даёт один и тот же бросок.

Директивы

Всё, что начинается с @ и не перечислено выше, — директива-эффект:

@bg forest_night
@ambient wind_howl loop
@jumpscare shadow_figure @sound stinger_01
@sanity_show
движок принял effect×4

Аргументы позиционные; именованные пишутся как @подфлаг значение. Ассеты — по идентификатору.

Все 94 директивы с типами аргументов и границами — в справочнике. Он собран из реестра движка, поэтому не может отстать от него.

Концовки

@end trespass
движок принял end

@end [имя] завершает сцену. Имя необязательно, но именованная концовка — это то, что читатель «нашёл», и то, что движок считает при обходе.

Что проверяется

Компилятор ловит синтаксис, пока вы печатаете. Валидатор ловит целостность: битые ссылки, недостижимые узлы, тупики, ловушки-циклы, необъявленные флаги, чтение до записи, отсутствующие ассеты, лицензию без атрибуции.

Коды и починки — в справочнике диагностик.

Директивы этой темы

Собрано из реестра движка: каждая директива этих категорий ведёт сюда из справочника.

  • @autoadvance Авто-адванс vs тап — темп чтения
  • @font Смена гарнитуры (serif/mono/sans)
  • @instant Мгновенный вывод реплики
  • @lineheight Межстрочный ритм (дыхание строк)
  • @redact Редакция: [ДАННЫЕ УДАЛЕНЫ]
  • @shout Крик — крупный резкий текст
  • @stagger Стаггер: слова проступают по одному
  • @text_corrupt Порча текста — буквы искажаются
  • @text_erase Самостирающийся текст
  • @text_fade Проявление/растворение строки
  • @text_shake Дрожь текста — нестабильная реплика
  • @textsize Размер текста — уровень 1–6
  • @textspeed Скорость печати текста
  • @thought Мысль персонажа — бабл рядом с ним
  • @unredact Снять редакцию — раскрыть скрытый текст
  • @whisper Шёпот — мелкий тусклый текст