import React from 'react';
import DocIcon from './docsIcons';
import { LangTabs } from './docsLang';

/**
 * docsData.jsx — контент вики редактора Рублокс (разделы A-J).
 *
 * Структура: DOCS = массив глав. Каждая глава —
 *   { id, icon, title, summary, sections: [{ id, title, body }] }
 *  - icon    — имя SVG-иконки из docsIcons.jsx (НЕ эмодзи).
 *  - summary — короткое описание для карточки на главной вики.
 *
 * Хелперы для оформления:
 *  - <Code>      — код-блок (тёмный, моноширинный)
 *  - <ScriptKind kind="global|object" on="...">  — плашка «куда писать скрипт»
 *  - <Step n="1"> — шаг инструкции
 *  - <Note>      — жёлтая плашка-подсказка
 *  - <Try>       — зелёная плашка «попробуй сам»
 *
 * Контент написан для детей 5 класса+. Каждый пример — рабочий код,
 * который можно скопировать в свою игру. Эмодзи в UI не используются —
 * только SVG-иконки (см. docsIcons.jsx).
 */

// ── Код-блок ──────────────────────────────────────────────────────
export const Code = ({ children }) => (
    <pre className="docCode"><code>{children}</code></pre>
);

// ── Плашка «куда писать скрипт» ───────────────────────────────────
// kind="global"  — глобальный скрипт (создаётся в категории «Скрипты»)
// kind="object"  — скрипт привязан к объекту (передай on="название объекта")
export const ScriptKind = ({ kind, on }) => {
    if (kind === 'object') {
        return (
            <div className="docScriptKind docScriptKind--object">
                <span className="docScriptKind__ico"><DocIcon name="pin" size={18} /></span>
                <span>
                    <b>Куда писать:</b> этот скрипт нужно <b>повесить на объект</b>
                    {on ? <> — на <b>{on}</b></> : null}. Выдели объект на сцене
                    и создай скрипт прямо на нём. Тогда внутри скрипта работает
                    слово <code>game.self</code> — это и есть твой объект.
                </span>
            </div>
        );
    }
    return (
        <div className="docScriptKind docScriptKind--global">
            <span className="docScriptKind__ico"><DocIcon name="globeIcon" size={18} /></span>
            <span>
                <b>Куда писать:</b> это <b>глобальный скрипт</b>. Создай его
                в иерархии в категории <b>Скрипты</b> (кнопка «+»). Он не привязан
                ни к какому объекту и запускается один раз при старте игры.
            </span>
        </div>
    );
};

// ── Шаг инструкции ────────────────────────────────────────────────
export const Step = ({ n, children }) => (
    <div className="docStep">
        <span className="docStep__num">{n}</span>
        <div className="docStep__body">{children}</div>
    </div>
);

// ── Жёлтая плашка-подсказка ───────────────────────────────────────
export const Note = ({ children }) => (
    <div className="docNote">
        <span className="docNote__ico"><DocIcon name="lightbulb" size={17} /></span>
        <div>{children}</div>
    </div>
);

// ── Зелёная плашка «попробуй сам» ─────────────────────────────────
export const Try = ({ children }) => (
    <div className="docTry">
        <span className="docTry__ico"><DocIcon name="target" size={17} /></span>
        <div>
            <b>Попробуй сам:</b> {children}
        </div>
    </div>
);

// ── Скриншот интерфейса с подписью ────────────────────────────────
// Версия вики-ассетов (cache-buster). Бампать при добавлении/замене картинок
// в public/wiki/ — иначе у юзеров, открывавших статью ДО заливки файла,
// браузер кэширует битый SPA-fallback (HTML вместо PNG) и Ctrl+Shift+R не
// помогает (инцидент 2026-06-03 с guide-taxisim). Новый ?v=N = новый URL.
export const WIKI_ASSET_V = 4;

/** URL вики-картинки с версией для обхода кэша. */
export const wikiUrl = (name) => `/wiki/${name}?v=${WIKI_ASSET_V}`;

// src — имя файла из public/wiki/, caption — подпись под картинкой.
// wide — для широких скринов (обзор, лента): растянуть на всю ширину.
export const Shot = ({ src, caption, wide }) => (
    <figure className={'docShot' + (wide ? ' docShot--wide' : '')}>
        <img src={wikiUrl(src)} alt={caption || ''} loading="lazy" />
        {caption && <figcaption>{caption}</figcaption>}
    </figure>
);

// ══════════════════════════════════════════════════════════════════
// DOCS — разделы вики A-J
// ══════════════════════════════════════════════════════════════════

// ════════════════════════════════════════════════════════════
// AI_CONTEXT — полный справочник API скриптов Рублокса одним
// текстом для вставки в нейросеть. Держать в синхроне с
// ScriptSandboxWorker.js при добавлении новых game-API.
// ════════════════════════════════════════════════════════════
const AI_CONTEXT = `Ты — помощник по написанию скриптов для онлайн-конструктора 3D-игр «Рублокс» (аналог Roblox, движок Babylon.js). Скрипты пишутся на JavaScript. Всё доступно через глобальный объект game. Ниже — полный API. Пиши ТОЛЬКО рабочий код, используя ТОЛЬКО эти методы. Не выдумывай команды. Координаты в метрах, повороты в РАДИАНАХ (90°=Math.PI/2).

=== ДВА ВИДА СКРИПТОВ ===
1) Глобальный — в категории «Скрипты», запускается 1 раз при старте. Управляет всей сценой.
2) На объекте — висит на примитиве/модели/блоке. В нём доступен game.self — сам объект-носитель.
Всегда указывай пользователю, КУДА писать скрипт.

=== ИГРОК game.player ===
.position -> {x,y,z}; .yaw, .pitch (рад); .forward -> {x,y,z} (куда смотрит); .hp, .maxHp, .alive
.teleport(x,y,z); .damage(n); .kill(); .heal(n); .respawn()
.setSpeed(mul); .setJumpPower(mul); .setGravityMul(mul); .setInputBlocked(bool)
.giveTool(toolId, {equip:true}); .removeTool(id); .setSkin(slug); .setTeam(name)
.isKeyDown('w'|'a'|'s'|'d'|'space'|'shift'...); .boostJump(strength); .setDoubleJump(bool)
.setCameraMode('first'|'third'|'front'); .playEmote('wave'|'dance'|'cheer'|'sit')

=== ОБЪЕКТ-НОСИТЕЛЬ game.self (только в скрипте на объекте) ===
.ref ('primitive:N'); .position -> {x,y,z}; .kind
.onTouch(fn) — игрок коснулся; .onUntouch(fn) — отошёл
.onClick(fn) — клик мышью по объекту
.onInteract(fn, {text:'Открыть', key:'e', distance:4, holdDuration:0}) — действие по клавише E
.move(x,y,z); .rotateY(rad); .setColor('#hex'); .setVisible(bool); .setCollide(bool)
.setLabel(text, {color,height}); .clearLabel(); .delete()

=== СЦЕНА game.scene ===
spawn(type, opts) -> объект. type: 'cube'|'sphere'|'cylinder'|'cone'|'pyramid'|'torus'|'wedge'|'plane' (примитивы), 'model:ID', 'block:ID', 'vehicle:car', 'light:point', 'billboard', 'trigger'.
  opts: {x,y,z, sx,sy,sz, rotationX,rotationY,rotationZ, color:'#hex', material:'matte'|'neon'|'metal'|'glass'|'studs', name, anchored:true(висит)/false(падает), canCollide, visible, mass, lifetime(сек до авто-удаления)}
delete(ref); move(ref,x,y,z); setRotation(ref,rx,ry,rz); setColor(ref,'#hex'); setMaterial(ref,name); setVisible(ref,bool); setCollide(ref,bool); setOpacity(ref,0..1); setScale(ref,sx,sy,sz)
setLabel(ref,text,opts); clearLabel(ref); setData(ref,key,val); getData(ref,key)
find(name)->[...]; findOne(name)->объект|null; all('primitive'|'model'|'block')
tag(ref,tag); untag(ref,tag); hasTag(ref,tag); getTagged(tag)->[refs]
clone(ref,{dx,dy,dz}); spawnParticles('fire'|'smoke'|'sparks'|'magic'|'explosion'|'confetti', {x,y,z}, {duration,count,color})
setSkybox({preset:'clear-summer-day'|'sunset'|'starry-night'|'space'|'cloudy'}); setFog({color,density}); setClouds({enabled,cover,speed})
spawnNpc(modelType, {x,y,z,hp,name,speed}) -> npc. npc: .position, .hp, .follow('player'|ref), .moveTo(x,z), .stop(), .say(text,sec), .damage(n), .setSpeed(s), .onDeath(fn), .remove()

=== ОБЪЕКТ-ПРОКСИ (то, что вернул spawn/findOne) ===
obj.ref; obj.position; obj.color='#hex'; obj.material='neon'; obj.scale=2; obj.opacity=0.5; obj.visible=false; obj.canCollide=false; obj.position={x,y,z}
obj.move(x,y,z); obj.rotateY(rad); obj.onTouch(fn); obj.onClick(fn); obj.onInteract(fn,opts); obj.clone({dx,dy,dz}); obj.destroy(); obj.tween(props,opts); obj.setLabel(t,opts); obj.addTag(t)

=== HUD game.ui ===
.score = N (счётчик в углу); .timer = N (таймер mm:ss); .showText('текст', сек) (крупно по центру)
.set(id, text, {x,y,color,size}) (своя метка, x/y в %); .remove(id); .clear()

=== GUI (кнопки/панели на экране) game.gui ===
create('button'|'text'|'frame'|'image', {name,x,y,w,h,text,bg:'#hex',color,fontSize,borderRadius}) -> id
onClick(id, fn); update(id, {text,...}); show(id); hide(id); remove(id); tween(id, props, {duration})

=== ТАЙМЕРЫ И КАДРЫ ===
game.onTick(fn) — каждый кадр, fn(dt) dt=сек с прошлого кадра
game.after(сек, fn) -> id — один раз через N сек
game.every(сек, fn) -> id — повторять каждые N сек
game.cancel(id) — отменить таймер
game.tween(ref, props, {duration, easing:'linear'|'ease'|'bounce'|'elastic', yoyo, repeat:-1, onDone}) — анимация свойств (props: x,y,z, rotationX/Y/Z, sx/sy/sz, color, opacity)

=== СОБЫТИЯ ===
game.onKey('w', fn); game.onKeyUp('w', fn); game.onClick(fn) (fn({point,target}))
game.onPlayerDied(fn); game.onHpChange(fn); game.onPlayerJump(fn); game.onMobKilled(fn)
game.broadcast(name, data) — послать сообщение всем скриптам
game.onMessage(name, fn) — принять сообщение (fn(data))

=== ФИЗИКА game.physics ===
raycast(origin, dir, {maxDistance}) -> {hit, ref, point, distance} (синхронно, для стрельбы)
applyImpulse(ref, {x,y,z}); setVelocity(ref, {x,y,z}); explode({x,y,z}, radius, {damage}); passThrough(refОrTag, bool)

=== ЭФФЕКТЫ game.fx ===
damageFloater(posОrRef, value, {isCrit,isHeal,isMiss,color}) — всплывающая цифра урона
autoMobFloaters(true) — авто-цифры над всеми мобами
beam({from,to,color,width}) -> луч; pointer({from,to,preset:'quest'}); trail(ref,{color,width})

=== ЗВУК game.sound ===
play('coin'|'jump'|'win'|'lose'|'click'|'hit'|'pickup' | 'sound_N', {volume,pitch,at:{x,y,z},loop}) -> {stop()}

=== КАМЕРА game.camera ===
shake(amp, sec); setFov(deg); focusOn(ref,{distance,height}); cutscene([{x,y,z}...], {lookAt,segDuration}); reset()

=== ОКРУЖЕНИЕ game.environment ===
setSkyColor('#hex'); setFog({enabled,color,density}); setTimeOfDay(0..24)

=== ИНВЕНТАРЬ / ПРЕДМЕТЫ ===
game.items.define([{id,name,emoji,rarity:'common'|'rare'|'epic'|'legendary',maxStack,onUseEffect:'heal:50'}])
game.inventory.give(id,count); .take(id,count); .has(id); .open(); .list()

=== ЛИДЕРБОРД И ДОСТИЖЕНИЯ ===
game.leaderstats.define('Монеты', {initial:0}); game.leaderstats.me.add('Монеты', 1); .me.set(name,val); .me.get(name)
game.achievements.define([{id,name,description,icon,rarity}]); game.achievements.unlock(id)

=== СОХРАНЕНИЕ (между сессиями) game.save ===
.merge(namespace, {patch:{поле:знач}, increment:{счётчик:дельта}, max:{рекорд:знач}})
.get(namespace, fn) (fn(data|null)); .increment(ns,key,delta); .leaderboard(ns,key,'desc',fn)

=== МОДАЛКИ game.modal ===
.dialog(npcName, [строки], onDone); .confirmation(title, body, onYes, onNo); .lootbox([{name,color,icon,rarity}], onPick); .close()

=== УТИЛИТЫ ===
game.log(...) — в консоль; game.random(min,max,целое?); game.clamp(v,min,max); game.lerp(a,b,t); game.distance(a,b) (точки или ref); game.format.time(сек,'mm:ss'); game.format.number(n,'short')

=== ВАЖНЫЕ ПРАВИЛА ===
- Повороты в РАДИАНАХ (Math.PI/2 = 90°).
- Счётчики/общую логику держи в ОДНОМ глобальном скрипте; объекты шлют game.broadcast (скрипты объектов не видят переменные друг друга).
- spawn примитива: тип без префикса ('cube'), модели — с 'model:', машина — 'vehicle:car'.
- material только: matte, neon, metal, glass, studs.
- Для сбора предмета: game.self.onTouch(()=>{ game.broadcast('coin'); game.self.delete(); }).
- Не используй require() и DOM/window — только game.* и обычный JS.

ПРИМЕР (килблок-лава, скрипт НА объекте):
game.self.onTouch(() => { game.player.kill(); game.ui.showText('Лава!', 2); });

ПРИМЕР (сбор монет, глобальный скрипт):
let s = 0; game.ui.score = 0;
game.onMessage('coin', () => { s++; game.ui.score = s; game.sound.play('coin'); });

Теперь напиши скрипт под мою задачу (она ниже). Укажи, КУДА его вставить (глобальный или на объект).`;

