Навыки для Claude Code. Клик — раскрыть документацию. Копировать — добавить себе.
Generate natural-sounding Russian narration audio for scientific trail POIs using Sber Salute Speech API with SSML markup for pauses, emphasis, and prosody control.
Before generating audio, the build script checks Salute Speech credentials:
SALUTE_AUTH_DATA in env → token request succeeds): use Salute Speech API (Bys_24000 voice, best quality, SSML support)edge-tts CLI, voice ru-RU-DmitryNeural, free, no API key)The script prints which engine is active at startup. Both engines produce MP3 output.
| Parameter | Value |
|---|---|
| Auth endpoint | https://ngw.devices.sberbank.ru:9443/api/v2/oauth |
| Synth endpoint | https://smartspeech.sber.ru/rest/v1/text:synthesize |
| Default voice | Bys_24000 (Борис, мужской) |
| Credentials | SALUTE_AUTH_DATA in /root/config/.env (base64 of client_id:client_secret) |
| Free tier | 200 000 символов/мес |
| Max per request | 4000 символов including SSML tags |
| Output | WAV 24kHz → convert to MP3 128kbps via ffmpeg |
| Output dir | /root/tropa/site/audio/ |
| ID | Name | Gender |
|---|---|---|
Nec_24000 |
Наталья | Ж |
Bys_24000 |
Борис | М |
May_24000 |
Марфа | Ж |
Tur_24000 |
Тарас | М |
Ost_24000 |
Александра | Ж |
Pon_24000 |
Сергей | М |
Token lives 30 min. Always get fresh before batch.
import requests, uuid, os
AUTH_DATA = os.environ.get('SALUTE_AUTH_DATA') # from /root/config/.env
resp = requests.post(
'https://ngw.devices.sberbank.ru:9443/api/v2/oauth',
headers={
'Authorization': f'Basic {AUTH_DATA}',
'RqUID': str(uuid.uuid4()),
'Content-Type': 'application/x-www-form-urlencoded'
},
data='scope=SALUTE_SPEECH_PERS',
verify=False, timeout=10
)
token = resp.json()['access_token']
resp = requests.post(
'https://smartspeech.sber.ru/rest/v1/text:synthesize',
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/ssml' # or 'application/text' for plain
},
params={'voice': 'Bys_24000'},
data=ssml_text.encode('utf-8'),
verify=False, timeout=20
)
# resp.content = WAV audio bytes
Always wrap in <speak> root tag:
<speak>
First paragraph text.
<break time="400ms"/>
Second paragraph text.
</speak>
| Context | Tag | Duration |
|---|---|---|
| Between paragraphs | <break time="400ms"/> |
300-500ms |
| After question | <break time="300ms"/> |
200-400ms |
| Dramatic pause | <break time="500ms"/> |
500-700ms |
| Comma-level | <break time="200ms"/> |
100-200ms |
| Between sentences | natural, no tag needed | — |
Asterisk directly before word (no space):
<speak>Ошибка в *одну миллионную долю секунды</speak>
TTS часто ошибается в ударениях научных и редких слов. Апостроф после ударной гласной:
<speak>Закон Фараде'я. Ковариа'нция. Трилатера'ция.</speak>
Обязательно проверять и размечать:
| Слово | Разметка | Почему |
|---|---|---|
| Фарадей | Фараде'я |
TTS ставит на первый слог |
| трилатерация | трилатера'ция |
Редкое слово |
| ковариация | ковариа'ция |
Мат. термин |
| когезия | коге'зия |
Физ. термин |
| кавитация | кавита'ция |
Физ. термин |
| ксилема | ксиле'ма |
Биол. термин |
| одометрия | одоме'трия |
Техн. термин |
| реверберация | ревербера'ция |
Акустический термин |
| изопериметрический | изопериметри'ческий |
Мат. термин |
| Вардроп | Вардро'п |
Фамилия |
| Браесс | Бра'есс |
Фамилия |
| Хаген-Пуазёйль | Хаге'н-Пуазёйль |
Двойная фамилия |
| Торричелли | Торриче'лли |
Фамилия |
Правило: перед генерацией прослушать тестовый фрагмент с каждым непростым словом. Если ударение неправильное — добавить апостроф. Лучше поставить лишний апостроф, чем пропустить ошибку.
<paint pitch="4" speed="3" loudness="4">важная фраза</paint>
Attributes: pitch (1-5), speed (1-5), loudness (1-5).
<voice mode="happy">радостная фраза</voice>
Modes: sad, annoyed, happy, whisper.
| Source | SSML text |
|---|---|
300 м |
триста метров |
7.5 км/ч |
семь с половиной километров в час |
10⁻³ |
десять в минус третьей |
ρgh |
ро же аш |
T₆₀ |
тэ шестьдесят |
≈ |
примерно |
ω² |
омега в квадрате |
μ |
мю |
Δt |
дельта тэ |
<say-as interpret-as="cardinal">42</say-as>
<say-as interpret-as="date" detail="d.m.y">25.01.2000</say-as>
<sub alias="мартэновских">мартеновских</sub>
All narrations MUST be fully comprehensible without looking at a screen, card, or stend. The listener is walking, looking around, not reading. This means: - Formulas are spoken as words: $\rho g h$ → "ро жэ аш", $T_{60} \approx 1.6$ → "тэ шестьдесят — примерно одна и шесть" - Visual references ("посмотри на график", "как показано на схеме") are FORBIDDEN - Spatial references are OK if they point to the physical world: "посмотри на деревья вокруг", "хлопни в ладоши здесь" - Structure conveyed by voice: pauses between sections, prosody changes for key points - Each level is a self-contained audio experience, not a supplement to a card
| Level | Duration | Content | Style |
|---|---|---|---|
| L1 (базовый) | 40–90 sec | Hook + action + one thought + anchor | Энергичный, удивляющий |
| L2 (с формулами) | 90–180 sec | Mechanism + formula as words + cross-section | Рассуждающий, как лекция |
| L3 (доп. факты) | 180–300 sec | 5 micro-stories, history, open question | Собеседник, как подкаст |
Audio production is a TWO-SKILL pipeline. Skipping the first skill produces robotic, AI-sounding narrations.
Before converting any text to SSML, run it through the anti-ai-text skill (/root/tropa/skills/anti-ai-text/SKILL.md). This catches:
- Канцелярит: "является", "представляет собой", "обеспечивает"
- AI patterns: "важно отметить", "в рамках данного", "таким образом"
- Faux-academic filler: "демонстрирует", "содействует", "подчёркивает"
- Structural tells: rule-of-three adjectives, trailing participles
Process: Take the l1/l2/l3 text from YAML → scan with anti-ai-text rules → rewrite flagged phrases → THEN convert to SSML.
A narration that passes TTS but fails anti-ai is worse than no narration — the listener will hear "AI voice reading AI text" and tune out.
Convert cleaned text to SSML with stress marks, breaks, emphasis, numbers-as-words per rules above.
See build_audio.py in this directory for the complete pipeline script.
Before committing audio: - [ ] Source text passed anti-ai scan (0 flags) - [ ] All formulas spoken as words (no symbols read as-is) - [ ] All scientific terms have stress marks - [ ] Narration makes sense without looking at screen - [ ] Duration within level range (L1: 40-90s, L2: 90-180s, L3: 180-300s)
Usage:
cd /root/tropa
python skills/salute-tts/build_audio.py # all POIs
python skills/salute-tts/build_audio.py --poi 01 05 # specific POIs
python skills/salute-tts/build_audio.py --voice Nec_24000 # different voice
| Mistake | Fix |
|---|---|
| Sending LaTeX/unicode math | Write as Russian words |
No <speak> wrapper |
SSML requires <speak> root |
Content-Type: application/text with SSML |
Use application/ssml |
| Token expired (30 min) | Fresh token before each batch |
| Text > 4000 chars | Split into segments |
& in text |
Escape as & |
Missing verify=False |
Sber API requires it |
A detection-and-rewrite skill grounded in:
- English: Wikipedia:Signs of AI writing
- Russian: Википедия:Признаки сгенерированности текста
- Practical rules from the crimeacs/ai-tells-validator skill and Russian humanizer research
Read the text and check against all categories below. Count violations.
For each violation, output:
[CATEGORY] "offending quote" → explanation
Apply rewrite rules (Section III) to produce clean text that: - Preserves meaning and factual content - Sounds like a competent human author - Passes re-scan with zero flags
| Word | Why it flags |
|---|---|
| delve, delving | #1 ChatGPT tell since 2023 |
| tapestry | metaphor overuse |
| intricate, intricacies | false sophistication |
| landscape | vague buzzword |
| meticulous, meticulously | inflation |
| pivotal | drama inflation |
| robust | tech buzzword |
| underscore, underscores | faux-academic |
| showcase, showcasing | promotional |
| testament | dramatic framing |
| enduring | significance inflation |
| fostering, foster | vague causation |
| garner | archaic formality |
| bolster, bolstered | inflation |
| interplay | faux-intellectual |
| leverage, leveraging | SaaS-speak |
| streamline, streamlined | SaaS-speak |
| transformative | hype |
| groundbreaking | hype |
| cutting-edge | hype |
| seamless, seamlessly | SaaS-speak |
| elevate, elevating | SaaS-speak |
| unlock, unlocking | SaaS-speak |
| empower, empowering | SaaS-speak |
| revolutionize | hype |
| paradigm | buzzword |
| synergy | corporate-speak |
| holistic | buzzword |
| vibrant | promotional fluff |
| Pattern | Example | Detection |
|---|---|---|
| Negative parallelism | "Not just X, but Y" | regex: not (just\|merely\|only) .+ but |
| Rule of Three | "clear, sourced, and trustworthy" | three comma-separated adjectives |
| Trailing participle | ", ensuring X" / ", driving Y" | comma + gerund at clause end |
| Whether-you're | "Whether you're X or Y..." | opener pattern |
| Excited-to | "Excited to share/announce" | opener pattern |
""'' instead of straight quotes--- inside body text| Слово/оборот | Почему палит |
|---|---|
| является | LLM используют 2-3x чаще людей, русский часто обходится без связки |
| данный | канцелярит, уместен только в юр. документах |
| указанный | то же |
| вышеупомянутый | то же |
| обеспечивает | шаблонный глагол поверхностного анализа |
| демонстрирует | то же |
| содействует | то же |
| соответствует | то же |
| подчёркивает | faux-academic |
| символизирует | драматизация |
| выступает (в роли) | канцелярит вместо простого "это" |
| осуществляет | номинализация: "осуществить проверку" вместо "проверить" |
| представляет собой | канцелярит |
| затрагивает | вода |
| способствует | вода |
| погружаться | калька с "delve" |
| гобелен | калька с "tapestry" |
| переплетение | калька с "interplay" |
| нюанс (мн.) | калька с "nuance" |
Канцелярит и наукообразие: - "В рамках" (данного исследования/проекта/статьи) - "Важно отметить" / "Стоит отметить" / "Стоит подчеркнуть" - "Необходимо учитывать" - "На основании вышеизложенного" - "В контексте" (чего-либо) - "Таким образом" (как вводное к выводу) - "В заключение следует отметить" - "Представляет собой" - "Играет важную/ключевую/значительную роль" - "Оказывает влияние на" - "Носит характер"
Рекламный язык: - "Может похвастаться" - "Расположенный в самом сердце" - "Потрясающая природная красота" - "Вековое наследие" - "Богатый, яркий, разнообразный" - "Уникальный" (без обоснования)
Ложная глубина: - "Это не просто X, это Y" - "Не только... но и..." - "Неизгладимый след" - "Поворотный момент" - "Служит напоминанием" - "Свидетельство мастерства/эпохи"
Диалоговые артефакты: - "Конечно!" / "Безусловно!" - "Я надеюсь, это помогло" - "Если хотите узнать больше, дайте знать" - "Сообщите мне" - "Давайте рассмотрим"
Ложные кальки с английского: - "В конце дня" (at the end of the day) - "Давайте нырнём" (let's dive in) - "За пределами коробки" (outside the box) - "На одной странице" (on the same page)
| Паттерн | Пример | Обнаружение |
|---|---|---|
| Цепочки родительного падежа | "улучшение качества обслуживания клиентов компании" | 3+ существительных в Р.п. подряд |
| Номинализация | "осуществить проверку" вместо "проверить" | глагол + отглагольное сущ. |
| Деепричастные нагромождения | "являясь ключевым элементом, обеспечивая..." | 2+ деепричастных оборота в одном предложении |
| Правило трёх | "быстрый, удобный и надёжный" | три однородных прилагательных |
| Параллелизм с отрицанием | "Не только X, но и Y" | шаблонная конструкция |
| Меризм (крайности) | "от лёгкого до тяжёлого" | "от X до Y" без конкретики |
| Шаблонные секции | "Проблемы и перспективы" → "Несмотря на... всё же..." | структурный шаблон |
| Принудительный оптимизм | Статья о проблемах заканчивается позитивом | структурный шаблон |
| Однообразие длин | все абзацы ~одинаковой длины | burstiness < порога |
##, **, --- в тексте не предназначенном для рендеринга| Что убить | Чем заменить |
|---|---|
| "является" | убрать связку: "Москва — столица" вместо "Москва является столицей" |
| "данный" | "этот", "такой", или убрать |
| "В рамках" | "В", "При", "Для", или перестроить |
| "осуществить X" | прямой глагол: "проверить" вместо "осуществить проверку" |
| "представляет собой" | тире или ничего |
| "оказывает влияние" | "влияет" |
| "играет роль" | "важен для" или конкретизировать |
| "Таким образом" | убрать или "Итого:" / "Значит," |
| "Стоит отметить" | убрать, написать факт напрямую |
| "В контексте X" | "для X", "при X", или убрать |
| "обеспечивает" | конкретный глагол: "даёт", "создаёт", "позволяет" |
| Цепочка Р.п. | разбить предлогами: "качество обслуживания для клиентов" |
| Деепричастный оборот ×2 | разбить на два предложения |
| Правило трёх | два элемента или абзац с пояснениями |
| Что убить | Чем заменить |
|---|---|
| "delve" | "look at", "examine", "explore" |
| "landscape" | name the specific domain |
| "leverage" | "use" |
| "streamline" | "simplify", "speed up" |
| "transformative" | describe the actual change |
| "seamless" | "smooth", "easy", or describe how |
| "unlock" | "enable", "allow", "open" |
| "robust" | "strong", "reliable", or specify |
| "I hope this finds you well" | cut entirely, start with substance |
| "in conclusion" | just state the conclusion |
| Trailing ", ensuring X" | new sentence: "This ensures X." |
| Em-dash parenthetical | use commas or restructure |
Use this checklist when reviewing text:
[ ] Banned words (EN): delve, tapestry, leverage, seamless, etc.
[ ] Banned words (RU): является, данный, обеспечивает, осуществляет, etc.
[ ] Banned phrases (EN): "important to note", "plays a key role", etc.
[ ] Banned phrases (RU): "В рамках", "Важно отметить", "Стоит подчеркнуть", etc.
[ ] Structural: Rule of Three present?
[ ] Structural: Trailing participle clauses?
[ ] Structural: Negative parallelism ("not just X, but Y")?
[ ] Structural (RU): Genitive chains (3+ in a row)?
[ ] Structural (RU): Nominalizations instead of verbs?
[ ] Structural (RU): Depricipal clause pileup?
[ ] Punctuation: Em-dash density (>1 per paragraph EN, >5/1000 chars RU)?
[ ] Punctuation: Smart/curly quotes?
[ ] Formatting: Excessive bold, emoji bullets, markdown artifacts?
[ ] Formatting: Title Case headings in Russian?
[ ] Sentence variety: all similar length? (burstiness check)
[ ] Tone: forced optimism at the end?
[ ] Tone: promotional language without substance?
[ ] Dialogue artifacts: "Конечно!", "Let me know", etc.?
[ ] English calques in Russian text?
Before (flagged):
В рамках данного исследования важно отметить, что предложенный метод является эффективным инструментом, обеспечивающим существенное улучшение качества обслуживания клиентов компании, демонстрируя при этом устойчивость к различным возмущениям.
Flags: - [PHRASE] "В рамках" → канцелярит - [WORD] "данного" → канцелярит - [PHRASE] "важно отметить" → дидактический маркер - [WORD] "является" → избыточная связка - [WORD] "обеспечивающим" → шаблонный глагол - [STRUCTURE] цепочка Р.п. "улучшение качества обслуживания клиентов компании" - [WORD] "демонстрируя" → шаблонный глагол
After (clean):
Предложенный метод улучшает обслуживание клиентов и устойчив к возмущениям.
Before (flagged):
I hope this finds you well. I wanted to reach out because we've built a transformative, seamless, and robust platform that helps companies leverage AI to unlock growth — driving efficiency across the entire pipeline.
Flags: - [PHRASE] "I hope this finds you well" - [PHRASE] "wanted to reach out" - [WORD] "transformative" + "seamless" + "robust" → triple banned word - [PATTERN] Rule of Three: "transformative, seamless, and robust" - [WORD] "leverage" - [WORD] "unlock" - [PUNCTUATION] em-dash - [PATTERN] trailing participle: ", driving efficiency"
After (clean):
We built a tool that cuts pipeline review time from 4 hours to 20 minutes. Three teams at [Company] use it today. Worth a 10-min call this week?
A POI (Point of Interest) is a single station on a scientific trail. Each POI has: - A scientific storyline tied to a physical location - Three levels of narration (L1 basic, L2 formulas, L3 deep facts) - A physical interactive — something visitors build, touch, or measure - Audio narration generated via TTS - A PDF card for print
Storyline candidate → GROUND ON REAL POI → Critical-visitor test → Feasibility check →
Text (3 levels) → Anti-AI scan → SSML → TTS → Audio (MP3)
↘ Typst → PDF card
The single biggest mistake: extracting a "cool idea" from a lecture/book and adding it to the bank without first checking it lands on a real POI on a real route. A storyline without a place to live on the trail is useless — the bank is not a museum catalog, it is a deployment queue.
Two routes currently exist:
- bot/config/poi.innopolis.yaml — Innopolis University, 8 POIs (entrance, atrium, robot path, Tesla marker, boulevard fork, sports zone, forest edge, data-center view)
- bot/config/poi.skolkovo.yaml — Skolkovo Big Boulevard, 7 POIs (MCD station, Tehnopark, World Class, central square, Hypercube, Matrex, Skoltech)
For each candidate storyline, BEFORE anything else, answer:
id.Common failure modes that trigger archive: - Pure abstract algorithm / pure game theory without a physical object on the route (e.g. tit-for-tat, Gale–Shapley, Arrow's theorem, Conway's Life, HyperLogLog, k-means). - Politics, voting systems, sociological models. - "Cool number trick" that needs paper/pencil and a quiet desk (Karatsuba, Newton division, Schwarz triangle). - Anything requiring a TV/screen/keyboard/touch device on the trail. - Anything where the only interactive is "read this text and think about it".
Common passes: - A story that uses a real lake, tree, rock, sky, building, fork in the path, bridge, statue as its anchor. - An abstract idea that has a bodily demo on a small stand (coin rotation paradox, Platonic-solid sculptures, Fermat-Torricelli weighted strings, complex number = rotation on a clock face).
Source: content/storylines.yaml.
Pick by: - Route location (what's physically visible at the point) - Section variety (don't cluster 5 geometry POIs in a row) - Feasibility rating (prefer "easy", avoid "hard") - Budget (aim for <500₽ per POI on average)
Every POI must pass ALL three gates:
Gate 1 — School workshop:
| Criterion | Required |
|---|---|
| Basic tools only | Wood, wire, string, magnets, metal — no CNC, no 3D printing |
| No electricity | No batteries, no power outlets, no electronics on the trail |
| No safety hazard | No chemicals, no fire, no sharp edges at child height |
| Portable | Fits in a car. Nothing heavier than 15 kg |
Gate 2 — Budget-accounted, non-exotic:
| Criterion | Required |
|---|---|
| Any material OK | Stones, boards, planks, metal, plastic, paint, magnets, springs — whatever fits. Found and bought materials both fine. |
| Budget must include all costs | The realistic budget tier (300/600/1000/1500+ ₽) has to actually cover the listed parts, including installation. Don't list a "разметка площадки" and tag it «до 300₽». |
| Avoid exotic | Prefer common shop / Авито / Леруа / Чип-и-Дип / AliExpress parts. Don't require CNC-3D-printed-laser-cut-on-Mars unless that's the only way. |
| Consumables OK if sourced | If a part is consumable (replacement markers, sample cards, fresh paint), say where to buy and how often to replace in «Как сделать». |
Still fails Gate 2: food, soap, fresh paper that gets wet daily, anything that can't be re-bought from a known shop.
Gate 3 — Any weather outdoors:
| Criterion | Required |
|---|---|
| Rain | Metal/wood/stone survive. Paper → laminate or metal engraving |
| Frost | No water, no rubber seals, no LCD screens |
| Wind | Loose parts chained/bolted. Nothing lighter than 200g free-standing |
| Sun | UV-resistant. No foam, no fabric, no food |
| Self-explanatory | Works without a guide. 20 seconds to understand |
Adaptation rule: If an idea is great but fails Gate 2/3, try: paper → metal engraving, cardboard → welded wire, loose objects → chained/mounted, flashlight → sunlight, water → dry alternative. If no viable adaptation exists → remove.
If a storyline fails any gate and can't be adapted → remove.
All narrations follow the Gasnikov style (see bot/config/style.md):
| Level | Duration | Content | Style |
|---|---|---|---|
| L1 (базовый) | 40-90 sec | Hook + action + one key idea | Energetic, surprising |
| L2 (формулы) | 90-180 sec | Mechanism + formula as words + cross-section | Analytical, like a lecture |
| L3 (факты) | 180-300 sec | 5 micro-stories, history, open question | Conversational, like a podcast |
Rules: 1. Start with local binding: "Посмотри на...", "Прямо здесь..." 2. One baffling opener per POI — a counter-intuitive claim 3. Numbers always with units. Formulas spoken as words in audio. 4. Short sentences (max 25 words for audio) 5. No filler: "очень интересный эффект" = forbidden 6. Eyes-free: narration must work without looking at a screen 7. Focus on ideas, not names — don't name-drop scientists unless the name IS the story
Before converting to SSML, run text through skills/anti-ai-text/SKILL.md.
Kill: "является", "данный", "важно отметить", "представляет собой", "обеспечивает", trailing participles, rule-of-three adjectives.
A narration that passes TTS but fails anti-AI is worse than no narration.
Use skills/salute-tts/SKILL.md for the full TTS pipeline.
The build script auto-selects engine:
- Salute Speech if SALUTE_AUTH_DATA available (best quality, SSML support)
- Edge TTS as fallback (free, no API key, ru-RU-DmitryNeural voice)
# Generate all levels for specific POIs
python3 skills/salute-tts/build_audio.py --poi 01 05
# Generate everything
python3 skills/salute-tts/build_audio.py
SSML files go in skills/salute-tts/narrations/ as {nn}_{poi_id}_{level}.xml.
Audio output: site/audio/{nn}_{poi_id}_{level}.mp3.
Each POI needs a hands-on element. Design principles from docs/physical-interactives.md:
Do: - One effect, large parts, no fragile electronics - Materials: plywood, metal, acrylic, rope, magnets, anti-vandal fasteners - Understandable in 20 seconds without instructions - Works in rain, wind, direct sun
Don't: - Touchscreens, small removable parts, long instructions - Anything dependent on power supply - Decoration without an experiment
| Material | Typical cost |
|---|---|
| Found materials (sticks, rocks, water) | 0₽ |
| Basic hardware (wire, magnets, springs) | 200-500₽ |
| Wood/plywood cuts | 500-1500₽ |
| Metal fabrication | 1500-3000₽ |
| Specialty items (prism, lens, tuning fork) | 1000-3000₽ |
Target: average 500₽ per POI, max 2000₽ for complex items.
Budget categories on the site: - до 300₽ — found/basic materials - до 600₽ — hardware store - до 1000₽ — wood workshop - свыше 1000₽ — specialty items
- id: 1
name: "university_entrance"
lat: 55.7527
lon: 48.7440
trigger_radius_m: 30
topic: "GPS/ГЛОНАСС, трилатерация"
scenario_brief: "One-sentence hook"
level1_seed: "L1 narration text"
level2_seed: "L2 narration with formulas"
level3_seed: "L3 narration with stories"
physical_interactive: "Description of hands-on element"
sources: ["source1", "source2"]
verified: false
budget_rub: 500
Before marking a POI as done:
Проектировщик уличной научпоп-инфраструктуры по манифесту: вандалоустойчивые объекты, поперечное сечение реальности, метод вместо энциклопедии, локальный ландшафт как часть смысла, тексты трёх уровней в каноне русского научпопа. Главный сценарий — генерация концепции по «тема + локация»; вспомогательные сценарии — аудит существующих объектов и генерация текстов для готовых конструкций.
references/manifesto-filters.md —
обязательно при любом формате. Без 8 фильтров скилл скатится в типовой
занимательный научпоп, что манифест прямо отвергает.ask_user_input_v0 с тремя вариантами (Проект / Аудит /
Тексты).format-project.md, format-audit.md или format-texts.md.references/cross-section-method.md и пройти все 5 шагов
алгоритма. Если сечение не вытаскивается — отбраковка с диагностикой.landscape-context.md
и construction-patterns.md. При работе с текстами — levels-a-b-c.md
и stylistic-playbook.md (восемь приёмов канона Перельмана/Ливанова).Перед выдачей ответа проверить два пункта:
Если хотя бы один не пройден — это не доработка, а отбраковка сюжета. Манифест категоричнее музейной педагогики.
examples/engineer-of-nature-rejected.md.stylistic-playbook.md).science-museum-curator: тот — для музейных экспозиций
под крышей; здесь — открытое пространство, тиражируемая сеть.| Файл | Назначение |
|---|---|
references/manifesto-filters.md |
8 фильтров: признаки, red flags, как чинить |
references/cross-section-method.md |
Метод поперечного сечения, главная отбраковочная процедура |
references/landscape-context.md |
Каталог ландшафтных триггеров и подходящих сечений |
references/construction-patterns.md |
Вандалоустойчивые типовые узлы |
references/levels-a-b-c.md |
Спецификация трёх уровней объяснения |
references/stylistic-playbook.md |
Канон Перельмана/Ливанова: 8 операциональных приёмов |
references/format-project.md |
Алгоритм и шаблон формата «Проект» |
references/format-audit.md |
Алгоритм и шаблон формата «Аудит» |
references/format-texts.md |
Алгоритм и шаблон формата «Тексты» |
examples/echo-distance-exemplar.md |
Эталон: разбор WP003 «Услышь расстояние» |
examples/engineer-of-nature-rejected.md |
Анти-эталон: разбор отбракованного WP005 |
Это не инструкция «что сделать», а планка качества и цикл обратной связи. Задача скилла — не «пройтись разок», а крутить цикл правок столько, сколько нужно, пока каждый из критически настроенных проверщиков — текстовых и визуальных — не подтвердит, что придраться больше не к чему. Артефакт готов не когда «я внёс правки», а когда я сам открыл результат (HTML и PDF) и ни один критик не нашёл ни одного дефекта два круга подряд.
Категорически запрещены shortcut'ы. Нельзя: проверить часть и экстраполировать на остальное; «на глаз» решить что и так нормально; принять свою же правку без повторного рендера и просмотра; остановиться на первом чистом круге. Лучше потратить много времени и итераций, чем выпустить «почти готово».
content/storylines/<slug>.md (или список).references/critic-panel.md — включая покрытие
визуалом (где идея просит схему — она есть и доведена до книжного качества
по references/figure-style.md), — и два полных круга подряд не дали ни
одной находки. Только тогда сюжет считается вычитанным.loop:
1. RENDER — пересобрать сайт (python3 build.py) → HTML + PDF уровней.
2. CRITICS — прогнать ВСЮ панель критиков (references/critic-panel.md):
каждый критик независимо, адверсариально, ищет дефекты.
Визуальные критики ОБЯЗАТЕЛЬНО открывают рендер
(см. references/visual-review.md) — скриншот HTML каждого
таба + просмотр PDF каждого уровня. Чтение исходника не
заменяет просмотр рендера.
3. COLLECT — собрать все находки в один список с severity (blocker/major/minor).
4. if находок == 0:
clean_rounds += 1
if clean_rounds >= 2: → ГОТОВО, выйти.
else:
clean_rounds = 0
FIX — устранить ВСЕ находки в исходнике .md (или в build.py/шаблоне,
если дефект системный — тогда чинить корень, а не симптом).
5. → loop
Параллелить критиков и сюжеты разумно (один субагент = один критик или один сюжет), но синтез находок и решение «готово/не готово» — централизованно. При большом объёме (вычитка всех сюжетов разом) запускать через Workflow: pipeline по сюжетам, внутри — панель критиков, цикл до чистоты.
| Критик | Что ловит | Чем смотрит |
|---|---|---|
| Структурный | нарушения формата (см. references/format-contract.md): строительные метки, прилипший дек, чужие ##, битые табы |
исходник + HTML |
| Научный | фактические ошибки, кривые/пропущенные формулы, единицы, числа | исходник + рендер формул |
| Язык и типографика | опечатки, канцелярит, ИИ-звучание, тире/кавычки, висячие предлоги | исходник + HTML |
| Канон Гасникова | локальная привязка, хук, метод вместо факта, уровни А/Б/В | исходник |
| Визуальный HTML | вёрстка, иллюстрация, переносы, пустоты, дек/подзаголовки, мобилка | скриншот каждого таба |
| Визуальный PDF | книжное качество: масштхед, буквица, типографика, формулы, footer, переносы | открытый PDF каждого уровня |
| Совещание автор↔зритель | доносит ли схема идею: автор (видит концепт) формулирует замысел, зритель (видит ТОЛЬКО картинку) — восприятие; радикально разошлись → чинить схему | 2 независимых агента на фигуру |
| Артефакт-критик | несёт ли артефакт мысль и выдержит ли буллшит-детектор: необходимость (не пересказ прозы), одна яркая идея, ни одной натянутой строки/пустой «—» ячейки, непротиворечивость прозе | скептичный эксперт-предметник по каждой таблице/схеме |
Каждый критик настроен скептически: его работа — найти, к чему придраться, а не подтвердить, что «нормально». Пустой отчёт критика допустим только если он реально не нашёл дефектов, просмотрев рендер.
build.py/шаблоне/формате, а не править каждый файл вручную.critic-panel.md или format-contract.md, — дописать его туда. Скилл
улучшается вместе с сюжетами.| Файл | Назначение |
|---|---|
references/format-contract.md |
Канонический формат сюжета + как он рендерится в HTML и PDF (контракт с build.py) |
references/critic-panel.md |
Полные чек-листы всех шести критиков |
references/visual-review.md |
Как поднять рендер, снять скриншоты HTML и открыть PDF; книжная планка качества |
references/figure-style.md |
Стиль научных схем (вектор, штрих, Libertinus Serif) + цикл полировки одной фигуры субагентом |
Full pipeline: storyline → L1/L2/L3 text → anti-AI → SSML → audio.
# Generate narrations + SSML for storyline #5, POI "hilltop", prefix 01
python3 skills/narration-gen/generate.py --storyline 5 --poi hilltop --nn 01
# Same + generate audio
python3 skills/narration-gen/generate.py --storyline 5 --poi hilltop --nn 01 --tts
Output: skills/salute-tts/narrations/{nn}_{poi}_{l1,l2,l3}.xml
When generating narrations directly (without the script), follow this exact structure.
From content/storylines.yaml, grab:
- title — the hook question
- topic — scientific domain
- cross_section — where else this principle appears
- section — category
Structure: 1. Local binding (1 sentence) — "Посмотри на...", "Прямо здесь..." 2. Baffling claim (1 sentence) — counter-intuitive, makes listener stop 3. Action (1-2 sentences) — what to do right now (look, touch, listen, count) 4. Explanation (2-3 sentences) — how it works, with one number+unit 5. Bridge (1 sentence) — where else this works
Example (GPS point):
Открой бот — он уже знает, что ты у главного входа. Но ни один спутник тебя не видел. Ни камеры, ни луча, ни фотографии. Спутники не ищут тебя. Каждый передаёт одно: сейчас такое-то время, я в такой-то точке. Телефон ловит сигналы и замеряет задержку. Один спутник — расстояние. Три спутника — три сферы. Точка пересечения — ты. Ошибка в миллионную долю секунды сдвигает на 300 метров. Поэтому на орбите — атомные часы. Так же охотится летучая мышь: крик, задержка, расстояние.
Structure: 1. Recap mechanism from L1 (1-2 sentences, don't repeat verbatim) 2. Formula step-by-step: explain what each symbol means BEFORE writing the formula 3. Numerical estimate: plug in real numbers, get a result with units 4. Cross-section: same math in another domain (1-2 sentences)
Formula rule: explain THEN name. "Расстояние равно скорости, умноженной на время задержки... записывается как ро равно цэ умножить на дельта тэ."
Five micro-stories, each 2-4 sentences: 1. Historical anecdote — who discovered this and how 2. Surprising application — where else this principle works (unexpected domain) 3. Record/extreme — biggest, smallest, fastest example 4. Paradox or failure — when it breaks or gives counter-intuitive result 5. Open question — what we still don't know
Each micro-story starts with a bold hook. Separate with pauses.
Scan EVERY generated text. Kill on sight:
| Kill | Replace with |
|---|---|
| "является" | тире or nothing |
| "данный" | "этот" or remove |
| "обеспечивает" | "даёт", "создаёт" |
| "В рамках" | "В", "При", "Для" |
| "Важно отметить" | just state the fact |
| "Таким образом" | remove or "Итого:" |
| "представляет собой" | тире |
| triple adjectives | keep two or rephrase |
| trailing ", обеспечивая X" | new sentence |
If ANY flag remains after one rewrite pass, rewrite again. Zero tolerance.
Wrap in <speak> tags. Rules:
<speak>
First paragraph text.
<break time="400ms"/>
Second paragraph. Use *emphasis before key words.
<break time="400ms"/>
Third paragraph.
</speak>
<break time="400ms"/> between paragraphs<break time="500ms"/> before dramatic reveal in L3* before emphasized words (no space: *триста метров)Stress dictionary (always apply):
трилатерация → трилатера'ция
реверберация → ревербера'ция
ковариация → ковариа'ция
когезия → коге'зия
кавитация → кавита'ция
ксилема → ксиле'ма
Фарадей → Фараде'й
Торричелли → Торриче'лли
Бернулли → Берну'лли
Вардроп → Вардро'п
Браесс → Бра'есс
Numbers as words: "300 м" → "триста метров", "10⁻³" → "десять в минус третьей", "ρgh" → "ро же аш".
skills/salute-tts/narrations/{nn}_{poi_id}_l1.xml
skills/salute-tts/narrations/{nn}_{poi_id}_l2.xml
skills/salute-tts/narrations/{nn}_{poi_id}_l3.xml
Then:
python3 skills/salute-tts/build_audio.py --poi {nn}
Before committing: - [ ] L1: 80-150 words, no formulas, one number+unit - [ ] L2: has formula explained step-by-step, numerical estimate - [ ] L3: 5 distinct micro-stories, each with own hook - [ ] Anti-AI: 0 flags on all three levels - [ ] SSML: stress marks on all tricky words - [ ] Listens well without looking at screen - [ ] No "посмотри на график" or "как показано на схеме"