motion-studio 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. motion_studio-0.1.0/LICENSE +21 -0
  2. motion_studio-0.1.0/MANIFEST.in +5 -0
  3. motion_studio-0.1.0/PKG-INFO +295 -0
  4. motion_studio-0.1.0/README.md +251 -0
  5. motion_studio-0.1.0/motion_studio/__init__.py +52 -0
  6. motion_studio-0.1.0/motion_studio/__main__.py +8 -0
  7. motion_studio-0.1.0/motion_studio/bundle.py +424 -0
  8. motion_studio-0.1.0/motion_studio/cli.py +459 -0
  9. motion_studio-0.1.0/motion_studio/config.py +58 -0
  10. motion_studio-0.1.0/motion_studio/core/__init__.py +8 -0
  11. motion_studio-0.1.0/motion_studio/core/plugins.py +285 -0
  12. motion_studio-0.1.0/motion_studio/core/types.py +72 -0
  13. motion_studio-0.1.0/motion_studio/library.py +188 -0
  14. motion_studio-0.1.0/motion_studio/plugins_builtin/__init__.py +8 -0
  15. motion_studio-0.1.0/motion_studio/plugins_builtin/_convert.py +108 -0
  16. motion_studio-0.1.0/motion_studio/plugins_builtin/corrector.py +79 -0
  17. motion_studio-0.1.0/motion_studio/plugins_builtin/corrector_impl.py +992 -0
  18. motion_studio-0.1.0/motion_studio/plugins_builtin/metrics.py +62 -0
  19. motion_studio-0.1.0/motion_studio/plugins_builtin/metrics_live.py +135 -0
  20. motion_studio-0.1.0/motion_studio/plugins_builtin/utils/__init__.py +74 -0
  21. motion_studio-0.1.0/motion_studio/plugins_builtin/utils/floor_utils.py +269 -0
  22. motion_studio-0.1.0/motion_studio/plugins_builtin/utils/metrics_utils.py +599 -0
  23. motion_studio-0.1.0/motion_studio/plugins_builtin/utils/motion_utils.py +880 -0
  24. motion_studio-0.1.0/motion_studio/server/__init__.py +1 -0
  25. motion_studio-0.1.0/motion_studio/server/api_bundle.py +649 -0
  26. motion_studio-0.1.0/motion_studio/server/api_motion.py +622 -0
  27. motion_studio-0.1.0/motion_studio/server/api_video.py +182 -0
  28. motion_studio-0.1.0/motion_studio/server/app.py +185 -0
  29. motion_studio-0.1.0/motion_studio/server/common.py +119 -0
  30. motion_studio-0.1.0/motion_studio/server/loaders.py +197 -0
  31. motion_studio-0.1.0/motion_studio/server/state.py +254 -0
  32. motion_studio-0.1.0/motion_studio/server/video_cache.py +283 -0
  33. motion_studio-0.1.0/motion_studio/smpl/__init__.py +5 -0
  34. motion_studio-0.1.0/motion_studio/smpl/convert.py +363 -0
  35. motion_studio-0.1.0/motion_studio/smpl/io.py +86 -0
  36. motion_studio-0.1.0/motion_studio/smpl/refit.py +370 -0
  37. motion_studio-0.1.0/motion_studio/static/app.js +4513 -0
  38. motion_studio-0.1.0/motion_studio/static/index.html +386 -0
  39. motion_studio-0.1.0/motion_studio/static/style.css +340 -0
  40. motion_studio-0.1.0/motion_studio/static/vendor/OrbitControls.js +1417 -0
  41. motion_studio-0.1.0/motion_studio/static/vendor/TransformControls.js +1573 -0
  42. motion_studio-0.1.0/motion_studio/static/vendor/three.module.js +53044 -0
  43. motion_studio-0.1.0/motion_studio.egg-info/PKG-INFO +295 -0
  44. motion_studio-0.1.0/motion_studio.egg-info/SOURCES.txt +60 -0
  45. motion_studio-0.1.0/motion_studio.egg-info/dependency_links.txt +1 -0
  46. motion_studio-0.1.0/motion_studio.egg-info/entry_points.txt +2 -0
  47. motion_studio-0.1.0/motion_studio.egg-info/requires.txt +23 -0
  48. motion_studio-0.1.0/motion_studio.egg-info/top_level.txt +1 -0
  49. motion_studio-0.1.0/pyproject.toml +84 -0
  50. motion_studio-0.1.0/setup.cfg +4 -0
  51. motion_studio-0.1.0/tests/test_api_surface.py +132 -0
  52. motion_studio-0.1.0/tests/test_bundle.py +153 -0
  53. motion_studio-0.1.0/tests/test_bundle_errors.py +88 -0
  54. motion_studio-0.1.0/tests/test_cli.py +299 -0
  55. motion_studio-0.1.0/tests/test_convert.py +149 -0
  56. motion_studio-0.1.0/tests/test_import_light.py +94 -0
  57. motion_studio-0.1.0/tests/test_info_routes.py +100 -0
  58. motion_studio-0.1.0/tests/test_io.py +144 -0
  59. motion_studio-0.1.0/tests/test_library.py +113 -0
  60. motion_studio-0.1.0/tests/test_plugin_contract.py +165 -0
  61. motion_studio-0.1.0/tests/test_plugins.py +276 -0
  62. motion_studio-0.1.0/tests/test_server.py +179 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Melissa Colin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ recursive-include motion_studio/static *