export const DOCS = [
    // ════════════════════════════════════════════════════
    // РАЗДЕЛ A — ОСНОВЫ
    // ════════════════════════════════════════════════════
    {
        id: 'basics',
        icon: 'rocket',
        title: 'Основы',
        summary: 'С чего начать: интерфейс редактора, инструменты, первая игра за 5 минут.',
        sections: [
            {
                id: 'what-is-rublox',
                title: 'A1. Что такое Рублокс и редактор игр',
                body: (
                    <>
                        <p>
                            <b>Рублокс</b> — это платформа, где можно играть в 3D-игры
                            и создавать свои собственные. Всё работает прямо в браузере:
                            ничего скачивать и устанавливать не нужно.
                        </p>
                        <p>
                            <b>Редактор игр</b> (его ещё называют Studio) — это место,
                            где ты строишь игру. Ты ставишь блоки и модели, рисуешь
                            кнопки, пишешь скрипты — а потом нажимаешь «Играть»
                            и сразу проверяешь, что получилось.
                        </p>
                        <p>В Рублоксе можно сделать почти любую игру:</p>
                        <ul>
                            <li>паркур и платформеры — прыгай по платформам;</li>
                            <li>гонки — мчись к финишу на время;</li>
                            <li>стрелялки и арены — сражайся с врагами;</li>
                            <li>головоломки и квесты — решай загадки;</li>
                            <li>выживалки и целые RPG с героями и заданиями.</li>
                        </ul>
                        <p>
                            <b>Как устроена эта вика.</b> Разделы A-C научат строить
                            мир и интерфейс. Разделы D-G — писать скрипты (код, который
                            оживляет игру). Раздел H — справочник всех команд. Раздел I —
                            словарик непонятных слов. Раздел J — что делать, если
                            что-то сломалось. Раздел K — 50 готовых игр-уроков.
                        </p>
                        <Note>
                            Не нужно читать всё подряд. Пройди раздел «Основы»,
                            а дальше открывай то, что нужно прямо сейчас.
                        </Note>
                    </>
                ),
            },
            {
                id: 'editor-interface',
                title: 'A2. Интерфейс редактора',
                body: (
                    <>
                        <p>
                            Когда ты открываешь игру в редакторе, экран делится
                            на части. Разберём каждую:
                        </p>
                        <Shot src="a2-overview.png" wide
                              caption="Четыре главные зоны редактора" />
                        <ul>
                            <li>
                                <b>1 — Шапка сверху</b> — название игры и кнопки:
                                <kbd className="kbd">Настройки</kbd>,
                                <kbd className="kbd">Сохранить</kbd>,
                                <kbd className="kbd">Играть</kbd>,
                                <kbd className="kbd">Опубликовать</kbd>.
                            </li>
                            <li>
                                <b>2 — Лента инструментов</b> под шапкой — вкладки
                                <i> Главная / Модель / Игра / Вид</i>. На каждой вкладке
                                свои кнопки и инструменты.
                            </li>
                            <li>
                                <b>3 — 3D-сцена (вьюпорт)</b> — твой игровой мир
                                в центре экрана. Тут ты всё и строишь.
                            </li>
                            <li>
                                <b>4 — Правая панель</b> — сверху <i>Иерархия</i> (список
                                всех объектов), снизу <i>Инспектор</i> (свойства того
                                объекта, который ты выделил мышкой).
                            </li>
                        </ul>
                        <p>
                            Когда ты выбираешь инструмент «Блок» или «Примитив»,
                            слева открывается ещё одна <b>палитра</b> — там лежат
                            фигуры, которые можно ставить на сцену.
                        </p>
                        <Shot src="a2-topbar.png"
                              caption="Шапка: название игры и главные кнопки" />
                        <Shot src="a2-ribbon.png" wide
                              caption="Лента инструментов — все инструменты создания" />
                        <p><b>Как двигать камеру в редакторе:</b></p>
                        <table className="docTable">
                            <tbody>
                                <tr><td>Правая кнопка мыши + движение</td><td>осмотреться по сторонам</td></tr>
                                <tr><td><kbd className="kbd">W</kbd><kbd className="kbd">A</kbd><kbd className="kbd">S</kbd><kbd className="kbd">D</kbd></td><td>лететь вперёд / влево / назад / вправо</td></tr>
                                <tr><td>Колесо мыши</td><td>приблизить / отдалить</td></tr>
                            </tbody>
                        </table>
                        <Note>
                            Камера редактора и камера игрока — это <b>разные</b> камеры.
                            То, как ты летаешь по сцене сейчас, не влияет на то, как
                            будет видеть мир игрок.
                        </Note>
                    </>
                ),
            },
            {
                id: 'first-game-5min',
                title: 'A3. Первая игра за 5 минут',
                body: (
                    <>
                        <p>
                            Соберём самую простую игру — площадку, по которой можно
                            ходить. Делай по шагам.
                        </p>
                        <Step n="1">
                            Открой редактор и создай <b>новую игру</b>
                            (или выбери пустой шаблон).
                        </Step>
                        <Step n="2">
                            На вкладке <b>Главная</b> выбери инструмент
                            <kbd className="kbd">Блок</kbd>. В левой палитре кликни
                            на блок травы — он станет выбранным.
                        </Step>
                        <Step n="3">
                            Кликай по сцене — блоки будут вставать один за другим.
                            Собери небольшую площадку примерно 6×6 блоков.
                        </Step>
                        <Step n="4">
                            Перейди на вкладку <b>Игра</b> и выбери
                            <kbd className="kbd">Ставить спавн</kbd>. Кликни
                            на площадку — там появится точка, где игрок начнёт игру.
                        </Step>
                        <Step n="5">
                            Нажми <kbd className="kbd">Играть</kbd> в шапке. Ты
                            окажешься на своей площадке и сможешь по ней ходить!
                        </Step>
                        <Step n="6">
                            Нажми <kbd className="kbd">Esc</kbd>, чтобы вернуться
                            в редактор, и <kbd className="kbd">Сохранить</kbd>.
                        </Step>
                        <p>
                            Поздравляем — это уже работающая игра. Дальше ты добавишь
                            в неё препятствия, врагов, монетки и логику.
                        </p>
                        <Try>
                            добавь по краям площадки стены из блоков, чтобы нельзя
                            было упасть. И поставь в центре несколько блоков-ступенек.
                        </Try>
                    </>
                ),
            },
            {
                id: 'creation-tools',
                title: 'A4. Инструменты: блок, примитив, модель, ландшафт',
                body: (
                    <>
                        <p>На вкладке <b>Главная</b> есть инструменты создания:</p>
                        <Shot src="a4-tools.png"
                              caption="Инструменты создания: Блок, Примитив, Модель" />
                        <ul>
                            <li>
                                <b>Блок</b> — ставит кубический блок (трава, камень,
                                дерево...). Блоки ровно встают по сетке — из них удобно
                                строить дома и стены, как из кубиков Лего.
                            </li>
                            <li>
                                <b>Примитив</b> — простая фигура: куб, сфера, цилиндр,
                                конус, плоскость, тор, клин. У примитива можно свободно
                                менять размер по каждой оси и красить в любой цвет.
                            </li>
                            <li>
                                <b>Модель</b> — готовая красивая 3D-модель из библиотеки
                                (дерево, бочка, машина, оружие). Можно загружать и свои
                                модели в формате <code>.glb</code>.
                            </li>
                            <li>
                                <b>Ландшафт</b> — инструмент лепки рельефа: холмы, горы,
                                пещеры. Об этом — раздел B4.
                            </li>
                            <li>
                                <b>Стереть</b> — удаляет блок или объект под курсором.
                            </li>
                        </ul>
                        <p>
                            Когда выбираешь «Блок» или «Примитив», слева открывается
                            <b> палитра</b> — выбери в ней фигуру, а потом кликай
                            по сцене, чтобы её поставить.
                        </p>
                        <Shot src="a4-palette.png"
                              caption="Палитра примитивов — выбранная фигура подсвечена синим" />
                        <p>
                            <b>Шаг привязки</b> (1.0 / 0.5 / 0.25 / Выкл) — задаёт,
                            насколько мелко объект «прилипает» к сетке, когда ты его
                            двигаешь. Шаг 1.0 — объект двигается крупными шагами,
                            ровно по клеткам. Маленький шаг 0.25 — точнее, но дольше.
                        </p>
                        <Shot src="a4-snap.png"
                              caption="Переключатель шага привязки" />
                        <Note>
                            Чем отличаются блок и примитив-куб? Блок всегда одного
                            размера и быстро ставится сеткой — он для стройки.
                            Примитив-куб можно растянуть в длинную платформу или
                            тонкую стенку — он для геймплея.
                        </Note>
                    </>
                ),
            },
            {
                id: 'gizmo',
                title: 'A5. Гизмо-манипуляторы: двигать, вращать, масштаб',
                body: (
                    <>
                        <p>
                            <b>Гизмо</b> — это цветные стрелки и кольца, которые
                            появляются на выделенном объекте. Они помогают точно
                            его двигать, поворачивать и менять размер.
                        </p>
                        <p>
                            Режим гизмо выбирается в ленте инструментов — группа
                            «Манипуляторы»:
                        </p>
                        <Shot src="a5-gizmo-tools.png"
                              caption="Кнопки гизмо: Выделить, Двигать, Вращать, Масштаб" />
                        <table className="docTable">
                            <tbody>
                                <tr><td><b>Выделить</b></td><td>обычный режим, клик выбирает объект</td></tr>
                                <tr><td><b>Двигать</b></td><td>три стрелки X / Y / Z — тяни, объект едет по оси</td></tr>
                                <tr><td><b>Вращать</b></td><td>три кольца — тяни, объект поворачивается</td></tr>
                                <tr><td><b>Масштаб</b></td><td>кубики на осях — тяни, объект растягивается</td></tr>
                            </tbody>
                        </table>
                        <p>
                            Вот как выглядит гизмо «Двигать» на выделенном кубе —
                            три цветные стрелки:
                        </p>
                        <Shot src="a5-gizmo.png"
                              caption="Гизмо «Двигать»: стрелки X (красная), Y (зелёная), Z (синяя)" />
                        <p>
                            Оси всегда одни и те же и покрашены одинаково:
                        </p>
                        <ul>
                            <li><b>X</b> (красная) — влево / вправо;</li>
                            <li><b>Y</b> (зелёная) — вверх / вниз;</li>
                            <li><b>Z</b> (синяя) — вперёд / назад.</li>
                        </ul>
                        <Note>
                            Эти же буквы X, Y, Z ты увидишь в скриптах. Когда команда
                            пишет <code>{`{ x: 5, y: 2, z: 0 }`}</code> — это точка
                            в мире: 5 вправо, 2 вверх, 0 вперёд.
                        </Note>
                    </>
                ),
            },
            {
                id: 'hierarchy',
                title: 'A6. Иерархия объектов и папки',
                body: (
                    <>
                        <p>
                            <b>Иерархия</b> — это список всех объектов твоей игры
                            в правой панели. Когда сцена большая, найти нужный куб
                            мышкой трудно — а в списке он всегда под рукой.
                        </p>
                        <Shot src="a6-hierarchy.png"
                              caption="Правая панель: сверху иерархия объектов, снизу инспектор свойств" />
                        <p>Объекты сгруппированы по категориям:</p>
                        <ul>
                            <li><b>Сцена</b> — точка спавна, окружение, свет;</li>
                            <li><b>Игрок</b> — скин персонажа;</li>
                            <li><b>Интерфейс</b> — GUI-элементы (кнопки, надписи);</li>
                            <li><b>Скрипты</b> — твой код.</li>
                        </ul>
                        <p>
                            <b>Имя объекта.</b> У каждого объекта есть имя — его видно
                            в иерархии и можно изменить в инспекторе. Имена очень важны
                            для скриптов: команда <code>game.scene.findOne('Дверь')</code>
                            находит объект <b>по имени</b>. Давай объектам понятные
                            имена: «Дверь», «Монетка1», «Босс».
                        </p>
                        <p>
                            <b>Папки.</b> Объекты можно складывать в свои папки —
                            например, папка «Уровень 1», папка «Враги». Это как
                            наводить порядок в шкафу: всё на своих полках. Двойной
                            клик по объекту в списке — камера прилетит прямо к нему.
                        </p>
                    </>
                ),
            },
            {
                id: 'hotkeys',
                title: 'A7. Горячие клавиши',
                body: (
                    <>
                        <p>Горячие клавиши экономят кучу времени:</p>
                        <table className="docTable">
                            <tbody>
                                <tr><td><kbd className="kbd">Ctrl</kbd>+<kbd className="kbd">S</kbd></td><td>Сохранить игру</td></tr>
                                <tr><td><kbd className="kbd">Ctrl</kbd>+<kbd className="kbd">Z</kbd></td><td>Отменить последнее действие</td></tr>
                                <tr><td><kbd className="kbd">Ctrl</kbd>+<kbd className="kbd">D</kbd></td><td>Дублировать выделенный объект</td></tr>
                                <tr><td><kbd className="kbd">Del</kbd></td><td>Удалить выделенное</td></tr>
                                <tr><td><kbd className="kbd">R</kbd></td><td>Повернуть объект на 90°</td></tr>
                                <tr><td><kbd className="kbd">Esc</kbd></td><td>Снять выделение / выйти из режима</td></tr>
                                <tr><td><kbd className="kbd">F</kbd></td><td>Навести камеру на выделенное</td></tr>
                            </tbody>
                        </table>
                        <Note>
                            Самая полезная привычка — почаще жать
                            <kbd className="kbd">Ctrl</kbd>+<kbd className="kbd">S</kbd>.
                            Сохраняться нужно не «когда закончил», а каждые пару минут.
                        </Note>
                    </>
                ),
            },
            {
                id: 'play-mode',
                title: 'A8. Режим игры: HP, смерть, респаун',
                body: (
                    <>
                        <p>
                            Кнопка <kbd className="kbd">Запустить</kbd> в правой части
                            ленты запускает игру. Сцена «оживает»: включается физика,
                            начинают работать скрипты, появляется HUD (счётчики поверх
                            экрана). Чтобы остановить игру — кнопка
                            <kbd className="kbd">Стоп</kbd> или клавиша
                            <kbd className="kbd">Esc</kbd>.
                        </p>
                        <Shot src="a8-play.png"
                              caption="Кнопка «Запустить» — проверить игру; «Стоп» — вернуться в редактор" />
                        <p><b>Управление в игре:</b></p>
                        <table className="docTable">
                            <tbody>
                                <tr><td><kbd className="kbd">W</kbd><kbd className="kbd">A</kbd><kbd className="kbd">S</kbd><kbd className="kbd">D</kbd></td><td>Идти</td></tr>
                                <tr><td><kbd className="kbd">Space</kbd></td><td>Прыжок</td></tr>
                                <tr><td><kbd className="kbd">Shift</kbd></td><td>Бег</td></tr>
                                <tr><td>Мышь</td><td>Поворот камеры</td></tr>
                                <tr><td>ЛКМ</td><td>Атака / стрельба</td></tr>
                                <tr><td><kbd className="kbd">E</kbd></td><td>Взаимодействовать</td></tr>
                                <tr><td><kbd className="kbd">1</kbd>…<kbd className="kbd">5</kbd></td><td>Слот инвентаря</td></tr>
                                <tr><td><kbd className="kbd">C</kbd></td><td>1-е / 3-е лицо</td></tr>
                            </tbody>
                        </table>
                        <p>
                            <b>HP (здоровье)</b> игрока видно в левом верхнем углу.
                            Когда игрок получает урон, полоска краснеет. Если HP падает
                            до нуля — игрок «умирает» и через пару секунд
                            <b> воскресает (респаун)</b> на точке спавна с полным
                            здоровьем.
                        </p>
                        <p>
                            Всем этим можно управлять из скриптов: наносить урон,
                            лечить, ставить чекпоинты. Об этом — раздел F1.
                        </p>
                    </>
                ),
            },
            {
                id: 'save-publish',
                title: 'A9. Сохранение и публикация',
                body: (
                    <>
                        <p>
                            <b>Сохранение</b> — кнопка <kbd className="kbd">Сохранить</kbd>
                            или <kbd className="kbd">Ctrl</kbd>+<kbd className="kbd">S</kbd>.
                            Игра автоматически сохраняется и сама время от времени,
                            но лучше не лениться и сохранять руками.
                        </p>
                        <p>
                            <b>Публикация</b> — когда игра готова, нажми
                            <kbd className="kbd">Опубликовать</kbd>. Выбери
                            возрастной рейтинг (6+, 12+, 16+, 18+) и куда отправить:
                        </p>
                        <ul>
                            <li>
                                <b>В главную ленту</b> — игру увидят все ученики.
                                Модерация строже.
                            </li>
                            <li>
                                <b>Только в профиле</b> — игра доступна по ссылке
                                и в твоём профиле, но в общей ленте её не будет.
                            </li>
                        </ul>
                        <p>
                            После отправки игру проверит модератор (обычно за 24-48
                            часов). Игра <b>не должна</b> содержать матов, рекламы,
                            чужого контента (модели из Roblox/Minecraft) и жестокости
                            не по возрасту.
                        </p>
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ B — ОБЪЕКТЫ СЦЕНЫ
    // ════════════════════════════════════════════════════
    {
        id: 'objects',
        icon: 'cube',
        title: 'Объекты сцены',
        summary: 'Блоки, примитивы, модели, ландшафт, свет, частицы и свойства объектов.',
        sections: [
            {
                id: 'blocks',
                title: 'B1. Блоки и их типы',
                body: (
                    <>
                        <p>
                            <b>Блок</b> — это кубик одного размера. Блоки ровно
                            встают по сетке, и из них удобно строить — как из кубиков
                            Лего. В палитре слева есть разные типы: трава, камень,
                            песок, дерево, кирпич, цветные блоки, блоки со снегом.
                        </p>
                        <p>
                            Чтобы поставить блок — выбери инструмент
                            <kbd className="kbd">Блок</kbd>, кликни нужный тип
                            в палитре и кликай по сцене. Чтобы убрать — инструмент
                            <kbd className="kbd">Стереть</kbd>.
                        </p>
                        <Shot src="b1-blocks.png"
                              caption="Палитра блоков — типы сгруппированы по вкладкам" />
                        <p>
                            У блока в инспекторе можно включить/выключить
                            <i> столкновение</i> (твёрдый он или сквозь него можно
                            пройти) и <i>видимость</i>.
                        </p>
                        <Note>
                            Невидимый блок с включённым столкновением — это уже
                            готовый «невидимый барьер». Игрок в него упрётся,
                            но не увидит. Так делают границы уровня.
                        </Note>
                    </>
                ),
            },
            {
                id: 'primitives',
                title: 'B2. Примитивы',
                body: (
                    <>
                        <p>
                            <b>Примитив</b> — простая 3D-фигура. В отличие от блока,
                            у примитива можно свободно менять размер по каждой оси
                            и красить в любой цвет. Виды:
                        </p>
                        <table className="docTable">
                            <tbody>
                                <tr><td><b>Куб</b></td><td>стены, платформы, ящики</td></tr>
                                <tr><td><b>Сфера</b></td><td>мячи, монетки, планеты</td></tr>
                                <tr><td><b>Цилиндр</b></td><td>колонны, бочки, трубы</td></tr>
                                <tr><td><b>Конус</b></td><td>шипы, ёлки, шляпы</td></tr>
                                <tr><td><b>Плоскость</b></td><td>тонкий лист — пол, экран</td></tr>
                                <tr><td><b>Тор</b></td><td>кольцо (как бублик)</td></tr>
                                <tr><td><b>Клин</b></td><td>наклонная фигура — пандус</td></tr>
                            </tbody>
                        </table>
                        <p>
                            Примитивы — главный «строительный материал» для игр.
                            Из растянутых кубов делают платформы для паркура,
                            из сфер — собираемые монетки, из конусов — смертельные
                            шипы.
                        </p>
                        <Note>
                            Чтобы в скрипте было легко найти примитив — дай ему
                            понятное имя в инспекторе. Например, «Платформа1». Потом
                            скрипт найдёт её командой
                            <code> game.scene.findOne('Платформа1')</code>.
                        </Note>
                    </>
                ),
            },
            {
                id: 'models',
                title: 'B3. Готовые модели и импорт своих',
                body: (
                    <>
                        <p>
                            <b>Модель</b> — готовая красивая 3D-фигура: дерево, камень,
                            бочка, машина, оружие, мебель. Их не нужно строить из
                            кубиков — просто бери из библиотеки и ставь на сцену.
                        </p>
                        <p>
                            Инструмент <kbd className="kbd">Модель</kbd> открывает
                            каталог. Модели разбиты по категориям (природа, город,
                            оружие...).
                        </p>
                        <Shot src="b3-models.png" wide
                              caption="Тулбокс — библиотека готовых 3D-моделей" />
                        <p>
                            <b>Свои модели.</b> Можно загрузить собственную 3D-модель
                            в формате <code>.glb</code>. Такие файлы делают в бесплатных
                            редакторах вроде Blender или берут на сайтах с бесплатными
                            моделями. После загрузки твоя модель появится в палитре
                            рядом с остальными.
                        </p>
                        <Note>
                            Не бери модели из других игр (Roblox, Minecraft) —
                            это чужой контент, игру с ним не пропустит модерация.
                            Бери только бесплатные модели «для свободного использования».
                        </Note>
                    </>
                ),
            },
            {
                id: 'terrain',
                title: 'B4. Ландшафт: воксельный и гладкий',
                body: (
                    <>
                        <p>
                            <b>Ландшафт</b> — это рельеф мира: холмы, горы, ямы, пещеры.
                            В Рублоксе два режима:
                        </p>
                        <ul>
                            <li>
                                <b>Воксельный</b> — рельеф из маленьких кубиков-вокселей.
                                Получается «ступенчатый», как в Minecraft. Удобно
                                рисовать пещеры и обрывы.
                            </li>
                            <li>
                                <b>Гладкий</b> — рельеф из плавных холмов без ступенек.
                                Похоже на настоящую землю.
                            </li>
                        </ul>
                        <p>
                            Инструменты лепки: <i>поднять</i>, <i>опустить</i>,
                            <i> разгладить</i>, <i>покрасить</i>. Есть и кисти-растения —
                            рисуешь по земле, и сразу вырастают деревья и трава.
                        </p>
                        <Note>
                            Если в игре есть гладкий ландшафт, ставь точку спавна
                            прямо на его поверхности. Если спавн окажется ниже земли —
                            игрок при старте провалится. Высоту земли в скрипте можно
                            узнать командой <code>game.scene.surfaceY(x, z)</code>.
                        </Note>
                    </>
                ),
            },
            {
                id: 'spawn-checkpoints',
                title: 'B5. Точка спавна и чекпоинты',
                body: (
                    <>
                        <p>
                            <b>Точка спавна</b> — место, где игрок появляется в начале
                            игры и куда возвращается после смерти. Ставится на вкладке
                            <i> Игра → Ставить спавн</i>. Точка спавна одна.
                        </p>
                        <p>
                            <b>Чекпоинт (контрольная точка)</b> — промежуточное место
                            сохранения в длинных уровнях. Когда игрок дошёл до чекпоинта,
                            при следующей смерти он воскреснет уже там, а не в самом
                            начале.
                        </p>
                        <p>
                            Чекпоинт делают скриптом на флажке-объекте: когда игрок
                            касается флажка, скрипт запоминает это место как новый спавн.
                        </p>
                        <ScriptKind kind="object" on="флажок-чекпоинт" />
                        <Code>{`// Когда игрок коснётся флажка —
// это место станет новой точкой возрождения.
game.self.onTouch(() => {
  // game.self.position — координаты самого флажка
  game.player.setSpawn(game.self.position);
  game.ui.showText('Чекпоинт сохранён!', 1.5);
  game.sound.play('pickup');
});`}</Code>
                        <p>
                            Что тут происходит: <code>onTouch</code> срабатывает,
                            когда игрок дотронулся до флажка. <code>setSpawn</code>
                            запоминает точку возрождения. <code>showText</code>
                            показывает надпись на 1.5 секунды. Готово — игрок
                            не начнёт уровень заново.
                        </p>
                    </>
                ),
            },
            {
                id: 'lamps',
                title: 'B6. Лампы (источники света)',
                body: (
                    <>
                        <p>
                            <b>Лампа</b> — это источник света. Кроме общего солнца,
                            можно поставить точечные лампы, которые освещают всё рядом
                            с собой. Они нужны для пещер, ночных уровней, подсветки
                            важных мест.
                        </p>
                        <p>
                            У лампы настраиваются <b>цвет</b>, <b>яркость</b>
                            и <b>радиус</b> (как далеко достаёт свет). Лампу можно
                            создать и из скрипта:
                        </p>
                        <ScriptKind kind="global" />
                        <Code>{`// Создаём тёплую лампу над сценой
game.scene.spawn('light:point', {
  x: 0, y: 4, z: 0,   // где висит лампа
  color: '#ffdd88',   // тёплый жёлтый свет
  brightness: 2,      // яркость
  range: 12           // радиус освещения
});`}</Code>
                    </>
                ),
            },
            {
                id: 'particles',
                title: 'B7. Эмиттеры частиц',
                body: (
                    <>
                        <p>
                            <b>Частицы</b> — это много маленьких летящих точек:
                            искры, дым, огонь, магия. Объект, который их создаёт,
                            называется <b>эмиттер</b>.
                        </p>
                        <p>
                            Частицы делают игру живой: костёр дымит, при победе летит
                            конфетти, у портала кружится магия. Из скрипта это команда
                            <code> game.scene.spawnParticles</code>:
                        </p>
                        <ScriptKind kind="global" />
                        <Code>{`// Залп конфетти над центром сцены
game.scene.spawnParticles(
  'confetti',              // тип эффекта
  { x: 0, y: 3, z: 0 },    // где появятся частицы
  { duration: 2, count: 3 } // длительность и густота
);`}</Code>
                        <p>
                            Типы эффектов: <code>fire</code> (огонь),
                            <code> smoke</code> (дым), <code>sparks</code> (искры),
                            <code> magic</code> (магия), <code>explosion</code> (взрыв),
                            <code> confetti</code> (конфетти).
                        </p>
                    </>
                ),
            },
            {
                id: 'triggers',
                title: 'B8. Триггеры',
                body: (
                    <>
                        <p>
                            <b>Триггер</b> — невидимая зона, которая что-то запускает,
                            когда игрок в неё входит. Например: игрок зашёл в зону —
                            открылась дверь, заиграла музыка, появился враг.
                        </p>
                        <p><b>Как сделать триггер:</b></p>
                        <Step n="1">
                            Поставь примитив-куб нужного размера — это и будет зона.
                        </Step>
                        <Step n="2">
                            В инспекторе <b>выключи столкновение</b> (чтобы игрок
                            проходил сквозь) и можно выключить <b>видимость</b>
                            (чтобы зону не было видно).
                        </Step>
                        <Step n="3">
                            Повесь на этот куб скрипт, который ловит касание игрока:
                        </Step>
                        <ScriptKind kind="object" on="куб-триггер" />
                        <Code>{`// Игрок вошёл в зону — показываем надпись
game.self.onTouch(() => {
  game.ui.showText('Ты вошёл в опасную зону!', 2);
});

// Игрок вышел из зоны
game.self.onUntouch(() => {
  game.ui.showText('Ты в безопасности', 1.5);
});`}</Code>
                    </>
                ),
            },
            {
                id: 'object-properties',
                title: 'B9. Свойства объекта: цвет, материал, физика, замок',
                body: (
                    <>
                        <p>
                            Когда ты выделяешь объект, в <b>Инспекторе</b> (правая
                            панель снизу) появляются его свойства:
                        </p>
                        <Shot src="b9-inspector.png"
                              caption="Инспектор свойств примитива: позиция, размер, цвет, материал" />
                        <table className="docTable">
                            <tbody>
                                <tr><td><b>Цвет</b></td><td>закрасить примитив в любой цвет</td></tr>
                                <tr><td><b>Материал</b></td><td>обычный, металл, стекло, неон — как объект блестит</td></tr>
                                <tr><td><b>Текстура</b></td><td>наложить свою картинку на поверхность</td></tr>
                                <tr><td><b>Столкновение</b></td><td>твёрдый объект или сквозь него можно пройти</td></tr>
                                <tr><td><b>Видимость</b></td><td>показать или спрятать объект</td></tr>
                                <tr><td><b>Закреплён</b></td><td>если выключить — объект падает под действием физики</td></tr>
                                <tr><td><b>Замок (Lock)</b></td><td>заблокировать, чтобы случайно не сдвинуть</td></tr>
                            </tbody>
                        </table>
                        <Note>
                            Свойство «Закреплён» — частая причина бага «объект
                            провалился сквозь пол». Для платформ, стен и декораций
                            всегда оставляй «Закреплён» включённым. Падать должны
                            только ящики и мячи, которым это нужно.
                        </Note>
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ C — ИНТЕРФЕЙС ИГРЫ (GUI)
    // ════════════════════════════════════════════════════
    {
        id: 'gui',
        icon: 'window',
        title: 'Интерфейс игры',
        summary: 'GUI: кнопки, надписи, поля ввода, меню и счётчики поверх экрана.',
        sections: [
            {
                id: 'gui-what-is',
                title: 'C1. Что такое GUI и редактор интерфейса',
                body: (
                    <>
                        <p>
                            <b>GUI</b> (читается «гуи») — это интерфейс игры:
                            всё, что нарисовано поверх 3D-сцены. Кнопки, надписи,
                            счётчик очков, полоска здоровья, меню — это всё GUI.
                        </p>
                        <p>
                            GUI не находится внутри игрового мира — он «приклеен»
                            к экрану. Куда бы ни смотрел игрок, кнопка остаётся
                            на том же месте экрана.
                        </p>
                        <p>
                            В редакторе есть <b>визуальный редактор UI</b>: ты
                            перетаскиваешь элементы мышкой, ставишь их в нужное место,
                            меняешь цвет и текст — и сразу видишь результат. Открыть
                            его можно через инструмент <kbd className="kbd">Интерфейс</kbd>.
                        </p>
                        <Note>
                            Не путай <b>GUI</b> и <b>HUD</b>. GUI — это элементы,
                            которые ты сам нарисовал в редакторе интерфейса.
                            HUD — стандартные счётчики (<code>game.ui.score</code>,
                            <code> game.ui.timer</code>), которые рисует сама игра
                            по команде из скрипта.
                        </Note>
                    </>
                ),
            },
            {
                id: 'gui-elements',
                title: 'C2. Контейнер, надпись, кнопка, поле ввода, картинка',
                body: (
                    <>
                        <p>Из чего собирается интерфейс:</p>
                        <Shot src="c2-gui-palette.png"
                              caption="Палитра элементов интерфейса — перетащи на экран игры" />
                        <ul>
                            <li>
                                <b>Контейнер (Frame)</b> — прямоугольник-коробка.
                                Сам по себе это просто фон, но внутрь него кладут
                                другие элементы. Контейнер — основа любого меню.
                            </li>
                            <li>
                                <b>Надпись (Label)</b> — текст на экране. Счёт, имя
                                игрока, подсказки.
                            </li>
                            <li>
                                <b>Кнопка (Button)</b> — на неё можно нажать. По клику
                                в скрипте срабатывает действие.
                            </li>
                            <li>
                                <b>Поле ввода (TextBox)</b> — сюда игрок печатает текст
                                или число. Например, ввести код от двери.
                            </li>
                            <li>
                                <b>Картинка (Image)</b> — изображение: иконка, логотип,
                                фон меню.
                            </li>
                        </ul>
                        <p>
                            <b>Имя элемента.</b> Как и у объектов сцены, у GUI-элемента
                            есть имя. Скрипт находит элемент по имени командой
                            <code> game.gui.find('Кнопка старта')</code>. Давай
                            кнопкам и надписям понятные имена.
                        </p>
                    </>
                ),
            },
            {
                id: 'gui-script',
                title: 'C3. Как оживить кнопку скриптом',
                body: (
                    <>
                        <p>
                            Нарисованная кнопка сама по себе ничего не делает —
                            нужен скрипт.
                        </p>
                        <ScriptKind kind="object" on="кнопку" />
                        <LangTabs
                            js={<Code>{`// Скрипт висит на кнопке.
// game.self — это сама кнопка.
game.self.onClick(() => {
  game.ui.showText('Кнопка нажата!', 2);
  game.sound.play('click');
});`}</Code>}
                            lua={<Code>{`-- Скрипт висит на кнопке (TextButton)
-- script.Parent — это сама кнопка.
local btn = script.Parent

btn.MouseButton1Click:Connect(function()
    print("Кнопка нажата!")
end)`}</Code>}
                        />
                        <p>Можно и наоборот — управлять кнопкой из глобального скрипта:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`// Находим кнопку по имени и вешаем на неё клик
const btnId = game.gui.find('Кнопка старта');

game.gui.onClick(btnId, () => {
  game.ui.showText('Игра началась!', 2);
  game.gui.hide(btnId);          // спрятать кнопку после нажатия
});`}</Code>}
                            lua={<Code>{`local Players = game:GetService("Players")
local player = Players.LocalPlayer
local gui = player:WaitForChild("PlayerGui")

-- Находим кнопку по имени (она лежит где-то в PlayerGui)
local btn = gui:FindFirstChild("Кнопка старта", true)

btn.MouseButton1Click:Connect(function()
    print("Игра началась!")
    btn.Visible = false        -- спрятать кнопку
end)`}</Code>}
                        />
                        <p>
                            JS: <code>game.gui.find</code> ищет элемент по имени.
                            <code> game.gui.onClick</code> вешает действие, <code>game.gui.hide</code> прячет.
                        </p>
                        <p>
                            Lua: <code>gui:FindFirstChild(name, true)</code> ищет рекурсивно
                            (третий аргумент <code>true</code> = во вложенных).
                            <code> MouseButton1Click</code> — стандартный сигнал клика на TextButton.
                            <code> btn.Visible = false</code> прячет элемент.
                        </p>
                    </>
                ),
            },
            {
                id: 'gui-textbox',
                title: 'C4. Поле ввода: дверь по коду',
                body: (
                    <>
                        <p>
                            <b>Поле ввода</b> позволяет игроку напечатать ответ.
                            Когда он нажмёт Enter, скрипт получает введённый текст.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`// Игрок вводит код. Правильный код — 1234.
const boxId = game.gui.find('Поле кода');

game.gui.onSubmit(boxId, (text) => {
  if (text === '1234') {
    game.ui.showText('Верно! Дверь открыта', 2);
    const door = game.scene.findOne('Дверь');
    game.tween(door, { y: 8 }, { duration: 1 });
  } else {
    game.ui.showText('Неверный код', 1.5);
  }
});`}</Code>}
                            lua={<Code>{`local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local player = Players.LocalPlayer
local gui = player:WaitForChild("PlayerGui")

-- Находим TextBox по имени
local box = gui:FindFirstChild("Поле кода", true)

-- FocusLost срабатывает когда игрок нажал Enter или ушёл с поля.
-- Первый параметр enterPressed = true только если был Enter.
box.FocusLost:Connect(function(enterPressed)
    if not enterPressed then return end

    if box.Text == "1234" then
        print("Верно! Дверь открыта")
        local door = workspace:WaitForChild("Дверь")
        local goal = { Position = door.Position + Vector3.new(0, 8, 0) }
        TweenService:Create(door, TweenInfo.new(1), goal):Play()
    else
        print("Неверный код")
    end
end)`}</Code>}
                        />
                        <p>
                            JS-разбор: <code>onSubmit</code> даёт переменную
                            <code> text</code> — то, что напечатал игрок.
                            <code> if (text === '1234')</code> — проверяем код.
                        </p>
                        <p>
                            Lua-разбор: на TextBox сигнал <code>FocusLost</code>
                            срабатывает когда поле теряет фокус (Enter или клик мимо).
                            Текст лежит в <code>box.Text</code>.
                        </p>
                        <Note>
                            Кавычки <code>"1234"</code> означают, что это
                            <b> текст</b>, а не число. Игрок печатает в поле всегда
                            текст, поэтому и сравнивать нужно с текстом.
                        </Note>
                    </>
                ),
            },
            {
                id: 'gui-styles',
                title: 'C5. Стили и загрузка картинок',
                body: (
                    <>
                        <p>
                            У каждого GUI-элемента в инспекторе настраивается внешний
                            вид: <b>цвет фона</b> и прозрачность, <b>граница</b>
                            (рамка, её цвет и толщина), <b>скругление углов</b>
                            (большое скругление делает кнопку «таблеткой»),
                            <b> тень</b> (мягкая тень под элементом),
                            <b> цвет и размер текста</b>.
                        </p>
                        <p>
                            В элемент <b>Картинка</b> можно загрузить своё изображение
                            с компьютера (PNG или JPG): логотип игры, иконку кнопки,
                            фон главного меню.
                        </p>
                        <Note>
                            Хороший интерфейс — это аккуратный интерфейс. Один стиль
                            для всех кнопок, один шрифт, выровненные отступы. Картинки
                            бери небольшие — огромные файлы делают игру тяжёлой.
                        </Note>
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ D — СКРИПТЫ — ОСНОВЫ
    // ════════════════════════════════════════════════════
    {
        id: 'scripts-basics',
        icon: 'code',
        title: 'Скрипты — основы',
        summary: 'Самый важный раздел: что такое скрипт, переменные, события, таймеры.',
        sections: [
            {
                id: 'js-or-lua',
                title: 'D0. Скриптинг: JS или Lua — что выбрать?',
                body: (
                    <>
                        <p>
                            В Рублоксе можно писать скрипты <b>на двух языках</b>:
                            <b> JavaScript</b> и <b>Lua</b>. Оба работают одинаково
                            хорошо. Игра не отличает их между собой — внутри одного
                            проекта одни скрипты могут быть на JS, другие на Lua,
                            и они общаются между собой как будто это один язык.
                        </p>
                        <p><b>Чем они отличаются?</b></p>
                        <table className="docTable">
                            <thead>
                                <tr><th></th><th>JavaScript</th><th>Lua</th></tr>
                            </thead>
                            <tbody>
                                <tr>
                                    <td><b>Где ещё используется</b></td>
                                    <td>Сайты, мобильные приложения, серверы.
                                        Самый популярный язык в мире.</td>
                                    <td>Roblox, World of Warcraft (моды),
                                        многие игры. Простой и быстрый.</td>
                                </tr>
                                <tr>
                                    <td><b>Главный API</b></td>
                                    <td><code>game.*</code> (game.player,
                                        game.log, game.scene)</td>
                                    <td><code>game.*</code> в Roblox-стиле
                                        (game:GetService("Players"), workspace)</td>
                                </tr>
                                <tr>
                                    <td><b>Похож на</b></td>
                                    <td>Roblox-LUA если знаешь Roblox</td>
                                    <td>Roblox-Studio — те же команды</td>
                                </tr>
                                <tr>
                                    <td><b>Когда выбрать</b></td>
                                    <td>Если планируешь делать сайты и приложения
                                        — JS пригодится везде.</td>
                                    <td>Если играешь в Roblox и видел там скрипты
                                        — Lua тебе знаком.</td>
                                </tr>
                            </tbody>
                        </table>

                        <p><b>Один и тот же пример на двух языках:</b></p>
                        <p>Когда игрок касается синего блока — печатаем «Привет».</p>
                        <LangTabs
                            js={<Code>{`// JS — глобальный скрипт
game.onTouch('синий-блок', (player) => {
    game.log('Привет, ' + player.name + '!');
});`}</Code>}
                            lua={<Code>{`-- Lua — скрипт на самом блоке
local part = script.Parent

part.Touched:Connect(function(hit)
    local player = game.Players:GetPlayerFromCharacter(hit.Parent)
    if player then
        print("Привет, " .. player.Name .. "!")
    end
end)`}</Code>}
                        />
                        <p>
                            Видишь — оба варианта делают <b>одно и то же</b>. Но
                            запись отличается. JS короче для простых вещей через
                            <code>game.onTouch</code>, Lua даёт точный Roblox-стиль
                            через <code>:Connect</code> и события.
                        </p>

                        <p><b>Что выбирать новичку?</b></p>
                        <Note>
                            Если ты <b>совсем новичок</b> — бери <b>JavaScript</b>.
                            Команды <code>game.*</code> в JS короче и проще читать.
                            Большая часть уроков в этой вике написана с примерами
                            на JS — все они работают, просто копируй.
                        </Note>
                        <Note>
                            Если ты <b>уже играл в Roblox</b> и видел там скрипты
                            — бери <b>Lua</b>. Команды почти один в один как
                            в Roblox Studio: <code>game:GetService</code>,
                            <code>:Connect</code>, <code>workspace</code>,
                            <code>script.Parent</code>.
                        </Note>

                        <p><b>Можно ли менять язык в одном скрипте?</b></p>
                        <p>
                            Да. В редакторе скрипта вверху есть две кнопки —
                            <b>JS</b> и <b>Lua</b>. Просто нажми на нужную.
                            Твой код на текущем языке <b>сохранится</b>, а
                            на другом языке откроется пустой шаблон или то, что
                            ты писал там раньше. Никогда ничего не теряется.
                        </p>
                        <Try>
                            Создай новый скрипт. Напиши пару строк на JS. Нажми
                            кнопку <b>Lua</b> — JS-код спрячется, появится
                            Lua-шаблон. Напиши там что-то. Нажми <b>JS</b>
                            обратно — твой JS-код вернётся. Магия!
                        </Try>

                        <p><b>А что под капотом?</b></p>
                        <p>
                            JS-скрипты исполняются в <code>WebWorker</code> —
                            это отдельный поток в браузере, чтобы скрипт не
                            тормозил саму игру. Lua-скрипты исполняются через
                            <b> wasmoon</b> — Lua-интерпретатор, скомпилированный
                            в WebAssembly. Оба варианта работают на любом
                            устройстве без установки.
                        </p>
                    </>
                ),
            },
            {
                id: 'what-is-script',
                title: 'D1. Что такое скрипт и как его создать',
                body: (
                    <>
                        <p>
                            <b>Скрипт</b> — это набор команд, который оживляет игру.
                            Блоки и модели сами по себе просто стоят. Чтобы монетка
                            собиралась, дверь открывалась, а враг гнался за игроком —
                            нужен скрипт.
                        </p>
                        <p>
                            Скрипты пишут на одном из двух языков: <b>JavaScript</b>
                            или <b>Lua</b>. Оба работают одинаково. Подробнее про
                            выбор языка — статья <b>D0</b> выше. В этом уроке покажем
                            пример на обоих языках — переключай вкладки, чтобы видеть
                            нужный.
                        </p>
                        <p><b>Как создать первый скрипт:</b></p>
                        <Step n="1">
                            В иерархии (правая панель) найди категорию <b>Скрипты</b>
                            и нажми кнопку «+».
                        </Step>
                        <Shot src="d1-scripts-tree.png"
                              caption="Категория «Скрипты» в иерархии объектов" />
                        <Step n="2">
                            Откроется окно кода. Вверху выбери язык (кнопки JS/Lua)
                            и напиши одну строку:
                        </Step>
                        <LangTabs
                            js={<Code>{`game.log('Привет! Игра запустилась.');`}</Code>}
                            lua={<Code>{`print("Привет! Игра запустилась.")`}</Code>}
                        />
                        <Shot src="d5-script-editor.png" wide
                              caption="Окно редактора кода скрипта" />
                        <Step n="3">
                            Нажми <kbd className="kbd">Играть</kbd>. Внизу справа
                            открой <b>Консоль</b> — там появится твоё сообщение.
                        </Step>
                        <p>
                            Это твой первый работающий скрипт.
                        </p>
                        <LangTabs
                            js={<Note>
                                Команда <code>game.log(...)</code> печатает в консоль.
                                Каждая команда в JavaScript заканчивается точкой с запятой
                                <code> ;</code> — как точка в предложении. Текст пишут
                                в кавычках: <code>'привет'</code>.
                            </Note>}
                            lua={<Note>
                                Команда <code>print(...)</code> печатает в консоль.
                                В Lua точку с запятой ставить <b>не нужно</b>.
                                Текст пишут в кавычках: <code>"привет"</code> или
                                <code> 'привет'</code>. Lua использует <code>..</code>
                                (две точки) для склейки текста: <code>"А=" .. 5</code>.
                            </Note>}
                        />
                    </>
                ),
            },
            {
                id: 'global-vs-object',
                title: 'D2. Глобальный скрипт и скрипт на объекте',
                body: (
                    <>
                        <p>
                            Это очень важно понять с самого начала. Скрипты бывают
                            <b> двух видов</b>, и в каждом уроке вики написано, какой
                            именно нужен.
                        </p>
                        <ScriptKind kind="global" />
                        <p>
                            Глобальный скрипт — это «мозг игры». Он не привязан
                            ни к чему. Запускается один раз при старте. В нём пишут
                            общие правила: подсчёт очков, таймер уровня, проверку
                            победы.
                        </p>
                        <ScriptKind kind="object" on="любой объект" />
                        <p>
                            Скрипт на объекте относится к конкретному кубу, модели
                            или кнопке. Внутри такого скрипта работает волшебное слово
                            (своё для каждого языка):
                        </p>
                        <LangTabs
                            js={<>
                                <Code>{`// JS: game.self — это и есть тот объект, на котором висит скрипт
game.self.onClick(() => {
  game.log('Кликнули по мне!');
});`}</Code>
                            </>}
                            lua={<>
                                <Code>{`-- Lua: script.Parent — это и есть тот объект, на котором висит скрипт
local part = script.Parent

part.Touched:Connect(function(hit)
    print("Касание объекта " .. part.Name)
end)`}</Code>
                            </>}
                        />
                        <p>
                            <b>Как привязать скрипт к объекту:</b> выдели объект
                            на сцене, потом создай скрипт — он автоматически привяжется
                            к выделенному объекту. Или укажи носителя в настройках
                            скрипта.
                        </p>
                        <LangTabs
                            js={<Note>
                                Простое правило: если в коде урока есть
                                <code> game.self</code> — это скрипт <b>на объекте</b>.
                                Если <code>game.self</code> нет — скрипт <b>глобальный</b>.
                                Плашка в начале каждого урока всегда подскажет.
                            </Note>}
                            lua={<Note>
                                Простое правило: если в коде есть
                                <code> script.Parent</code> — это скрипт <b>на объекте</b>.
                                Если только <code>game</code> — глобальный.
                                В Lua глобальные скрипты обычно работают со списком
                                игроков: <code>game:GetService("Players")</code>.
                            </Note>}
                        />
                    </>
                ),
            },
            {
                id: 'variables',
                title: 'D3. Переменные — память скрипта',
                body: (
                    <>
                        <p>
                            <b>Переменная</b> — это «коробочка с именем», в которой
                            скрипт хранит значение. Например, количество очков,
                            имя игрока, выбранный уровень.
                        </p>
                        <LangTabs
                            js={<Code>{`// JS: создаём переменную через let
let score = 0;

// Меняем значение
score = score + 10;   // теперь в score лежит 10
score = score + 5;    // теперь 15

game.log('Очков:', score);   // напечатает: Очков: 15`}</Code>}
                            lua={<Code>{`-- Lua: создаём переменную через local
local score = 0

-- Меняем значение
score = score + 10   -- теперь в score лежит 10
score = score + 5    -- теперь 15

print("Очков:", score)   -- напечатает: Очков: 15`}</Code>}
                        />
                        <LangTabs
                            js={<p>
                                <code>let</code> — это слово «создать переменную». Пишут
                                его только <b>один раз</b>, когда коробочку заводят. Дальше
                                меняют значение уже без <code>let</code>.
                            </p>}
                            lua={<p>
                                <code>local</code> — это слово «создать переменную внутри
                                скрипта». Пишут его только <b>один раз</b>. Если опустить
                                <code> local</code> — переменная станет глобальной (доступна
                                всем скриптам), это редко нужно.
                            </p>}
                        />
                        <p>В переменную можно класть не только числа:</p>
                        <LangTabs
                            js={<Code>{`let name = 'Герой';        // текст — в кавычках
let isWin = false;         // да/нет — true или false
let coinCount = 0;         // число — без кавычек`}</Code>}
                            lua={<Code>{`local name = "Герой"       -- текст — в кавычках
local isWin = false        -- да/нет — true или false
local coinCount = 0        -- число — без кавычек`}</Code>}
                        />
                        <LangTabs
                            js={<Note>
                                Если значение <b>никогда</b> не меняется — вместо
                                <code> let</code> можно писать <code>const</code>
                                («постоянная»). Например, найденную один раз дверь:
                                <code> const door = game.scene.findOne('Дверь');</code>
                            </Note>}
                            lua={<Note>
                                В Lua нет отдельного слова для «не-меняющейся» переменной —
                                всё через <code>local</code>. Если хочешь явно показать
                                что значение не меняется, пиши имя ЗАГЛАВНЫМИ:
                                <code> local DOOR = workspace.Дверь</code>.
                                Это договорённость, а не правило Lua.
                            </Note>}
                        />
                    </>
                ),
            },
            {
                id: 'game-object',
                title: 'D4. Объект game — главный инструмент',
                body: (
                    <>
                        <p>
                            В каждом скрипте есть одно главное волшебное слово —
                            <code> game</code>. Через него ты управляешь всей игрой.
                            Но «отделы» у JS и Lua разные:
                        </p>
                        <LangTabs
                            js={<>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>game.player</code></td><td>управление игроком</td></tr>
                                        <tr><td><code>game.scene</code></td><td>объекты сцены</td></tr>
                                        <tr><td><code>game.ui</code></td><td>счётчики и текст на экране</td></tr>
                                        <tr><td><code>game.gui</code></td><td>кнопки и меню</td></tr>
                                        <tr><td><code>game.sound</code></td><td>звуки</td></tr>
                                        <tr><td><code>game.physics</code></td><td>лучи, импульсы, взрывы</td></tr>
                                        <tr><td><code>game.self</code></td><td>объект-носитель скрипта</td></tr>
                                    </tbody>
                                </table>
                                <p>
                                    Запись через точку читается слева направо.
                                    <code> game.player.teleport(0, 5, 0)</code> читается так:
                                    «у <b>игры</b>, у <b>игрока</b>, выполни <b>телепорт</b>
                                    в точку 0, 5, 0».
                                </p>
                            </>}
                            lua={<>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>workspace</code></td><td>3D-объекты сцены</td></tr>
                                        <tr><td><code>game:GetService("Players")</code></td><td>список игроков</td></tr>
                                        <tr><td><code>game.Workspace</code></td><td>то же что workspace</td></tr>
                                        <tr><td><code>script.Parent</code></td><td>объект-носитель скрипта</td></tr>
                                        <tr><td><code>game:GetService("RunService")</code></td><td>каждый кадр (Heartbeat)</td></tr>
                                        <tr><td><code>game:GetService("UserInputService")</code></td><td>клавиши и мышь</td></tr>
                                        <tr><td><code>game:GetService("TweenService")</code></td><td>плавные движения</td></tr>
                                    </tbody>
                                </table>
                                <p>
                                    Знак <code>:</code> (двоеточие) в Lua — это вызов
                                    метода объекта. <code>game:GetService("Players")</code>
                                    читается так: «у <b>game</b> вызови <b>GetService</b>
                                    и дай ему текст <b>Players</b>».
                                </p>
                                <p>
                                    Точка <code>.</code> — это доступ к полю объекта.
                                    <code> workspace.Floor.BrickColor</code> — у workspace
                                    взять Floor, у него взять BrickColor.
                                </p>
                            </>}
                        />
                        <p>
                            Полный список всех команд — в Справочнике (раздел H). Не нужно
                            его заучивать: при наборе кода редактор сам показывает подсказки.
                        </p>
                    </>
                ),
            },
            {
                id: 'log-console',
                title: 'D5. log/print, консоль, отладка',
                body: (
                    <>
                        <p>
                            <b>Консоль</b> — окошко в правом нижнем углу редактора.
                            Туда выводятся все сообщения и ошибки скриптов.
                        </p>
                        <LangTabs
                            js={<p>
                                Команда <code>game.log(...)</code> печатает в консоль
                                что угодно. Это главный инструмент <b>отладки</b> —
                                проверки, что код работает правильно:
                            </p>}
                            lua={<p>
                                Команда <code>print(...)</code> печатает в консоль
                                что угодно. Это главный инструмент <b>отладки</b> —
                                проверки, что код работает правильно:
                            </p>}
                        />
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`let score = 0;
score = score + 10;
game.log('Очки сейчас:', score);  // Очки сейчас: 10

let pos = game.player.position;
game.log('Игрок стоит в точке:', pos);`}</Code>}
                            lua={<Code>{`local score = 0
score = score + 10
print("Очки сейчас:", score)  -- Очки сейчас: 10

local pos = game.Players.LocalPlayer.Character.HumanoidRootPart.Position
print("Игрок стоит в точке:", pos)`}</Code>}
                        />
                        <LangTabs
                            js={<p>
                                Если игра ведёт себя странно — расставь
                                <code> game.log</code> по коду и посмотри, какие значения
                                печатаются. Так ты увидишь, где именно что-то пошло не так.
                            </p>}
                            lua={<p>
                                Если игра ведёт себя странно — расставь
                                <code> print</code> по коду и посмотри, какие значения
                                печатаются. Так ты увидишь, где именно что-то пошло не так.
                            </p>}
                        />
                        <Note>
                            Если в скрипте опечатка — текст ошибки появится
                            в Консоли <b>красным</b>, и там же будет написан номер
                            строки с ошибкой. Всегда заглядывай в Консоль первым делом.
                        </Note>
                    </>
                ),
            },
            {
                id: 'events',
                title: 'D6. События: тик, клавиши, клик, касание',
                body: (
                    <>
                        <p>
                            <b>Событие</b> — это «что-то случилось». Скрипт может
                            ждать событие и реагировать на него. Самые важные:
                        </p>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.onTick(fn)</code></td><td>каждый кадр (60 раз в секунду)</td></tr>
                                    <tr><td><code>game.onKey('space', fn)</code></td><td>игрок нажал клавишу</td></tr>
                                    <tr><td><code>game.self.onClick(fn)</code></td><td>игрок кликнул по объекту</td></tr>
                                    <tr><td><code>game.self.onTouch(fn)</code></td><td>игрок коснулся объекта</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>RunService.Heartbeat:Connect(fn)</code></td><td>каждый кадр</td></tr>
                                    <tr><td><code>UserInputService.InputBegan:Connect(fn)</code></td><td>любая клавиша</td></tr>
                                    <tr><td><code>part.ClickDetector.MouseClick:Connect(fn)</code></td><td>клик по объекту</td></tr>
                                    <tr><td><code>part.Touched:Connect(fn)</code></td><td>касание объекта</td></tr>
                                </tbody>
                            </table>}
                        />
                        <p>Пример — куб, который исчезает по клику:</p>
                        <ScriptKind kind="object" on="куб" />
                        <LangTabs
                            js={<Code>{`game.self.onClick(() => {
  game.self.delete();          // удалить сам себя
  game.log('Куб удалён!');
});`}</Code>}
                            lua={<Code>{`local part = script.Parent
local clickDetector = Instance.new("ClickDetector")
clickDetector.Parent = part

clickDetector.MouseClick:Connect(function(player)
    part:Destroy()             -- удалить сам себя
    print("Куб удалён!")
end)`}</Code>}
                        />
                        <LangTabs
                            js={<p>
                                <b>Что такое <code>{`() => { ... }`}</code>?</b> Это
                                «функция» — набор команд, упакованных вместе. Команды
                                внутри фигурных скобок выполнятся <b>не сразу</b>, а только
                                когда случится событие. То есть «когда кликнули — тогда
                                удалить и напечатать».
                            </p>}
                            lua={<p>
                                <b>Что такое <code>function() ... end</code>?</b> Это
                                «функция» — набор команд, упакованных вместе. Команды
                                между <code>function()</code> и <code>end</code> выполнятся
                                <b> не сразу</b>, а только когда случится событие. То есть
                                «когда кликнули — тогда удалить и напечатать».
                                Метод <code>:Connect</code> «подключает» функцию
                                к событию.
                            </p>}
                        />
                        <LangTabs
                            js={<Note>
                                <code>onTick</code> выполняется ОЧЕНЬ часто — 60 раз
                                в секунду. Не делай внутри него тяжёлых вещей. Подробнее
                                об этой ошибке — раздел J4.
                            </Note>}
                            lua={<Note>
                                <code>Heartbeat</code> выполняется ОЧЕНЬ часто — 60 раз
                                в секунду. Не делай внутри тяжёлых вычислений. Подробнее
                                об этой ошибке — раздел J4.
                            </Note>}
                        />
                    </>
                ),
            },
            {
                id: 'conditions',
                title: 'D7. Условия: if / else',
                body: (
                    <>
                        <p>
                            <b>Условие</b> — это развилка: «<b>если</b> что-то верно —
                            сделай одно, <b>иначе</b> — другое». В обоих языках это
                            слова <code>if</code> («если») и <code>else</code>
                            («иначе»), но запись чуть отличается.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`let coins = 7;

if (coins >= 10) {
  game.ui.showText('Хватает на покупку!', 2);
} else {
  game.ui.showText('Нужно больше монет', 2);
}`}</Code>}
                            lua={<Code>{`local coins = 7

if coins >= 10 then
    print("Хватает на покупку!")
else
    print("Нужно больше монет")
end`}</Code>}
                        />
                        <p>
                            Тут проверяется: <code>coins {'>'}= 10</code> — «монет
                            10 или больше?». Сейчас монет 7, значит условие неверно,
                            и сработает ветка <code>else</code>.
                        </p>
                        <p><b>Знаки сравнения:</b></p>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>a === b</code></td><td>a равно b</td></tr>
                                    <tr><td><code>a !== b</code></td><td>a не равно b</td></tr>
                                    <tr><td><code>a {'>'} b</code></td><td>a больше b</td></tr>
                                    <tr><td><code>a {'<'} b</code></td><td>a меньше b</td></tr>
                                    <tr><td><code>a {'>'}= b</code></td><td>a больше или равно b</td></tr>
                                    <tr><td><code>a {'<'}= b</code></td><td>a меньше или равно b</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>a == b</code></td><td>a равно b</td></tr>
                                    <tr><td><code>a ~= b</code></td><td>a не равно b</td></tr>
                                    <tr><td><code>a {'>'} b</code></td><td>a больше b</td></tr>
                                    <tr><td><code>a {'<'} b</code></td><td>a меньше b</td></tr>
                                    <tr><td><code>a {'>'}= b</code></td><td>a больше или равно b</td></tr>
                                    <tr><td><code>a {'<'}= b</code></td><td>a меньше или равно b</td></tr>
                                </tbody>
                            </table>}
                        />
                        <LangTabs
                            js={<Note>
                                В JS для проверки «равно» пишут <b>три</b> знака равенства
                                <code> ===</code>, а не один. Один знак <code>=</code> —
                                это «положить значение в переменную», совсем другое
                                действие. И не равно — это <code>!==</code>.
                            </Note>}
                            lua={<Note>
                                В Lua для проверки «равно» пишут <b>два</b> знака равенства
                                <code> ==</code>. А «не равно» — это <code>~=</code>
                                (тильда + равно). Запомни этот значок — он встречается
                                только в Lua.
                            </Note>}
                        />
                    </>
                ),
            },
            {
                id: 'timers',
                title: 'D8. Таймеры: задержка, повтор, отмена',
                body: (
                    <>
                        <p>
                            Таймеры запускают команды <b>не сразу, а потом</b>:
                        </p>
                        <LangTabs
                            js={<ul>
                                <li>
                                    <code>game.after(сек, fn)</code> — выполнить
                                    <b> один раз</b> через несколько секунд;
                                </li>
                                <li>
                                    <code>game.every(сек, fn)</code> — выполнять
                                    <b> снова и снова</b> каждые несколько секунд;
                                </li>
                                <li>
                                    <code>game.cancel(id)</code> — остановить таймер.
                                </li>
                            </ul>}
                            lua={<ul>
                                <li>
                                    <code>task.delay(сек, fn)</code> — выполнить
                                    <b> один раз</b> через несколько секунд;
                                </li>
                                <li>
                                    <code>task.wait(сек)</code> — приостановить скрипт
                                    на N секунд (внутри цикла или функции);
                                </li>
                                <li>
                                    Для повторяющихся таймеров — обычный цикл
                                    <code> while true do task.wait(1); ... end</code>
                                    в отдельной корутине через <code>task.spawn</code>.
                                </li>
                            </ul>}
                        />
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`// Через 3 секунды показать текст
game.after(3, () => {
  game.ui.showText('Игра началась!', 2);
});

// Каждую секунду прибавлять очко.
// every возвращает номер таймера — запомним его.
const ticker = game.every(1, () => {
  game.ui.score = (game.ui.score || 0) + 1;
});

// Через 10 секунд остановить начисление очков
game.after(10, () => {
  game.cancel(ticker);
  game.ui.showText('Время вышло!', 2);
});`}</Code>}
                            lua={<Code>{`-- Через 3 секунды показать текст
task.delay(3, function()
    print("Игра началась!")
end)

-- Каждую секунду прибавлять очко.
-- Запускаем в отдельной корутине чтобы не блокировать скрипт.
local score = 0
local running = true
task.spawn(function()
    while running do
        task.wait(1)
        score = score + 1
    end
end)

-- Через 10 секунд остановить начисление очков
task.delay(10, function()
    running = false
    print("Время вышло! Набрано очков:", score)
end)`}</Code>}
                        />
                        <LangTabs
                            js={<p>
                                Запись <code>(game.ui.score || 0)</code> читается так:
                                «возьми счёт, а если его ещё нет — возьми 0». Это защита
                                от ошибки в самом начале, когда счётчик ещё пустой.
                            </p>}
                            lua={<p>
                                В Lua переменная <code>running</code> — флаг работы цикла.
                                Когда нужно остановить таймер, ставим <code>running = false</code>,
                                и цикл сам завершится после <code>task.wait(1)</code>.
                                Это проще, чем хранить номер таймера.
                            </p>}
                        />
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ E — СКРИПТЫ — ДВИЖЕНИЕ И АНИМАЦИЯ
    // ════════════════════════════════════════════════════
    {
        id: 'scripts-motion',
        icon: 'run',
        title: 'Движение и анимация',
        summary: 'Управление игроком, плавные твины, спавн и перемещение объектов.',
        sections: [
            {
                id: 'player-control',
                title: 'E1. Управление игроком: скорость, прыжок, гравитация',
                body: (
                    <>
                        <p>Скриптом можно менять, как двигается игрок.</p>
                        <LangTabs
                            js={<>
                                <p>В JS используем команды-«множители»: 1 — обычно,
                                2 — в два раза сильнее, 0.5 — в два раза слабее.</p>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>game.player.setSpeed(mul)</code></td><td>скорость бега</td></tr>
                                        <tr><td><code>game.player.setJumpPower(mul)</code></td><td>сила прыжка</td></tr>
                                        <tr><td><code>game.player.setGravityMul(mul)</code></td><td>сила притяжения</td></tr>
                                        <tr><td><code>game.player.setDoubleJump(true)</code></td><td>двойной прыжок</td></tr>
                                        <tr><td><code>game.player.teleport(x,y,z)</code></td><td>мгновенно переставить</td></tr>
                                    </tbody>
                                </table>
                            </>}
                            lua={<>
                                <p>В Lua скорость и прыжок — это <b>прямые значения</b>
                                в Humanoid (не множители). По умолчанию WalkSpeed=16,
                                JumpPower=50.</p>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>humanoid.WalkSpeed = 32</code></td><td>скорость (16 = норма)</td></tr>
                                        <tr><td><code>humanoid.JumpPower = 80</code></td><td>сила прыжка (50 = норма)</td></tr>
                                        <tr><td><code>workspace.Gravity = 100</code></td><td>гравитация (196 = норма)</td></tr>
                                        <tr><td><code>humanoid:ChangeState(Enum.HumanoidStateType.Jumping)</code></td><td>прыгнуть</td></tr>
                                        <tr><td><code>hrp.CFrame = CFrame.new(x,y,z)</code></td><td>телепорт</td></tr>
                                    </tbody>
                                </table>
                            </>}
                        />
                        <p>Пример — «зелье скорости» при касании сферы:</p>
                        <ScriptKind kind="object" on="сфера-зелье" />
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  // ускоряем игрока в 2 раза
  game.player.setSpeed(2);
  game.ui.showText('Скорость x2 на 5 секунд!', 2);
  game.sound.play('pickup');

  // зелье исчезает
  game.self.delete();

  // через 5 секунд скорость снова обычная
  game.after(5, () => {
    game.player.setSpeed(1);
  });
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local humanoid = hit.Parent:FindFirstChild("Humanoid")
    if not humanoid then return end

    -- ускоряем игрока в 2 раза (16 → 32)
    humanoid.WalkSpeed = 32
    print("Скорость x2 на 5 секунд!")

    -- зелье исчезает
    part:Destroy()

    -- через 5 секунд скорость обратно норма
    task.delay(5, function()
        humanoid.WalkSpeed = 16
    end)
end)`}</Code>}
                        />
                        <Note>
                            Не забывай возвращать скорость обратно. Иначе игрок
                            останется быстрым навсегда — а это может сломать твой уровень.
                        </Note>
                    </>
                ),
            },
            {
                id: 'player-animations',
                title: 'E2. Анимации-эмоции персонажа',
                body: (
                    <>
                        <p>Персонаж умеет показывать эмоции.</p>
                        <LangTabs
                            js={<p>
                                Команда <code>game.player.playAnimation(имя)</code> проигрывает
                                анимацию: <code>'wave'</code> (помахать),
                                <code> 'dance'</code> (танец), <code>'cheer'</code>
                                (радость), <code>'sit'</code> (сесть).
                            </p>}
                            lua={<p>
                                В Lua анимации проигрываются через Animator на Humanoid'е.
                                Roblox-стиль: создать Animation-объект, вызвать
                                <code> Animator:LoadAnimation(anim)</code>,
                                потом <code>track:Play()</code>.
                            </p>}
                        />
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`// При победе персонаж радуется
game.player.playAnimation('cheer');

// Через 3 секунды перестать
game.after(3, () => {
  game.player.stopAnimation();
});`}</Code>}
                            lua={<Code>{`local Players = game:GetService("Players")
local player = Players.LocalPlayer
local humanoid = player.Character:WaitForChild("Humanoid")
local animator = humanoid:FindFirstChildOfClass("Animator")

-- Создаём анимацию (упрощённый шаблон — в реальности нужен AnimationId)
local anim = Instance.new("Animation")
-- anim.AnimationId = "rbxassetid://..."  -- свой Animation ID
local track = animator:LoadAnimation(anim)

track:Play()

-- Через 3 секунды перестать
task.delay(3, function()
    track:Stop()
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'tweens',
                title: 'E3. Твины — плавные движения',
                body: (
                    <>
                        <p>
                            <b>Твин</b> — это плавное изменение чего-либо за время.
                            Если просто переставить объект — он телепортируется рывком.
                            А твин <b>плавно</b> доедет из точки в точку.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>Команда: <code>game.tween(объект, что менять, настройки)</code></p>
                                <Code>{`// Находим платформу-лифт по имени
const lift = game.scene.findOne('Лифт');

// Платформа за 2 секунды плавно поднимается на высоту 10
game.tween(lift, { y: 10 }, {
  duration: 2,        // длительность в секундах
  easing: 'ease'      // характер движения
});`}</Code>
                                <p><b>Полезные настройки твина:</b></p>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>duration</code></td><td>сколько секунд длится</td></tr>
                                        <tr><td><code>easing</code></td><td>'linear' / 'ease' / 'bounce'</td></tr>
                                        <tr><td><code>repeat</code></td><td>сколько раз повторить</td></tr>
                                        <tr><td><code>yoyo: true</code></td><td>двигаться туда-обратно</td></tr>
                                        <tr><td><code>onDone</code></td><td>что сделать, когда твин закончится</td></tr>
                                    </tbody>
                                </table>
                                <Code>{`// Платформа вечно ездит вверх-вниз
const plat = game.scene.findOne('Качалка');
game.tween(plat, { y: 8 }, {
  duration: 2,
  yoyo: true,
  repeat: 999
});`}</Code>
                            </>}
                            lua={<>
                                <p>В Lua используется <b>TweenService</b> — встроенный
                                сервис Roblox-стиля. Создаёшь TweenInfo и Tween, вызываешь Play.</p>
                                <Code>{`local TweenService = game:GetService("TweenService")

-- Находим платформу-лифт по имени
local lift = workspace:WaitForChild("Лифт")

-- Настройка анимации: 2 сек, плавно
local info = TweenInfo.new(2, Enum.EasingStyle.Quad)

-- Что менять: новая Position (поднимаем на 10 вверх)
local goal = { Position = lift.Position + Vector3.new(0, 10, 0) }

-- Создаём и запускаем твин
local tween = TweenService:Create(lift, info, goal)
tween:Play()`}</Code>
                                <p><b>Полезные настройки TweenInfo:</b></p>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td>1-й арг — секунды</td><td>сколько длится</td></tr>
                                        <tr><td>EasingStyle</td><td>Linear / Quad / Bounce / Elastic</td></tr>
                                        <tr><td>EasingDirection</td><td>In / Out / InOut</td></tr>
                                        <tr><td>repeatCount</td><td>сколько раз повторить (-1 = бесконечно)</td></tr>
                                        <tr><td>reverses</td><td>true = туда-обратно</td></tr>
                                        <tr><td>tween.Completed:Connect</td><td>событие «закончен»</td></tr>
                                    </tbody>
                                </table>
                                <Code>{`-- Платформа вечно ездит вверх-вниз
local plat = workspace:WaitForChild("Качалка")
local info = TweenInfo.new(
    2,                          -- секунды
    Enum.EasingStyle.Quad,      -- плавно
    Enum.EasingDirection.InOut,
    -1,                         -- бесконечно
    true                        -- туда-обратно
)
local goal = { Position = plat.Position + Vector3.new(0, 8, 0) }
TweenService:Create(plat, info, goal):Play()`}</Code>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'spawn-delete',
                title: 'E4. Спавн и удаление объектов',
                body: (
                    <>
                        <p>
                            <b>Спавн</b> — создание нового объекта прямо во время игры.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>Команда <code>game.scene.spawn(тип, настройки)</code>:</p>
                                <Code>{`// Создаём золотую монетку-сферу
const coin = game.scene.spawn('primitive:sphere', {
  x: 5, y: 1, z: 0,    // где появится
  color: '#ffd700'     // золотой цвет
});

game.log('Создали монетку, её адрес:', coin);`}</Code>
                                <p>
                                    Тип бывает <code>'block:трава'</code>,
                                    <code> 'primitive:cube'</code>, <code>'model:tree'</code>.
                                    Команда <b>возвращает ref</b> — «адрес» объекта,
                                    по которому к нему можно обращаться.
                                </p>
                                <p><b>Удаление объекта:</b></p>
                                <Code>{`game.scene.delete(coin);              // сразу
game.scene.deleteAfter(coin, 3);      // через 3 секунды`}</Code>
                                <Note>
                                    Запоминай <code>ref</code> в переменную. Без адреса
                                    ты потом не сможешь объект ни подвинуть, ни удалить.
                                </Note>
                            </>}
                            lua={<>
                                <p>Команда <code>Instance.new("Part")</code> создаёт новый Part:</p>
                                <Code>{`-- Создаём золотую монетку-сферу
local coin = Instance.new("Part")
coin.Shape = Enum.PartType.Ball
coin.Size = Vector3.new(1, 1, 1)
coin.Position = Vector3.new(5, 1, 0)
coin.BrickColor = BrickColor.new("Bright yellow")
coin.Anchored = true
coin.Parent = workspace

print("Создали монетку:", coin)`}</Code>
                                <p>
                                    Чтобы объект появился в игре — обязательно ставь
                                    <code> .Parent = workspace</code>.
                                    <code> Anchored = true</code> — чтобы не падал.
                                </p>
                                <p><b>Удаление объекта:</b></p>
                                <Code>{`coin:Destroy()                  -- сразу

-- через 3 секунды
game:GetService("Debris"):AddItem(coin, 3)`}</Code>
                                <Note>
                                    Сохраняй ссылку на объект в переменную (<code>local coin = ...</code>).
                                    Без неё ты потом не сможешь объект ни подвинуть, ни удалить.
                                </Note>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'move-objects',
                title: 'E5. Перемещение объектов',
                body: (
                    <>
                        <p>Передвинуть объект скриптом можно несколькими способами:</p>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.scene.move(ref,x,y,z)</code></td><td>мгновенно переставить</td></tr>
                                    <tr><td><code>game.scene.rotate(ref,угол)</code></td><td>повернуть</td></tr>
                                    <tr><td><code>game.self.move(x,y,z)</code></td><td>скрипт двигает сам себя</td></tr>
                                    <tr><td><code>game.tween(...)</code></td><td>плавное перемещение (E3)</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>part.Position = Vector3.new(x,y,z)</code></td><td>мгновенно переставить</td></tr>
                                    <tr><td><code>part.CFrame = part.CFrame * CFrame.Angles(0, math.rad(45), 0)</code></td><td>повернуть</td></tr>
                                    <tr><td><code>script.Parent.Position = ...</code></td><td>скрипт двигает сам себя</td></tr>
                                    <tr><td><code>TweenService:Create(...)</code></td><td>плавное перемещение (E3)</td></tr>
                                </tbody>
                            </table>}
                        />
                        <p>Пример — дверь уезжает вверх и освобождает проход:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`const door = game.scene.findOne('Дверь');

// плавно поднимаем дверь на 6 единиц вверх
game.tween(door, { y: 6 }, { duration: 1 });`}</Code>}
                            lua={<Code>{`local TweenService = game:GetService("TweenService")
local door = workspace:WaitForChild("Дверь")

-- плавно поднимаем дверь на 6 единиц вверх
local goal = { Position = door.Position + Vector3.new(0, 6, 0) }
TweenService:Create(door, TweenInfo.new(1), goal):Play()`}</Code>}
                        />
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ F — СКРИПТЫ — ИГРОВАЯ ЛОГИКА
    // ════════════════════════════════════════════════════
    {
        id: 'scripts-logic',
        icon: 'target',
        title: 'Игровая логика',
        summary: 'HP и урон, физика, теги, взаимодействие по E, связи между объектами.',
        sections: [
            {
                id: 'player-hp',
                title: 'F1. HP игрока: урон, лечение, смерть, чекпоинт',
                body: (
                    <>
                        <p>Команды для здоровья игрока:</p>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.player.hp</code></td><td>текущее здоровье</td></tr>
                                    <tr><td><code>game.player.damage(n)</code></td><td>нанести урон</td></tr>
                                    <tr><td><code>game.player.heal(n)</code></td><td>вылечить</td></tr>
                                    <tr><td><code>game.player.kill()</code></td><td>мгновенно убить</td></tr>
                                    <tr><td><code>game.player.respawn()</code></td><td>воскресить на спавне</td></tr>
                                    <tr><td><code>game.player.setSpawn(точка)</code></td><td>новая точка возрождения</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>humanoid.Health</code></td><td>текущее здоровье</td></tr>
                                    <tr><td><code>humanoid:TakeDamage(n)</code></td><td>нанести урон</td></tr>
                                    <tr><td><code>humanoid.Health = humanoid.Health + n</code></td><td>вылечить</td></tr>
                                    <tr><td><code>humanoid.Health = 0</code></td><td>мгновенно убить</td></tr>
                                    <tr><td><code>player:LoadCharacter()</code></td><td>воскресить</td></tr>
                                    <tr><td><code>player.RespawnLocation = spawn</code></td><td>новая точка возрождения</td></tr>
                                </tbody>
                            </table>}
                        />
                        <p><b>Пример 1 — шипы наносят урон:</b></p>
                        <ScriptKind kind="object" on="шипы (конус)" />
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  game.player.damage(20);     // отнять 20 здоровья
  game.sound.play('hit');
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local humanoid = hit.Parent:FindFirstChild("Humanoid")
    if humanoid then
        humanoid:TakeDamage(20)     -- отнять 20 здоровья
    end
end)`}</Code>}
                        />
                        <p><b>Пример 2 — аптечка лечит:</b></p>
                        <ScriptKind kind="object" on="аптечку" />
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  game.player.heal(50);       // добавить 50 здоровья
  game.ui.showText('+50 HP', 1.5);
  game.self.delete();         // аптечка исчезает
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local humanoid = hit.Parent:FindFirstChild("Humanoid")
    if not humanoid then return end

    -- добавить 50 здоровья, но не выше MaxHealth
    humanoid.Health = math.min(humanoid.Health + 50, humanoid.MaxHealth)
    print("+50 HP")
    part:Destroy()       -- аптечка исчезает
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'physics',
                title: 'F2. Физика: raycast, импульсы, взрывы',
                body: (
                    <>
                        <LangTabs
                            js={<>
                                <p>Отдел <code>game.physics</code> отвечает за «настоящую» физику:</p>
                                <ul>
                                    <li><code>raycast(откуда, куда, опции)</code> — луч для стрельбы;</li>
                                    <li><code>applyImpulse(ref, сила)</code> — толкнуть объект;</li>
                                    <li><code>explode(точка, радиус, опции)</code> — взрыв.</li>
                                </ul>
                            </>}
                            lua={<>
                                <p>В Lua для физики используется <code>workspace</code> и стандартный Roblox API:</p>
                                <ul>
                                    <li><code>workspace:Raycast(origin, dir, params)</code> — луч;</li>
                                    <li><code>part:ApplyImpulse(Vector3)</code> — толкнуть Part;</li>
                                    <li><code>Instance.new("Explosion")</code> — создать взрыв.</li>
                                </ul>
                            </>}
                        />
                        <p><b>Пример — стрельба лучом из камеры игрока:</b></p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`game.onClick(() => {
  const p = game.player.position;

  const hit = game.physics.raycast(
    { x: p.x, y: p.y + 1.5, z: p.z },  // откуда (от головы)
    game.player.forward,                // куда (взгляд)
    { maxDistance: 50 }
  );

  if (hit.hit) {
    game.log('Попал в объект:', hit.ref);
    game.sound.play('hit');
  }
});`}</Code>}
                            lua={<Code>{`local UIS = game:GetService("UserInputService")
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local mouse = player:GetMouse()

UIS.InputBegan:Connect(function(input)
    if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end

    local hrp = player.Character.HumanoidRootPart
    local origin = hrp.Position + Vector3.new(0, 1.5, 0)
    local direction = (mouse.Hit.Position - origin).Unit * 50

    local raycastResult = workspace:Raycast(origin, direction)
    if raycastResult then
        print("Попал в объект:", raycastResult.Instance.Name)
    end
end)`}</Code>}
                        />
                        <LangTabs
                            js={<p>
                                <code>hit.hit</code> — попал ли луч во что-нибудь.
                                <code> hit.ref</code> — адрес объекта.
                            </p>}
                            lua={<p>
                                <code>raycastResult</code> равно <code>nil</code> если
                                луч ни во что не попал. Иначе у него есть поля
                                <code> .Instance</code> (что попало),
                                <code> .Position</code> (точка попадания),
                                <code> .Normal</code> (нормаль поверхности).
                            </p>}
                        />
                    </>
                ),
            },
            {
                id: 'attributes',
                title: 'F3. Атрибуты объектов',
                body: (
                    <>
                        <p>
                            <b>Атрибут</b> — это значение, которое ты «приклеиваешь»
                            к объекту. Например, сколько здоровья у конкретного врага
                            или сколько монет стоит товар.
                        </p>
                        <ScriptKind kind="object" on="товар в магазине" />
                        <LangTabs
                            js={<Code>{`// При старте игры запоминаем цену прямо на товаре
game.scene.setData(game.self.ref, 'price', 50);

// Когда игрок кликает по товару — читаем цену
game.self.onClick(() => {
  const price = game.scene.getData(game.self.ref, 'price');
  game.ui.showText('Этот товар стоит ' + price + ' монет', 2);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

-- При старте игры запоминаем цену прямо на товаре
part:SetAttribute("Price", 50)

-- Когда игрок кликает — читаем цену
local clickDetector = Instance.new("ClickDetector", part)
clickDetector.MouseClick:Connect(function(player)
    local price = part:GetAttribute("Price")
    print("Этот товар стоит " .. price .. " монет")
end)`}</Code>}
                        />
                        <p>
                            Чем атрибут лучше обычной переменной? Переменная одна
                            на весь скрипт. А атрибут — свой у каждого объекта.
                            Один и тот же скрипт можно повесить на 10 разных товаров,
                            и у каждого будет своя цена.
                        </p>
                    </>
                ),
            },
            {
                id: 'tags',
                title: 'F4. Теги объектов',
                body: (
                    <>
                        <p>
                            <b>Тег</b> — это «ярлык» на объекте. Удобно ставить сразу на
                            много объектов и потом одной командой находить их все.
                        </p>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.scene.tag(ref, 'звезда')</code></td><td>повесить тег</td></tr>
                                    <tr><td><code>game.scene.untag(ref, 'звезда')</code></td><td>снять тег</td></tr>
                                    <tr><td><code>game.scene.hasTag(ref, 'звезда')</code></td><td>есть ли тег</td></tr>
                                    <tr><td><code>game.scene.getTagged('звезда')</code></td><td>все объекты с тегом</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>CollectionService:AddTag(part, "звезда")</code></td><td>повесить тег</td></tr>
                                    <tr><td><code>CollectionService:RemoveTag(part, "звезда")</code></td><td>снять тег</td></tr>
                                    <tr><td><code>CollectionService:HasTag(part, "звезда")</code></td><td>есть ли тег</td></tr>
                                    <tr><td><code>CollectionService:GetTagged("звезда")</code></td><td>все объекты с тегом</td></tr>
                                </tbody>
                            </table>}
                        />
                        <p><b>Пример — игра «собери все звёзды»:</b></p>
                        <ScriptKind kind="object" on="каждую звезду" />
                        <LangTabs
                            js={<Code>{`// Этот скрипт висит на звезде.
game.scene.tag(game.self.ref, 'звезда');

game.self.onTouch(() => {
  game.self.delete();
  game.sound.play('coin');

  const left = game.scene.getTagged('звезда').length;
  if (left === 0) {
    game.ui.showText('Все звёзды собраны! Победа!', 3);
  } else {
    game.ui.showText('Осталось звёзд: ' + left, 1.5);
  }
});`}</Code>}
                            lua={<Code>{`local CS = game:GetService("CollectionService")
local part = script.Parent

-- Помечаем звезду тегом
CS:AddTag(part, "звезда")

part.Touched:Connect(function()
    part:Destroy()

    local left = #CS:GetTagged("звезда")
    if left == 0 then
        print("Все звёзды собраны! Победа!")
    else
        print("Осталось звёзд: " .. left)
    end
end)`}</Code>}
                        />
                        <Note>
                            Снятие тега убирает только ярлык. Цвет, размер и другие
                            свойства объекта при этом не меняются.
                        </Note>
                    </>
                ),
            },
            {
                id: 'proximity',
                title: 'F5. Взаимодействие по клавише E (ProximityPrompt)',
                body: (
                    <>
                        <p>
                            Часто игра просит «подойди и нажми E»: открыть сундук,
                            поговорить с торговцем, дёрнуть рычаг.
                        </p>
                        <ScriptKind kind="object" on="сундук" />
                        <LangTabs
                            js={<Code>{`game.self.onInteract(() => {
  game.ui.showText('Сундук открыт!', 2);
  game.scene.spawnParticles('sparks',
    game.self.position, { duration: 1 });
  game.sound.play('pickup');
}, {
  text: 'Открыть сундук',   // подсказка над объектом
  distance: 4               // на сколько метров подойти
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

-- ProximityPrompt — стандартный Roblox-способ
local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Открыть"
prompt.ObjectText = "Сундук"
prompt.MaxActivationDistance = 4
prompt.KeyboardKeyCode = Enum.KeyCode.E
prompt.Parent = part

prompt.Triggered:Connect(function(player)
    print("Сундук открыт!")
    -- Можно создать эффект частиц или проиграть звук
end)`}</Code>}
                        />
                        <p>
                            Когда игрок подойдёт на расстояние взаимодействия, над
                            объектом появится подсказка с текстом. Нажатие
                            <kbd className="kbd">E</kbd> запустит функцию.
                        </p>
                    </>
                ),
            },
            {
                id: 'billboard',
                title: 'F6. Billboard-метки над объектами',
                body: (
                    <>
                        <p>
                            <b>Billboard</b> — это текст-табличка, которая висит
                            над объектом в 3D-мире и всегда повёрнута к игроку.
                            Так показывают имена врагов, их HP, названия мест.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`// npc — это адрес созданного NPC.
game.scene.setLabel(npc.ref, 'Торговец Боб', {
  color: '#ffffff',
  height: 2.5     // на 2.5 метра над объектом
});

// Позже можно убрать табличку
game.scene.clearLabel(npc.ref);`}</Code>}
                            lua={<Code>{`-- BillboardGui в Roblox — это GUI поверх Part
local part = workspace:WaitForChild("NPC")

local billboard = Instance.new("BillboardGui")
billboard.Size = UDim2.new(4, 0, 1, 0)
billboard.StudsOffset = Vector3.new(0, 2.5, 0)  -- над объектом
billboard.Parent = part

local label = Instance.new("TextLabel")
label.BackgroundTransparency = 1
label.Size = UDim2.new(1, 0, 1, 0)
label.Text = "Торговец Боб"
label.TextColor3 = Color3.new(1, 1, 1)
label.TextScaled = true
label.Parent = billboard

-- Позже можно убрать табличку
-- billboard:Destroy()`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'pass-through',
                title: 'F7. Проходимость объектов',
                body: (
                    <>
                        <p>
                            Иногда стена должна стать проходимой — призрачная стена,
                            секретный проход, исчезающий мост.
                        </p>
                        <ScriptKind kind="object" on="секретную стену" />
                        <LangTabs
                            js={<Code>{`game.self.onClick(() => {
  game.physics.passThrough(game.self.ref, true);
  game.scene.setOpacity(game.self.ref, 0.3);  // полупрозрачная
  game.ui.showText('Секретный проход открыт!', 2);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent
local clickDetector = Instance.new("ClickDetector", part)

clickDetector.MouseClick:Connect(function(player)
    part.CanCollide = false       -- игрок проходит насквозь
    part.Transparency = 0.7        -- полупрозрачная (0=видна, 1=невидима)
    print("Секретный проход открыт!")
end)`}</Code>}
                        />
                        <Note>
                            Если сделать стену снова твёрдой, пока игрок стоит внутри
                            неё — игра аккуратно вытолкнет его наружу, он не застрянет.
                        </Note>
                    </>
                ),
            },
            {
                id: 'constraints',
                title: 'F8. Связи: склейка, петля, пружина',
                body: (
                    <>
                        <p>
                            <b>Связи (constraints)</b> соединяют объекты, чтобы они
                            двигались вместе или по правилам физики.
                        </p>
                        <ul>
                            <li><b>Склейка (weld)</b> — намертво приклеивает один объект к другому;</li>
                            <li><b>Петля (hinge)</b> — объект вращается вокруг оси, как дверь или качели;</li>
                            <li><b>Пружина (spring)</b> — объект упруго колеблется, как батут.</li>
                        </ul>
                        <p><b>Пример — качели на петле:</b></p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`const swing = game.scene.findOne('Качели');

const h = game.constraints.hinge(swing, {
  pivotX: 0, pivotZ: 0,
  angle: 30
});

// раскачиваем в другую сторону каждую секунду
let dir = -30;
game.every(1, () => {
  h.setAngle(dir);
  dir = -dir;
});`}</Code>}
                            lua={<Code>{`-- В Roblox HingeConstraint — стандартный способ
local swing = workspace:WaitForChild("Качели")
local mount = workspace:WaitForChild("Опора")   -- неподвижная точка

-- Attachment'ы (точки крепления)
local a0 = Instance.new("Attachment", mount)
local a1 = Instance.new("Attachment", swing)

local hinge = Instance.new("HingeConstraint")
hinge.Attachment0 = a0
hinge.Attachment1 = a1
hinge.ActuatorType = Enum.ActuatorType.Servo
hinge.ServoMaxTorque = 10000
hinge.AngularSpeed = 2
hinge.Parent = swing

-- Раскачиваем
local dir = 30
while true do
    hinge.TargetAngle = dir
    task.wait(1)
    dir = -dir
end`}</Code>}
                        />
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ G — СКРИПТЫ — БОЛЬШИЕ СИСТЕМЫ
    // ════════════════════════════════════════════════════
    {
        id: 'scripts-systems',
        icon: 'gear',
        title: 'Большие системы',
        summary: 'NPC, инвентарь и оружие, звук, камера и катсцены, мультиплеер.',
        sections: [
            {
                id: 'npc',
                title: 'G1. NPC: создание, движение, диалоги',
                body: (
                    <>
                        <p>
                            <b>NPC</b> (неигровой персонаж) — это житель твоей игры:
                            торговец, враг, проводник.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>В JS используем <code>game.scene.spawnNpc(модель, опции)</code>:</p>
                                <Code>{`// Создаём NPC по имени Боб
const bob = game.scene.spawnNpc('character-a', {
  x: 5, y: 0, z: 0,
  name: 'Боб',
  hp: 100,
  speed: 3
});

bob.say('Привет, путник!', 3);  // реплика над головой
bob.moveTo(10, 0);              // идёт в точку`}</Code>
                                <p><b>Что умеет NPC:</b></p>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>moveTo(x, z)</code></td><td>идти в точку</td></tr>
                                        <tr><td><code>follow('player')</code></td><td>гнаться за игроком</td></tr>
                                        <tr><td><code>stop()</code></td><td>остановиться</td></tr>
                                        <tr><td><code>say(текст, сек)</code></td><td>реплика над головой</td></tr>
                                        <tr><td><code>damage(n)</code></td><td>нанести урон NPC</td></tr>
                                        <tr><td><code>remove()</code></td><td>убрать</td></tr>
                                        <tr><td><code>onDeath(fn)</code></td><td>при гибели</td></tr>
                                    </tbody>
                                </table>
                                <p><b>Пример — враг гонится за игроком:</b></p>
                                <Code>{`const enemy = game.scene.spawnNpc('character-b', {
  x: 0, y: 0, z: 20, name: 'Враг', hp: 50, speed: 2
});

enemy.follow('player');
enemy.onDeath(() => {
  game.ui.showText('Враг побеждён!', 2);
});`}</Code>
                            </>}
                            lua={<>
                                <p>
                                    В Lua NPC — это обычный Model с Humanoid внутри.
                                    Движение делается через <code>humanoid:MoveTo(point)</code>.
                                    Реплики — через ChatService или BillboardGui.
                                </p>
                                <Code>{`-- NPC модель должна лежать в Workspace.
-- Внутри Model должны быть Part'ы и Humanoid.
local npc = workspace:WaitForChild("Боб")
local humanoid = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")

-- Реплика над головой через BillboardGui
local function say(text, duration)
    local bg = Instance.new("BillboardGui")
    bg.Size = UDim2.new(4, 0, 1, 0)
    bg.StudsOffset = Vector3.new(0, 3, 0)
    bg.Parent = npc.Head or hrp
    local label = Instance.new("TextLabel", bg)
    label.Size = UDim2.new(1, 0, 1, 0)
    label.BackgroundTransparency = 1
    label.TextColor3 = Color3.new(1, 1, 1)
    label.TextScaled = true
    label.Text = text
    task.delay(duration, function() bg:Destroy() end)
end

say("Привет, путник!", 3)

-- Идёт в точку
humanoid:MoveTo(Vector3.new(10, hrp.Position.Y, 0))`}</Code>
                                <p><b>Враг гонится за игроком:</b></p>
                                <Code>{`local enemy = workspace:WaitForChild("Враг")
local humanoid = enemy.Humanoid
local Players = game:GetService("Players")

-- Каждые 0.5 сек обновляем цель — позицию игрока
task.spawn(function()
    while enemy.Parent do
        local player = Players:GetPlayers()[1]
        if player and player.Character then
            local target = player.Character.HumanoidRootPart.Position
            humanoid:MoveTo(target)
        end
        task.wait(0.5)
    end
end)

-- При гибели
humanoid.Died:Connect(function()
    print("Враг побеждён!")
end)`}</Code>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'inventory-tools',
                title: 'G2. Инвентарь и инструменты',
                body: (
                    <>
                        <p>
                            <b>Инвентарь</b> — сумка предметов. <b>Инструмент</b> —
                            предмет, который игрок берёт в руку: меч, фонарик.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <Code>{`// Выдать игроку меч прямо в руку
game.player.giveTool('sword', {
  name: 'Стальной меч',
  equip: true
});

// Ловим, когда игрок применил инструмент (ЛКМ)
game.player.onToolUse((e) => {
  game.log('Игрок применил:', e.tool);
});`}</Code>
                                <p>
                                    Команды <code>game.inventory</code>: <code>add</code>,
                                    <code> remove</code>, <code>has</code>, <code>list</code>.
                                </p>
                            </>}
                            lua={<>
                                <Code>{`-- В Roblox инструмент — это Tool-инстанс в Backpack игрока.
local Players = game:GetService("Players")
local player = Players.LocalPlayer

-- Создаём меч
local sword = Instance.new("Tool")
sword.Name = "Стальной меч"
sword.RequiresHandle = false   -- упрощённо без Handle-Part
sword.Parent = player.Backpack

-- Сразу взять в руку (переложить в Character)
sword.Parent = player.Character

-- Ловим применение (ЛКМ или активация)
sword.Activated:Connect(function()
    print("Игрок применил меч!")
end)`}</Code>
                                <p>
                                    Инвентарь игрока = его <code>Backpack</code> (Roblox-сервис).
                                    Чтобы посмотреть что есть: <code>player.Backpack:GetChildren()</code>.
                                </p>
                            </>}
                        />
                        <p><b>Пример — игра «ключ и сундук»:</b></p>
                        <ScriptKind kind="object" on="сундук" />
                        <LangTabs
                            js={<Code>{`game.self.onInteract(() => {
  if (game.inventory.has('Ключ')) {
    game.ui.showText('Сундук открыт!', 2);
    game.inventory.remove('Ключ');
  } else {
    game.ui.showText('Нужен ключ', 1.5);
  }
}, { text: 'Открыть', distance: 4 });`}</Code>}
                            lua={<Code>{`local part = script.Parent
local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Открыть"
prompt.MaxActivationDistance = 4
prompt.Parent = part

prompt.Triggered:Connect(function(player)
    -- Ищем ключ в Backpack
    local key = player.Backpack:FindFirstChild("Ключ")
    if not key then
        key = player.Character and player.Character:FindFirstChild("Ключ")
    end
    if key then
        print("Сундук открыт!")
        key:Destroy()    -- ключ потрачен
    else
        print("Нужен ключ")
    end
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'sound',
                title: 'G3. Звук: свои звуки и 3D-позиционный звук',
                body: (
                    <>
                        <p>Звук оживляет игру.</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>В JS — команда <code>game.sound.play(id, опции)</code>:</p>
                                <Code>{`// Готовые звуки-пресеты
game.sound.play('coin');
game.sound.play('win');
game.sound.play('jump');
game.sound.play('hit');

// Свой загруженный звук, потише
game.sound.play('sound_1', { volume: 0.7 });`}</Code>
                                <p>
                                    Пресеты: <code>jump</code>, <code>pickup</code>,
                                    <code> win</code>, <code>lose</code>, <code>click</code>,
                                    <code> hit</code>, <code>coin</code>.
                                </p>
                                <p>
                                    <b>3D-звук</b> — опция <code>at</code> привязывает
                                    звук к точке в мире, тише с расстоянием.
                                </p>
                                <Code>{`game.sound.play('sound_2', {
  at: { x: 0, y: 1, z: 0 },
  loop: true
});`}</Code>
                            </>}
                            lua={<>
                                <p>В Lua используется <code>Sound</code>-инстанс:</p>
                                <Code>{`-- Простой звук — играет везде одинаково
local sound = Instance.new("Sound")
sound.SoundId = "rbxassetid://9120386436"   -- свой ID
sound.Volume = 0.7
sound.Parent = workspace
sound:Play()`}</Code>
                                <p>
                                    <b>3D-звук</b> — родителем ставим Part в мире.
                                    Sound автоматически становится позиционным.
                                </p>
                                <Code>{`-- Звук костра — слышен близко
local campfire = workspace.Костёр
local sound = Instance.new("Sound")
sound.SoundId = "rbxassetid://..."
sound.RollOffMaxDistance = 30   -- метры до полной тишины
sound.Looped = true
sound.Parent = campfire         -- родитель = Part → 3D-звук
sound:Play()`}</Code>
                            </>}
                        />
                        <Note>
                            Звук обязателен — игра без звука кажется «мёртвой».
                            Но не запускай длинную музыку в начале — это тормозит старт.
                            Звуки вешай на события: прыжок, попадание, победа.
                        </Note>
                    </>
                ),
            },
            {
                id: 'camera',
                title: 'G4. Камера: FOV, привязка, катсцены',
                body: (
                    <>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>В JS — отдел <code>game.camera</code>:</p>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>setFov(градусы)</code></td><td>угол обзора</td></tr>
                                        <tr><td><code>shake(сила, сек)</code></td><td>тряска камеры</td></tr>
                                        <tr><td><code>focusOn(ref)</code></td><td>навести на объект</td></tr>
                                        <tr><td><code>cutscene(точки, опции)</code></td><td>пролёт камеры</td></tr>
                                        <tr><td><code>reset()</code></td><td>вернуть игроку</td></tr>
                                    </tbody>
                                </table>
                                <Code>{`// Облёт уровня при старте
game.camera.cutscene([
  { x: 0, y: 20, z: -30 },
  { x: 0, y: 15, z: 0 },
  { x: 0, y: 10, z: 30 }
], { segDuration: 2 });

game.onCutsceneDone(() => {
  game.ui.showText('Поехали!', 2);
});`}</Code>
                            </>}
                            lua={<>
                                <p>В Lua — стандартный Roblox Camera через Workspace.CurrentCamera:</p>
                                <table className="docTable">
                                    <tbody>
                                        <tr><td><code>camera.FieldOfView = 90</code></td><td>угол обзора</td></tr>
                                        <tr><td><code>camera.CameraType = Enum.CameraType.Scriptable</code></td><td>отключить авто-следование</td></tr>
                                        <tr><td><code>camera.CFrame = CFrame.new(pos, look)</code></td><td>поставить камеру</td></tr>
                                        <tr><td><code>TweenService:Create(camera, ...)</code></td><td>плавный пролёт</td></tr>
                                    </tbody>
                                </table>
                                <Code>{`local TweenService = game:GetService("TweenService")
local camera = workspace.CurrentCamera

-- Отключаем авто-следование за игроком
camera.CameraType = Enum.CameraType.Scriptable

-- Облёт через 3 точки за 6 секунд (3 этапа по 2 сек)
local points = {
    Vector3.new(0, 20, -30),
    Vector3.new(0, 15, 0),
    Vector3.new(0, 10, 30),
}

for _, point in ipairs(points) do
    local goal = { CFrame = CFrame.new(point, Vector3.new(0, 5, 0)) }
    local tween = TweenService:Create(camera, TweenInfo.new(2), goal)
    tween:Play()
    tween.Completed:Wait()
end

-- Вернуть камеру игроку
camera.CameraType = Enum.CameraType.Custom
print("Поехали!")`}</Code>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'beam-trail',
                title: 'G5. Лучи и следы (Beam и Trail)',
                body: (
                    <>
                        <p>
                            <b>Beam</b> — светящаяся линия между двумя точками
                            (лазер, мост света), <b>Trail</b> — шлейф за движущимся
                            объектом (след за ракетой).
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`// Лазер между двумя башнями
const t1 = game.scene.findOne('Башня1');
const t2 = game.scene.findOne('Башня2');

const laser = game.fx.beam({
  from: t1, to: t2,
  color: '#ff3344', width: 0.3
});`}</Code>}
                            lua={<Code>{`-- В Roblox Beam — это инстанс на Attachment'е
local t1 = workspace:WaitForChild("Башня1")
local t2 = workspace:WaitForChild("Башня2")

-- Attachment'ы — точки на Part'ах
local a0 = Instance.new("Attachment", t1)
local a1 = Instance.new("Attachment", t2)

local beam = Instance.new("Beam")
beam.Attachment0 = a0
beam.Attachment1 = a1
beam.Color = ColorSequence.new(Color3.fromRGB(255, 51, 68))
beam.Width0 = 0.3
beam.Width1 = 0.3
beam.LightEmission = 1
beam.Parent = t1`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'multiplayer',
                title: 'G6. Мультиплеер: игроки, комната, команды',
                body: (
                    <>
                        <p>В Рублоксе можно сделать игру на несколько игроков.</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>В JS — отделы <code>game.players</code>, <code>game.room</code>, <code>game.teams</code>:</p>
                                <Code>{`// Общий счёт команды — виден всем игрокам
game.room.set('totalScore', 0);

// когда счёт меняется — обновляем надпись
game.room.onChange('totalScore', (val) => {
  game.ui.set('score', 'Счёт команды: ' + val);
});

game.log('Игроков:', game.players.count());

game.onPlayerJoin((p) => {
  game.ui.showText(p.name + ' присоединился!', 2);
});`}</Code>
                            </>}
                            lua={<>
                                <p>В Lua — стандартный Roblox-стиль:</p>
                                <Code>{`local Players = game:GetService("Players")
local Teams = game:GetService("Teams")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- Общий счёт команды через NumberValue в ReplicatedStorage
-- (виден всем игрокам через .Changed)
local totalScore = Instance.new("NumberValue")
totalScore.Name = "TotalScore"
totalScore.Value = 0
totalScore.Parent = ReplicatedStorage

totalScore.Changed:Connect(function(newValue)
    print("Счёт команды:", newValue)
end)

print("Игроков:", #Players:GetPlayers())

-- Когда новый игрок зашёл
Players.PlayerAdded:Connect(function(player)
    print(player.Name .. " присоединился!")
end)`}</Code>
                                <p><b>Команды (Teams):</b></p>
                                <Code>{`-- Команды создают в Teams сервисе или скриптом
local redTeam = Instance.new("Team")
redTeam.Name = "Red"
redTeam.TeamColor = BrickColor.new("Bright red")
redTeam.AutoAssignable = true
redTeam.Parent = game:GetService("Teams")

-- Назначить игрока в команду
Players.PlayerAdded:Connect(function(player)
    player.Team = redTeam
end)`}</Code>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'leaderstats',
                title: 'G7. Лидерборды и достижения',
                body: (
                    <>
                        <p>
                            <b>Лидерборд</b> — таблица очков справа-сверху (как в Roblox).
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <Code>{`game.leaderstats.define('Монеты', { initial: 0, icon: 'coin' });
game.leaderstats.define('Уровень', { initial: 1 });

game.leaderstats.me.add('Монеты', 5);
game.leaderstats.me.set('Уровень', 2);
const c = game.leaderstats.me.get('Монеты');`}</Code>
                                <p><b>Достижения</b>:</p>
                                <Code>{`game.achievements.define([
  { id: 'first_coin', name: 'Первая монетка', icon: 'coin', rarity: 'common' },
  { id: 'rich', name: 'Богач', description: '100 монет', icon: 'trophy', rarity: 'legendary' }
]);
game.achievements.unlock('first_coin');
game.achievements.bindToStat('rich', 'Монеты', 100);`}</Code>
                            </>}
                            lua={<>
                                <p>В Lua — стандартный Roblox-паттерн: создаём папку
                                <code> leaderstats</code> в Player с IntValue внутри:</p>
                                <Code>{`local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    -- Папка leaderstats — Roblox автоматически показывает её в HUD
    local stats = Instance.new("Folder")
    stats.Name = "leaderstats"
    stats.Parent = player

    -- Стат "Монеты"
    local coins = Instance.new("IntValue")
    coins.Name = "Монеты"
    coins.Value = 0
    coins.Parent = stats

    -- Стат "Уровень"
    local level = Instance.new("IntValue")
    level.Name = "Уровень"
    level.Value = 1
    level.Parent = stats
end)

-- Добавить монеты текущему игроку
local function addCoins(player, amount)
    local stats = player:FindFirstChild("leaderstats")
    if stats then
        stats.Монеты.Value = stats.Монеты.Value + amount
    end
end`}</Code>
                                <p>
                                    Папка с именем <code>leaderstats</code> на игроке —
                                    магическое имя в Roblox. Любые IntValue/NumberValue/StringValue
                                    внутри неё автоматически попадают в HUD справа сверху.
                                </p>
                            </>}
                        />
                        <Note>
                            Лидерборд и достижения сохраняются в БД и подтягиваются при
                            следующем входе игрока (DataStoreService в Roblox).
                        </Note>
                    </>
                ),
            },
            {
                id: 'damage-floaters',
                title: 'G8. Облачка урона (damage floaters)',
                body: (
                    <>
                        <p>
                            Всплывающие <b>цифры урона</b> над врагом — как в RPG.
                        </p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>В JS это готовая команда:</p>
                                <Code>{`game.fx.autoMobFloaters(true);   // авто для всех мобов

// или вручную
game.fx.damageFloater(enemy.position, 25);
game.fx.damageFloater(enemy.position, 100, { isCrit: true });
game.fx.damageFloater('player', 30, { isHeal: true });
game.fx.damageFloater(pos, 0, { isMiss: true });`}</Code>
                            </>}
                            lua={<>
                                <p>В Lua делаем сами через BillboardGui + TweenService:</p>
                                <Code>{`local TweenService = game:GetService("TweenService")

local function showDamage(position, amount, isCrit)
    -- Невидимый Part-якорь в нужной точке
    local anchor = Instance.new("Part")
    anchor.Anchored = true
    anchor.CanCollide = false
    anchor.Transparency = 1
    anchor.Size = Vector3.new(0.1, 0.1, 0.1)
    anchor.Position = position + Vector3.new(0, 2, 0)
    anchor.Parent = workspace

    -- BillboardGui над якорем
    local bg = Instance.new("BillboardGui", anchor)
    bg.Size = UDim2.new(3, 0, 1, 0)
    bg.AlwaysOnTop = true

    local label = Instance.new("TextLabel", bg)
    label.Size = UDim2.new(1, 0, 1, 0)
    label.BackgroundTransparency = 1
    label.Text = "-" .. amount
    label.TextColor3 = isCrit
        and Color3.fromRGB(255, 200, 0)   -- жёлтый крит
        or Color3.fromRGB(255, 80, 80)    -- красный обычный
    label.TextScaled = true
    label.Font = Enum.Font.GothamBold

    -- Анимируем вверх + исчезание
    local goal = { Position = anchor.Position + Vector3.new(0, 4, 0) }
    TweenService:Create(anchor, TweenInfo.new(1), goal):Play()

    task.delay(1, function() anchor:Destroy() end)
end

-- Пример использования:
showDamage(workspace.Враг.Position, 25, false)
showDamage(workspace.Враг.Position, 100, true)   -- крит`}</Code>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'items-inventory',
                title: 'G9. Предметы и инвентарь с редкостями',
                body: (
                    <>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>В JS — готовый отдел <code>game.items</code> и <code>game.inventory</code>:</p>
                                <Code>{`game.items.define([
  { id: 'berry',  name: 'Ягоды', emoji: '🍓', rarity: 'common',    maxStack: 16 },
  { id: 'potion', name: 'Зелье', emoji: '🧪', rarity: 'rare',      maxStack: 8, onUseEffect: 'heal:50' },
  { id: 'sword',  name: 'Меч',   emoji: '⚔️', rarity: 'legendary', maxStack: 1 },
]);

game.inventory.give('sword', 1);
game.inventory.give('berry', 5);`}</Code>
                                <p>Сбор предмета с земли:</p>
                                <Code>{`game.self.onInteract(() => {
  game.inventory.give('berry', 2);
  game.self.delete();
}, { text: 'Собрать', distance: 3 });`}</Code>
                                <Note>
                                    Редкости: common (серый), uncommon (зелёный), rare (голубой),
                                    epic (фиолетовый), legendary (золотой). Окно инвентаря —
                                    клавиша <kbd className="kbd">I</kbd>, drag-drop, ПКМ-меню.
                                </Note>
                            </>}
                            lua={<>
                                <p>
                                    В Roblox инвентарь — это <code>Backpack</code> игрока с Tool'ами,
                                    плюс свои <code>IntValue</code>'ы для подсчёта стаков.
                                    Готового «инвентаря с редкостями» нет — собирается из частей:
                                </p>
                                <Code>{`-- Пример: ягоды как IntValue в leaderstats
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    local stats = Instance.new("Folder")
    stats.Name = "leaderstats"
    stats.Parent = player

    local berries = Instance.new("IntValue", stats)
    berries.Name = "Ягоды"
    berries.Value = 0
end)

-- Сбор ягод (скрипт на собираемом Part)
local part = script.Parent
local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Собрать"
prompt.Parent = part

prompt.Triggered:Connect(function(player)
    local berries = player.leaderstats and player.leaderstats:FindFirstChild("Ягоды")
    if berries then
        berries.Value = berries.Value + 2
        part:Destroy()
    end
end)`}</Code>
                                <p>
                                    Для полноценной системы с редкостями, иконками и UI окном —
                                    надо собирать ScreenGui вручную (по статье C). Это много кода —
                                    проще использовать JS-вариант с готовым <code>game.items</code>.
                                </p>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'sky-environment',
                title: 'G10. Небо, облака, туман, время суток',
                body: (
                    <>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p>Пресеты неба одной командой:</p>
                                <Code>{`game.scene.setSkybox({ preset: 'sunset' });
// пресеты: clear-summer-day | lowpoly-roblox | cloudy | sunset | starry-night | space

game.scene.setClouds({ enabled: true, cover: 0.5, speed: 0.02 });
game.scene.setFog({ color: '#dddddd', density: 0.006 });
game.scene.skybox.fadeTo({ preset: 'starry-night' }, 3);

game.environment.setSkyColor('#0a1024');
game.environment.setTimeOfDay(0);    // ночь
game.environment.setTimeOfDay(12);   // полдень`}</Code>
                            </>}
                            lua={<>
                                <p>В Roblox небо — это инстансы <code>Sky</code> и <code>Atmosphere</code>
                                в Lighting:</p>
                                <Code>{`local Lighting = game:GetService("Lighting")

-- Sky-инстанс с собственными текстурами
local sky = Instance.new("Sky")
sky.SkyboxBk = "rbxassetid://..."  -- задняя грань
sky.SkyboxFt = "rbxassetid://..."  -- передняя
sky.SkyboxLf = "rbxassetid://..."  -- левая
sky.SkyboxRt = "rbxassetid://..."  -- правая
sky.SkyboxUp = "rbxassetid://..."  -- верх
sky.SkyboxDn = "rbxassetid://..."  -- низ
sky.Parent = Lighting

-- Туман
Lighting.FogColor = Color3.fromRGB(221, 221, 221)
Lighting.FogStart = 50
Lighting.FogEnd = 500

-- Atmosphere (мгла, плотность)
local atmosphere = Instance.new("Atmosphere")
atmosphere.Density = 0.3
atmosphere.Color = Color3.fromRGB(199, 199, 199)
atmosphere.Parent = Lighting

-- Время суток (часы и минуты от полуночи)
Lighting:SetMinutesAfterMidnight(12 * 60)   -- полдень
Lighting:SetMinutesAfterMidnight(0)         -- полночь`}</Code>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'modal-menu-loading',
                title: 'G11. Диалоги, меню, экран загрузки',
                body: (
                    <>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p><b>Диалог NPC</b>:</p>
                                <Code>{`game.modal.dialog('Староста', [
  'Привет, путник!',
  'Собери 10 монет и возвращайся.',
], () => game.ui.showText('Квест начат!', 2));`}</Code>
                                <p><b>Окно Да/Нет</b> и <b>лутбокс</b>:</p>
                                <Code>{`game.modal.confirmation('Выход', 'Точно выйти?',
  () => game.player.respawn(), null);

game.modal.lootbox([
  { name: 'Меч', color: '#f0ad4e', rarity: 'legendary' },
  { name: 'Щит', color: '#5bc0de', rarity: 'rare' },
], (item) => game.ui.showText('Выпал: ' + item.name, 3));`}</Code>
                                <p><b>Экран загрузки</b>:</p>
                                <Code>{`game.loading.show({
  style: 'ken-burns',
  placeName: 'Глава 2 — Шахта',
  duration: 2
});
game.loading.onHide(() => game.ui.showText('Добро пожаловать!', 2));`}</Code>
                            </>}
                            lua={<>
                                <p>
                                    В Roblox/Lua нет готовых модалок — всё собирается через
                                    <b> ScreenGui</b> с Frame'ами. Это много кода (~30-100 строк
                                    на диалог), но полностью кастомизируется.
                                </p>
                                <Code>{`-- Простейший диалог: ScreenGui + Frame + TextLabel + Button
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local gui = player:WaitForChild("PlayerGui")

local function showDialog(speaker, lines, onDone)
    local screen = Instance.new("ScreenGui", gui)
    local frame = Instance.new("Frame", screen)
    frame.Size = UDim2.new(0.6, 0, 0.25, 0)
    frame.Position = UDim2.new(0.2, 0, 0.65, 0)
    frame.BackgroundColor3 = Color3.new(0, 0, 0)
    frame.BackgroundTransparency = 0.4

    local nameLabel = Instance.new("TextLabel", frame)
    nameLabel.Size = UDim2.new(1, 0, 0.2, 0)
    nameLabel.Text = speaker
    nameLabel.TextColor3 = Color3.fromRGB(255, 220, 100)
    nameLabel.BackgroundTransparency = 1

    local textLabel = Instance.new("TextLabel", frame)
    textLabel.Size = UDim2.new(1, -20, 0.6, 0)
    textLabel.Position = UDim2.new(0, 10, 0.2, 0)
    textLabel.TextColor3 = Color3.new(1, 1, 1)
    textLabel.BackgroundTransparency = 1
    textLabel.TextWrapped = true

    local idx = 1
    local function showLine()
        textLabel.Text = lines[idx]
    end

    local btn = Instance.new("TextButton", frame)
    btn.Size = UDim2.new(0.3, 0, 0.15, 0)
    btn.Position = UDim2.new(0.65, 0, 0.82, 0)
    btn.Text = "Дальше"

    btn.MouseButton1Click:Connect(function()
        idx = idx + 1
        if idx > #lines then
            screen:Destroy()
            if onDone then onDone() end
        else
            showLine()
        end
    end)

    showLine()
end

showDialog("Староста", {
    "Привет, путник!",
    "Собери 10 монет и возвращайся.",
}, function() print("Квест начат!") end)`}</Code>
                            </>}
                        />
                    </>
                ),
            },
            {
                id: 'vehicles-menu',
                title: 'G12. Машины и главное меню',
                body: (
                    <>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<>
                                <p><b>Машина</b>, на которой можно ездить (вход hold-F, WASD руль):</p>
                                <Code>{`game.scene.spawn('vehicle:car', { x: 0, y: 1, z: 0, name: 'Тачка' });
game.onVehicleEnter(() => game.ui.showText('За рулём! WASD — ехать', 2));
game.onVehicleExit(() => game.ui.showText('Вышел', 1));`}</Code>
                                <p><b>Главное меню</b>:</p>
                                <Code>{`game.mainMenu.show({
  title: 'МОЯ ИГРА',
  camera: 'orbit',
  playButtonText: 'ИГРАТЬ',
  patchNotes: { title: 'Что нового', items: ['Добавлены машины', 'Новая карта'] },
  onPlay: () => game.ui.showText('Поехали!', 2)
});`}</Code>
                            </>}
                            lua={<>
                                <p>
                                    В Roblox машина — это сложная Model с VehicleSeat
                                    внутри. Когда игрок садится в VehicleSeat — у него
                                    появляются <code>.Throttle</code> и <code>.Steer</code>
                                    свойства от WASD автоматически:
                                </p>
                                <Code>{`-- VehicleSeat внутри Model
local seat = workspace:WaitForChild("Тачка"):WaitForChild("VehicleSeat")

-- Слушаем игрока в кресле
seat:GetPropertyChangedSignal("Occupant"):Connect(function()
    if seat.Occupant then
        print("За рулём! WASD — ехать")
    else
        print("Вышел")
    end
end)

-- Throttle (W/S) и Steer (A/D) — автоматически в seat.Throttle и seat.Steer
-- Применяй их к скорости/повороту в RunService.Heartbeat`}</Code>
                                <p>
                                    Главное меню — собирается через ScreenGui (см. C2-C3),
                                    или используется готовый StarterGui от Roblox.
                                </p>
                            </>}
                        />
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ H — СПРАВОЧНИК game.*
    // ════════════════════════════════════════════════════
    {
        id: 'reference',
        icon: 'book',
        title: 'Справочник game.*',
        summary: 'Шпаргалка: все команды game.* списком по отделам.',
        sections: [
            {
                id: 'cheatsheet',
                title: 'H1. Шпаргалка — все команды списком',
                body: (
                    <>
                        <p>
                            Здесь собраны все команды по отделам. Это шпаргалка —
                            не нужно её запоминать, держи под рукой. Переключатель
                            сверху меняет язык.
                        </p>

                        <h4 className="docRefHead"><DocIcon name="run" size={17} /> Игрок</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.player.position</code></td><td>позиция игрока {`{x,y,z}`}</td></tr>
                                    <tr><td><code>game.player.hp</code> / <code>maxHp</code></td><td>здоровье и максимум</td></tr>
                                    <tr><td><code>game.player.alive</code></td><td>жив ли игрок</td></tr>
                                    <tr><td><code>game.player.forward</code></td><td>куда смотрит</td></tr>
                                    <tr><td><code>game.player.teleport(x,y,z)</code></td><td>телепорт</td></tr>
                                    <tr><td><code>game.player.damage(n)</code> / <code>heal(n)</code></td><td>урон / лечение</td></tr>
                                    <tr><td><code>game.player.kill()</code> / <code>respawn()</code></td><td>убить / воскресить</td></tr>
                                    <tr><td><code>game.player.setSpawn(точка)</code></td><td>новая точка возрождения</td></tr>
                                    <tr><td><code>game.player.setSpeed(mul)</code></td><td>скорость (множитель)</td></tr>
                                    <tr><td><code>game.player.setJumpPower(mul)</code></td><td>прыжок (множитель)</td></tr>
                                    <tr><td><code>game.player.setGravityMul(mul)</code></td><td>гравитация (множитель)</td></tr>
                                    <tr><td><code>game.player.setDoubleJump(on)</code></td><td>двойной прыжок</td></tr>
                                    <tr><td><code>game.player.playAnimation(имя)</code></td><td>эмоция</td></tr>
                                    <tr><td><code>game.player.giveTool(тип,опции)</code></td><td>инструмент в руку</td></tr>
                                    <tr><td><code>game.player.isKeyDown(клавиша)</code></td><td>зажата ли клавиша</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>hrp.Position</code></td><td>позиция (Vector3)</td></tr>
                                    <tr><td><code>humanoid.Health</code> / <code>MaxHealth</code></td><td>здоровье</td></tr>
                                    <tr><td><code>humanoid.Health {'>'}  0</code></td><td>жив ли</td></tr>
                                    <tr><td><code>camera.CFrame.LookVector</code></td><td>куда смотрит</td></tr>
                                    <tr><td><code>hrp.CFrame = CFrame.new(x,y,z)</code></td><td>телепорт</td></tr>
                                    <tr><td><code>humanoid:TakeDamage(n)</code> / <code>humanoid.Health += n</code></td><td>урон / лечение</td></tr>
                                    <tr><td><code>humanoid.Health = 0</code> / <code>player:LoadCharacter()</code></td><td>убить / воскресить</td></tr>
                                    <tr><td><code>player.RespawnLocation = spawn</code></td><td>точка возрождения</td></tr>
                                    <tr><td><code>humanoid.WalkSpeed = N</code></td><td>скорость (16 = норма)</td></tr>
                                    <tr><td><code>humanoid.JumpPower = N</code></td><td>сила прыжка (50 = норма)</td></tr>
                                    <tr><td><code>workspace.Gravity = N</code></td><td>гравитация (196 = норма)</td></tr>
                                    <tr><td><code>humanoid:ChangeState(Jumping)</code></td><td>прыгнуть</td></tr>
                                    <tr><td><code>animator:LoadAnimation(anim):Play()</code></td><td>анимация</td></tr>
                                    <tr><td><code>Instance.new("Tool",player.Character)</code></td><td>инструмент в руку</td></tr>
                                    <tr><td><code>UserInputService:IsKeyDown(key)</code></td><td>зажата ли клавиша</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="cube" size={17} /> Объекты сцены</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.scene.spawn(тип,опции)</code></td><td>создать объект → ref</td></tr>
                                    <tr><td><code>game.scene.delete(ref)</code></td><td>удалить</td></tr>
                                    <tr><td><code>game.scene.deleteAfter(ref,сек)</code></td><td>удалить через N секунд</td></tr>
                                    <tr><td><code>game.scene.move(ref,x,y,z)</code></td><td>переместить</td></tr>
                                    <tr><td><code>game.scene.rotate(ref,угол)</code></td><td>повернуть</td></tr>
                                    <tr><td><code>game.scene.setColor(ref,цвет)</code></td><td>цвет</td></tr>
                                    <tr><td><code>game.scene.setCollide(ref,да)</code></td><td>твёрдость</td></tr>
                                    <tr><td><code>game.scene.setVisible(ref,да)</code></td><td>видимость</td></tr>
                                    <tr><td><code>game.scene.setOpacity(ref,0..1)</code></td><td>прозрачность</td></tr>
                                    <tr><td><code>game.scene.find(имя)</code> / <code>findOne(имя)</code></td><td>поиск по имени</td></tr>
                                    <tr><td><code>game.scene.all(тип)</code></td><td>все объекты типа</td></tr>
                                    <tr><td><code>game.scene.setData/getData</code></td><td>атрибуты</td></tr>
                                    <tr><td><code>game.scene.tag/untag/hasTag</code></td><td>теги</td></tr>
                                    <tr><td><code>game.scene.getTagged(тег)</code></td><td>все объекты с тегом</td></tr>
                                    <tr><td><code>game.scene.setLabel/clearLabel</code></td><td>метка над объектом</td></tr>
                                    <tr><td><code>game.scene.spawnNpc(модель,опции)</code></td><td>создать NPC</td></tr>
                                    <tr><td><code>game.scene.spawnParticles(тип,...)</code></td><td>частицы</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>Instance.new("Part", workspace)</code></td><td>создать объект</td></tr>
                                    <tr><td><code>part:Destroy()</code></td><td>удалить</td></tr>
                                    <tr><td><code>Debris:AddItem(part, N)</code></td><td>удалить через N секунд</td></tr>
                                    <tr><td><code>part.Position = Vector3.new(x,y,z)</code></td><td>переместить</td></tr>
                                    <tr><td><code>part.Orientation = Vector3.new(...)</code></td><td>повернуть</td></tr>
                                    <tr><td><code>part.Color = Color3.fromRGB(...)</code></td><td>цвет</td></tr>
                                    <tr><td><code>part.CanCollide = true/false</code></td><td>твёрдость</td></tr>
                                    <tr><td><code>part.Transparency = 1</code></td><td>невидимость (0=видно)</td></tr>
                                    <tr><td><code>part.Transparency = 0.4</code></td><td>полупрозрачность</td></tr>
                                    <tr><td><code>workspace:FindFirstChild("Имя")</code> / <code>workspace.Имя</code></td><td>поиск по имени</td></tr>
                                    <tr><td><code>CollectionService:GetTagged("тег")</code></td><td>все объекты с тегом</td></tr>
                                    <tr><td><code>part:SetAttribute/GetAttribute</code></td><td>атрибуты</td></tr>
                                    <tr><td><code>CollectionService:AddTag/RemoveTag/HasTag</code></td><td>теги</td></tr>
                                    <tr><td><code>CollectionService:GetTagged(tag)</code></td><td>все объекты с тегом</td></tr>
                                    <tr><td><code>BillboardGui + TextLabel</code></td><td>метка над объектом</td></tr>
                                    <tr><td>Model + Humanoid + Anim</td><td>NPC (вручную)</td></tr>
                                    <tr><td><code>Instance.new("ParticleEmitter", part)</code></td><td>частицы</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="pin" size={17} /> Объект-носитель скрипта</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.self.ref</code> / <code>position</code></td><td>адрес и позиция</td></tr>
                                    <tr><td><code>game.self.onClick(fn)</code></td><td>клик по объекту</td></tr>
                                    <tr><td><code>game.self.onTouch(fn)</code></td><td>игрок коснулся</td></tr>
                                    <tr><td><code>game.self.onUntouch(fn)</code></td><td>игрок вышел</td></tr>
                                    <tr><td><code>game.self.onInteract(fn,опции)</code></td><td>взаимодействие по E</td></tr>
                                    <tr><td><code>game.self.move(x,y,z)</code></td><td>переместить себя</td></tr>
                                    <tr><td><code>game.self.delete()</code></td><td>удалить себя</td></tr>
                                    <tr><td><code>game.self.setText(t)</code></td><td>сменить текст</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>script.Parent</code> / <code>.Position</code></td><td>сам объект и его позиция</td></tr>
                                    <tr><td><code>ClickDetector.MouseClick:Connect</code></td><td>клик по объекту</td></tr>
                                    <tr><td><code>part.Touched:Connect</code></td><td>игрок коснулся</td></tr>
                                    <tr><td><code>part.TouchEnded:Connect</code></td><td>игрок вышел</td></tr>
                                    <tr><td><code>ProximityPrompt.Triggered:Connect</code></td><td>взаимодействие по E</td></tr>
                                    <tr><td><code>part.Position = Vector3.new(x,y,z)</code></td><td>переместить</td></tr>
                                    <tr><td><code>part:Destroy()</code></td><td>удалить</td></tr>
                                    <tr><td><code>textLabel.Text = "..."</code></td><td>сменить текст (для GUI)</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="window" size={17} /> HUD: счётчики и текст</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.ui.score</code> / <code>timer</code></td><td>счётчики в углу</td></tr>
                                    <tr><td><code>game.ui.showText(текст,сек)</code></td><td>текст по центру</td></tr>
                                    <tr><td><code>game.ui.set(id,текст,опции)</code></td><td>своя метка</td></tr>
                                    <tr><td><code>game.ui.remove(id)</code> / <code>clear()</code></td><td>убрать метку / всё</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>leaderstats папка + IntValue</code></td><td>счётчики в углу (HUD автомат)</td></tr>
                                    <tr><td><code>ScreenGui + TextLabel (центр)</code></td><td>текст по центру</td></tr>
                                    <tr><td><code>label.Text = "..."</code></td><td>обновить метку</td></tr>
                                    <tr><td><code>label:Destroy()</code> / <code>screen:Destroy()</code></td><td>убрать метку / всё</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="palette" size={17} /> GUI: кнопки и меню</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.gui.find(имя)</code> / <code>get(id)</code></td><td>найти элемент</td></tr>
                                    <tr><td><code>game.gui.update(id,patch)</code></td><td>изменить свойства</td></tr>
                                    <tr><td><code>game.gui.show(id)</code> / <code>hide(id)</code></td><td>показать / скрыть</td></tr>
                                    <tr><td><code>game.gui.onClick(id,fn)</code></td><td>клик по кнопке</td></tr>
                                    <tr><td><code>game.gui.onSubmit(id,fn)</code></td><td>ввод в поле завершён</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>gui:FindFirstChild(имя, true)</code></td><td>найти элемент</td></tr>
                                    <tr><td><code>elem.Text = "..."</code> / прямая запись свойств</td><td>изменить свойства</td></tr>
                                    <tr><td><code>elem.Visible = true/false</code></td><td>показать / скрыть</td></tr>
                                    <tr><td><code>button.MouseButton1Click:Connect</code></td><td>клик по кнопке</td></tr>
                                    <tr><td><code>textbox.FocusLost:Connect(fn)</code></td><td>ввод завершён</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="target" size={17} /> Физика, эффекты, связи</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.physics.raycast(...)</code></td><td>луч — во что попал</td></tr>
                                    <tr><td><code>game.physics.applyImpulse(...)</code></td><td>толкнуть объект</td></tr>
                                    <tr><td><code>game.physics.explode(...)</code></td><td>взрыв</td></tr>
                                    <tr><td><code>game.physics.passThrough(...)</code></td><td>проходимость</td></tr>
                                    <tr><td><code>game.fx.beam(опции)</code></td><td>светящийся луч</td></tr>
                                    <tr><td><code>game.fx.trail(ref,опции)</code></td><td>след за объектом</td></tr>
                                    <tr><td><code>game.fx.damageFloater(...)</code></td><td>цифры урона</td></tr>
                                    <tr><td><code>game.constraints.weld(a,b)</code></td><td>склейка</td></tr>
                                    <tr><td><code>game.constraints.hinge(...)</code></td><td>петля</td></tr>
                                    <tr><td><code>game.constraints.spring(...)</code></td><td>пружина</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>workspace:Raycast(origin,dir,params)</code></td><td>луч — во что попал</td></tr>
                                    <tr><td><code>part:ApplyImpulse(Vector3)</code></td><td>толкнуть объект</td></tr>
                                    <tr><td><code>Instance.new("Explosion", workspace)</code></td><td>взрыв</td></tr>
                                    <tr><td><code>part.CanCollide = false</code></td><td>проходимость</td></tr>
                                    <tr><td><code>Instance.new("Beam") + Attachments</code></td><td>светящийся луч</td></tr>
                                    <tr><td><code>Instance.new("Trail") + Attachments</code></td><td>след за объектом</td></tr>
                                    <tr><td>BillboardGui + TweenService</td><td>цифры урона (вручную)</td></tr>
                                    <tr><td><code>Instance.new("WeldConstraint")</code></td><td>склейка</td></tr>
                                    <tr><td><code>Instance.new("HingeConstraint")</code></td><td>петля</td></tr>
                                    <tr><td><code>Instance.new("SpringConstraint")</code></td><td>пружина</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="camera" size={17} /> Камера и звук</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.camera.setFov(град)</code></td><td>угол обзора</td></tr>
                                    <tr><td><code>game.camera.shake(сила,сек)</code></td><td>тряска</td></tr>
                                    <tr><td><code>game.camera.cutscene(...)</code></td><td>пролёт камеры</td></tr>
                                    <tr><td><code>game.camera.reset()</code></td><td>вернуть камеру игроку</td></tr>
                                    <tr><td><code>game.sound.play(id,опции)</code></td><td>проиграть звук</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>workspace.CurrentCamera.FieldOfView = N</code></td><td>угол обзора</td></tr>
                                    <tr><td><code>camera.CFrame = CFrame.new(...)</code> + рандом</td><td>тряска (вручную)</td></tr>
                                    <tr><td><code>camera.CameraType = Scriptable + TweenService</code></td><td>пролёт камеры</td></tr>
                                    <tr><td><code>camera.CameraType = Custom</code></td><td>вернуть игроку</td></tr>
                                    <tr><td><code>Instance.new("Sound"):Play()</code></td><td>проиграть звук</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="gear" size={17} /> События и таймеры</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.onTick(fn)</code></td><td>каждый кадр</td></tr>
                                    <tr><td><code>game.onKey/onKeyUp(клавиша,fn)</code></td><td>клавиатура</td></tr>
                                    <tr><td><code>game.onClick(fn)</code></td><td>клик в игре</td></tr>
                                    <tr><td><code>game.after(сек,fn)</code></td><td>через N секунд</td></tr>
                                    <tr><td><code>game.every(сек,fn)</code></td><td>каждые N секунд</td></tr>
                                    <tr><td><code>game.cancel(id)</code></td><td>отменить таймер</td></tr>
                                    <tr><td><code>game.tween(ref,св-ва,опции)</code></td><td>плавная анимация</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>RunService.Heartbeat:Connect(fn)</code></td><td>каждый кадр</td></tr>
                                    <tr><td><code>UserInputService.InputBegan/Ended</code></td><td>клавиатура</td></tr>
                                    <tr><td><code>mouse.Button1Down:Connect(fn)</code></td><td>клик в игре</td></tr>
                                    <tr><td><code>task.delay(сек, fn)</code></td><td>через N секунд</td></tr>
                                    <tr><td><code>task.spawn(function() while ... task.wait(N) end end)</code></td><td>каждые N секунд</td></tr>
                                    <tr><td><code>connection:Disconnect()</code></td><td>отменить подписку</td></tr>
                                    <tr><td><code>TweenService:Create(obj, info, goal):Play()</code></td><td>плавная анимация</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="code" size={17} /> Утилиты</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.random(min,max)</code></td><td>случайное число</td></tr>
                                    <tr><td><code>game.distance(a,b)</code></td><td>расстояние между точками</td></tr>
                                    <tr><td><code>game.clamp(v,min,max)</code></td><td>зажать в границах</td></tr>
                                    <tr><td><code>game.lerp(a,b,t)</code></td><td>плавный переход</td></tr>
                                    <tr><td><code>game.log(...)</code></td><td>в консоль</td></tr>
                                    <tr><td><code>game.broadcast/onMessage</code></td><td>сообщения между скриптами</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>math.random(min,max)</code></td><td>случайное число</td></tr>
                                    <tr><td><code>(a - b).Magnitude</code></td><td>расстояние между Vector3</td></tr>
                                    <tr><td><code>math.clamp(v,min,max)</code></td><td>зажать в границах</td></tr>
                                    <tr><td><code>a + (b-a)*t</code> или <code>Vector3:Lerp(other,t)</code></td><td>плавный переход</td></tr>
                                    <tr><td><code>print(...)</code> / <code>warn(...)</code></td><td>в консоль</td></tr>
                                    <tr><td><code>BindableEvent:Fire</code> + <code>.Event:Connect</code></td><td>сообщения между скриптами</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="users" size={17} /> Мультиплеер, лидерборды, команды</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.players.all() / count() / me()</code></td><td>список игроков</td></tr>
                                    <tr><td><code>game.room.set/get/onChange</code></td><td>общее состояние комнаты</td></tr>
                                    <tr><td><code>game.teams.*</code></td><td>команды</td></tr>
                                    <tr><td><code>game.leaderstats.define(имя,опции)</code></td><td>объявить стат</td></tr>
                                    <tr><td><code>game.leaderstats.me.add/set/get</code></td><td>текущему игроку</td></tr>
                                    <tr><td><code>game.achievements.define/unlock</code></td><td>достижения</td></tr>
                                    <tr><td><code>game.save.merge/get</code></td><td>сохранение прогресса</td></tr>
                                    <tr><td><code>game.onPlayerJoin/Leave(fn)</code></td><td>игрок зашёл / ушёл</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>Players:GetPlayers()</code> / <code>#Players:GetPlayers()</code> / <code>Players.LocalPlayer</code></td><td>список / число / я</td></tr>
                                    <tr><td><code>ReplicatedStorage + Value + .Changed</code></td><td>общее состояние</td></tr>
                                    <tr><td><code>Teams сервис + Instance.new("Team")</code></td><td>команды</td></tr>
                                    <tr><td><code>Instance.new("Folder","leaderstats")+IntValue</code></td><td>лидерборд</td></tr>
                                    <tr><td><code>stats.Имя.Value = N</code></td><td>обновить стат</td></tr>
                                    <tr><td><code>BadgeService:AwardBadge(uid, id)</code></td><td>достижения (badges)</td></tr>
                                    <tr><td><code>DataStoreService:GetAsync/SetAsync</code></td><td>сохранение прогресса</td></tr>
                                    <tr><td><code>Players.PlayerAdded:Connect</code> / <code>PlayerRemoving</code></td><td>игрок зашёл / ушёл</td></tr>
                                </tbody>
                            </table>}
                        />

                        <h4 className="docRefHead"><DocIcon name="sparkle" size={17} /> Небо, освещение, инвентарь, модалки</h4>
                        <LangTabs
                            js={<table className="docTable">
                                <tbody>
                                    <tr><td><code>game.scene.setSkybox/fadeTo</code></td><td>пресеты неба</td></tr>
                                    <tr><td><code>game.scene.setFog/setClouds</code></td><td>туман и облака</td></tr>
                                    <tr><td><code>game.environment.setTimeOfDay(0..24)</code></td><td>время суток</td></tr>
                                    <tr><td><code>game.items.define(список)</code></td><td>описать предметы</td></tr>
                                    <tr><td><code>game.inventory.give/remove/has/list</code></td><td>инвентарь</td></tr>
                                    <tr><td><code>game.modal.dialog/confirmation/lootbox</code></td><td>модальные окна</td></tr>
                                    <tr><td><code>game.mainMenu.show/hide</code></td><td>главное меню</td></tr>
                                    <tr><td><code>game.loading.show/onHide</code></td><td>экран загрузки</td></tr>
                                </tbody>
                            </table>}
                            lua={<table className="docTable">
                                <tbody>
                                    <tr><td><code>Lighting + Sky / Atmosphere</code></td><td>пресеты неба (вручную)</td></tr>
                                    <tr><td><code>Lighting.FogColor / FogEnd / Atmosphere</code></td><td>туман и облака</td></tr>
                                    <tr><td><code>Lighting:SetMinutesAfterMidnight(N)</code></td><td>время суток</td></tr>
                                    <tr><td>Свои Tool'ы в ServerStorage</td><td>предметы (вручную)</td></tr>
                                    <tr><td><code>player.Backpack:GetChildren()</code> / <code>Tool.Parent = Backpack</code></td><td>инвентарь</td></tr>
                                    <tr><td>ScreenGui + Frame + Button</td><td>модалки (вручную, см. G11)</td></tr>
                                    <tr><td>ScreenGui + Frame</td><td>главное меню (вручную)</td></tr>
                                    <tr><td><code>ReplicatedFirst + loading screen</code></td><td>экран загрузки</td></tr>
                                </tbody>
                            </table>}
                        />
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ I — ГЛОССАРИЙ
    // ════════════════════════════════════════════════════
    {
        id: 'glossary',
        icon: 'glossary',
        title: 'Глоссарий',
        summary: 'Словарик: все непонятные слова из вики простым языком.',
        sections: [
            {
                id: 'terms',
                title: 'I1. Термины простым языком',
                body: (
                    <>
                        <p>Словарик слов, которые встречаются в вики:</p>
                        <table className="docTable">
                            <tbody>
                                <tr><td><b>Примитив</b></td><td>Простая 3D-фигура: куб, сфера, цилиндр. Главный строительный материал.</td></tr>
                                <tr><td><b>Модель</b></td><td>Готовая красивая 3D-фигура из библиотеки (дерево, машина).</td></tr>
                                <tr><td><b>Блок</b></td><td>Кубик одного размера, ровно встаёт по сетке.</td></tr>
                                <tr><td><b>Сцена</b></td><td>Весь игровой мир — всё, что ты построил.</td></tr>
                                <tr><td><b>Вьюпорт</b></td><td>Окно с 3D-сценой в центре редактора.</td></tr>
                                <tr><td><b>Гизмо</b></td><td>Цветные стрелки и кольца для перемещения объектов.</td></tr>
                                <tr><td><b>Иерархия</b></td><td>Список всех объектов игры в правой панели.</td></tr>
                                <tr><td><b>Инспектор</b></td><td>Панель со свойствами выделенного объекта.</td></tr>
                                <tr><td><b>Скрипт</b></td><td>Набор команд (код), который оживляет игру.</td></tr>
                                <tr><td><b>JavaScript</b></td><td>Язык программирования, на котором пишут скрипты.</td></tr>
                                <tr><td><b>Глобальный скрипт</b></td><td>Скрипт-«мозг», не привязан к объекту, запускается один раз.</td></tr>
                                <tr><td><b>Скрипт на объекте</b></td><td>Скрипт конкретного объекта, в нём работает game.self.</td></tr>
                                <tr><td><b>Переменная</b></td><td>«Коробочка с именем» — скрипт хранит в ней значение.</td></tr>
                                <tr><td><b>Функция</b></td><td>Набор команд, который выполнится, когда его позовут.</td></tr>
                                <tr><td><b>Событие</b></td><td>«Что-то случилось» — клик, касание, нажатие клавиши.</td></tr>
                                <tr><td><b>Условие (if)</b></td><td>Развилка: если что-то верно — сделай одно, иначе — другое.</td></tr>
                                <tr><td><b>Спавн</b></td><td>Появление: точка спавна — где появляется игрок; «заспавнить» — создать объект.</td></tr>
                                <tr><td><b>Респаун</b></td><td>Воскрешение игрока после смерти.</td></tr>
                                <tr><td><b>Чекпоинт</b></td><td>Контрольная точка — место, откуда игрок воскреснет.</td></tr>
                                <tr><td><b>HP</b></td><td>Здоровье игрока. При HP=0 он умирает.</td></tr>
                                <tr><td><b>ref</b></td><td>«Адрес» объекта. Команда spawn возвращает ref, по нему обращаются к объекту.</td></tr>
                                <tr><td><b>Твин</b></td><td>Плавное изменение свойства за время (плавное движение).</td></tr>
                                <tr><td><b>Тег</b></td><td>Ярлык на объекте. По тегу можно найти все помеченные объекты.</td></tr>
                                <tr><td><b>Атрибут</b></td><td>Своё значение, приклеенное к объекту (через setData).</td></tr>
                                <tr><td><b>Констрейнт</b></td><td>Связь между объектами: склейка, петля, пружина.</td></tr>
                                <tr><td><b>Эмиттер</b></td><td>Объект, создающий частицы (искры, дым, огонь).</td></tr>
                                <tr><td><b>Частицы</b></td><td>Много маленьких летящих точек для эффектов.</td></tr>
                                <tr><td><b>GUI</b></td><td>Интерфейс: кнопки, надписи, меню поверх 3D-сцены.</td></tr>
                                <tr><td><b>HUD</b></td><td>Счётчики и индикаторы поверх экрана (счёт, HP).</td></tr>
                                <tr><td><b>NPC</b></td><td>Неигровой персонаж: торговец, враг, проводник.</td></tr>
                                <tr><td><b>Триггер</b></td><td>Невидимая зона, которая что-то запускает при входе игрока.</td></tr>
                                <tr><td><b>Raycast</b></td><td>Невидимый луч — узнать, во что он попал (для стрельбы).</td></tr>
                                <tr><td><b>FOV</b></td><td>Угол обзора камеры. Больше — «шире» видно.</td></tr>
                                <tr><td><b>Катсцена</b></td><td>Видеовставка: камера сама пролетает по точкам.</td></tr>
                                <tr><td><b>Мультиплеер</b></td><td>Игра на нескольких игроков в одной комнате.</td></tr>
                                <tr><td><b>Модерация</b></td><td>Проверка игры перед публикацией в общей ленте.</td></tr>
                            </tbody>
                        </table>
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ J — ЧАСТЫЕ ОШИБКИ
    // ════════════════════════════════════════════════════
    {
        id: 'mistakes',
        icon: 'bug',
        title: 'Частые ошибки',
        summary: 'Что делать, если скрипт не работает или игра ведёт себя странно.',
        sections: [
            {
                id: 'script-not-working',
                title: 'J1. Скрипт не работает или не сохраняется',
                body: (
                    <>
                        <p>
                            <b>Первым делом — проверь Консоль.</b> Если в скрипте
                            опечатка, её текст появится в Консоли красным — там
                            написано, в какой строке ошибка.
                        </p>
                        <p>Самые частые опечатки:</p>
                        <ul>
                            <li>забыли точку с запятой <code>;</code> в конце команды;</li>
                            <li>
                                не закрыли скобку — открывающих и закрывающих
                                <code> ( )</code>, <code>{`{ }`}</code> должно быть
                                поровну;
                            </li>
                            <li>
                                имя команды с ошибкой: <code>game.player.teelport</code>
                                вместо <code>teleport</code>;
                            </li>
                            <li>
                                русская буква вместо английской (с виду одинаковы:
                                русская <code>с</code> и английская <code>c</code>).
                            </li>
                        </ul>
                        <p>
                            После правки скрипта — <b>сохрани игру</b>
                            (<kbd className="kbd">Ctrl</kbd>+<kbd className="kbd">S</kbd>)
                            и перезапусти Play.
                        </p>
                    </>
                ),
            },
            {
                id: 'fell-through-floor',
                title: 'J2. Объект провалился сквозь пол',
                body: (
                    <p>
                        Если объект <b>не закреплён</b> (свойство «Закреплён»
                        выключено), он падает под действием физики. Для платформ,
                        стен и декораций <b>включи «Закреплён»</b> в инспекторе —
                        тогда объект будет висеть на месте. Падать должны только те
                        объекты, которым это нужно (ящики, мячи).
                    </p>
                ),
            },
            {
                id: 'findone-null',
                title: 'J3. findOne вернул «ничего» (null) на старте',
                body: (
                    <>
                        <p>
                            Если позвать <code>game.scene.findOne(...)</code> в самой
                            первой строке скрипта — объект может быть ещё не готов,
                            и команда вернёт <code>null</code> («ничего»). Потом
                            обращение к этому <code>null</code> сломает скрипт.
                        </p>
                        <p>
                            <b>Решение:</b> ищи объект не на старте, а внутри
                            <code> onTick</code> или после небольшой задержки:
                        </p>
                        <Code>{`let door = null;
game.onTick(() => {
  // ищем дверь, пока не найдём
  if (!door) door = game.scene.findOne('Дверь');
  // ... работаем с door, когда он уже найден
});`}</Code>
                    </>
                ),
            },
            {
                id: 'ui-set-every-frame',
                title: 'J4. game.ui.set каждый кадр — игра лагает',
                body: (
                    <>
                        <p>
                            <code>onTick</code> выполняется 60 раз в секунду. Если
                            внутри него на каждом кадре звать <code>game.ui.set(...)</code>,
                            интерфейс будет обновляться слишком часто и игра начнёт
                            тормозить.
                        </p>
                        <p>
                            <b>Решение:</b> обновляй интерфейс только когда значение
                            реально изменилось:
                        </p>
                        <Code>{`let lastScore = -1;
game.onTick(() => {
  const s = game.ui.score || 0;
  if (s !== lastScore) {        // значение изменилось?
    game.ui.set('hud', 'Счёт: ' + s);
    lastScore = s;
  }
});`}</Code>
                    </>
                ),
            },
            {
                id: 'other-mistakes',
                title: 'J5. Прочие типичные грабли',
                body: (
                    <ul>
                        <li>
                            <b>Враг идёт сквозь стены</b> — проверь, что у стен
                            включено «Столкновение».
                        </li>
                        <li>
                            <b>Звук не играет</b> — проверь громкость
                            (<code>volume</code>) и что звук загружен. Не запускай
                            длинный звук в самом начале — это тормозит старт.
                        </li>
                        <li>
                            <b>Кнопка не нажимается</b> — проверь, что на неё повешен
                            <code> game.gui.onClick(...)</code> с правильным id,
                            и что у элемента правильное имя.
                        </li>
                        <li>
                            <b>Объект не двигается твином</b> — у твина свойство
                            должно быть числом (<code>{`{ y: 10 }`}</code>), а первым
                            аргументом — настоящий <code>ref</code> объекта.
                        </li>
                        <li>
                            <b>Скрипт на объекте, но game.self пустой</b> — значит
                            скрипт не привязан. Выдели объект и пересоздай скрипт
                            на нём, либо укажи носителя в настройках скрипта.
                        </li>
                        <li>
                            <b>Игрок застрял в стене</b> — не делай стену твёрдой,
                            пока игрок внутри. Используй <code>passThrough</code>
                            аккуратно.
                        </li>
                    </ul>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ — СКРИПТЫ: ГОТОВЫЕ РЕЦЕПТЫ
    // ════════════════════════════════════════════════════
    {
        id: 'recipes',
        icon: 'code',
        title: 'Скрипты: рецепты',
        summary: 'Готовые мини-скрипты, которые можно скопировать и вставить: килблок, сбор предметов, исчезновение и телепорт при касании, кнопки, таймеры, все свойства примитивов.',
        sections: [
            {
                id: 'recipes-howto',
                title: 'S1. Куда писать скрипты',
                body: (
                    <>
                        <p>В Рублоксе есть <b>два вида скриптов</b>:</p>
                        <ul>
                            <li><b>Глобальный</b> — создаётся в иерархии в категории
                                <b> «Скрипты»</b> (кнопка «+»). Запускается один раз при
                                старте игры. В нём управляешь всей сценой через
                                <code> game.scene</code>, <code>game.player</code>, <code>game.ui</code>.</li>
                            <li><b>На объекте</b> — вешается прямо на примитив/модель/блок.
                                В нём работает <code>game.self</code> — это сам объект-носитель.
                                Удобно для «этот блок убивает», «этот сундук открывается».</li>
                        </ul>
                        <Note>
                            В рецептах ниже над каждым примером написано, <b>куда его
                            писать</b>. Просто скопируй код и вставь в нужный скрипт.
                        </Note>
                        <p>
                            Полезное: <code>game.log(...)</code> печатает в консоль (значок
                            «Консоль» внизу) — для отладки. <code>game.player.position</code>
                            — где сейчас игрок (<code>{'{x, y, z}'}</code>).
                        </p>
                    </>
                ),
            },
            {
                id: 'recipes-touch',
                title: 'S2. Касание объекта',
                body: (
                    <>
                        <p>Самое частое событие — <b>игрок коснулся объекта</b>.</p>
                        <ScriptKind kind="object" on="любой объект (плита, зона, предмет)" />
                        <LangTabs
                            js={<Code>{`// Игрок наступил на объект — показать надпись и звук
game.self.onTouch(() => {
  game.ui.showText('Ты коснулся плиты!', 2);
  game.sound.play('click');
});

// Когда игрок ушёл с объекта
game.self.onUntouch(() => {
  game.ui.showText('Отошёл', 1);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

-- Игрок наступил
part.Touched:Connect(function(hit)
    local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
    if player then
        print("Ты коснулся плиты!")
    end
end)

-- Игрок ушёл
part.TouchEnded:Connect(function(hit)
    local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
    if player then
        print("Отошёл")
    end
end)`}</Code>}
                        />
                        <p>Подписаться на <b>чужой</b> объект из глобального скрипта:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`const trap = game.scene.findOne('Ловушка');
trap.onTouch(() => game.player.damage(20));`}</Code>}
                            lua={<Code>{`local trap = workspace:WaitForChild("Ловушка")
trap.Touched:Connect(function(hit)
    local humanoid = hit.Parent:FindFirstChild("Humanoid")
    if humanoid then humanoid:TakeDamage(20) end
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-killblock',
                title: 'S3. Килблок — урон и смерть при касании',
                body: (
                    <>
                        <p>
                            <b>Килблок</b> — объект, который наносит урон или мгновенно
                            убивает при касании (лава, шипы, кислота).
                        </p>
                        <ScriptKind kind="object" on="блок-ловушку (лава, шипы)" />
                        <LangTabs
                            js={<Code>{`// Мгновенная смерть при касании
game.self.onTouch(() => {
  game.player.kill();
  game.ui.showText('Ты сгорел в лаве!', 2);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local humanoid = hit.Parent:FindFirstChild("Humanoid")
    if humanoid then
        humanoid.Health = 0    -- мгновенная смерть
    end
end)`}</Code>}
                        />
                        <p>Если хочешь не убивать сразу, а наносить урон:</p>
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  game.player.damage(25);
  game.camera.shake(0.2, 0.3);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local humanoid = hit.Parent:FindFirstChild("Humanoid")
    if humanoid then humanoid:TakeDamage(25) end
end)`}</Code>}
                        />
                        <p><b>Постоянный урон</b>, пока игрок стоит в зоне:</p>
                        <LangTabs
                            js={<Code>{`let inside = false;
game.self.onTouch(() => { inside = true; });
game.self.onUntouch(() => { inside = false; });
game.every(0.5, () => {
  if (inside) game.player.damage(5);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent
local inside = {}    -- humanoid → true

part.Touched:Connect(function(hit)
    local h = hit.Parent:FindFirstChild("Humanoid")
    if h then inside[h] = true end
end)
part.TouchEnded:Connect(function(hit)
    local h = hit.Parent:FindFirstChild("Humanoid")
    if h then inside[h] = nil end
end)

-- Урон каждые 0.5 сек пока стоит
while true do
    task.wait(0.5)
    for h in pairs(inside) do
        if h.Parent then h:TakeDamage(5) end
    end
end`}</Code>}
                        />
                        <Try>
                            Сделай красный неоновый куб, повесь на него скрипт смерти —
                            получится лава. Поставь его в проёме как преграду.
                        </Try>
                    </>
                ),
            },
            {
                id: 'recipes-disappear',
                title: 'S4. Исчезновение при касании (сбор монет)',
                body: (
                    <>
                        <p>
                            Предмет <b>исчезает</b> при касании — основа сбора монет.
                        </p>
                        <ScriptKind kind="object" on="монетку / собираемый предмет" />
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  game.sound.play('coin');
  game.self.delete();
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local h = hit.Parent:FindFirstChild("Humanoid")
    if h then
        part:Destroy()
    end
end)`}</Code>}
                        />
                        <p>Со <b>счётчиком</b>: монетка увеличивает leaderstats игрока:</p>
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  game.broadcast('coin');
  game.self.delete();
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
    if not player then return end

    -- Прибавить монетку в leaderstats
    local stats = player:FindFirstChild("leaderstats")
    if stats and stats:FindFirstChild("Монеты") then
        stats.Монеты.Value = stats.Монеты.Value + 1
    end

    part:Destroy()
end)`}</Code>}
                        />
                        <p>JS: глобальный скрипт принимает broadcast и считает:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`let score = 0;
game.ui.score = 0;
game.onMessage('coin', () => {
  score = score + 1;
  game.ui.score = score;
  if (score >= 10) game.ui.showText('Собрал все!', 3);
});`}</Code>}
                            lua={<Code>{`-- В Lua счёт уже в leaderstats игрока (см. код на монетке выше).
-- Проверим достижение цели в глобальном скрипте:
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    -- Создаём leaderstats папку при заходе
    local stats = Instance.new("Folder", player)
    stats.Name = "leaderstats"
    local coins = Instance.new("IntValue", stats)
    coins.Name = "Монеты"
    coins.Value = 0

    coins.Changed:Connect(function(newVal)
        if newVal >= 10 then
            print("Собрал все!")
        end
    end)
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-teleport',
                title: 'S5. Телепорт и смена позиции при касании',
                body: (
                    <>
                        <p>
                            При касании <b>переместить игрока</b> (портал) или
                            <b> сдвинуть сам объект</b>.
                        </p>
                        <p><b>Портал</b> — телепорт игрока:</p>
                        <ScriptKind kind="object" on="портал" />
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  game.player.teleport(0, 20, 50);
  game.sound.play('win');
  game.camera.shake(0.15, 0.2);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local h = hit.Parent:FindFirstChild("Humanoid")
    if not h then return end
    local hrp = hit.Parent:FindFirstChild("HumanoidRootPart")
    if hrp then
        hrp.CFrame = CFrame.new(0, 20, 50)
    end
end)`}</Code>}
                        />
                        <p><b>Сдвинуть сам объект</b> при касании (опустить мост):</p>
                        <LangTabs
                            js={<Code>{`let opened = false;
game.self.onTouch(() => {
  if (opened) return;
  opened = true;
  const p = game.self.position;
  game.self.move(p.x, p.y - 3, p.z);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent
local opened = false

part.Touched:Connect(function(hit)
    if opened then return end
    if not hit.Parent:FindFirstChild("Humanoid") then return end
    opened = true
    part.Position = part.Position - Vector3.new(0, 3, 0)
end)`}</Code>}
                        />
                        <p><b>Плавно</b> сдвинуть — через TweenService:</p>
                        <LangTabs
                            js={<Code>{`const p = game.self.position;
game.self.onTouch(() => {
  game.tween(game.self.ref, { x: p.x + 4 },
    { duration: 1, easing: 'ease' });
});`}</Code>}
                            lua={<Code>{`local TweenService = game:GetService("TweenService")
local part = script.Parent

part.Touched:Connect(function(hit)
    if not hit.Parent:FindFirstChild("Humanoid") then return end
    local goal = { Position = part.Position + Vector3.new(4, 0, 0) }
    TweenService:Create(part, TweenInfo.new(1), goal):Play()
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-primitive-props',
                title: 'S6. Все свойства примитивов из скрипта',
                body: (
                    <>
                        <p>
                            Любой примитив можно <b>создать</b> и <b>менять</b> из скрипта.
                        </p>
                        <ScriptKind kind="global" />
                        <p><b>Создать примитив</b>:</p>
                        <LangTabs
                            js={<Code>{`const box = game.scene.spawn('cube', {
  x: 0, y: 2, z: 0,
  sx: 2, sy: 1, sz: 3,
  rotationX: 0, rotationY: 0.8, rotationZ: 0,
  color: '#ff5533',
  material: 'neon',
  name: 'МойКуб',
  anchored: true,
  canCollide: true,
  visible: true,
  mass: 5,
});`}</Code>}
                            lua={<Code>{`local box = Instance.new("Part")
box.Name = "МойКуб"
box.Shape = Enum.PartType.Block
box.Size = Vector3.new(2, 1, 3)
box.Position = Vector3.new(0, 2, 0)
box.Orientation = Vector3.new(0, math.deg(0.8), 0)  -- градусы
box.Color = Color3.fromRGB(255, 85, 51)
box.Material = Enum.Material.Neon
box.Anchored = true
box.CanCollide = true
box.Transparency = 0
-- Если Anchored=false: box.Mass читается, не задаётся.
-- Управляется через PhysicalProperties и Density.
box.Parent = workspace`}</Code>}
                        />
                        <p>Типы примитивов:</p>
                        <LangTabs
                            js={<Code>{`'cube'  'sphere'  'cylinder'  'cone'  'pyramid'  'torus'  'wedge'  'cornerwedge'  'plane'`}</Code>}
                            lua={<Code>{`Enum.PartType.Block / Ball / Cylinder / Wedge / CornerWedge
-- Для cone/pyramid/torus используются MeshPart или SpecialMesh:
local sphere = Instance.new("Part")
sphere.Shape = Enum.PartType.Ball  -- сфера`}</Code>}
                        />
                        <p><b>Менять свойства</b> существующего объекта:</p>
                        <LangTabs
                            js={<Code>{`game.scene.setColor(box, '#00ff88');
game.scene.setMaterial(box, 'glass');
game.scene.setVisible(box, false);
game.scene.setCollide(box, false);
game.scene.setOpacity(box, 0.4);
game.scene.setScale(box, 3, 1, 1);
game.scene.move(box, 5, 2, 0);
game.scene.setRotation(box, 0, 1.57, 0);
game.scene.setLabel(box, 'Привет!', { color:'#fff', height: 2.5 });

// Или через прокси:
const obj = game.scene.findOne('МойКуб');
obj.color = '#ffd700';
obj.material = 'metal';
obj.scale = 2;
obj.opacity = 0.5;
obj.visible = false;
obj.canCollide = false;
obj.position = { x: 0, y: 10, z: 0 };
obj.rotateY(1.57);
obj.destroy();`}</Code>}
                            lua={<Code>{`-- Прямое присваивание свойств Part
box.Color = Color3.fromRGB(0, 255, 136)
box.Material = Enum.Material.Glass
box.Transparency = 0.6           -- 0=видно, 1=невидимо
box.CanCollide = false
box.Size = Vector3.new(3, 1, 1)
box.Position = Vector3.new(5, 2, 0)
box.Orientation = Vector3.new(0, 90, 0)
-- Скрыть: Transparency = 1 (или Parent = nil)

box:Destroy()                    -- удалить`}</Code>}
                        />
                        <LangTabs
                            js={<Note>
                                <b>Радианы:</b> поворот в радианах. 90° = <code>Math.PI/2</code> ≈ 1.57.
                            </Note>}
                            lua={<Note>
                                <b>Градусы:</b> Orientation в градусах (не радианах).
                                Для CFrame.Angles — в радианах: <code>math.rad(90)</code>.
                            </Note>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-anim',
                title: 'S7. Движение, вращение, мигание',
                body: (
                    <>
                        <p><b>Вращающийся объект</b> (монета, портал):</p>
                        <ScriptKind kind="object" on="вращающийся объект" />
                        <LangTabs
                            js={<Code>{`let angle = 0;
game.onTick((dt) => {
  angle = angle + dt * 2;
  game.self.rotateY(angle);
});`}</Code>}
                            lua={<Code>{`local RunService = game:GetService("RunService")
local part = script.Parent
local angle = 0

RunService.Heartbeat:Connect(function(dt)
    angle = angle + dt * 2
    part.CFrame = CFrame.new(part.Position) * CFrame.Angles(0, angle, 0)
end)`}</Code>}
                        />
                        <p><b>Парение вверх-вниз</b>:</p>
                        <LangTabs
                            js={<Code>{`const start = game.self.position;
let t = 0;
game.onTick((dt) => {
  t = t + dt;
  const dy = Math.sin(t * 2) * 0.4;
  game.self.move(start.x, start.y + dy, start.z);
});`}</Code>}
                            lua={<Code>{`local RunService = game:GetService("RunService")
local part = script.Parent
local startPos = part.Position
local t = 0

RunService.Heartbeat:Connect(function(dt)
    t = t + dt
    local dy = math.sin(t * 2) * 0.4
    part.Position = Vector3.new(startPos.X, startPos.Y + dy, startPos.Z)
end)`}</Code>}
                        />
                        <p><b>Пульсация размера</b>:</p>
                        <LangTabs
                            js={<Code>{`game.tween(game.self.ref, { sy: 1.4 }, {
  duration: 0.6, easing: 'ease', yoyo: true, repeat: -1
});`}</Code>}
                            lua={<Code>{`local TweenService = game:GetService("TweenService")
local part = script.Parent
local origSize = part.Size

local info = TweenInfo.new(
    0.6, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut,
    -1,   -- бесконечно
    true  -- yoyo (туда-обратно)
)
local goal = { Size = Vector3.new(origSize.X, origSize.Y * 1.4, origSize.Z) }
TweenService:Create(part, info, goal):Play()`}</Code>}
                        />
                        <p><b>Мигание цветом</b>:</p>
                        <LangTabs
                            js={<Code>{`let on = false;
game.every(0.5, () => {
  on = !on;
  game.self.setColor(on ? '#ff0000' : '#330000');
});`}</Code>}
                            lua={<Code>{`local part = script.Parent
local on = false

while true do
    task.wait(0.5)
    on = not on
    part.Color = on and Color3.fromRGB(255, 0, 0)
                     or Color3.fromRGB(51, 0, 0)
end`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-button-door',
                title: 'S8. Кнопка по E и дверь',
                body: (
                    <>
                        <p><b>Взаимодействие по клавише E</b>:</p>
                        <ScriptKind kind="object" on="кнопку / рычаг / сундук" />
                        <LangTabs
                            js={<Code>{`game.self.onInteract(() => {
  game.ui.showText('Открыто!', 2);
  game.broadcast('open-door');
}, { text: 'Открыть', key: 'e', distance: 4 });`}</Code>}
                            lua={<Code>{`local part = script.Parent

local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Открыть"
prompt.MaxActivationDistance = 4
prompt.KeyboardKeyCode = Enum.KeyCode.E
prompt.Parent = part

-- BindableEvent для оповещения "open-door"
local doorEvent = workspace:FindFirstChild("DoorOpenEvent")
    or Instance.new("BindableEvent", workspace)
doorEvent.Name = "DoorOpenEvent"

prompt.Triggered:Connect(function(player)
    print("Открыто!")
    doorEvent:Fire()
end)`}</Code>}
                        />
                        <p>На двери:</p>
                        <ScriptKind kind="object" on="дверь" />
                        <LangTabs
                            js={<Code>{`const closed = game.self.position;
game.onMessage('open-door', () => {
  game.tween(game.self.ref, { y: closed.y + 4 },
    { duration: 1, easing: 'ease' });
  game.self.setCollide(false);
});`}</Code>}
                            lua={<Code>{`local TweenService = game:GetService("TweenService")
local door = script.Parent
local closedPos = door.Position

local doorEvent = workspace:WaitForChild("DoorOpenEvent")

doorEvent.Event:Connect(function()
    local goal = { Position = closedPos + Vector3.new(0, 4, 0) }
    TweenService:Create(door, TweenInfo.new(1), goal):Play()
    door.CanCollide = false
end)`}</Code>}
                        />
                        <Note>
                            <code>holdDuration: 1</code> в onInteract / <code>prompt.HoldDuration = 1</code>
                            в Roblox — держать E одну секунду.
                        </Note>
                    </>
                ),
            },
            {
                id: 'recipes-gui-timer',
                title: 'S9. HUD надписи, таймер, кнопки',
                body: (
                    <>
                        <p><b>HUD-надписи</b>:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`game.ui.score = 0;             // счётчик в углу
game.ui.score = 50;
game.ui.timer = 60;            // таймер
game.ui.showText('Старт!', 2);
game.ui.set('hp', 'Жизни: 3', { x: 50, y: 90, color: '#fff' });
game.ui.remove('hp');`}</Code>}
                            lua={<Code>{`-- В Roblox HUD = leaderstats папка (см. G7) или свой ScreenGui
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local gui = player:WaitForChild("PlayerGui")

-- Своя метка по центру
local screen = Instance.new("ScreenGui", gui)
local label = Instance.new("TextLabel", screen)
label.Size = UDim2.new(0.4, 0, 0.1, 0)
label.Position = UDim2.new(0.3, 0, 0.4, 0)
label.Text = "Старт!"
label.TextScaled = true
label.BackgroundTransparency = 0.5

task.delay(2, function() screen:Destroy() end)`}</Code>}
                        />
                        <p><b>Обратный отсчёт</b>:</p>
                        <LangTabs
                            js={<Code>{`let time = 30;
game.ui.timer = time;
const id = game.every(1, () => {
  time = time - 1;
  game.ui.timer = time;
  if (time <= 0) {
    game.cancel(id);
    game.ui.showText('Время вышло!', 3);
    game.player.kill();
  }
});`}</Code>}
                            lua={<Code>{`local time = 30

while time > 0 do
    task.wait(1)
    time = time - 1
    print("Осталось: " .. time)
end

print("Время вышло!")
-- Убить локального игрока
local player = game:GetService("Players").LocalPlayer
if player.Character and player.Character:FindFirstChild("Humanoid") then
    player.Character.Humanoid.Health = 0
end`}</Code>}
                        />
                        <p><b>Кнопка GUI</b>:</p>
                        <LangTabs
                            js={<Code>{`const btn = game.gui.create('button', {
  name: 'start', text: 'НАЧАТЬ', x: 50, y: 80,
  w: 20, h: 8, bg: '#3a6ee0', color: '#fff'
});
game.gui.onClick(btn, () => {
  game.ui.showText('Поехали!', 2);
  game.gui.hide(btn);
});`}</Code>}
                            lua={<Code>{`local player = game:GetService("Players").LocalPlayer
local gui = player:WaitForChild("PlayerGui")
local screen = Instance.new("ScreenGui", gui)

local btn = Instance.new("TextButton", screen)
btn.Size = UDim2.new(0.2, 0, 0.08, 0)
btn.Position = UDim2.new(0.4, 0, 0.8, 0)
btn.Text = "НАЧАТЬ"
btn.BackgroundColor3 = Color3.fromRGB(58, 110, 224)
btn.TextColor3 = Color3.new(1, 1, 1)

btn.MouseButton1Click:Connect(function()
    print("Поехали!")
    btn.Visible = false
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-spawn-fall',
                title: 'S10. Спавн, падение, проверка падения вниз',
                body: (
                    <>
                        <p><b>Спавнить объекты с неба</b> каждую секунду:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`game.every(1, () => {
  const x = game.random(-10, 10);
  game.scene.spawn('sphere', {
    x: x, y: 20, z: 0,
    color: '#ffd700', material: 'neon',
    anchored: false,
    lifetime: 8
  });
});`}</Code>}
                            lua={<Code>{`local Debris = game:GetService("Debris")

while true do
    task.wait(1)
    local x = math.random(-10, 10)

    local ball = Instance.new("Part")
    ball.Shape = Enum.PartType.Ball
    ball.Size = Vector3.new(1, 1, 1)
    ball.Position = Vector3.new(x, 20, 0)
    ball.Color = Color3.fromRGB(255, 215, 0)
    ball.Material = Enum.Material.Neon
    ball.Anchored = false   -- падает
    ball.Parent = workspace

    Debris:AddItem(ball, 8)  -- удалить через 8 сек
end`}</Code>}
                        />
                        <p><b>Игрок упал вниз</b>:</p>
                        <LangTabs
                            js={<Code>{`game.onTick(() => {
  if (game.player.position.y < -10) {
    game.player.respawn();
    game.ui.showText('Упал!', 2);
  }
});`}</Code>}
                            lua={<Code>{`local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

RunService.Heartbeat:Connect(function()
    local player = Players.LocalPlayer
    if not player.Character then return end
    local hrp = player.Character:FindFirstChild("HumanoidRootPart")
    if hrp and hrp.Position.Y < -10 then
        player:LoadCharacter()    -- респавн
        print("Упал!")
    end
end)`}</Code>}
                        />
                        <p><b>Финиш</b>:</p>
                        <ScriptKind kind="object" on="финишную плиту" />
                        <LangTabs
                            js={<Code>{`game.self.onTouch(() => {
  game.ui.showText('ПОБЕДА!', 4);
  game.sound.play('win');
  game.player.setInputBlocked(true);
});`}</Code>}
                            lua={<Code>{`local part = script.Parent

part.Touched:Connect(function(hit)
    local h = hit.Parent:FindFirstChild("Humanoid")
    if not h then return end
    print("ПОБЕДА!")
    h.WalkSpeed = 0     -- заморозить
    h.JumpPower = 0
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-npc-enemy',
                title: 'S11. Враг, который идёт за игроком',
                body: (
                    <>
                        <p><b>NPC/враг</b>, преследующий игрока:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`const enemy = game.scene.spawnNpc('zombie', {
  x: 10, y: 0, z: 10,
  hp: 100, name: 'Зомби', speed: 3
});
enemy.follow('player');
enemy.say('Хочу тебя поймать!', 3);

enemy.onDeath(() => {
  game.ui.showText('Враг повержен!', 2);
});

// Урон когда близко
game.every(0.5, () => {
  const d = game.distance(enemy.position, game.player.position);
  if (d < 2) game.player.damage(10);
});`}</Code>}
                            lua={<Code>{`-- Враг должен быть Model с Humanoid и HumanoidRootPart в workspace.
-- Например workspace.Зомби.
local Players = game:GetService("Players")
local enemy = workspace:WaitForChild("Зомби")
local humanoid = enemy:WaitForChild("Humanoid")
local hrp = enemy:WaitForChild("HumanoidRootPart")

-- Преследование игрока
task.spawn(function()
    while enemy.Parent and humanoid.Health > 0 do
        local player = Players:GetPlayers()[1]
        if player and player.Character then
            local target = player.Character:FindFirstChild("HumanoidRootPart")
            if target then
                humanoid:MoveTo(target.Position)
            end
        end
        task.wait(0.5)
    end
end)

humanoid.Died:Connect(function()
    print("Враг повержен!")
end)

-- Урон когда близко
task.spawn(function()
    while enemy.Parent and humanoid.Health > 0 do
        task.wait(0.5)
        local player = Players:GetPlayers()[1]
        if player and player.Character then
            local target = player.Character:FindFirstChild("HumanoidRootPart")
            local playerHum = player.Character:FindFirstChild("Humanoid")
            if target and playerHum then
                local dist = (target.Position - hrp.Position).Magnitude
                if dist < 2 then
                    playerHum:TakeDamage(10)
                end
            end
        end
    end
end)`}</Code>}
                        />
                    </>
                ),
            },
            {
                id: 'recipes-save',
                title: 'S12. Сохранение прогресса и лидерборд',
                body: (
                    <>
                        <p><b>Лидерборд</b>:</p>
                        <ScriptKind kind="global" />
                        <LangTabs
                            js={<Code>{`game.leaderstats.define('Монеты', { initial: 0 });
game.leaderstats.me.add('Монеты', 1);`}</Code>}
                            lua={<Code>{`-- leaderstats: см. G7
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
    local stats = Instance.new("Folder", player)
    stats.Name = "leaderstats"
    local coins = Instance.new("IntValue", stats)
    coins.Name = "Монеты"
    coins.Value = 0
end)

-- Прибавить монетку (например, при сборе)
local function addCoin(player, amount)
    local stats = player:FindFirstChild("leaderstats")
    if stats then
        stats.Монеты.Value = stats.Монеты.Value + amount
    end
end`}</Code>}
                        />
                        <p><b>Сохранение между сессиями</b>:</p>
                        <LangTabs
                            js={<Code>{`game.save.merge('progress', {
  patch: { level: 3 },
  increment: { coins: 10 },
  max: { bestScore: 5000 }
});

game.save.get('progress', (data) => {
  if (data) {
    game.ui.showText('С возвращением! Уровень ' + data.level, 3);
  }
});`}</Code>}
                            lua={<Code>{`-- В Roblox сохранение через DataStoreService (требует онлайн-игру)
local DataStoreService = game:GetService("DataStoreService")
local progress = DataStoreService:GetDataStore("Progress")
local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    -- Прочитать при входе
    local success, data = pcall(function()
        return progress:GetAsync(player.UserId)
    end)
    if success and data then
        print("С возвращением! Уровень " .. (data.level or 1))
        -- Применить прогресс: leaderstats.Монеты.Value = data.coins и т.п.
    end
end)

Players.PlayerRemoving:Connect(function(player)
    -- Сохранить при выходе
    local data = {
        level = 3,
        coins = 10,
        bestScore = 5000,
    }
    pcall(function()
        progress:SetAsync(player.UserId, data)
    end)
end)`}</Code>}
                        />
                        <Try>
                            Собери всё вместе: монетки добавляются в leaderstats →
                            глобальный скрипт раз в N монет вызывает save.merge
                            или DataStore:SetAsync. Получится игра с прогрессом.
                        </Try>
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ — СОВМЕСТНОЕ РЕДАКТИРОВАНИЕ (Team Create)
    // ════════════════════════════════════════════════════
    {
        id: 'collab',
        icon: 'users',
        title: 'Вместе с друзьями',
        summary: 'Совместное редактирование игры в реальном времени: приглашай друзей, стройте сцену вдвоём, видьте курсоры и правки друг друга.',
        sections: [
            {
                id: 'collab-what',
                title: 'V1. Что такое совместное редактирование',
                body: (
                    <>
                        <p>
                            <b>Совместное редактирование (Team Create)</b> — это когда
                            одну игру в студии редактируют <b>несколько человек
                            одновременно</b>. Ты строишь дом, друг в это же время
                            ставит деревья — и каждый видит правки другого
                            <b> вживую</b>, без перезагрузки страницы.
                        </p>
                        <p>Что синхронизируется в реальном времени:</p>
                        <ul>
                            <li><b>Блоки</b> — поставил/удалил блок, друг сразу видит;</li>
                            <li><b>Примитивы</b> — добавил, подвинул, повернул, изменил
                                цвет или размер;</li>
                            <li><b>Модели</b> — добавил из Тулбокса или удалил;</li>
                            <li><b>Курсоры друзей</b> — где сейчас «мышка» каждого
                                соавтора (цветная точка с ником);</li>
                            <li><b>Кто онлайн</b> — список соавторов с цветными
                                аватарками вверху сцены.</li>
                        </ul>
                        <Shot src="collab-scene.png" wide
                              caption="Сцена при совместном редактировании: вверху — кто онлайн (аватарки «У» и «М», всего 2), на сцене — курсор соавтора «УтреннийРозмарин4633» (оранжевая точка с ником) и блок, который он только что поставил." />
                        <Note>
                            Это как Google Документы, только для 3D-игр. Удобно делать
                            игру в команде, помогать ученику или показывать, как что
                            устроено — прямо в его проекте.
                        </Note>
                    </>
                ),
            },
            {
                id: 'collab-invite',
                title: 'V2. Как пригласить друга',
                body: (
                    <>
                        <p>
                            Открой свою игру в студии и перейди на вкладку
                            <kbd className="kbd">Игра</kbd> в верхней панели. Там, в
                            группе <b>«Вместе»</b>, есть кнопка
                            <kbd className="kbd">Пригласить</kbd>.
                        </p>
                        <Shot src="collab-button.png" wide
                              caption="Вкладка «Игра» → группа «Вместе» → кнопка «Пригласить». Когда соавторы подключатся, на ней появится счётчик «Вместе (2)»." />
                        <Step n={1}>
                            Нажми <kbd className="kbd">Пригласить</kbd> — ссылка-приглашение
                            автоматически скопируется в буфер обмена (появится
                            уведомление).
                        </Step>
                        <Step n={2}>
                            Отправь эту ссылку другу (в чат, мессенджер — как угодно).
                        </Step>
                        <Step n={3}>
                            Друг открывает ссылку — и попадает в <b>ту же сцену</b>.
                            Теперь вы редактируете вместе. На кнопке появится счётчик:
                            <b> «Вместе (2)»</b>.
                        </Step>
                        <Note>
                            Приглашать может только <b>автор игры</b>. Ссылка действует
                            24 часа. Друг должен быть зарегистрирован на Рублоксе и
                            войти в свой аккаунт.
                        </Note>
                    </>
                ),
            },
            {
                id: 'collab-how',
                title: 'V3. Как это работает и правила',
                body: (
                    <>
                        <p>
                            <b>Блокировка объекта.</b> Пока один соавтор выделил объект
                            и двигает его — этот объект <b>заблокирован</b> для других
                            (никто другой не сможет его двигать одновременно). Так
                            правки не конфликтуют. Как только выделение снято — объект
                            снова свободен.
                        </p>
                        <p>
                            <b>Кто сохраняет.</b> Игру в базу сохраняет <b>автор</b>
                            (владелец проекта). Приглашённые друзья видят пометку
                            «Совместное редактирование» вместо кнопок Сохранить и
                            Опубликовать — это правильно: они помогают строить, а
                            управляет игрой автор.
                        </p>
                        <p>
                            <b>Цвета.</b> У каждого соавтора свой цвет — им подсвечены
                            его курсор и аватарка, чтобы было понятно, кто что делает.
                        </p>
                        <Note>
                            Если друг ненадолго потерял связь (вылетел интернет) — у
                            него есть несколько секунд, чтобы переподключиться и
                            продолжить с того же места.
                        </Note>
                        <p>
                            <b>Совет:</b> договоритесь заранее, кто какую часть карты
                            делает (например, один — здания, другой — ландшафт и
                            декор) — так работать вместе быстрее и без накладок.
                        </p>
                    </>
                ),
            },
        ],
    },

    // ════════════════════════════════════════════════════
    // РАЗДЕЛ — КОНТЕКСТ ДЛЯ НЕЙРОНКИ (AI)
    // ════════════════════════════════════════════════════
    {
        id: 'ai-context',
        icon: 'lightbulb',
        title: 'Контекст для нейронки',
        summary: 'Готовый текст со всем API скриптов Рублокса. Скопируй его целиком, вставь в ChatGPT/нейросеть — и она будет писать тебе рабочие скрипты под твою задачу.',
        sections: [
            {
                id: 'ai-howto',
                title: 'AI1. Как писать скрипты с нейросетью',
                body: (
                    <>
                        <p>
                            Хочешь, чтобы скрипт написала <b>нейросеть</b> (ChatGPT,
                            DeepSeek, Claude и т.п.)? Проблема в том, что нейросеть <b>не
                            знает</b> устройство Рублокса — придумает несуществующие
                            команды. Решение простое:
                        </p>
                        <Step n={1}>
                            Открой статью <b>«AI2. Контекст — скопируй в нейросеть»</b> ниже.
                        </Step>
                        <Step n={2}>
                            <b>Выдели и скопируй весь текст</b> из серого блока (он
                            описывает все команды Рублокса).
                        </Step>
                        <Step n={3}>
                            Вставь его в нейросеть <b>первым сообщением</b>. Затем добавь
                            свою задачу, например: «Напиши скрипт: при касании синего куба
                            игрок прыгает высоко и играет звук».
                        </Step>
                        <Step n={4}>
                            Нейросеть выдаст готовый код. Скопируй его в скрипт в студии
                            (глобальный или на объекте — она подскажет куда).
                        </Step>
                        <Note>
                            Если нейросеть всё равно ошиблась в команде — скинь ей текст
                            ошибки из «Консоли» студии, она исправит. И всегда проверяй
                            результат запуском игры.
                        </Note>
                    </>
                ),
            },
            {
                id: 'ai-context-text',
                title: 'AI2. Контекст — скопируй в нейросеть',
                body: (
                    <>
                        <p>
                            <b>Выдели весь текст ниже и скопируй</b> (Ctrl+A внутри блока
                            или мышью), затем вставь в нейросеть перед своим вопросом:
                        </p>
                        <Code>{AI_CONTEXT}</Code>
                    </>
                ),
            },
        ],
    },
];


