Imported from JHamidun/claude-code-config-pack (
.claude/skills/romance-novel-pipeline/SKILL.md). Install upstream withnpx skills add JHamidun/claude-code-config-pack --skill romance-novel-pipeline. Copyright stays with the author.
Romance Novel Pipeline — конвейер жанрового романа
Методология длинной художественной формы (150-200k знаков) с иллюстрациями. Решает три болезни ИИ-прозы на дистанции: персонаж плывёт (глаза меняли цвет трижды), стиль скатывается в рубленые фразы и тире, факты мира противоречат сами себе.
Лечится не «пиши лучше», а конструкцией: сначала канон (Bible), потом посценный план, и только потом текст — каждая глава проверяется против канона автоматически.
Что понадобится
| Нужно | Платно? | Где взять |
|---|---|---|
| Модель для текста | по подписке | она у тебя уже есть |
| Иллюстрации | да, по расходу | навык image-generation (Gemini Image по GOOGLE_API_KEY — ключ бесплатно в Google AI Studio, генерация тарифицируется за картинку). 25-30 иллюстраций на книгу — считай бюджет заранее |
Сборка .docx |
нет | pip install python-docx; либо PDF через навык pdf, либо конвертация навыком file-converter |
Отдельной команды-запускалки у навыка нет: опиши задачу словами («собери библию персонажей для мафия-романса про X»), фазы идут по порядку ниже.
Когда использовать
- Создание полноценного романа (150-200k знаков)
- Dark Romance / Mafia Romance / Forbidden Romance и смежные жанры
- Книги с иллюстрациями
Нон-фикшн — не сюда: там источники важнее сюжета, см. book-post.
5-фазный пайплайн
ФАЗА 1: BIBLE (канон)
Создать файл {book_name}_bible.md. Это единственный источник истины: всё, чего в нём нет,
в тексте появляться не должно.
# BIBLE: {Название книги}
## ПЕРСОНАЖИ
### Главная героиня
- **Имя:** полное имя (как называют друзья, как называет герой)
- **Возраст:** точный
- **Внешность:** цвет волос, глаз, рост, телосложение, особые приметы
- **Характер:** 3-5 ключевых черт
- **Бэкграунд:** семья, образование, работа, травмы
- **Цель:** чего хочет
- **Страх:** чего боится
- **Секрет:** что скрывает
### Главный герой
[Аналогично]
### Антагонист
[Аналогично]
### Второстепенные персонажи
[Краткое описание каждого]
## ОТНОШЕНИЯ
- Героиня → Герой: как относится, как меняется
- Герой → Героиня: как относится, как меняется
- Герой ↔ Антагонист: история конфликта
## ЛОКАЦИИ
- Основная локация: детальное описание
- Дополнительные локации
## ТАЙМЛАЙН
- Когда происходит действие
- Сколько длится история
- Ключевые даты
## ФАКТЫ И ПРАВИЛА МИРА
- Криминальная структура
- Правила организации
- Важные детали мира
## ТЕРМИНОЛОГИЯ
- Как герои называют друг друга
- Специфические термины
ФАЗА 2: SYNOPSIS (посценный план)
Создать файл {book_name}_synopsis.md:
# SYNOPSIS: {Название книги}
## СТРУКТУРА: 18 глав (~9000 знаков каждая)
### АКТ 1: Завязка (главы 1-6)
**Цель акта:** знакомство, первый конфликт, искра между героями
#### Глава 1: {Название}
- **POV:** от кого
- **Локация:** где
- **Время:** когда
- **События:**
1. Конкретное событие 1
2. Конкретное событие 2
3. ...
- **Эмоциональная дуга:** от какого состояния к какому
- **Крючок в конце:** чем заканчивается
[Аналогично для каждой главы]
### АКТ 2: Развитие (главы 7-12)
**Цель акта:** сближение, раскрытие секретов, нарастание угрозы
### АКТ 3: Кульминация (главы 13-18)
**Цель акта:** кризис, разлука, воссоединение, HEA
ФАЗА 3: WRITING + VALIDATION
Правила написания:
- Длина главы: 8000-10000 знаков
- POV: первое лицо (героиня), одна глава от героя (15 или 16)
- Темп: чередовать action/reflection
- Диалоги: 30-40% текста
СТОП-СЛОВА (избегать):
- "—" (тире) в начале абзацев → заменить на нормальные предложения
- Короткие рубленые фразы подряд → объединять в сложные
- "Он/Она" в начале каждого предложения → варьировать
- Клише: "сердце замерло", "дыхание перехватило" → 1 раз на главу максимум
- Повторение слов в соседних предложениях
Валидация после каждой главы. Скрипт даёт только механическую часть (стиль и упоминания); смысловые противоречия с каноном по-прежнему ловит читающий агент — но пусть он ловит их на пяти сомнительных местах, а не на всей главе.
# validate_chapter.py — stdlib only, запускать после каждой главы
import re
# Короткое = 6 слов и меньше. Порог подобран под русскую прозу: ниже него
# фраза почти всегда «рубленая», выше — уже нормальное простое предложение.
SHORT_WORDS = 6
CLICHES = ["сердце замерло", "дыхание перехватило", "по спине пробежал холодок",
"воздух стал густым", "время остановилось"]
def split_sentences(text: str) -> list[str]:
"""Грубая нарезка на предложения. Точность здесь не нужна — нужен стабильный счётчик."""
parts = re.split(r'(?<=[.!?…])\s+', text.replace('\n', ' '))
return [p.strip() for p in parts if p.strip()]
def count_sentences(text: str) -> int:
return len(split_sentences(text))
def count_short_sentences(text: str, max_words: int = SHORT_WORDS) -> int:
return sum(1 for s in split_sentences(text) if len(s.split()) <= max_words)
def unknown_proper_nouns(text: str, bible_text: str) -> list[str]:
"""Слова с заглавной НЕ в начале предложения — почти всегда имена и топонимы.
Два фильтра, оба обязательны, оба проверены на живом тексте:
- первое слово предложения пропускаем, иначе в отчёт попадёт каждое «Она» и «Нет»;
- слово после тире тоже пропускаем — в диалоге тире открывает реплику, то есть
это опять начало фразы. Без второго фильтра в романе с 40% диалогов шум
возвращается почти полностью."""
found = set()
for s in split_sentences(text):
words = s.split()
prev = None
for i, raw in enumerate(words):
w = raw.strip('«»""\'(),.!?:;—-')
starts_phrase = (i == 0) or (prev in ('—', '–', '-'))
if not starts_phrase and re.fullmatch(r'[А-ЯЁ][а-яё]{2,}', w) and w not in bible_text:
found.add(w)
prev = raw
return sorted(found)
def validate_chapter(chapter_text: str, bible_text: str, characters: list[str]) -> list[str]:
errors = []
# 1. Имена: персонаж, которого нет в Bible, — это выдуманный на ходу персонаж
mentioned = {n for n in characters if n in chapter_text}
if not mentioned:
errors.append("В главе не упомянут ни один персонаж из Bible — проверь имена")
unknown = unknown_proper_nouns(chapter_text, bible_text)
if unknown:
errors.append("Имена/топонимы вне Bible: " + ", ".join(unknown)
+ " (либо внеси в канон, либо убери)")
# 2. Стиль: тире в начале абзацев
dash_starts = sum(1 for ln in chapter_text.split('\n') if ln.lstrip().startswith('—'))
if dash_starts > 10:
errors.append(f"Слишком много абзацев, начатых с тире: {dash_starts}")
# 3. Стиль: доля рубленых фраз
total = count_sentences(chapter_text)
short = count_short_sentences(chapter_text)
if total and short / total > 0.30:
errors.append(f"Слишком много коротких предложений: {short}/{total} ({short / total:.0%})")
# 4. Клише
for c in CLICHES:
n = chapter_text.lower().count(c)
if n > 1:
errors.append(f"Клише «{c}» повторено {n} раз (норма — 1 на главу)")
# 5. Объём
if not 8000 <= len(chapter_text) <= 10000:
errors.append(f"Объём главы {len(chapter_text)} знаков вне коридора 8000-10000")
return errors
if __name__ == "__main__":
import sys
chapter = open(sys.argv[1], encoding="utf-8").read()
bible = open(sys.argv[2], encoding="utf-8").read()
names = sys.argv[3:] # имена персонажей из Bible
problems = validate_chapter(chapter, bible, names)
print("OK" if not problems else "\n".join("- " + p for p in problems))
Дубль по именам собственным даст ложные срабатывания на топонимах и марках — это осознанно: дешевле один раз внести «Милан» в Bible, чем на 14-й главе обнаружить город, которого в романе не было.
ФАЗА 4: STYLISTIC POLISH
Автоматические исправления:
-
Тире → предложения
- "— Да. — Нет." → "Да, — ответила она. — Нет."
-
Рубленые фразы → сложные
- "Он встал. Подошёл к окну. Закурил." → "Он встал и, подойдя к окну, закурил."
-
Повторы → синонимы
- Использовать тезаурус для замены повторяющихся слов
-
Ритм:
- Короткие предложения для напряжения
- Длинные для описаний и размышлений
- Чередование!
Для общей чистки от ИИ-почерка есть отдельные навыки: de-ai-ify (клише и штампы) и
ru-text (канцелярит и типографика). Художественный текст ими правь выборочно —
они настроены на нон-фикшн и могут срезать намеренную стилизацию.
ФАЗА 5: FORMATTING + ILLUSTRATIONS
Документ:
- Обложка
- Титульная страница
- Аннотация
- Содержание (опционально)
- Главы с иллюстрациями
- «КОНЕЦ»
Сборка: python-docx для .docx, навык pdf — для PDF, навык file-converter —
если исходник в markdown и нужен другой формат.
Иллюстрации (25-30 штук) — через навык image-generation:
- Обложка: герои вместе, атмосфера жанра
- По 1-2 на главу: ключевые сцены
- Консистентность персонажей держится на том, что описание берётся дословно из Bible, одним и тем же блоком текста в каждом промпте. Перефразировал — получил другого человека.
Промпт-шаблон:
Generate image: [описание сцены].
[ГЕРОИНЯ_DESC]: [детальное описание из Bible — копировать дословно]
[ГЕРОЙ_DESC]: [детальное описание из Bible — копировать дословно]
Style: cinematic photorealistic, dramatic lighting, movie poster quality,
8K, ultra detailed, professional photography, dark moody atmosphere,
romantic thriller aesthetic
Структура файлов
Корень выбираешь сам — например ./novels/ в рабочем каталоге или ~/novels/.
novels/
└── {book_name}/
├── {book_name}_bible.md
├── {book_name}_synopsis.md
├── {book_name}_part1.txt
├── {book_name}_part2.txt
├── {book_name}_part3.txt
├── {book_name}_full.txt
├── images/
│ ├── 00_cover.jpg
│ ├── 01_scene.jpg
│ └── ...
└── {book_name}_final.docx
Чеклист качества
- Bible заполнена полностью
- Synopsis содержит все главы с деталями
- Каждая глава 8000-10000 знаков
-
validate_chapter.pyпо каждой главе отдал OK - Стилистическая полировка (тире < 10 на главу)
- Общий объём 150000-180000 знаков
- Иллюстрации сгенерированы и встроены
- Документ собран
Примеры жанровых особенностей
Mafia Romance
- Герой: глава клана/синдиката
- Конфликт: враждующие семьи или внутреннее предательство
- Danger + Possession
Forbidden Romance
- Запретные отношения (разница в статусе/возрасте/положении)
- Guilt + Desire
- Секретность
Bodyguard Romance
- Она защищает его (или наоборот)
- Профессионализм vs Чувства
- Proximity + Danger