Skip to main content

xgaida-x-nixi-animation

Скелетная анимация Guildmaster: риг из трансформов (точки вращения, кости, хват предмета), авторинг клипов через риг-API (Bend от покоя, Aim в мировой угол, Arc для направления дуги), профиль-замер рига, валидатор клипов, контактные листы и probe-разметка, миграция имён узлов. Зови на любую задачу про клипы, позы, повороты частей тела, оружие в руке, маски слоёв, аватар и всё под Prefabs/Bones и EditorTools/AnimationLab. НЕ применять к: боевому времени и hitstop (combat-sim), визуальным эффектам удара (gamefeel-vfx), «глаголам движения» на корне юнита (это код LitMotion, gamefeel-vfx), тех-доке об анимации (tech-scribe).

Jump to install

Source facts

Repository
Kaliguri/Guildmaster-Autobattler
Last source activity
August 7, 2026 at 10:28
Detected SKILL.md language
Russian
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
xgaida-x-nixi-animation
description
Скелетная анимация Guildmaster: риг из трансформов (точки вращения, кости, хват предмета), авторинг клипов через риг-API (Bend от покоя, Aim в мировой угол, Arc для направления дуги), профиль-замер рига, валидатор клипов, контактные листы и probe-разметка, миграция имён узлов. Зови на любую задачу про клипы, позы, повороты частей тела, оружие в руке, маски слоёв, аватар и всё под Prefabs/Bones и EditorTools/AnimationLab. НЕ применять к: боевому времени и hitstop (combat-sim), визуальным эффектам удара (gamefeel-vfx), «глаголам движения» на корне юнита (это код LitMotion, gamefeel-vfx), тех-доке об анимации (tech-scribe).
# Скелетная анимация — рабочий контур Guildmaster Этот скилл — процедура, а не справка. Он существует потому, что работа с поворотами уходила в костыли: углы клинка считались как «куда он должен смотреть в мире минус вклад плеча и локтя», в голове и каждый раз заново — и три захода подряд атаки выходили сломанными без единой строчки в консоли. **Роль на этом слое:** механика внутри клипа — моя (тайминги, кривые, дуги, оверлаппинг, чистка, проводка). Художественное решение — Макса: какие позы, какой характер, куда смотрит поза, где стоит точка хвата. Я не двигаю позы и не меняю вид персонажа без его слова; я меряю, показываю картинкой и предлагаю. ## Карта инструментов Всё под `Assets/_Project/Scripts/EditorTools/AnimationLab/` (asmdef `Guildmaster.AnimationLab.Editor`, editor-only). | Что | Где | |---|---| | Профиль-замер рига: id сустава → путь, поза покоя, ось и длина кости, знак сгиба, лимит, калибровка предмета | `Rig/RigProfile.cs` (+ `RigProfileBuilder`) | | Авторинг клипов: `Bend`, `Set`, `Aim`, `Sweep`, `Move`, `Write` | `Rig/RigWriter.cs` | | Фильтр непрерывности для готовых кривых | `Rig/RigWriter.cs` → `RigEulerFilter` | | Проверка клипов против рига | `Rig/RigValidator.cs` | | Разметка рига картинкой (суставы, оси, хват, ноль предмета) | `Rig/RigProbe.cs` | | Зона удара картинкой и числами: путь клинка, фазы, перекрытие щитом; умеет составную позу (`Composition`) и надстройки (`Layers`) | `Rig/RigSweep.cs` | | Гизмо локомоции: путь подошв, линия земли, длина шага, доля опоры | `Rig/RigStride.cs` | | Темп локомоции в префаб вида (ед. земли за секунду) | `Rig/LocomotionStrideMeter.cs` | | Композиция слоёв: СТЕК масок в двух режимах (`Override` / `Additive`), как в Animator | `Rig/RigLayerBlend.cs` | | Рисование поверх рендера (общее для пробы и зоны) | `Rig/RigCanvas.cs` | | Переименование узлов с переносом всех путей | `Rig/RigMigrate.cs` | | Контактный лист и onion skin из клипа | `AnimationLabRenderer.cs` | | Пост-обработка кривых (оверлаппинг, тангенсы, чистка констант) | `AnimationLabProcessor.cs` | Меню — `Alebardium/Animation/…`: пересборка профиля (610), валидация клипов (620). Профиль рига: `Assets/_Project/Prefabs/Bones/BoneUnit_Standart_RigProfile.asset`. Журнал решений и замеров — `docs/skeletal-animation-progress.md`, канон дизайна — `docs/wiki/gdd/10-vision/character-animation.md`. ## Модель рига - **Кость — это трансформ.** Никаких пакетов: связка `Transform` + `SpriteRenderer` + `Animator` уже является скелеткой. Ничего не покупаем (см. `skeletal-animation-vector`). - **Точки вращения названы явно:** `Rotation Point (Shoulder / Elbow / Grip / Hip / Knee / Ankle)`. То, что в скобках, — логический id для API (плюс сторона: `elbow.R`, `knee.L`). - **Ноль имеет смысл только там, где его калибровали.** У меча: при нуле хвата клинок стоит под прямым углом к предплечью (замер 90.61°). У щита: при нуле верх щита вертикален (мировые 90°). Калибровочный оффсет живёт **в спрайтовом дочернем узле** (`Sword` = −89.39°, `Shield` = −24.76°), поэтому анимируемый узел остаётся чистым нулём. - **Стойка живёт в анимируемых узлах** (плечо 10°, предплечье 26.61°, бедро 22.12°) — решение Макса. Поэтому API работает **в дельтах от покоя**, а не в абсолютных углах. - **Два слоя движения:** риг намеренно скучный, узнаваемость даёт код на корне (LitMotion). Не вкладывать уникальность в клипы. ## Процедура: клип от постановки до сдачи 1. **Прочитать профиль**, а не префаб глазами. Если структура рига менялась — пересобрать профиль (`Alebardium/Animation/Rebuild Rig Profile`). Замеряемые поля обновятся, авторские (знак сгиба, лимиты) переживут пересборку. 2. **Писать клип через `RigWriter`**, а не через сырые кривые: `Bend("elbow.R", 40)` — от покоя, «плюс всегда сгибается»; `Aim("weapon", -140)` — мировой угол, цепочка вычитается сама; `Sweep("weapon", -25, Arc.Ccw)` — длинная дуга, направление явно. 3. **Прочитать отчёт `Write`.** Он предупреждает о том, что не легло: цель, которую клип не играет; сгиб за лимитом; засеянный ключ в нуле. 4. **Прогнать `RigValidator`** по папке клипов. Ошибка — чинить до показа; предупреждение `wrapped-arc` — подтвердить, что длинная дуга задумана. 5. **Посмотреть глазами:** `AnimationLabRenderer.RenderContactSheet` с `InBetweens = 1..2` (ровные интервалы врут — удар живёт в трёх кадрах) и `RigProbe` там, где вопрос про геометрию, а не про позу. 6. **Для атаки — прогнать `RigSweep`** ПЕРЕД доводкой клипа, а не после. Он отвечает на то, чего поза не показывает: где проходит клинок, сколько длится удар, где стоит контакт относительно него и какую долю тела реально закрывает щит. Три правила приёмки атаки: дуга широкая (размах — это линия, по которой потом рисуется слеш-трейл и свечение), дуга не идёт сквозь собственные ноги и землю, контакт стоит **внутри** быстрой фазы и на корпусной высоте цели (у этого рига полоса тела −0.07…0.19 по мировому Y). Удар меньше ~0.12 с на дугу в 200°+ размажет трейл в кольцо — растягивать, а не сужать. 6b. **Для локомоции — прогнать `RigStride`**, у неё свои три вопроса, и поза не отвечает ни на один. Длина шага — число, на которое показ делит скорость юнита (`_runUnitsPerSecond` / `_sprintUnitsPerSecond` в `UnitView`, пишет `LocomotionStrideMeter`): короткий шаг заставляет клип крутиться быстро, и юнит семенит. Подошва не должна уходить под линию земли. Опорная нога должна СТОЯТЬ, пока тело проходит над ней (доля опоры ~40-55% на ногу; меньше — юнит парит). Гизмо мерит **подошву спрайта, а не узел голеностопа**, и уровень земли берёт из позы покоя каждой ноги отдельно: ноги этого рига разной длины (правая голень 0.105 против 0.117), и по общей линии короткая читалась бы как вечно висящая в воздухе. 7. **Показать Максу ДВЕ картинки: кадры И ГИЗМО.** HARD, требование Макса от 29.07 — сдача правки клипа без гизмо не принимается. Контактный лист показывает позы, но не показывает ГЛАВНОГО: где на самом деле идёт клинок. Одна поза может выглядеть отлично и при этом вести дугу сквозь ноги, ронять контакт мимо корпусной полосы или рисовать эпициклоиду. Для локомоции гизмо — `RigStride` (путь подошв и земля), для удара — `RigSweep` (путь клинка) вместо круга — на листе этого не видно, на гизмо видно мгновенно. - **атака** — `RigSweep` обязателен (путь клинка, фазы, контакт, перекрытие щитом), и с 30.07 — по СОСТАВНОЙ позе: атака едет слоем, база под ней живёт своей жизнью. Судить надо обе боевые комбинации: удар с разбега поверх бега и обычный удар поверх стойки, обе — с гвардией; - **локомоция и позы** — `RigSweep` по клипу тоже: он показывает, что несомое оружие не пашет землю и не проходит сквозь тело; - если клип трогали больше одного раза — гизмо после КАЖДОГО прогона, а не в конце. Боевую приёмку в play-mode делает Макс. ## Форма удара — правила Макса (29.07), приняты после разбора гизмо Это про геймфил, а не про технику. Нарушение видно на гизмо мгновенно. - **Слеш — это два ключа.** Где дуга началась и где кончилась. Ключ ВНУТРИ дуги разбивает одно ускорение на два, ключ ПОСЛЕ удара перезапускает уже остановившийся клинок — оба читаются как лаг, а не как вес. Вес после удара живёт в паузе и в возврате в стойку. - **Доп. кадры не добавлять и в рекавери.** Прямой запрет Макса: разная скорость на этапах выглядит плохо. Возврат тоже два ключа; форма задаётся дугой и тангенсами, не промежуточной позой. - **Дуга должна быть круглой.** Круг получается тогда и только тогда, когда **угол между клинком и предплечьем постоянен**: рука с мечом работает как жёсткий рычаг, и кончик описывает окружность вокруг плеча. Как только кисть докручивает поверх руки, два вращения с разной скоростью дают эпициклоиду — на гизмо это «загогулина» с вмятиной у основания. Замер: разница клинок−рука плыла с +11° до −49°, радиус кончика рос на 30% за удар; после фиксации разницы (11°→6°) разброс 3%. - **Низкий финиш покупается корпусом, а не кистью.** Наклон опускает плечо, а вместе с ним весь круг. Доворот кисти на те же градусы ломает форму. Цена честности: жёсткий рычаг отдаёт ~40° дуги. - **Широкая дуга — цель, а не риск.** Размах — это линия, по которой потом рисуется слеш-трейл и свечение (SAO-переход). Узкий удар нечем украшать. - **Клинок, направленный в пол, — норма.** Для большого замаха снизу его специально опускают; «пашет землю» само по себе не дефект, дефект — когда сквозь ноги проходит вся дуга. - **Единый ритм у обычных атак, свой у разбега.** Сетка Макса: замах 0.25 → пауза до 0.333 → удар до 0.583 → пауза до 0.667 → возврат. `AttackCharge` живёт отдельно: удар 0.30 с, паузы по 8 кадров, дуга 293°, таз проваливается сквозь удар. ## Локомоция — правила и числа (30.07) - **Четыре позы на шаг, а не две:** contact → down → passing → up. Двухпозный цикл (contact + passing) и есть причина семенящего шага: расти шагу негде, кроме угла бедра, а таз обязан проседать НА контакте, где настоящий ещё падает. Таз внизу в `down`, вверху в `up`. - **Голеностопы анимируются.** Без переката (носок вверх на контакте, вниз на отталкивании) стопа — доска на шарнире колена, и это видно при любой длине шага. - **Длина шага — это ЧИСЛО, на которое показ делит скорость** (`_runUnitsPerSecond` / `_sprintUnitsPerSecond`). Короткий шаг вынуждает клип крутиться быстро, чтобы ноги не скользили, — отсюда мельтешение. Замеры 30.07: ходьба шаг 0.80 мировых при цикле 0.7 с (темп 2.27 ед/с), разбег 0.93 при 0.5 с (3.70). Это ~3.2 и ~3.6 шага в секунду на скорости Защитника. - **Своё число у каждого клипа локомоции.** Общее на бег и разбег гнало разбег в 1.8 раза быстрее земли. - **Числа пишет `LocomotionStrideMeter`, мерит `RigStride`** — один владелец. Правишь размах в рецепте — перегони замер, а не подкручивай поле руками. ## Слои: телеграф-поза и композиция (30.07) - **Надстройка скрабится СВОИМ окном, а не проигрывается.** Глобальный `animator.speed` принадлежит свингу и в замахе равен нулю: щит, поднимающийся «сам», в этот момент застыл бы. - **Телеграф — это «встать и подождать», а не «успеть к кадру».** Поза обязана быть в финале за 0.1–0.2 с ДО события (Макс, 30.07): подъём кончается раньше, остаток подводки — стоп-кадр. Линейный скраб на всё окно приводит позу к финалу ровно к событию, и жест читается как реакция, а не как предупреждение. - **Клип надстройки не возвращается в стойку.** Опускать руку — дело ВЕСА слоя; клип держит позу столько, сколько его держат. Возврат внутри клипа уводил щит раньше, чем кончался барьер. - **Композицию судить композицией.** Игра не играет один клип: щит встаёт поверх бега, свинга, разбега. И контактный лист, и `RigSweep` берут стек через `RigLayerBlend` (`Composition` — «этот клип едет слоем на движущемся теле», `Layers` — «а это лежит поверх»), кадрирование считается по составной позе. Сэмплировать два клипа подряд НЕЛЬЗЯ — второй перезаписывает риг вместе с маской. - **Маска щита — только рука со щитом**, поэтому база (ноги, торс) продолжает своё. ## Атака живёт СЛОЕМ, а не стейтом базы (30.07) Переезд случился потому, что удар с разбега физически едет вперёд весь замах (сим снял рут, см. `CanCloseIntoReach`): свинг, владеющий всем телом, вёз бы юнита на неподвижных ногах. | Слой | Режим | Маска | Что держит | |---|---|---|---| | Base | — | всё тело | локомоция, стан, смерть — всё, что владеет НОГАМИ | | `Action` | Override | `Mask_Action` (руки + торс + голова, 19 из 34 узлов) | свинг: атаки и будущие касты | | `ActionHips` | Additive | `Mask_Hips` (только `Hips`) | просадку таза ДЕЛЬТОЙ поверх bob'а базы | | `Block` | Override | `Mask_ShieldArm` | гвардию, и лежит ВЫШЕ удара | - **Каст — не отдельный слой.** Атака и каст никогда не идут одновременно: `IsCastBusy` не пускает новый замах, а занесённый замах каст доигрывает. Верх тела занимает ровно одно ДЕЙСТВИЕ, поэтому слой один. Второй был бы копией, которая всю жизнь простаивает (решение Макса, 30.07). - **Порядок решает спор масок.** `Mask_Action` и `Mask_ShieldArm` обе держат левую руку. `Block` выше — и это измеримо: без гвардии перекрытие тела щитом на контакте 9%, с гвардией 51%. - **Таз — Additive, и это снимает выбор.** Override заставил бы выбирать: маска без таза роняет вес удара (он держится на просадке), маска с тазом роняет bob бега. Аддитив складывает. Замер на живом риге: таз бега 0.038, с аддитивным слоем 0.001, дельта −0.037 — ровно дельта клипа; Override дал бы абсолютные −0.022 и стёр бы bob. - **Дельта считается от ПЕРВОГО КАДРА клипа**, а не от позы покоя рига — так её берёт Animator. У `AttackCharge` нулевой кадр это поза бега, и отсчёт обязан идти от неё. - **База выбирается по тому, чем юнит занят НОГАМИ:** локомоция, если сим его везёт, и тот же клип действия, если он стоит. Решается на входе в свинг и до конца свинга не меняется. Так стоячий удар сохраняет свой выпад, а едущий получает бегущие ноги. - **Покадровым это не грозит:** слоёв у них нет, они деградируют на прежнее поведение — как уже деградирует гвардия. ### Что теперь можно судить соло, а что нельзя (замер 30.07) Композиция меняет не всё, и знать это полезно, чтобы не гонять лишние рендеры: - **Дугу клинка можно смотреть и по одному клипу.** Рука целиком на слое, бег ей не мешает: путь кончика 4.369 соло против 4.416 в композиции, разворот те же 536°. - **Позу, ноги и щит — только композицией.** Путь кончика ЩИТА за тот же удар: 0.253 соло против 0.435 в композиции — почти вдвое. Он висит на левой руке, но качается вместе с тазом и корпусом. ## Гизмо предметов — что мерить (30.07) - **Зона строится по ПЛОЩАДИ спрайта, а не по отрезку «рукоять-кончик».** Для клинка разница мала, для щита принципиальна: он плоскость, и вопрос к нему — сколько он закрывает. Отрезок рисовал веер, который не отвечал ни на что (поймал Макс). - **Углы берутся через трансформ узла**, а не из мирового AABB рендерера: AABB даёт прямоугольник по осям экрана и врёт ровно в наклоне, ради которого гизмо и рисуется. - **В кадре обязан быть второй предмет** (контуром): блок судят, видя, где меч, удар — видя, где щит. - **Перекрытие тела — число, а не впечатление.** Поза «щит поднят» с перекрытием 6-10% не блок; после правки локтя (он РАЗГИБАЛСЯ, и прямая рука уводила щит от тела) стало 51%. ## Направление вращения — пять ловушек, все замерены Это самый дорогой класс ошибок на этом слое: Макс поймал пять подряд. Перед любой работой с углами прочитать таблицу целиком. | Ловушка | Правило | |---|---| | Дуга в локальных углах | `Arc` задаётся для **мировой** дуги предмета, не для локального угла хвата: автор видит клинок, а не кисть. | | Абсолютный расчёт | Целевой локальный угол считать **в дельтах** (сколько мира нужно минус сколько даёт цепочка). Эквивалент ±360k «совпадает» по позе, но кисть проворачивается целиком. | | `DeltaAngle` для пути | Вклад цепочки — это **пройденный путь**, интеграл по кадрам. `DeltaAngle` складывает всё больше 180° в диапазон: −194° читается как +166°, и предмет докручивает фантомные 360°. | | Короткий путь ≠ верный | У сустава сторона задаётся явно, когда путь близок к 180°: от 168° до −26° короткий путь +166° уводит руку назад над головой, нужный −194°. | | Значение без анатомии | Шарнир (локоть, колено) гнётся в одну сторону. Числа из чужих клипов проверять на переразгиб, отсчёт **от позы покоя рига**, а не от нуля. | Проверки, которые это ловят автоматически: `long-way-round`, `hinge-inverted`, `swing-stutter`, самопроверка аимов в `RigWriter.Write` (порог 8° — меньше даёт шум от оверлаппинга). ## HARD-правила - **Углы пишутся непрерывным рядом и не нормализуются.** Значения вне ±180 (357, −420) — законны: именно они несут дугу. Нормализовать = схлопнуть замах. - **Кривая пишется целиком.** Отсутствующую ось Unity дописывает нулём, а не оставляет как было: `localEulerAnglesRaw` — все три оси, `m_LocalPosition` — все три. - **Один тип rotation-биндингов на клип.** У нас везде `localEulerAnglesRaw` (режим Unity «Euler Angles», держит полный диапазон). Кватернионные кривые срезают дугу по короткому пути и больше 180° не умеют — не смешивать. - **ОРУЖИЕ НЕ КРУТИТСЯ САМО — ни хватом, ни своим трансформом (HARD, 07.08.2026).** Узлы `Weapon_R` / `Weapon_L` не анимируются вовсе: поворот клинка живёт на КИСТИ, и меч следует за ней, потому что держат его жёстко. Держит тест `WeaponFollowsTheHandTests` — клип с кривой на узле предмета роняет прогон. <br>Прежняя формулировка звучала «предмет крутится своим хватом», и девять клипов честно крутили хват — то есть заводили ВТОРОГО владельца ориентации оружия. Расплата пришла оттуда, где не ждали: дуга за клинком строится от плеча к острию, «где остриё» стало зависеть от двух независимых поворотов, и след лёг мимо меча. Требование Макса дословно: «надо поставить клинок в одно положение с рукой вдоль одной прямой и ЗАПРЕТИТЬ крутить оружие без руки... И чтобы на анимации любой это тоже НЕ сломалось. Всегда соблюдалось.» <br>Следствие для постановки: поворачивая кисть, ты поворачиваешь и меч — это и есть задуманное поведение, а не побочный эффект. - **Куда смотрит оружие — говорит РИСУНОК, а не число.** Длина вылета объявляется на `UnitHeldItem` (величина игровая, перерисовка арта не должна её двигать), направление всегда берётся с меша рабочей части. Числом направление объявлялось до 07.08.2026 и разошлось с картинкой на 33°. - **Узлы рига переименовываются только через `RigMigrate`.** Иначе молча рвутся пути в клипах, записи масок и аватар — ни одной ошибки в консоли. - **`Cw` / `Ccw` заданы для нефлипнутого facing** (юнит смотрит вправо). Разворот идёт через `scale.x = −1` на facing-root, а зеркальный трансформ обращает видимое направление вращения. Авторить для неотражённой стороны. - **Сохранять точечно** (`AssetDatabase.SaveAssetIfDirty`), не `SaveAssets` — он уносит чужие несохранённые правки. Перед правкой префаба проверять открытую prefab-stage. - **Правки Макса в окне Animation живут в памяти редактора.** На диске их нет, `git status` чист, а рецепт при следующем прогоне их сотрёт. Порядок: проверить `EditorUtility.IsDirty` по клипам → сохранить → закоммитить его правки ОТДЕЛЬНЫМ коммитом → перенести их в рецепты → только потом править. Рецепт и клип с разными значениями — это два владельца одного факта, то есть дефект. - **Не гнать рецепт до перекомпиляции.** После правки `.cs` сначала `refresh_unity`, потом вызов: иначе выполнится старая версия метода и запишет старые числа (ловилось на маркере события). - **Не менять позы и вид персонажа без слова Макса.** Мера, картинка, предложение — да; тихая правка стойки — нет. ## Готчи, каждая куплена заходом - **Кривая держит первый ключ назад во времени.** Одинокий ключ на 0.8 с сгибает сустав с нулевого кадра. `RigWriter` засевает покой в t=0 сам; при ручной работе — помнить. - **Цель нельзя решать в момент вызова.** Более поздний `Bend` выше по цепочке уводит клинок (замер: 40° на локте сдвинули цель на 25°). Аимы решаются в конце, когда поза готова. Засев покоя тоже идёт **до** решения аимов — иначе своя же ошибка на 40°. - **Euler filter не восстанавливает намерение.** Как только 297.8 нормализовали в −62.2, длинная дуга потеряна навсегда — её надо переавторить через `Arc`. Фильтр лечит только разрывы (170 → −170 = 340° назад вместо 20° вперёд). - **Хват — не конец кости.** Он точка крепления внутри кисти и на этом риге стоит в пивоте предплечья: считать его следующим суставом дало «длину локтевой кости» 0.0024. - **Маски и аватар молчат.** `AvatarMask` без валидного аватара на generic-риге не работает без единого предупреждения; аватар описывает иерархию, поэтому переименование его инвалидирует. `CopySerialized` переносит и имя — возвращать руками. С четырьмя слоями вместо одного цена случайного переименования выросла: только через `RigMigrate`, без исключений. - **Синхронизированный слой НЕ наследует клипы источника.** Он молча играет пустоту: первый замер аддитивного таза дал дельту ровно 0.000 при внешне правильной раскладке. Каждому стейту источника нужен явный `AnimatorControllerLayer.SetOverrideMotion`. - **`RigLayerBlend.Sample` начинается с сэмпла базы**, поэтому доложить слои поверх уже собранной композиции им нельзя — сотрёт её целиком и молча съест слой. Для этого есть `Fold`. - **Переименование маски guid не рвёт.** `AssetDatabase.RenameAsset` сохраняет guid, ссылка из контроллера остаётся живой (`Mask_Arms` → `Mask_Action` пережила это без правки контроллера). - **`execute_code` может отработать, а ответ потерять.** Несколько правок контроллера отдали «Timeout receiving Unity response», хотя применились. Перед повтором — ПРОВЕРИТЬ состояние, иначе сделаешь работу дважды. - **Одинаковый угол ≠ одинаковое число.** Одна поза лежит и как −16.34, и как 343.66: сравнивать только через `Mathf.DeltaAngle`. - **Ровный контактный лист врёт.** Удар занимает 3 кадра, ровная сетка шагает через него, а длинный возврат получает большинство ячеек — сэмплить ключи плюс промежуточные. - **`execute_code` исполняет тело метода:** `using` нельзя, писать полные имена; `Object` неоднозначен — только `UnityEngine.Object`. `AssetDatabase.DeleteAsset` требует `safety_checks: false`.
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub