Перейти к содержимому

Датасеты

Если вы делаете что-то поверх наших датасетов — редактор, импортёр, конвертер из своего формата, ИИ-генератор контента — начните отсюда. Страница самодостаточна: всё, что нужно, либо здесь, либо по публичному URL.

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

Внутри всё устроено на грантах: сущность не имеет полей «навыки» и «бонусы», она имеет массив типизированных грантов — «дай владение навыком», «дай +1 к Ловкости», «предложи выбрать один из…». Словарь грантов закрыт — 26 типов. Вы не пишете DSL и не исполняете чужой код, вы наполняете типизированный JSON.

Статические файлы, забираются curl’ом без ключей и регистрации.

Артефакт URL
Схема всего датасета https://longstoryshort.app/schema/v1/wizard-dataset.json
Схемы по сущностям …/schema/v1/dataset-{class,subclass,race,subrace,background,feat}.json
Схема гранта …/schema/v1/grant.json
SRD 5.1 https://longstoryshort.app/datasets/srd-2014.json (~204 KB)
SRD 5.2 https://longstoryshort.app/datasets/srd-2024.json (~269 KB)

JSON Schema — draft-07. Схема генерируется из тех же исходников, по которым работает приложение, и включает description на каждом типе гранта: она же и есть справочник по полям, отдельной таблицы полей нет и не нужно.

SRD-наборы — не игрушечные примеры: это ровно те данные, на которых работает продакшен. Вместе — 24 класса и 24 подкласса на 20 уровней, 18 видов с линиями, черты, счётчики, развилки снаряжения.

Правите JSON руками — одна строка даёт автокомплит и подсветку ошибок в VS Code, JetBrains и любом редакторе с поддержкой JSON Schema:

{
"$schema": "https://longstoryshort.app/schema/v1/wizard-dataset.json",
"id": "my-homebrew",
"name": "Мой хоумбрю",
"system": "dnd_5",
"edition": "2024",
"author": "Вы",
"license": "CC-BY-4.0",
"races": []
}

Пишете код — валидируйте чем угодно:

const validate = new Ajv().compile(await (await fetch(SCHEMA_URL)).json());
if (!validate(dataset)) console.error(validate.errors);

Хотите понять формат — откройте srd-2024.json и найдите варвара.

26 типов, дискриминация по полю type. Точные поля каждого — в grant.json.

Канал Типы
Владения skill-fixed, skill-choice, expertise-choice, tool-fixed, tool-choice, language-fixed, language-choice, armor-prof, weapon-prof, saving-throw
Числа bonus, asi-fixed, asi-flexible, asi-pool, hp-die, speed, size
Контент trait, resource, spellcasting, feat
Снаряжение equipment-fixed, equipment-choice, gold, gold-dice
Развилка pick-one

pick-one вкладывает гранты в свои options — обходя датасет, рекурсируйте внутрь, иначе половина контента пройдёт мимо вашей валидации.

bonus бьёт по таргету. Схема содержит закрытый enum допустимых таргетов — в нём только те, которые лист реально читает. Всё остальное отклоняется наравне с опечаткой, и это то поведение, которое вам нужно: бонус на неподдержанный таргет так же невидим, как prof.skill.stelth. Открытые семейства, где ключ приходит из данных персонажа (weapon.<любое>.attack), выражены через pattern и проходят.

Схема проверяет форму, а не смысл. Валидный по схеме датасет всё ещё может молча ничего не делать — потому что оставшиеся правила межполевые и межсущностные, а JSON Schema так не умеет.

Схема поймает Схема НЕ поймает
Опечатку в имени поля или лишнее поле Всё из таблицы ниже
Неизвестный тип гранта
Опечатку в таргете бонуса или ключе навыка
Таргет, который лист не читает
Отсутствие обязательного поля, неверный тип значения

Проверки, которые надо сделать самим. Ровно этот список гоняет наш импортёр; error блокирует импорт, warning пускает — но почти каждый warning означает «грант записан и не сделает ничего»:

