Start typing to search packages!
smartmotion
By @alqw
Roblox
MirroredSmartMotion
Root motion + bone-driven animation system для Roblox. Решает проблему скинд-меш ригов (Mixamo и подобных), где стандартный Animator не двигает кости, плюс даёт честный root motion без двойного счёта.
TL;DR: позволяет анимациям визуально работать как в Animation Editor preview (включая сальто, стойки на руках, body twists) И при этом физически двигать персонажа по миру (как root motion в Unity / Unreal). Коллизия следует за телом.
Установка
Через Wally — добавь в wally.toml своего проекта:
[dependencies]
SmartMotion = "alqw/smartmotion@0.1.0"
wally install
Пакет окажется в ReplicatedStorage.Packages.SmartMotion:
local SmartMotion = require(ReplicatedStorage.Packages.SmartMotion)
Полный гайд по интеграции в реальную игру (server + client + RemoteEvent) — docs/TUTORIAL.md.
Зачем это нужно
Проблема 1: Стандартный Animator + скинд-меш = тело не анимируется
При импорте Mixamo character как skinned mesh:
HumanoidRootPart=MeshPart(всё тело — один skinned mesh)- Иерархия
Boneинстансов внутри MeshPart
Когда Animator:LoadAnimation(anim):Play():
- ✓ Track запускается,
IsPlaying = true - ✗
Bone.Transformостаётся identity — animator не записывает в bones - ✗
Track.TimePositionостаётся 0 - ✗ Тело визуально не двигается
SmartMotion обходит: BoneDrive mode читает pose data из KeyframeSequence
сам и каждый кадр устанавливает Bone.Transform вручную.
Проблема 2: Root motion в Roblox из коробки нет
Анимации Roblox это "in-place" — двигают кости относительно HRP, но сам HRP не двигается. Чтобы character физически перемещался — нужен отдельный механизм.
SmartMotion обходит: RootMotion mode запекает позиционные смещения
mixamorig:Hips в маркеры (Keyframe с именами SM;x,y,z,...), и runtime
каждый кадр выставляет HRP.CFrame согласно интерполированному маркеру.
Проблема 3: Двойной счёт при комбинации BoneDrive + RootMotion
Если оба активны одновременно:
- BoneDrive: Hips bone Transform = pose (lift +5.6 Y)
- RootMotion: HRP CFrame += pose (lift +5.6 Y)
- Визуально Hips world = HRP + bone = +11.2 Y (DOUBLE)
SmartMotion обходит: RootBone setting в BoneDrive — для указанной кости
применяется только rotation (translation handled by HRP RootMotion).
Default "mixamorig:Hips" для Mixamo.
Проблема 4: Bone.Transform не реплицируется server→client
Если запустить BoneDrive на сервере — клиенты видят T-pose.
SmartMotion обходит: BoneDrive обязан запускаться в LocalScript. HRP motion наоборот — на сервере (CFrame реплицируется server→client).
Проблема 5: HRP.CFrame не реплицируется client→server для NPC
Если двигать HRP NPC из клиента — сервер не примет (server-owned).
SmartMotion обходит: с AnchorRoot = true сервер анкорит HRP, что
bypass'ит network ownership — все клиенты получают CFrame обновления.
Архитектура
┌──────────────────────────────────┐ ┌──────────────────────────────────┐
│ CLIENT │ │ SERVER │
│ StarterPlayerScripts.LocalScript│ │ ServerScriptService. │
│ │ │ SmartMotionRunner │
│ • Ловит ввод (E) │ RemoteEvent │ │
│ • Шлёт сигнал серверу │ ──FireServer(mode)─> │ • Принимает сигнал │
│ │ │ • Запускает HRP root motion │
│ │ <─FireAllClients()── │ • Шлёт "start"/"stop" клиентам │
│ • На "start": BoneDrive │ │ │
│ запускает кости локально │ │ Mode = "RootMotion" │
│ Skipping Hips translation │ │ AnchorRoot = true │
│ (keeps Hips rotation) │ │ RotationMode = "None" │
│ │ │ │
│ Mode = "BoneDrive" │ │ │
│ RootBone = "mixamorig:Hips" │ │ │
└──────────────────────────────────┘ └──────────────────────────────────┘
│ │
│ Bone.Transform │ HumanoidRootPart.CFrame
│ (локально, не реплицируется) │ (реплицируется server→client)
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ observer (NPC Model) │
│ │
│ HumanoidRootPart [MeshPart] ←── server двигает CFrame │
│ └─ mixamorig:Hips [Bone] ←── client держит at identity │
│ translation (но крутит rot) │
│ └─ mixamorig:Spine [Bone] │
│ └─ ... 54 костей ←── каждый клиент крутит │
│ Bone.Transform у себя │
└─────────────────────────────────────────────────────────────────┘
Почему такой split
Математически эквивалентны два подхода:
| Подход | Bones | HRP | Visual | Collision |
|---|---|---|---|---|
| A (used) | rotation only at root | translates per bake | identical to Anim Editor | follows body |
| B | full pose | static | identical to Anim Editor | stays at start |
Оба дают тот же визуал (доказывается компонентным разложением CFrame). Подход A выбран потому что коллизия HRP следует за телом — важно для прыжков, лазания, чтобы capsule оказалась там же где body визуально.
Файлы
Структура репозитория:
| Путь в репо | Назначение |
|---|---|
src/init.luau | ModuleScript SmartMotion — public API (façade) |
src/Player.luau | Motion loops: RootMotion + BoneDrive |
src/RigAdapter.luau | Абстракция над ригами (R15 / R6 / Mixamo / custom) |
src/MarkerCodec.luau | Encode/decode маркеров root motion |
examples/server/SmartMotionRunner.server.luau | Пример: server HRP motion + warmup |
examples/client/SmartMotionController.client.luau | Пример: client BoneDrive + ввод + warmup |
plugin/SmartMotionBaker.server.luau | Studio-плагин: бейкер маркеров |
docs/ | TUTORIAL · WORKFLOW · REFERENCE · INDEX |
В рантайме (после wally install + Rojo):
| Инстанс | Класс | Назначение |
|---|---|---|
ReplicatedStorage.Packages.SmartMotion | ModuleScript | Public API (shared) |
ReplicatedStorage.SmartMotionToggle | RemoteEvent | Client↔Server сигнал |
ServerScriptService.* | Script | Server HRP motion (translation) |
StarterPlayer.StarterPlayerScripts.* | LocalScript | Client BoneDrive (визуал) + ввод |
%LOCALAPPDATA%\Roblox\Plugins\SmartMotionBaker.rbxm | LocalPlugin | Бейкер маркеров |
Quick start
- Подключи пакет (Wally) + скрипты из examples/ в плейс со скинд-меш NPC
observer(подробно — docs/TUTORIAL.md). - F5 (Play Solo).
- В Output должно появиться:
[Server] SmartMotion warmup complete [Client] SmartMotion warmup complete (hidden) [Server] SmartMotionRunner ready. E = full root motion, Q = in-place only - Character стоит в T-pose (warmup произошёл невидимо).
- E → full root motion: HRP едет, body анимируется, всё точно как в Animation Editor.
- Q → in-place: HRP стоит, body танцует на месте.
Следующее
- Подключить в свою игру — установка через Wally + server/client/RemoteEvent
- Добавить новую анимацию — полный шаг-за-шагом гайд
- API reference + опции — все settings, методы, форматы
- Troubleshooting — типичные баги
- Установка плагина — Studio Local Plugin
- Вся документация
Package Details
Install command (Click to copy)
Version
0.1.0
License
MIT
Safe for commercial use
Automated license review — not legal advice.