2
+ include LICENSE README.md
3
+ prune build
4
+ global-exclude __pycache__
5
+ global-exclude *.pyc
@@ -0,0 +1,295 @@
1
+ Metadata-Version: 2.4
2
+ Name: motion-studio
3
+ Version: 0.1.0
4
+ Summary: A clean, installable multi-person SMPL motion editor with pluggable auto-correction and metrics.
5
+ Author-email: Melissa Colin <github@melissacolin.ai>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/melissa-colin/motion-studio
8
+ Project-URL: Repository, https://github.com/melissa-colin/motion-studio
9
+ Project-URL: Documentation, https://github.com/melissa-colin/motion-studio#readme
10
+ Project-URL: Issues, https://github.com/melissa-colin/motion-studio/issues
11
+ Keywords: smpl,motion,motion-capture,3d,animation,pose,dance,editor,visualization
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Intended Audience :: Science/Research
20
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy
25
+ Requires-Dist: flask>=3.0
26
+ Provides-Extra: smpl
27
+ Requires-Dist: torch; extra == "smpl"
28
+ Requires-Dist: smplx; extra == "smpl"
29
+ Provides-Extra: video
30
+ Requires-Dist: pillow; extra == "video"
31
+ Requires-Dist: torchvision; extra == "video"
32
+ Requires-Dist: librosa; extra == "video"
33
+ Requires-Dist: scipy; extra == "video"
34
+ Provides-Extra: all
35
+ Requires-Dist: torch; extra == "all"
36
+ Requires-Dist: smplx; extra == "all"
37
+ Requires-Dist: pillow; extra == "all"
38
+ Requires-Dist: torchvision; extra == "all"
39
+ Requires-Dist: librosa; extra == "all"
40
+ Requires-Dist: scipy; extra == "all"
41
+ Provides-Extra: dev
42
+ Requires-Dist: pytest; extra == "dev"
43
+ Dynamic: license-file
44
+
45
+ # Motion Studio
46
+
47
+ [![PyPI version](https://img.shields.io/pypi/v/motion-studio.svg)](https://pypi.org/project/motion-studio/)
48
+ [![Python versions](https://img.shields.io/pypi/pyversions/motion-studio.svg)](https://pypi.org/project/motion-studio/)
49
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
50
+ [![CI](https://github.com/melissa-colin/motion-studio/actions/workflows/ci.yml/badge.svg)](https://github.com/melissa-colin/motion-studio/actions/workflows/ci.yml)
51
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-261230.svg)](https://github.com/astral-sh/ruff)
52
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
53
+
54
+ A clean, installable **multi-person SMPL motion editor** for the browser, with
55
+ a 3D view (Three.js), a video/music background, frame-by-frame pose editing,
56
+ and **pluggable** auto-correction and metrics.
57
+
58
+ It started as an internal pose editor for the AIOZ-GDANCE dataset and was
59
+ rewritten as a small, modular, self-contained tool: no dependency on any
60
+ external research repo, a single save-file format, and a plugin contract so you
61
+ can drop in **your own** correction / metrics classes without touching the app.
62
+
63
+ ![Motion Studio — playing a clip over its source video while orbiting the camera](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/demo.gif)
64
+
65
+ *Editing a multi-person clip: the SMPL motion and the source video play in sync while you orbit the camera.*
66
+
67
+ ---
68
+
69
+ ## Features
70
+
71
+ - **3D editor**: skeleton + SMPL mesh, per-joint and whole-body editing, undo/redo.
72
+ - **Video & music background**: place the source video in the scene (position,
73
+ scale, opacity, time offset), server-side background removal, audio playback
74
+ synced to the timeline.
75
+ - **Floor**: estimate / edit / recompute the ground plane.
76
+ - **Auto-correction & metrics**: run a correction pipeline and score the motion;
77
+ both are **plugins** (built-in by default, swappable for your own).
78
+ - **One save file**: a `.motion` bundle holds the original motion, your edits,
79
+ the video, the music, placement parameters, comments and a metrics snapshot.
80
+ - **Two ways to load**: open a single SMPL `.pkl` (with optional video/music),
81
+ or point at a whole `GDance/` folder and convert it into the workspace.
82
+
83
+ ---
84
+
85
+ ## Screenshots
86
+
87
+ ![The 3D editor](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/editor.png)
88
+ *The 3D editor: multiple SMPL dancers (mesh + skeleton), per-joint and
89
+ whole-body editing, the automatic corrector (a plugin), and the live metrics
90
+ panel. One **Save (.motion)** button and an **Export (.pkl)** button.*
91
+
92
+ ![Video background](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/video.png)
93
+ *The source video as a placeable background — position, scale, opacity, time
94
+ offset and server-side background removal — to check the motion against the
95
+ real footage.*
96
+
97
+ ![Estimated floor](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/floor.png)
98
+ *The ground plane is estimated on load (RANSAC on foot contacts) and can be
99
+ edited or recomputed.*
100
+
101
+ ![Empty start](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/empty.png)
102
+ *On startup the editor is empty (no clip auto-loaded, no pop-up). From the
103
+ **Clip** tab you choose: browse loaded clips, open a folder, or import a .pkl.*
104
+
105
+ ---
106
+
107
+ ## Install
108
+
109
+ ```bash
110
+ pip install "motion-studio[all]" # recommended: full feature set
111
+ ```
112
+
113
+ `[all]` pulls in torch, smplx, torchvision, pillow, librosa and scipy — the SMPL
114
+ forward kinematics, pose refit, built-in corrector/metrics, server-side
115
+ background removal and music import. Narrower extras are available:
116
+
117
+ ```bash
118
+ pip install motion-studio # core only (numpy + flask): no SMPL/video
119
+ pip install "motion-studio[smpl]" # + torch, smplx
120
+ pip install "motion-studio[video]" # + pillow, torchvision, librosa, scipy
121
+ pip install "motion-studio[dev]" # + pytest, ruff, black, pre-commit
122
+ ```
123
+
124
+ Requires Python >= 3.9. The SMPL body models are **not** shipped; point the tool
125
+ at your local copy with `--smpl-dir`.
126
+
127
+ ## Run
128
+
129
+ ```bash
130
+ motion-studio --workspace ~/MotionStudio --smpl-dir ~/smpl/models --port 8815
131
+ # optional: import a raw dataset folder
132
+ motion-studio --data /path/to/GDance --smpl-dir ~/smpl/models
133
+ ```
134
+
135
+ Then open <http://127.0.0.1:8815>.
136
+
137
+ The **workspace** is the root folder that holds your saved `.motion` bundles,
138
+ like any desktop app keeps its documents.
139
+
140
+ ---
141
+
142
+ ## Command line
143
+
144
+ The bare command (or `motion-studio serve`) starts the editor server. Two
145
+ headless subcommands run the same plugins from a terminal, no browser:
146
+
147
+ ```bash
148
+ motion-studio serve --smpl-dir ~/smpl/models # start the editor (default)
149
+
150
+ # Run the auto-corrector on a .motion and write the corrected bundle:
151
+ motion-studio correct in.motion -o out.motion
152
+ motion-studio correct in.motion -o out.motion --corrector ./my.py:MyCorrector
153
+
154
+ # Compute metrics on a .motion and print them:
155
+ motion-studio metrics in.motion
156
+ motion-studio metrics in.motion --metrics ./my.py:MyMetrics
157
+
158
+ motion-studio --version
159
+ ```
160
+
161
+ `--corrector` / `--metrics` take a plugin spec (`<module-or-path>:<Class>`),
162
+ the same as the server flags; omit them to use the built-in plugins.
163
+
164
+ ---
165
+
166
+ ## Docker
167
+
168
+ A `Dockerfile` is included. Build the image, then run it with your SMPL models
169
+ mounted in and the port published:
170
+
171
+ ```bash
172
+ docker build -t motion-studio .
173
+ docker run -p 8815:8815 -v ~/smpl/models:/models -e SMPL_DIR=/models motion-studio
174
+ ```
175
+
176
+ Then open <http://127.0.0.1:8815>. Mount a host folder to `/workspace` (and set
177
+ `MOTION_STUDIO_HOME=/workspace`) to persist your `.motion` bundles across runs.
178
+
179
+ ---
180
+
181
+ ## Python API
182
+
183
+ Motion Studio is also a library — import it and use the data model, bundle I/O
184
+ and plugin loaders directly, headless:
185
+
186
+ ```python
187
+ import motion_studio as ms
188
+
189
+ bundle = ms.load_bundle("session.motion") # -> Bundle (original/edited + media)
190
+ motion = bundle.original # -> Motion(poses, trans, betas, …)
191
+
192
+ corrector = ms.load_corrector(
193
+ "motion_studio.plugins_builtin.corrector:Corrector",
194
+ smpl_dir="~/smpl/models",
195
+ )
196
+ fixed = corrector.correct(motion)
197
+
198
+ ms.save_bundle("fixed.motion", original=motion, edited=fixed)
199
+ ```
200
+
201
+ The top-level surface (`__all__`) is: `Motion`, `Floor`, `load_bundle`,
202
+ `save_bundle`, `load_corrector`, `load_metrics`, `scan_dataset`, `Config`,
203
+ `__version__`. The library core imports with only numpy + flask (no torch).
204
+
205
+ ---
206
+
207
+ ## The `.motion` save file
208
+
209
+ A `.motion` file is a single ZIP archive bundling an entire editing session:
210
+
211
+ ```
212
+ manifest.json format/version, comments, video placement params,
213
+ metrics snapshot, timestamps
214
+ motion_original.npz the original SMPL motion (poses, trans, betas, fps, gender)
215
+ motion_edited.npz your edited motion (omitted if you have not edited)
216
+ video.mp4 the source video (optional)
217
+ music.<ext> the music track (optional)
218
+ ```
219
+
220
+ Open a `.motion` to **continue** where you left off; the SMPL `.pkl` is written
221
+ out only when you click **Export**.
222
+
223
+ ---
224
+
225
+ ## Plugins: bring your own correction / metrics
226
+
227
+ Motion Studio depends only on a small contract, not on any concrete
228
+ implementation. A plugin is any class matching one of these protocols
229
+ (`motion_studio/core/plugins.py`):
230
+
231
+ ```python
232
+ class MotionCorrector(Protocol):
233
+ def __init__(self, *, smpl_dir, floor=None): ...
234
+ def correct(self, motion: Motion, log=print) -> Motion: ...
235
+
236
+ class MotionMetrics(Protocol):
237
+ def __init__(self, *, smpl_dir): ...
238
+ def compute(self, motion: Motion, floor: Floor) -> dict[str, float]: ...
239
+ ```
240
+
241
+ `Motion` and `Floor` are the only types exchanged
242
+ (`motion_studio/core/types.py`):
243
+
244
+ ```python
245
+ @dataclass
246
+ class Motion:
247
+ poses: np.ndarray # (N, T, 24, 3) axis-angle, z-up
248
+ trans: np.ndarray # (N, T, 3)
249
+ betas: np.ndarray | None
250
+ gender: str
251
+ fps: float
252
+ name: str
253
+
254
+ @dataclass
255
+ class Floor:
256
+ plane: tuple[float, float, float] # z = a*x + b*y + c
257
+ ```
258
+
259
+ Point the tool at your own classes (a dotted module **or** a file path,
260
+ followed by the class name); they are re-imported on every run, so edits take
261
+ effect on the next click:
262
+
263
+ ```bash
264
+ motion-studio --corrector ./my_corrector.py:MyCorrector \
265
+ --metrics ./my_metrics.py:MyMetrics
266
+ ```
267
+
268
+ The built-in plugins live in `motion_studio/plugins_builtin/`.
269
+
270
+ **New to plugins?** See the full authoring guide in
271
+ [`docs/PLUGINS.md`](docs/PLUGINS.md) and the runnable, dependency-light
272
+ examples in [`examples/`](examples). For instance, the pure-numpy metrics
273
+ example (no torch / no SMPL needed) shows custom keys rendering end to end:
274
+
275
+ ```bash
276
+ motion-studio --metrics ./examples/simple_metrics.py:SimpleMetrics
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Documentation
282
+
283
+ - [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — module map, data model,
284
+ request flow, the heavy-lock model, the `.motion` format.
285
+ - [`docs/PLUGINS.md`](docs/PLUGINS.md) — the plugin authoring guide.
286
+ - [`docs/USAGE.md`](docs/USAGE.md) — day-to-day editor usage.
287
+ - [`docs/API.md`](docs/API.md) — the HTTP API.
288
+ - [`CONTRIBUTING.md`](CONTRIBUTING.md) — dev install, tests, lint/format.
289
+ - [`SECURITY.md`](SECURITY.md) — the threat model and `--allow-remote` risk.
290
+
291
+ ---
292
+
293
+ ## License
294
+
295
+ Released under the **MIT License** (see the `LICENSE` file in the repository).
@@ -0,0 +1,251 @@
1
+ # Motion Studio
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/motion-studio.svg)](https://pypi.org/project/motion-studio/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/motion-studio.svg)](https://pypi.org/project/motion-studio/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![CI](https://github.com/melissa-colin/motion-studio/actions/workflows/ci.yml/badge.svg)](https://github.com/melissa-colin/motion-studio/actions/workflows/ci.yml)
7
+ [![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-261230.svg)](https://github.com/astral-sh/ruff)
8
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
9
+
10
+ A clean, installable **multi-person SMPL motion editor** for the browser, with
11
+ a 3D view (Three.js), a video/music background, frame-by-frame pose editing,
12
+ and **pluggable** auto-correction and metrics.
13
+
14
+ It started as an internal pose editor for the AIOZ-GDANCE dataset and was
15
+ rewritten as a small, modular, self-contained tool: no dependency on any
16
+ external research repo, a single save-file format, and a plugin contract so you
17
+ can drop in **your own** correction / metrics classes without touching the app.
18
+
19
+ ![Motion Studio — playing a clip over its source video while orbiting the camera](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/demo.gif)
20
+
21
+ *Editing a multi-person clip: the SMPL motion and the source video play in sync while you orbit the camera.*
22
+
23
+ ---
24
+
25
+ ## Features
26
+
27
+ - **3D editor**: skeleton + SMPL mesh, per-joint and whole-body editing, undo/redo.
28
+ - **Video & music background**: place the source video in the scene (position,
29
+ scale, opacity, time offset), server-side background removal, audio playback
30
+ synced to the timeline.
31
+ - **Floor**: estimate / edit / recompute the ground plane.
32
+ - **Auto-correction & metrics**: run a correction pipeline and score the motion;
33
+ both are **plugins** (built-in by default, swappable for your own).
34
+ - **One save file**: a `.motion` bundle holds the original motion, your edits,
35
+ the video, the music, placement parameters, comments and a metrics snapshot.
36
+ - **Two ways to load**: open a single SMPL `.pkl` (with optional video/music),
37
+ or point at a whole `GDance/` folder and convert it into the workspace.
38
+
39
+ ---
40
+
41
+ ## Screenshots
42
+
43
+ ![The 3D editor](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/editor.png)
44
+ *The 3D editor: multiple SMPL dancers (mesh + skeleton), per-joint and
45
+ whole-body editing, the automatic corrector (a plugin), and the live metrics
46
+ panel. One **Save (.motion)** button and an **Export (.pkl)** button.*
47
+
48
+ ![Video background](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/video.png)
49
+ *The source video as a placeable background — position, scale, opacity, time
50
+ offset and server-side background removal — to check the motion against the
51
+ real footage.*
52
+
53
+ ![Estimated floor](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/floor.png)
54
+ *The ground plane is estimated on load (RANSAC on foot contacts) and can be
55
+ edited or recomputed.*
56
+
57
+ ![Empty start](https://raw.githubusercontent.com/melissa-colin/motion-studio/main/docs/img/empty.png)
58
+ *On startup the editor is empty (no clip auto-loaded, no pop-up). From the
59
+ **Clip** tab you choose: browse loaded clips, open a folder, or import a .pkl.*
60
+
61
+ ---
62
+
63
+ ## Install
64
+
65
+ ```bash
66
+ pip install "motion-studio[all]" # recommended: full feature set
67
+ ```
68
+
69
+ `[all]` pulls in torch, smplx, torchvision, pillow, librosa and scipy — the SMPL
70
+ forward kinematics, pose refit, built-in corrector/metrics, server-side
71
+ background removal and music import. Narrower extras are available:
72
+
73
+ ```bash
74
+ pip install motion-studio # core only (numpy + flask): no SMPL/video
75
+ pip install "motion-studio[smpl]" # + torch, smplx
76
+ pip install "motion-studio[video]" # + pillow, torchvision, librosa, scipy
77
+ pip install "motion-studio[dev]" # + pytest, ruff, black, pre-commit
78
+ ```
79
+
80
+ Requires Python >= 3.9. The SMPL body models are **not** shipped; point the tool
81
+ at your local copy with `--smpl-dir`.
82
+
83
+ ## Run
84
+
85
+ ```bash
86
+ motion-studio --workspace ~/MotionStudio --smpl-dir ~/smpl/models --port 8815
87
+ # optional: import a raw dataset folder
88
+ motion-studio --data /path/to/GDance --smpl-dir ~/smpl/models
89
+ ```
90
+
91
+ Then open <http://127.0.0.1:8815>.
92
+
93
+ The **workspace** is the root folder that holds your saved `.motion` bundles,
94
+ like any desktop app keeps its documents.
95
+
96
+ ---
97
+
98
+ ## Command line
99
+
100
+ The bare command (or `motion-studio serve`) starts the editor server. Two
101
+ headless subcommands run the same plugins from a terminal, no browser:
102
+
103
+ ```bash
104
+ motion-studio serve --smpl-dir ~/smpl/models # start the editor (default)
105
+
106
+ # Run the auto-corrector on a .motion and write the corrected bundle:
107
+ motion-studio correct in.motion -o out.motion
108
+ motion-studio correct in.motion -o out.motion --corrector ./my.py:MyCorrector
109
+
110
+ # Compute metrics on a .motion and print them:
111
+ motion-studio metrics in.motion
112
+ motion-studio metrics in.motion --metrics ./my.py:MyMetrics
113
+
114
+ motion-studio --version
115
+ ```
116
+
117
+ `--corrector` / `--metrics` take a plugin spec (`<module-or-path>:<Class>`),
118
+ the same as the server flags; omit them to use the built-in plugins.
119
+
120
+ ---
121
+
122
+ ## Docker
123
+
124
+ A `Dockerfile` is included. Build the image, then run it with your SMPL models
125
+ mounted in and the port published:
126
+
127
+ ```bash
128
+ docker build -t motion-studio .
129
+ docker run -p 8815:8815 -v ~/smpl/models:/models -e SMPL_DIR=/models motion-studio
130
+ ```
131
+
132
+ Then open <http://127.0.0.1:8815>. Mount a host folder to `/workspace` (and set
133
+ `MOTION_STUDIO_HOME=/workspace`) to persist your `.motion` bundles across runs.
134
+
135
+ ---
136
+
137
+ ## Python API
138
+
139
+ Motion Studio is also a library — import it and use the data model, bundle I/O
140
+ and plugin loaders directly, headless:
141
+
142
+ ```python
143
+ import motion_studio as ms
144
+
145
+ bundle = ms.load_bundle("session.motion") # -> Bundle (original/edited + media)
146
+ motion = bundle.original # -> Motion(poses, trans, betas, …)
147
+
148
+ corrector = ms.load_corrector(
149
+ "motion_studio.plugins_builtin.corrector:Corrector",
150
+ smpl_dir="~/smpl/models",
151
+ )
152
+ fixed = corrector.correct(motion)
153
+
154
+ ms.save_bundle("fixed.motion", original=motion, edited=fixed)
155
+ ```
156
+
157
+ The top-level surface (`__all__`) is: `Motion`, `Floor`, `load_bundle`,
158
+ `save_bundle`, `load_corrector`, `load_metrics`, `scan_dataset`, `Config`,
159
+ `__version__`. The library core imports with only numpy + flask (no torch).
160
+
161
+ ---
162
+
163
+ ## The `.motion` save file
164
+
165
+ A `.motion` file is a single ZIP archive bundling an entire editing session:
166
+
167
+ ```
168
+ manifest.json format/version, comments, video placement params,
169
+ metrics snapshot, timestamps
170
+ motion_original.npz the original SMPL motion (poses, trans, betas, fps, gender)
171
+ motion_edited.npz your edited motion (omitted if you have not edited)
172
+ video.mp4 the source video (optional)
173
+ music.<ext> the music track (optional)
174
+ ```
175
+
176
+ Open a `.motion` to **continue** where you left off; the SMPL `.pkl` is written
177
+ out only when you click **Export**.
178
+
179
+ ---
180
+
181
+ ## Plugins: bring your own correction / metrics
182
+
183
+ Motion Studio depends only on a small contract, not on any concrete
184
+ implementation. A plugin is any class matching one of these protocols
185
+ (`motion_studio/core/plugins.py`):
186
+
187
+ ```python
188
+ class MotionCorrector(Protocol):
189
+ def __init__(self, *, smpl_dir, floor=None): ...
190
+ def correct(self, motion: Motion, log=print) -> Motion: ...
191
+
192
+ class MotionMetrics(Protocol):
193
+ def __init__(self, *, smpl_dir): ...
194
+ def compute(self, motion: Motion, floor: Floor) -> dict[str, float]: ...
195
+ ```
196
+
197
+ `Motion` and `Floor` are the only types exchanged
198
+ (`motion_studio/core/types.py`):
199
+
200
+ ```python
201
+ @dataclass
202
+ class Motion:
203
+ poses: np.ndarray # (N, T, 24, 3) axis-angle, z-up
204
+ trans: np.ndarray # (N, T, 3)
205
+ betas: np.ndarray | None
206
+ gender: str
207
+ fps: float
208
+ name: str
209
+
210
+ @dataclass
211
+ class Floor:
212
+ plane: tuple[float, float, float] # z = a*x + b*y + c
213
+ ```
214
+
215
+ Point the tool at your own classes (a dotted module **or** a file path,
216
+ followed by the class name); they are re-imported on every run, so edits take
217
+ effect on the next click:
218
+
219
+ ```bash
220
+ motion-studio --corrector ./my_corrector.py:MyCorrector \
221
+ --metrics ./my_metrics.py:MyMetrics
222
+ ```
223
+
224
+ The built-in plugins live in `motion_studio/plugins_builtin/`.
225
+
226
+ **New to plugins?** See the full authoring guide in
227
+ [`docs/PLUGINS.md`](docs/PLUGINS.md) and the runnable, dependency-light
228
+ examples in [`examples/`](examples). For instance, the pure-numpy metrics
229
+ example (no torch / no SMPL needed) shows custom keys rendering end to end:
230
+
231
+ ```bash
232
+ motion-studio --metrics ./examples/simple_metrics.py:SimpleMetrics
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Documentation
238
+
239
+ - [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — module map, data model,
240
+ request flow, the heavy-lock model, the `.motion` format.
241
+ - [`docs/PLUGINS.md`](docs/PLUGINS.md) — the plugin authoring guide.
242
+ - [`docs/USAGE.md`](docs/USAGE.md) — day-to-day editor usage.
243
+ - [`docs/API.md`](docs/API.md) — the HTTP API.
244
+ - [`CONTRIBUTING.md`](CONTRIBUTING.md) — dev install, tests, lint/format.
245
+ - [`SECURITY.md`](SECURITY.md) — the threat model and `--allow-remote` risk.
246
+
247
+ ---
248
+
249
+ ## License
250
+
251
+ Released under the **MIT License** (see the `LICENSE` file in the repository).
@@ -0,0 +1,52 @@
1
+ """Motion Studio: a clean, installable multi-person SMPL motion editor.
2
+
3
+ The names re-exported here are the package's stable public API. Everything in
4
+ this top-level namespace is torch-free and safe to import in a numpy+flask-only
5
+ ("core") install: the heavy server stack and the built-in torch/SMPL plugins
6
+ are imported lazily, never at package import time.
7
+
8
+ Typical use::
9
+
10
+ import motion_studio as ms
11
+
12
+ bundle = ms.load_bundle("session.motion")
13
+ motion = bundle.original # ms.Motion
14
+ corrector = ms.load_corrector(ms.Config().corrector_spec,
15
+ smpl_dir="~/smpl/models")
16
+ fixed = corrector.correct(motion)
17
+ ms.save_motion_pkl(fixed, "fixed.pkl")
18
+ """
19
+ from __future__ import annotations
20
+
21
+ from .bundle import load_bundle, save_bundle
22
+ from .config import Config
23
+ from .core.plugins import (MotionCorrector, MotionMetrics, load_corrector,
24
+ load_metrics)
25
+ from .core.types import Floor, Motion
26
+ from .library import import_dataset, scan_dataset
27
+ from .smpl.io import load_motion_pkl, save_motion_pkl
28
+
29
+ __version__ = "0.1.0"
30
+
31
+ __all__ = [
32
+ # Core data types.
33
+ "Motion",
34
+ "Floor",
35
+ # Plugin contracts + loaders.
36
+ "MotionCorrector",
37
+ "MotionMetrics",
38
+ "load_corrector",
39
+ "load_metrics",
40
+ # SMPL pkl I/O.
41
+ "load_motion_pkl",
42
+ "save_motion_pkl",
43
+ # .motion bundle I/O.
44
+ "save_bundle",
45
+ "load_bundle",
46
+ # Dataset discovery / import.
47
+ "scan_dataset",
48
+ "import_dataset",
49
+ # Configuration.
50
+ "Config",
51
+ "__version__",
52
+ ]
@@ -0,0 +1,8 @@
1
+ """Allow ``python -m motion_studio`` to start the server."""
2
+
3
+ import sys
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())