Проверка Что ломается
bonus несёт ровно одно из value | expr error
expr-формула вычисляется error
Ключи навыков, характеристик, брони и оружия — из известных error
Грант выбора предлагает хотя бы один слот (count > 0) error
id уникален внутри коллекции error
classId / raceId / featId ведёт в существующую сущность error
Именованный pick-one лежит там, где его вообще раскрывают error
resource несёт ровно одно из max | maxExpr; формулы вычисляются error
Лицензия — из белого списка (см. «Жёсткие правила») error
trait несёт params и прозу — текст потеряется, канал не тот warning
Формула броска у trait парсится warning
pairId счётчика указывает на существующую черту (или явный null) warning
Счётчик стоит там, где его никто не читает warning
Тип гранта реален, но канала-потребителя у него нет warning
Открытый фит-слот, под который нет ни одного кандидата warning

Ссылки между наборами легальны. Хоумбрю-книга подклассов вправе ссылаться classId на SRD-класс, которого в ней самой нет. Ваш валидатор должен резолвить ссылки не только внутри проверяемого файла, но и по всем подключённым наборам, иначе пометит битой каждую такую ссылку.

Готового пакета с этими проверками мы пока не отдаём — реализуйте у себя.

id сущности — внешний ключ, а не название. По нему резолвятся ссылки и привязываются выборы игрока. Переименовали id в опубликованном наборе — сломали чужие листы. Слаг английского названия, один раз и навсегда.

Лицензия обязательна и проверяется. Пустое поле отклоняет импорт так же, как неподходящее. Проходят только CC0, CC-BY и CC-BY-SA с версией (CC-BY-4.0, не CC-BY). OGL, MIT, свободный текст, любые NC/ND-варианты — нет. Это касается и вашего собственного оригинального контента.

Правка датасета ретроактивно меняет уже собранных персонажей. Поле version есть, но импорт его не читает, и защиты с нашей стороны пока нет. Ваше разделение «черновик / опубликовано» — единственный барьер. v1 в URL схемы — про версию формата, не про версию контента.

Публиковать датасет пока некуда. Реестра сообщества нет; подключение идёт через импорт JSON-файла.

Тексты черт лежат в description у trait-гранта. Это единственный канал; файлы самодостаточные, скачали — и у вас полный набор с текстами. Авторьте так же.

Часть черт намеренно без текста — в 2024 таких 21 идентификатор, все ссылки на заклинания (spell-misty-step, cantrip-fire-bolt и подобные): их name и есть вся полезная информация. Не считайте это пробелом и не «чините» при конвертации.

Перед публикацией оба набора прогоняются всеми проверками из раздела выше, и при любой находке файл не выкладывается — так что как эталон им можно доверять.

Валидатор в своём пайплайне. Самое дешёвое и самое полезное: схема — в CI, проверки из раздела выше — рядом.

Визуальный редактор. Схема даёт формы и типы полей почти даром. Но enum таргетов — не украшение: никогда не давайте автору вводить таргет строкой, стройте пикер из списка в схеме.

Генерация датасетов моделью. Артефакты складываются в связку:

  1. По-сущностные схемы — не для удобства, а по необходимости. Полная схема — union из 26 вариантов с вложенностью в несколько уровней; для structured output это плохо. Генерируйте один класс за вызов против dataset-class.json — дешевле и заметно надёжнее.
  2. SRD как few-shot. Модель учится формату на примерах существенно лучше, чем на схеме, а у вас их 24 класса и 18 видов — эталонных, не выдуманных.
  3. Схема закрывает пространство выбора. Закрытый enum таргетов против свободной строки — это разница между «модель попадает» и «модель придумывает prof.skill.stelth».
  4. Проверки замыкают цикл. Сгенерировали → провалидировали → прогнали проверки → вернули сообщение в модель → перегенерировали. Без четвёртого шага вы получите датасеты, которые проходят валидацию и молча не работают.

Конвертер из своего формата. SRD-наборы — ваш golden file: гоняйте конвертацию в обратную сторону и сверяйтесь.