cozyclay 1.9.0 → 2.0.0

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 (286) hide show
  1. package/CHANGELOG.md +171 -0
  2. package/bin/agent/agent-routes.mjs +74 -70
  3. package/bin/agent/agent-runner.mjs +10 -3
  4. package/bin/agent/motion-runtime.mjs +32 -260
  5. package/bin/agent/providers.mjs +46 -3
  6. package/bin/agent/session-store.mjs +41 -5
  7. package/bin/agent/studio-prompt.mjs +1 -1
  8. package/bin/agent/studio-tools.mjs +48 -11
  9. package/bin/cozyclay.mjs +26 -8
  10. package/bin/live/cli.mjs +22 -3
  11. package/bin/mcp-runtime.mjs +35 -20
  12. package/bin/telemetry-state.mjs +5 -2
  13. package/bin/update-check.mjs +15 -0
  14. package/dist/app/index.html +6 -6
  15. package/dist/assets/analytics-MVZOEW8O.js +1 -0
  16. package/dist/assets/app-C1sdVbg4.css +1 -0
  17. package/dist/assets/app-CA55tcI3.js +4876 -0
  18. package/dist/assets/{demo-B-eg1CT8.js → demo-ByeYp-dY.js} +1 -1
  19. package/dist/assets/{first-shot-handoff-CGgnvNu8.js → first-shot-handoff-DgT28ZiV.js} +1 -1
  20. package/dist/assets/{landing-IbRp3FnQ.js → landing-BaXkpFip.js} +1 -1
  21. package/dist/assets/shot-prompt-CbqWcWYi.css +1 -0
  22. package/dist/assets/shot-prompt-Yrt99wZx.js +17 -0
  23. package/dist/assets/{ticket-BgIzOBOf.js → ticket-BcmsnHn5.js} +1 -1
  24. package/dist/assets/workflow-DRdwoDBT.css +1 -0
  25. package/dist/assets/workflow-dNPGY9xz.js +179 -0
  26. package/dist/cozyclay-package.json +1 -1
  27. package/dist/fonts/IBM-Plex-Sans-OFL.txt +92 -0
  28. package/dist/fonts/JetBrains-Mono-OFL.txt +93 -0
  29. package/dist/fonts/README.md +13 -9
  30. package/dist/fonts/ibm-plex-sans-400-latin.woff2 +0 -0
  31. package/dist/fonts/ibm-plex-sans-500-latin.woff2 +0 -0
  32. package/dist/fonts/ibm-plex-sans-600-latin.woff2 +0 -0
  33. package/dist/fonts/jetbrains-mono-400-latin.woff2 +0 -0
  34. package/dist/fonts/jetbrains-mono-500-latin.woff2 +0 -0
  35. package/dist/index.html +7 -7
  36. package/dist/privacy/index.html +13 -8
  37. package/dist/sitemap.xml +6 -6
  38. package/dist/workflow/index.html +5 -5
  39. package/mcp/LIVE-PROTOCOL.md +1 -1
  40. package/mcp/live-hub.mjs +35 -93
  41. package/mcp/mesh-file.mjs +48 -0
  42. package/mcp/server.mjs +6 -77
  43. package/mcp/tool-handlers.mjs +224 -377
  44. package/package.json +2 -1
  45. package/src/App.jsx +1273 -9075
  46. package/src/analytics.js +393 -9
  47. package/src/app-context.js +211 -0
  48. package/src/app-stage.jsx +25 -24
  49. package/src/ardy/auto-fix-panel.css +108 -0
  50. package/src/ardy/collision-blockers.js +9 -3
  51. package/src/ardy/fix-collisions.js +10 -66
  52. package/src/ardy/ground.js +4 -4
  53. package/src/ardy/ik-drag.js +101 -0
  54. package/src/ardy/ik-key-json.js +43 -0
  55. package/src/ardy/ik.js +122 -76
  56. package/src/ardy/physics-panel.css +2 -0
  57. package/src/ardy/physics-panel.jsx +17 -5
  58. package/src/ardy/platform-fit-panel.css +64 -0
  59. package/src/ardy/platform-fit-panel.jsx +40 -0
  60. package/src/ardy/platform-fit.js +326 -0
  61. package/src/ardy/playback.js +166 -20
  62. package/src/ardy/range-pin.js +299 -0
  63. package/src/ardy/timeline-coordinates.js +26 -0
  64. package/src/ardy/timeline.css +1199 -0
  65. package/src/ardy/timeline.jsx +149 -41
  66. package/src/ardy/waypoints.js +2 -2
  67. package/src/asset-pane.css +462 -0
  68. package/src/asset-pane.jsx +461 -232
  69. package/src/command-bus.js +349 -0
  70. package/src/commands/ai.js +31 -0
  71. package/src/commands/cast.js +140 -0
  72. package/src/commands/elements/character.js +13 -0
  73. package/src/commands/elements/motion.js +14 -0
  74. package/src/commands/elements/object.js +22 -0
  75. package/src/commands/elements/scene.js +16 -0
  76. package/src/commands/elements/shot.js +9 -0
  77. package/src/commands/elements/stage.js +11 -0
  78. package/src/commands/elements.js +155 -0
  79. package/src/commands/export.js +20 -0
  80. package/src/commands/index.js +40 -0
  81. package/src/commands/motion.js +231 -0
  82. package/src/commands/objects.js +174 -0
  83. package/src/commands/project.js +53 -0
  84. package/src/commands/scene.js +81 -0
  85. package/src/commands/shared.js +19 -0
  86. package/src/commands/shot.js +103 -0
  87. package/src/commands/stage.js +17 -0
  88. package/src/commands/view.js +42 -0
  89. package/src/document-store.js +144 -0
  90. package/src/domains/cast.js +1007 -0
  91. package/src/domains/motion.js +3219 -0
  92. package/src/domains/objects.js +932 -0
  93. package/src/domains/scenes.js +817 -0
  94. package/src/domains/shots.js +404 -0
  95. package/src/domains/stage.js +93 -0
  96. package/src/dualview.jsx +113 -57
  97. package/src/facing-marks.js +3 -0
  98. package/src/first-success-guide.jsx +14 -14
  99. package/src/grid-view.js +18 -5
  100. package/src/hierarchy-model.js +24 -16
  101. package/src/hierarchy-panel.css +386 -0
  102. package/src/hierarchy-panel.jsx +150 -21
  103. package/src/{fal-motion-client.js → i2v-motion-client.js} +13 -13
  104. package/src/i2v-motion-studio.jsx +180 -0
  105. package/src/ik-camera.js +3 -0
  106. package/src/main.jsx +6 -0
  107. package/src/motion/generation.js +105 -0
  108. package/src/motion-readiness-ui.jsx +4 -4
  109. package/src/motion-readiness.js +11 -0
  110. package/src/motion-trail.js +366 -9
  111. package/src/object-gizmo.jsx +7 -1
  112. package/src/otio.js +2 -1
  113. package/src/panels/CameraPanel.jsx +60 -0
  114. package/src/panels/CharacterTransformPanel.jsx +48 -0
  115. package/src/panels/EnvironmentPanel.jsx +40 -0
  116. package/src/panels/Foldout.jsx +32 -0
  117. package/src/panels/LightPanel.jsx +24 -0
  118. package/src/panels/ObjectTransformPanel.jsx +554 -0
  119. package/src/panels/PosePanel.jsx +97 -0
  120. package/src/panels/ProjectPanel.jsx +33 -0
  121. package/src/panels/PromptBlocksPanel.jsx +442 -0
  122. package/src/panels/PropsPanel.jsx +70 -0
  123. package/src/panels/ReferenceImageField.jsx +91 -0
  124. package/src/panels/RigControlPanel.jsx +78 -0
  125. package/src/panels/RigPanel.jsx +37 -0
  126. package/src/panels/SubjectBox.jsx +47 -0
  127. package/src/panels/SubjectsPanel.jsx +39 -0
  128. package/src/panels/VideoCapturePanel.jsx +180 -0
  129. package/src/panels/details.css +1171 -0
  130. package/src/panels/motion.css +197 -0
  131. package/src/panels/pose.css +39 -0
  132. package/src/planview.jsx +60 -31
  133. package/src/posestudio.jsx +59 -4
  134. package/src/project-browser.css +1073 -0
  135. package/src/project-browser.jsx +284 -123
  136. package/src/range-pin-object-transform.js +19 -0
  137. package/src/range-pin-panel.css +518 -0
  138. package/src/range-pin-panel.jsx +344 -0
  139. package/src/result-modal.jsx +5 -5
  140. package/src/room.jsx +79 -51
  141. package/src/scene-objects.js +37 -1
  142. package/src/scenes.js +5 -0
  143. package/src/semantic-edit.js +2 -0
  144. package/src/settings-menu.jsx +39 -105
  145. package/src/shell/BottomDock.jsx +450 -0
  146. package/src/shell/DetailsSlot.jsx +513 -0
  147. package/src/shell/LibrarySlot.jsx +86 -0
  148. package/src/shell/MenuBar.jsx +601 -0
  149. package/src/shell/OutlinerSlot.jsx +50 -0
  150. package/src/shell/PreferencesDialog.jsx +538 -0
  151. package/src/shell/PreferencesSlot.jsx +40 -0
  152. package/src/shell/StatusBar.jsx +125 -0
  153. package/src/shell/StudioShell.jsx +92 -0
  154. package/src/shell/TopBar.jsx +129 -0
  155. package/src/shell/ViewportToolbar.jsx +656 -0
  156. package/src/shell/agent-glass.css +296 -0
  157. package/src/shell/dock.css +93 -0
  158. package/src/shell/glass-regions.css +985 -0
  159. package/src/shell/glass.css +687 -0
  160. package/src/shell/log-store.js +52 -0
  161. package/src/shell/mode.css +9 -0
  162. package/src/shell/preferences.css +651 -0
  163. package/src/shell/shell.css +282 -0
  164. package/src/shell/studio-shell-context.js +19 -0
  165. package/src/shell/topbar.css +435 -0
  166. package/src/shell/viewport.css +451 -0
  167. package/src/store/authored-intent.js +22 -0
  168. package/src/store/runtime-adapters.js +92 -0
  169. package/src/store/scene-stage.js +21 -0
  170. package/src/store/use-document-store.js +14 -0
  171. package/src/studio-actions.js +210 -0
  172. package/src/studio-agent-commands.js +41 -271
  173. package/src/studio-agent-context.js +39 -10
  174. package/src/studio-agent-motion.js +122 -373
  175. package/src/studio-agent-protocol.js +67 -31
  176. package/src/studio-app-binding.js +379 -0
  177. package/src/studio-contact-sheet.js +73 -0
  178. package/src/studio-elements.js +58 -51
  179. package/src/styles/themes.css +200 -0
  180. package/src/styles/tokens.css +69 -0
  181. package/src/styles.css +460 -1742
  182. package/src/theme.js +44 -0
  183. package/src/timeline-extent.js +16 -0
  184. package/src/trail-key-conflicts.js +39 -0
  185. package/src/trail-pick.js +59 -0
  186. package/src/ui.jsx +8 -8
  187. package/src/use-case-question.jsx +66 -0
  188. package/src/workflow/AgentPanel.jsx +82 -69
  189. package/src/workflow/agent-client.js +12 -2
  190. package/src/workflow/agent-panel.css +34 -32
  191. package/src/workflow/cozy-scene-node.css +2 -0
  192. package/src/workflow/workflow.css +2 -0
  193. package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
  194. package/tools/ardy/bridge.mjs +164 -146
  195. package/tools/ardy/visual-qa.mjs +5 -5
  196. package/tools/bench/EXP3.md +61 -0
  197. package/tools/bench/cclay_bench_extract_incam.py +125 -0
  198. package/tools/bench/cclay_bench_extract_obs.py +204 -0
  199. package/tools/bench/cclay_bench_runner.py +42 -0
  200. package/tools/bench/cube-contact.mjs +162 -0
  201. package/tools/bench/exp3.mjs +152 -0
  202. package/tools/bench/extract-bench-lib.mjs +216 -0
  203. package/tools/bench/extract-bench.mjs +302 -0
  204. package/tools/bench/fal-generate.mjs +88 -0
  205. package/tools/bench/fit/README.md +189 -0
  206. package/tools/bench/fit/camera.mjs +59 -0
  207. package/tools/bench/fit/contact.mjs +419 -0
  208. package/tools/bench/fit/footlock.mjs +234 -0
  209. package/tools/bench/fit/motion.mjs +85 -0
  210. package/tools/bench/fit/pin.mjs +27 -0
  211. package/tools/bench/fit/remote.mjs +105 -0
  212. package/tools/bench/fit-bench.mjs +126 -0
  213. package/tools/bench/fit-sanity.mjs +45 -0
  214. package/tools/bench/metrics.mjs +313 -0
  215. package/tools/bench/obs/depth.mjs +258 -0
  216. package/tools/bench/obs/extrinsics.mjs +175 -0
  217. package/tools/bench/obs/fit_mannequin_betas.py +340 -0
  218. package/tools/bench/obs/ground.mjs +294 -0
  219. package/tools/bench/obs/heading.mjs +151 -0
  220. package/tools/bench/obs/ladder.mjs +555 -0
  221. package/tools/bench/obs/mannequin-betas.json +124 -0
  222. package/tools/bench/obs/remote.mjs +83 -0
  223. package/tools/bench/obs/rest_joints.py +52 -0
  224. package/tools/bench/obs/ybot-targets.mjs +49 -0
  225. package/tools/bench/obs-bench.mjs +520 -0
  226. package/tools/bench/score.mjs +343 -0
  227. package/tools/bench/summarize.mjs +86 -0
  228. package/tools/dev/pages/privacy.html +13 -8
  229. package/tools/gt-render/browser.mjs +159 -0
  230. package/tools/gt-render/camera-math.mjs +276 -0
  231. package/tools/gt-render/page.mjs +267 -0
  232. package/tools/gt-render/render.mjs +514 -0
  233. package/tools/gt-render/scene-box.mjs +31 -0
  234. package/tools/gt-render/take-transform.mjs +87 -0
  235. package/tools/morphgs/assets/gen_truth.py +39 -0
  236. package/tools/morphgs/assets/mesh_ori_rig.txt +27 -0
  237. package/tools/morphgs/assets/playback-check.mjs +30 -0
  238. package/tools/morphgs/demo-gate.sh +26 -0
  239. package/tools/morphgs/fbx2morphgs.mjs +68 -0
  240. package/tools/morphgs/morphgs-to-cskel27.mjs +105 -0
  241. package/tools/morphgs/patches/preprocess_src-none-mode.patch +76 -0
  242. package/tools/morphgs/setup-on-cluster.sh +126 -0
  243. package/tools/qa/css-rule-usage.mjs +283 -0
  244. package/tools/qa/studio-control-count.mjs +70 -32
  245. package/tools/run-tests.mjs +134 -12
  246. package/tools/track/DESIGN.md +513 -0
  247. package/tools/track/backfill-provenance.mjs +116 -0
  248. package/tools/track/budget.mjs +8 -0
  249. package/tools/track/check-rig.mjs +209 -0
  250. package/tools/track/diagnostics.schema.json +60 -0
  251. package/tools/track/export-rig.mjs +256 -0
  252. package/tools/track/fallback.mjs +7 -0
  253. package/tools/track/fk-parity-fixture.mjs +161 -0
  254. package/tools/track/gate.mjs +349 -0
  255. package/tools/track/masks.mjs +318 -0
  256. package/tools/track/metrics.mjs +201 -0
  257. package/tools/track/publish-obs.mjs +108 -0
  258. package/tools/track/py/check_env.py +61 -0
  259. package/tools/track/py/eval_lr.py +229 -0
  260. package/tools/track/py/lr_viterbi.py +294 -0
  261. package/tools/track/py/masks.py +405 -0
  262. package/tools/track/py/objective.py +382 -0
  263. package/tools/track/py/rig.py +508 -0
  264. package/tools/track/py/scene.py +326 -0
  265. package/tools/track/py/test_joint_indices.py +123 -0
  266. package/tools/track/py/test_lr_viterbi.py +195 -0
  267. package/tools/track/py/test_masks.py +229 -0
  268. package/tools/track/py/test_rig.py +288 -0
  269. package/tools/track/py/test_scene.py +354 -0
  270. package/tools/track/py/test_track.py +328 -0
  271. package/tools/track/py/track.py +411 -0
  272. package/tools/track/remote.mjs +140 -0
  273. package/tools/track/rig-dump.mjs +227 -0
  274. package/tools/track/run-box-tests.mjs +14 -0
  275. package/tools/track/run-box.mjs +168 -0
  276. package/tools/track/setup-box.sh +59 -0
  277. package/tools/track/study-2d.mjs +728 -0
  278. package/dist/assets/analytics-B1hnH66c.js +0 -1
  279. package/dist/assets/app-BWusbqgO.js +0 -4861
  280. package/dist/assets/app-qKDo4PBX.css +0 -1
  281. package/dist/assets/shot-prompt-CHUtw6af.js +0 -17
  282. package/dist/assets/shot-prompt-C_g2BHVc.css +0 -1
  283. package/dist/assets/workflow-CVwzMhz2.js +0 -179
  284. package/dist/assets/workflow-DsudxKHF.css +0 -1
  285. package/src/fal-motion-studio.jsx +0 -180
  286. package/src/scene-history.js +0 -129
@@ -1 +1 @@
1
- {"payload":"{\"distribution\":\"npm\",\"package\":\"cozyclay\",\"version\":\"1.9.0\",\"repository\":\"NomaDamas/CozyClay\",\"content_sha256\":\"23d024bcbaab90240eba74f15829cde20e5647557d3d47a419c84662308762c6\"}","signature":"drtYdytc0gTfOfzIvj5Ca0me8xnmJqrdyF/O8DjO821uAAbszX0Fk2WP/Ai6rQOMjL9jWNw3JEhNKyQzIUGSAw=="}
1
+ {"payload":"{\"distribution\":\"npm\",\"package\":\"cozyclay\",\"version\":\"2.0.0\",\"repository\":\"NomaDamas/CozyClay\",\"content_sha256\":\"2df2a5c5568a32133c5f4efc43abbd1ecb7bd07d89538eb6860a24afe12a98c5\"}","signature":"stRY9RUg5dAQVwVhfhYrieP1HpXK+ahX3U5g8qFMzsQYw2ZFEF+iXRblkvYNjk5MS2g43qKAEMN9F8K0MP3vAA=="}
@@ -0,0 +1,92 @@
1
+ Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+ -----------------------------------------------------------
8
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9
+ -----------------------------------------------------------
10
+
11
+ PREAMBLE
12
+ The goals of the Open Font License (OFL) are to stimulate worldwide
13
+ development of collaborative font projects, to support the font creation
14
+ efforts of academic and linguistic communities, and to provide a free and
15
+ open framework in which fonts may be shared and improved in partnership
16
+ with others.
17
+
18
+ The OFL allows the licensed fonts to be used, studied, modified and
19
+ redistributed freely as long as they are not sold by themselves. The
20
+ fonts, including any derivative works, can be bundled, embedded,
21
+ redistributed and/or sold with any software provided that any reserved
22
+ names are not used by derivative works. The fonts and derivatives,
23
+ however, cannot be released under any other type of license. The
24
+ requirement for fonts to remain under this license does not apply
25
+ to any document created using the fonts or their derivatives.
26
+
27
+ DEFINITIONS
28
+ "Font Software" refers to the set of files released by the Copyright
29
+ Holder(s) under this license and clearly marked as such. This may
30
+ include source files, build scripts and documentation.
31
+
32
+ "Reserved Font Name" refers to any names specified as such after the
33
+ copyright statement(s).
34
+
35
+ "Original Version" refers to the collection of Font Software components as
36
+ distributed by the Copyright Holder(s).
37
+
38
+ "Modified Version" refers to any derivative made by adding to, deleting,
39
+ or substituting -- in part or in whole -- any of the components of the
40
+ Original Version, by changing formats or by porting the Font Software to a
41
+ new environment.
42
+
43
+ "Author" refers to any designer, engineer, programmer, technical
44
+ writer or other person who contributed to the Font Software.
45
+
46
+ PERMISSION & CONDITIONS
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
49
+ redistribute, and sell modified and unmodified copies of the Font
50
+ Software, subject to the following conditions:
51
+
52
+ 1) Neither the Font Software nor any of its individual components,
53
+ in Original or Modified Versions, may be sold by itself.
54
+
55
+ 2) Original or Modified Versions of the Font Software may be bundled,
56
+ redistributed and/or sold with any software, provided that each copy
57
+ contains the above copyright notice and this license. These can be
58
+ included either as stand-alone text files, human-readable headers or
59
+ in the appropriate machine-readable metadata fields within text or
60
+ binary files as long as those fields can be easily viewed by the user.
61
+
62
+ 3) No Modified Version of the Font Software may use the Reserved Font
63
+ Name(s) unless explicit written permission is granted by the corresponding
64
+ Copyright Holder. This restriction only applies to the primary font name as
65
+ presented to the users.
66
+
67
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68
+ Software shall not be used to promote, endorse or advertise any
69
+ Modified Version, except to acknowledge the contribution(s) of the
70
+ Copyright Holder(s) and the Author(s) or with their explicit written
71
+ permission.
72
+
73
+ 5) The Font Software, modified or unmodified, in part or in whole,
74
+ must be distributed entirely under this license, and must not be
75
+ distributed under any other license. The requirement for fonts to
76
+ remain under this license does not apply to any document created
77
+ using the Font Software.
78
+
79
+ TERMINATION
80
+ This license becomes null and void if any of the above conditions are
81
+ not met.
82
+
83
+ DISCLAIMER
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ https://scripts.sil.org/OFL
6
+
7
+
8
+ -----------------------------------------------------------
9
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10
+ -----------------------------------------------------------
11
+
12
+ PREAMBLE
13
+ The goals of the Open Font License (OFL) are to stimulate worldwide
14
+ development of collaborative font projects, to support the font creation
15
+ efforts of academic and linguistic communities, and to provide a free and
16
+ open framework in which fonts may be shared and improved in partnership
17
+ with others.
18
+
19
+ The OFL allows the licensed fonts to be used, studied, modified and
20
+ redistributed freely as long as they are not sold by themselves. The
21
+ fonts, including any derivative works, can be bundled, embedded,
22
+ redistributed and/or sold with any software provided that any reserved
23
+ names are not used by derivative works. The fonts and derivatives,
24
+ however, cannot be released under any other type of license. The
25
+ requirement for fonts to remain under this license does not apply
26
+ to any document created using the fonts or their derivatives.
27
+
28
+ DEFINITIONS
29
+ "Font Software" refers to the set of files released by the Copyright
30
+ Holder(s) under this license and clearly marked as such. This may
31
+ include source files, build scripts and documentation.
32
+
33
+ "Reserved Font Name" refers to any names specified as such after the
34
+ copyright statement(s).
35
+
36
+ "Original Version" refers to the collection of Font Software components as
37
+ distributed by the Copyright Holder(s).
38
+
39
+ "Modified Version" refers to any derivative made by adding to, deleting,
40
+ or substituting -- in part or in whole -- any of the components of the
41
+ Original Version, by changing formats or by porting the Font Software to a
42
+ new environment.
43
+
44
+ "Author" refers to any designer, engineer, programmer, technical
45
+ writer or other person who contributed to the Font Software.
46
+
47
+ PERMISSION & CONDITIONS
48
+ Permission is hereby granted, free of charge, to any person obtaining
49
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
50
+ redistribute, and sell modified and unmodified copies of the Font
51
+ Software, subject to the following conditions:
52
+
53
+ 1) Neither the Font Software nor any of its individual components,
54
+ in Original or Modified Versions, may be sold by itself.
55
+
56
+ 2) Original or Modified Versions of the Font Software may be bundled,
57
+ redistributed and/or sold with any software, provided that each copy
58
+ contains the above copyright notice and this license. These can be
59
+ included either as stand-alone text files, human-readable headers or
60
+ in the appropriate machine-readable metadata fields within text or
61
+ binary files as long as those fields can be easily viewed by the user.
62
+
63
+ 3) No Modified Version of the Font Software may use the Reserved Font
64
+ Name(s) unless explicit written permission is granted by the corresponding
65
+ Copyright Holder. This restriction only applies to the primary font name as
66
+ presented to the users.
67
+
68
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69
+ Software shall not be used to promote, endorse or advertise any
70
+ Modified Version, except to acknowledge the contribution(s) of the
71
+ Copyright Holder(s) and the Author(s) or with their explicit written
72
+ permission.
73
+
74
+ 5) The Font Software, modified or unmodified, in part or in whole,
75
+ must be distributed entirely under this license, and must not be
76
+ distributed under any other license. The requirement for fonts to
77
+ remain under this license does not apply to any document created
78
+ using the Font Software.
79
+
80
+ TERMINATION
81
+ This license becomes null and void if any of the above conditions are
82
+ not met.
83
+
84
+ DISCLAIMER
85
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -1,15 +1,19 @@
1
1
  # Bundled fonts
2
2
 
3
3
  The `.woff2` files in this directory are redistributed with CozyClay under the
4
- SIL Open Font License 1.1, which permits bundling them with software provided
5
- each copy carries the copyright notice and the licence. Those are the two
6
- `-OFL.txt` files here; keep them alongside the fonts.
4
+ SIL Open Font License 1.1. Each family has its upstream OFL text beside the
5
+ font files. The existing Inter and Instrument Serif files remain until their
6
+ later cleanup todo.
7
7
 
8
- | File | Family | Copyright | Licence |
9
- | --- | --- | --- | --- |
10
- | `inter-latin.woff2` | [Inter](https://github.com/rsms/inter) | Copyright (c) 2016 The Inter Project Authors | [OFL-1.1](Inter-OFL.txt) |
11
- | `instrument-serif-latin.woff2`, `instrument-serif-italic-latin.woff2` | [Instrument Serif](https://github.com/Instrument/instrument-serif) | Copyright 2022 The Instrument Serif Project Authors | [OFL-1.1](InstrumentSerif-OFL.txt) |
8
+ | Files | Family | Upstream release | Copyright | Licence |
9
+ | --- | --- | --- | --- | --- |
10
+ | `ibm-plex-sans-400-latin.woff2`, `ibm-plex-sans-500-latin.woff2`, `ibm-plex-sans-600-latin.woff2` | IBM Plex Sans | [`@ibm/plex-sans@1.1.0`](https://github.com/IBM/plex/releases/tag/%40ibm/plex-sans%401.1.0) ([asset](https://github.com/IBM/plex/releases/download/%40ibm/plex-sans%401.1.0/ibm-plex-sans.zip)) | Copyright (c) 2017 IBM Corp. with Reserved Font Name "Plex" | [OFL-1.1](IBM-Plex-Sans-OFL.txt) |
11
+ | `jetbrains-mono-400-latin.woff2`, `jetbrains-mono-500-latin.woff2` | JetBrains Mono | [`v2.304`](https://github.com/JetBrains/JetBrainsMono/releases/tag/v2.304) ([asset](https://github.com/JetBrains/JetBrainsMono/releases/download/v2.304/JetBrainsMono-2.304.zip)) | Copyright 2020 The JetBrains Mono Project Authors | [OFL-1.1](JetBrains-Mono-OFL.txt) |
12
+ | `inter-latin.woff2` | [Inter](https://github.com/rsms/inter) | existing bundle | Copyright (c) 2016 The Inter Project Authors | [OFL-1.1](Inter-OFL.txt) |
13
+ | `instrument-serif-latin.woff2`, `instrument-serif-italic-latin.woff2` | [Instrument Serif](https://github.com/Instrument/instrument-serif) | existing bundle | Copyright 2022 The Instrument Serif Project Authors | [OFL-1.1](InstrumentSerif-OFL.txt) |
12
14
 
13
- Both are subsets. Under OFL a modified copy may not use the Reserved Font Name,
14
- so if a subset is ever renamed or edited beyond subsetting, check clause 3 before
15
+ The IBM Plex Sans files are the upstream Latin1 webfont subsets. Korean text
16
+ continues through the Pretendard and Noto Sans KR fallbacks in `--sans`.
17
+ Under the OFL, a modified copy may not use the Reserved Font Name, so if a
18
+ subset is ever renamed or edited beyond subsetting, check clause 3 before
15
19
  shipping it.
package/dist/index.html CHANGED
@@ -272,9 +272,9 @@
272
272
  header.site nav { gap: 14px; width: 100%; margin-left: 0; padding-bottom: 10px; }
273
273
  }
274
274
  </style>
275
- <script type="module" crossorigin src="/assets/landing-IbRp3FnQ.js"></script>
276
- <link rel="modulepreload" crossorigin href="/assets/analytics-B1hnH66c.js">
277
- <link rel="modulepreload" crossorigin href="/assets/first-shot-handoff-CGgnvNu8.js">
275
+ <script type="module" crossorigin src="/assets/landing-BaXkpFip.js"></script>
276
+ <link rel="modulepreload" crossorigin href="/assets/analytics-MVZOEW8O.js">
277
+ <link rel="modulepreload" crossorigin href="/assets/first-shot-handoff-DgT28ZiV.js">
278
278
  </head>
279
279
  <body>
280
280
  <header class="site">
@@ -331,7 +331,7 @@
331
331
  <a class="btn ghost" href="https://github.com/NomaDamas/CozyClay">View on GitHub</a>
332
332
  </div>
333
333
  <p class="note">
334
- Or run it on your machine: <code>npx cozyclay</code>. No Blender, no Unity. Open a saved <code>.cclayproject</code> from the first dialog.
334
+ Or run it on your machine: <code>npx cozyclay --via site</code>. No Blender, no Unity. Open a saved <code>.cclayproject</code> from the first dialog.
335
335
  </p>
336
336
  </div>
337
337
 
@@ -343,7 +343,7 @@
343
343
  <button class="playground-cover" id="playground-start" type="button" aria-label="Start the playground">
344
344
  <span class="btn primary">Play with the scene</span>
345
345
  <small>Loads the studio in this box (about 2 MB)</small>
346
- <span class="playground-phone">Needs a mouse and keyboard. Come back on a computer, or run <code>npx cozyclay</code>.</span>
346
+ <span class="playground-phone">Needs a mouse and keyboard. Come back on a computer, or run <code>npx cozyclay --via site</code>.</span>
347
347
  </button>
348
348
  <div class="playground-loading">Loading the studio…</div>
349
349
  <div class="tutorial-card" id="tutorial-card" aria-live="polite">
@@ -354,7 +354,7 @@
354
354
  <div class="playground-bar">
355
355
  <div class="tutorial-done" id="tutorial-done" hidden>
356
356
  <p>Take your shot with you. Video export is not offered in this embedded Playground.</p>
357
- <p>Download your edited project, run <code>npx cozyclay</code>, and open the downloaded <code>.cclayproject</code> in the local Studio. Use its existing Export menu for video.</p>
357
+ <p>Download your edited project, run <code>npx cozyclay --via playground</code>, and open the downloaded <code>.cclayproject</code> in the local Studio. Use its existing Export menu for video.</p>
358
358
  <button type="button" id="playground-download" class="copy">Download my project</button>
359
359
  <button type="button" id="playground-handoff-dismiss">Continue editing</button>
360
360
  </div>
@@ -392,7 +392,7 @@
392
392
  <section id="start">
393
393
  <h2>Quick start</h2>
394
394
  <p class="sub">Node.js 22.13+ and a Chromium browser.</p>
395
- <pre class="with-copy"><code>npx cozyclay</code><button type="button" class="copy" data-copy="npx cozyclay">Copy</button></pre>
395
+ <pre class="with-copy"><code>npx cozyclay --via site</code><button type="button" class="copy" data-copy="npx cozyclay --via site">Copy</button></pre>
396
396
  <p class="sub">Or from source:</p>
397
397
  <pre><code>git clone https://github.com/NomaDamas/CozyClay.git
398
398
  cd CozyClay
@@ -85,6 +85,8 @@
85
85
  CLI restarts, ports and browser storage resets. The browser's memory-only SDK starts with this
86
86
  anonymous ID on each launch. Independent state files receive independent random IDs, without
87
87
  fingerprinting, account linking or cross-device matching; do not copy the state file between users.
88
+ A copied start command such as <code>npx cozyclay --via site</code> stores that one source label
89
+ with the first-launch receipt instead of asking where you heard about CozyClay.
88
90
  Prompt text, asset names,
89
91
  file names, project content, local paths and any user-entered text are never collected. Session
90
92
  duration and action counts are bucketed. Source checkouts, forks, development servers, CI and tests
@@ -129,20 +131,20 @@ cclay telemetry on</code></pre>
129
131
  <table>
130
132
  <thead><tr><th>Event</th><th>Purpose</th></tr></thead>
131
133
  <tbody>
132
- <tr><td>install:first_launch, app:session_started, app:session_ended</td><td>Counting installs and sessions; duration and action counts are bucketed</td></tr>
133
- <tr><td>feature:used</td><td>One signal per feature per session</td></tr>
134
+ <tr><td>install:first_launch, app:session_started, app:session_ended</td><td>Counting installs and sessions; duration and action counts are bucketed. install:first_launch may carry heard_from (x, hn, reddit, github, friend, other, site or playground), from the first-launch prompt or a copied <code>npx cozyclay --via</code> command. app:session_ended also carries per-session edit gesture counts in five groups, pose_edit_bucket, camera_edit_bucket, object_edit_bucket, shot_edit_bucket and prompt_edit_bucket, each bucketed (0, 1-3, 4-10 or gte11); never what was edited</td></tr>
135
+ <tr><td>feature:used</td><td>One signal per feature per session: a fixed feature name such as pose_edit (a real bone or pose change), pose_save (saving a pose to the library), fal_motion_open (opening the AI video A/B card), camera_fly or export_video</td></tr>
134
136
  <tr><td>$pageview, scene:created, scene:loaded, craft:first_action, activation:completed</td><td>Funnel and drop-off analysis</td></tr>
135
137
  <tr><td>craft:first_edit</td><td>First successful Studio authoring change per editor mount; only a fixed edit-kind label and definition version 1 (not camera navigation, playback, loading, restore, or undo/redo)</td></tr>
136
138
  <tr><td>playground:first_edit</td><td>The same versioned first-edit definition for Playground, counted separately from Studio; no prompts or scene contents</td></tr>
137
139
  <tr><td>project:saved, project:opened</td><td>Whether people keep their work (object counts and ages are bucketed; never names or paths)</td></tr>
138
140
  <tr><td>motion:backend_state</td><td>Session capability baseline: backend (none, local_kimodo or hosted) and boolean host_configured, never a host address</td></tr>
139
- <tr><td>motion:generate_requested</td><td>Explicit generation intent, not prompt-block editing: initiating surface (timeline, line_edit, trail or mcp), input_mode (prompt, pose or edit) and an ephemeral random request_id</td></tr>
140
- <tr><td>motion:preflight_blocked</td><td>Request readiness refusal: request_id, surface and normalized reason (unconfigured, unreachable or unsupported_route)</td></tr>
141
- <tr><td>motion:preflight_passed</td><td>Request readiness accepted, before job start: request_id, surface and backend (none, local_kimodo or hosted)</td></tr>
141
+ <tr><td>motion:generate_requested</td><td>Explicit generation intent, not prompt-block editing: initiating surface (timeline, line_edit, trail, mcp, fal_card or agent), input_mode (prompt, pose, edit, a_to_b or still) and an ephemeral random request_id</td></tr>
142
+ <tr><td>motion:preflight_blocked</td><td>Request readiness refusal: request_id, surface and normalized reason (unconfigured, unreachable, unsupported_route, locked or missing_input). locked means the AI video route is not enabled for the account yet; missing_input means the A/B captures were incomplete</td></tr>
143
+ <tr><td>motion:preflight_passed</td><td>Request readiness accepted, before job start: request_id, surface and backend (none, local_kimodo, hosted or fal)</td></tr>
142
144
  <tr><td>motion:job_started</td><td>Generation execution started: request_id, backend and input_mode</td></tr>
143
145
  <tr><td>motion:job_succeeded</td><td>Generation completed before result application: request_id, backend, input_mode and bucketed duration_bucket (lt1s, 1-3s, 3-10s, 10-30s or gte30s)</td></tr>
144
- <tr><td>motion:job_failed</td><td>Generation failure or real cancellation: request_id, backend, input_mode, duration_bucket and normalized error_code (aborted, unsupported_route, generation_failed or unknown), never raw error messages</td></tr>
145
- <tr><td>motion:result_applied</td><td>A generated result was applied to its requesting character: request_id and backend. Job success alone does not prove application.</td></tr>
146
+ <tr><td>motion:job_failed</td><td>Generation failure or real cancellation: request_id, backend, input_mode, duration_bucket and normalized error_code (aborted, unsupported_route, generation_failed, quota or unknown), never raw error messages</td></tr>
147
+ <tr><td>motion:result_applied</td><td>A generated result was applied to its requesting character: request_id and backend. For the fal AI video route, applied means the generated clip was loaded into the Studio for extraction. Job success alone does not prove application.</td></tr>
146
148
  <tr><td>workflow:run_requested</td><td>Workflow execution requests: surface (workflow), ephemeral run_id and node_count_bucket (0, 1-3, 4-10 or gte11). No graph contents, node labels or outputs.</td></tr>
147
149
  <tr><td>workflow:run_succeeded, workflow:run_failed, workflow:run_cancelled</td><td>Workflow outcomes paired by run_id, with duration_bucket (lt1s, 1-3s, 3-10s, 10-30s or gte30s); failures and actual cancellations also include failure_code (aborted, capture_failed, generation_failed or unknown). Starting another run does not imply cancellation.</td></tr>
148
150
  <tr><td>workflow:result_applied</td><td>Captured or generated image/video output was written to the Workflow canvas: run_id only, at most once per run, independently of a later failure. No image bytes or output contents.</td></tr>
@@ -157,6 +159,9 @@ cclay telemetry on</code></pre>
157
159
  <tr><td>export:attempt_started, export:attempt_succeeded, export:attempt_failed, export:attempt_cancelled</td><td>Export attempts and outcomes, paired by an ephemeral random attempt_id; export_kind (video, depth_video, frame or keyframe_pack), format (mp4, png or zip) and initiating surface (studio, workflow or embed). Terminal events include a bucketed duration_bucket; failures and real cancellations include only a normalized failure_code (unsupported_codec, encode_failed, render_failed, aborted or unknown), never raw error messages, filenames, URLs, paths, prompts or scene content. Success means pipeline completion or download handoff, not confirmation that the OS saved a file.</td></tr>
158
160
  <tr><td>export:keyframe_pack</td><td>Legacy Workflow pack handoffs, with numeric entries count and source=workflow; not an additional export attempt</td></tr>
159
161
  <tr><td>playground:opened, playground:first_action</td><td>Whether the home-page playground gets used</td></tr>
162
+ <tr><td>app:error</td><td>Uncaught errors and unhandled promise rejections, at most ten distinct per session: error_kind (error or unhandled_rejection), error_type (a built-in name such as TypeError or DOMException, other or non_error), error_source (app, extension, external or unknown) and, only for the app's own scripts, error_file (the bundle file name), error_line and error_col. Never the error message, stack text, URLs, query strings, paths, prompts or scene content.</td></tr>
163
+ <tr><td>device:profile</td><td>Once per session, whether the studio can run smoothly: gpu_vendor (nvidia, amd, intel, apple, qualcomm, arm, software, other or unknown), gpu_class (discrete, integrated, software or unknown), webgl (webgl2, webgl1 or none), cpu_bucket (1-4, 5-8, 9-16, gte17 or unknown), memory_bucket (lt4, 4-7, gte8 or unknown) and frame_rate_bucket (lt20, 20-40, 40-55, gte55 or unknown) from one three-second sample. The GPU renderer string and exact hardware values never leave the browser.</td></tr>
164
+ <tr><td>survey:use_case</td><td>An optional question shown at most once after a successful export, only while telemetry is on: use_case (animation, film, game, ad_mv, personal, other or skip) and team (team, solo or skip). Closed choices only; no free text.</td></tr>
160
165
  <tr><td>hosted:composer_viewed, hosted:login_started, hosted:ticket_created, hosted:result_opened, hosted:opened_in_studio</td><td>Hosted demo funnel</td></tr>
161
166
  <tr><td>tutorial:started</td><td>Camera tutorial attempts on surface (studio or playground), with numeric tutorial_version 1 and start_source (query, settings or landing). Restarting starts a new attempt; no tutorial attempt identifier or user text is sent.</td></tr>
162
167
  <tr><td>tutorial:step_entered, tutorial:dismissed</td><td>Entered steps and explicit dismissal of an unfinished tutorial; surface (studio or playground), numeric tutorial_version 1 and step_kind (fly, walk, dolly, orbit, shot, rail or play). Missing completion can indicate abandonment or missing telemetry; browser close does not promise a dismissal event.</td></tr>
@@ -166,7 +171,7 @@ cclay telemetry on</code></pre>
166
171
  </table>
167
172
  </div>
168
173
  <p class="note">Motion request_id values are fresh random 32-character hexadecimal values, held only for one request; they are not persisted or derived from prompts, hosts, credentials, project content or other identifiers. The ambiguous motion:generate_blocked event stopped being emitted in the September 15, 2026 issue #273 contract. Historical events are not relabeled and are excluded from the new explicit-demand metric. Automatic line previews and prompt-block edits are not explicit Generate requests.</p>
169
- <p class="note">Every regular app event and session-end beacon carries the same distribution (npm or hosted), app_version when available, origin_kind (local or hosted), internal_qa boolean, coarse operating-system label and, for npm sessions, install_kind (npx or global). PostHog's free plan retains events for one year.</p>
174
+ <p class="note">Every regular app event and session-end beacon carries the same distribution (npm or hosted), app_version when available, origin_kind (local or hosted), internal_qa boolean, coarse operating-system label and, for npm sessions, install_kind (npx or global) and update_status (latest, outdated or unknown), read from the package's own cached update check. PostHog's free plan retains events for one year.</p>
170
175
  <p class="note">Workflow run_id, Agent turn_id and MCP request_id values are fresh random 32-character hexadecimal values held only for one execution. Execution telemetry contains only closed categories, outcomes and elapsed-time buckets; missing telemetry is left unknown, and a disconnected MCP editor is not backfilled.</p>
171
176
  </section>
172
177
 
package/dist/sitemap.xml CHANGED
@@ -2,26 +2,26 @@
2
2
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
3
  <url>
4
4
  <loc>https://cozyclay.org/</loc>
5
- <lastmod>2026-09-15</lastmod>
5
+ <lastmod>2026-10-01</lastmod>
6
6
  </url>
7
7
  <url>
8
8
  <loc>https://cozyclay.org/greybox-to-video/</loc>
9
- <lastmod>2026-09-14</lastmod>
9
+ <lastmod>2026-10-01</lastmod>
10
10
  </url>
11
11
  <url>
12
12
  <loc>https://cozyclay.org/previs-software/</loc>
13
- <lastmod>2026-09-10</lastmod>
13
+ <lastmod>2026-10-01</lastmod>
14
14
  </url>
15
15
  <url>
16
16
  <loc>https://cozyclay.org/seedance-camera-control/</loc>
17
- <lastmod>2026-09-10</lastmod>
17
+ <lastmod>2026-10-01</lastmod>
18
18
  </url>
19
19
  <url>
20
20
  <loc>https://cozyclay.org/ai-camera-control/</loc>
21
- <lastmod>2026-09-10</lastmod>
21
+ <lastmod>2026-10-01</lastmod>
22
22
  </url>
23
23
  <url>
24
24
  <loc>https://cozyclay.org/privacy/</loc>
25
- <lastmod>2026-09-15</lastmod>
25
+ <lastmod>2026-10-01</lastmod>
26
26
  </url>
27
27
  </urlset>
@@ -8,12 +8,12 @@
8
8
  <meta name="theme-color" content="#101116" />
9
9
  <meta name="description" content="CozyClay visual workflow builder" />
10
10
  <title>CozyClay Workflow</title>
11
- <script type="module" crossorigin src="/assets/workflow-CVwzMhz2.js"></script>
11
+ <script type="module" crossorigin src="/assets/workflow-dNPGY9xz.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-hePW80VL.js">
13
- <link rel="modulepreload" crossorigin href="/assets/analytics-B1hnH66c.js">
14
- <link rel="modulepreload" crossorigin href="/assets/shot-prompt-CHUtw6af.js">
15
- <link rel="stylesheet" crossorigin href="/assets/shot-prompt-C_g2BHVc.css">
16
- <link rel="stylesheet" crossorigin href="/assets/workflow-DsudxKHF.css">
13
+ <link rel="modulepreload" crossorigin href="/assets/analytics-MVZOEW8O.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/shot-prompt-Yrt99wZx.js">
15
+ <link rel="stylesheet" crossorigin href="/assets/shot-prompt-CbqWcWYi.css">
16
+ <link rel="stylesheet" crossorigin href="/assets/workflow-DRdwoDBT.css">
17
17
  </head>
18
18
  <body>
19
19
  <div id="workflow-root"></div>
@@ -153,7 +153,7 @@ scene document already uses.
153
153
  | `remove_character` | `{ ref }` | `{ id }` | must refuse to empty the cast |
154
154
  | `place_object` | `{ kind, x?, z?, y?, rot?, name?, parent? }` | `{ id }` | `kind` from OBJECT_LIBRARY; optional `name` labels the object and optional `parent` attaches it under another object |
155
155
  | `import_asset` | `{ name, mimeType, dataUrl, placeAs, clay?, x?, y?, z?, rot?, height? }` | `{ assetId, objectId }` | decode `dataUrl` and store the bytes in the content-addressed asset store under `assetId`, then stand the result up through the Studio's own import pipeline. `placeAs: "cutout"` is a 1.8 m standee 2.6 m in front of the shot camera; `placeAs: "backdrop"` is the same card as a 5 m background plate 12 m down the shot camera's view ray, turned to face the lens (PNG, WebP, JPEG or GIF; `dataUrl` must be `data:image/…`; `mimeType` optional when the data URL carries it). `placeAs: "mesh"` imports a GLB, a Wavefront OBJ or an FBX (`data:model/gltf-binary`, `data:model/obj`, `data:model/fbx`, `data:text/plain` when `name` ends in `.obj` or `.fbx`, or `data:application/octet-stream`, and those same types as `mimeType`), fits height/footprint once, and stands the model on the floor. Omit both `x` and `z` to place it in front of the shot camera; if either is present, those are world metres and the missing axis is 0. Optional `rot` is yaw in degrees (omitted is 0, like the Import button). Optional `height` overrides the fitted standing size. Optional `y` is lift off the floor, applied after mint (`createMeshObject` always writes `y: 0`). Optional `clay: true` replaces file materials with matte clay. Bytes decide the format (glTF magic first, then FBX magic/`FBXVersion:`, then OBJ vertices). Exactly ONE undo entry: a single Ctrl+Z removes the placed object (the asset bytes stay, being content-addressed). This deliberately does NOT reuse the Workflow-tab scene sync, which writes the document without touching undo. |
156
- | `update_object` | `{ id, x?, y?, z?, rot?, rotX?, rotZ?, scale?, scaleX?, scaleY?, scaleZ?, color?, name?, height?, clay? }` | `{ id }` | `scale` sets all three axes; per-axis values override it; `name` renames the object. `height` is metres (cutout card height, or a mesh's fitted box height). `clay` is a boolean on mesh objects (file materials when false, matte clay when true). |
156
+ | `update_object` | `{ id, x?, y?, z?, rot?, rotX?, rotZ?, scale?, scaleX?, scaleY?, scaleZ?, color?, name?, height?, clay?, hidden? }` | `{ id }` | `scale` sets all three axes; per-axis values override it; `name` renames the object. `height` is metres (cutout card height, or a mesh's fitted box height). `clay` is a boolean on mesh objects (file materials when false, matte clay when true). `hidden` shows or hides the prop without deleting it. |
157
157
  | `remove_object` | `{ id }` | `{ id }` | |
158
158
  | `group_objects` | `{ parent, children }` | `{ parent, children }` | attach every child under parent |
159
159
  | `ungroup_objects` | `{ children }` | `{ children }` | detach every child |
package/mcp/live-hub.mjs CHANGED
@@ -7,98 +7,19 @@ import { mcpToolCategory } from "../src/execution-telemetry.js";
7
7
  import { WebSocket, WebSocketServer } from "ws";
8
8
 
9
9
  export const DEFAULT_COMMAND_TIMEOUT_MS = 5_000;
10
- /** A per-call override may extend a command, never past this ceiling: a hub
11
- * that waits longer than this can no longer tell a slow editor from a dead one. */
10
+ /** A per-call override may extend a non-motion command, never past this ceiling. */
12
11
  export const MAX_COMMAND_TIMEOUT_MS = 300_000;
13
12
  export const DEFAULT_HEARTBEAT_MS = 15_000;
14
13
  export const RUN_WORKFLOW_TIMEOUT_MS = 180_000;
15
14
  export const LOAD_MOTION_TIMEOUT_MS = 30_000;
16
15
  export const IMPORT_ASSET_TIMEOUT_MS = 30_000;
17
16
  export const CAPTURE_FRAME_TIMEOUT_MS = 30_000;
18
- export const MOTION_JOB_TTL_MS = 10 * 60_000;
19
- export const MOTION_JOB_POLL_INTERVAL_MS = 0;
20
- export const MAX_ACTIVE_MOTION_JOBS = 2;
21
- export const MAX_ACTIVE_MOTION_JOBS_PER_WORKSPACE = 1;
22
-
23
- const terminalMotionStatuses = new Set(["completed", "failed", "cancelled", "expired"]);
24
-
25
- /** MCP-internal job retention for push-only motion work. Its clock is injected
26
- * so expiry is deterministic without a polling loop or timing-based test. */
27
- export class MotionJobRegistry {
28
- constructor({ clock = () => Date.now(), ttlMs = MOTION_JOB_TTL_MS } = {}) {
29
- this.clock = clock;
30
- this.ttlMs = ttlMs;
31
- this.jobs = new Map();
32
- }
33
-
34
- create(workspaceId) {
35
- this.cleanup();
36
- const active = [...this.jobs.values()].filter((job) => !terminalMotionStatuses.has(job.status));
37
- if (active.length >= MAX_ACTIVE_MOTION_JOBS) throw new Error(`Motion job capacity reached (${MAX_ACTIVE_MOTION_JOBS} active globally).`);
38
- if (active.filter((job) => job.workspaceId === workspaceId).length >= MAX_ACTIVE_MOTION_JOBS_PER_WORKSPACE) {
39
- throw new Error(`This workspace already has an active motion job.`);
40
- }
41
- const now = this.clock();
42
- const job = {
43
- taskId: randomUUID(), workspaceId, status: "queued", createdAt: now,
44
- lastUpdatedAt: now, ttlMs: this.ttlMs, pollIntervalMs: MOTION_JOB_POLL_INTERVAL_MS,
45
- cancel: null, expiresAt: null, outcome: null,
46
- deliveredWorkspaceIds: new Set(),
47
- installationStates: new Map(),
48
- };
49
- this.jobs.set(job.taskId, job);
50
- return job;
51
- }
52
-
53
- task(job) {
54
- return {
55
- taskId: job.taskId, status: job.status, createdAt: job.createdAt,
56
- lastUpdatedAt: job.lastUpdatedAt, ttlMs: job.ttlMs, pollIntervalMs: job.pollIntervalMs,
57
- };
58
- }
59
-
60
- transition(job, status, outcome = null) {
61
- this.cleanup();
62
- job.status = status;
63
- job.lastUpdatedAt = this.clock();
64
- job.outcome = outcome;
65
- job.expiresAt = terminalMotionStatuses.has(status) ? job.lastUpdatedAt + job.ttlMs : null;
66
- if (job.expiresAt !== null) {
67
- const timer = setTimeout(() => this.cleanup(), job.ttlMs);
68
- timer.unref?.();
69
- }
70
- return this.task(job);
71
- }
72
-
73
- cancel(taskId, workspaceId) {
74
- this.cleanup();
75
- const job = this.jobs.get(taskId);
76
- if (!job || job.workspaceId !== workspaceId || terminalMotionStatuses.has(job.status)) return null;
77
- job.cancel?.();
78
- return this.transition(job, "cancelled", { message: "Generation cancelled before editor delivery." });
79
- }
80
-
81
- forWorkspace(workspaceId) {
82
- this.cleanup();
83
- return [...this.jobs.values()].filter((job) =>
84
- job.workspaceId === workspaceId && terminalMotionStatuses.has(job.status) && job.status !== "expired" && !job.deliveredWorkspaceIds.has(workspaceId));
85
- }
86
-
87
- cleanup() {
88
- const now = this.clock();
89
- for (const job of this.jobs.values()) {
90
- if (job.expiresAt === null || now < job.expiresAt) continue;
91
- if (job.status === "expired") {
92
- this.jobs.delete(job.taskId);
93
- continue;
94
- }
95
- job.status = "expired";
96
- job.lastUpdatedAt = now;
97
- job.outcome = { message: "Motion job outcome expired before this workspace reconnected." };
98
- job.expiresAt = now + job.ttlMs;
99
- }
100
- }
101
- }
17
+ export const STUDIO_COMMAND_TIMEOUT_MS = 30_000;
18
+ const studioCommands = new Set([
19
+ "inspect_studio", "operate_studio", "arrange_objects", "arrange_characters", "patch_elements",
20
+ "frame_shot", "verify_result", "undo_edit", "read_studio_context", "resolve_studio_image",
21
+ "capture_framing_png", "reconcile_studio_command", "run_action",
22
+ ]);
102
23
 
103
24
  const mutationCommands = new Set([
104
25
  "set_camera",
@@ -114,8 +35,8 @@ const mutationCommands = new Set([
114
35
  "set_prompt_blocks",
115
36
  "load_motion",
116
37
  "load_scenes",
117
- "operate_studio", "arrange_objects", "arrange_characters", "patch_elements", "frame_shot", "undo_edit",
118
- "commit_motion_candidate", "import_asset",
38
+ "operate_studio", "arrange_objects", "arrange_characters", "patch_elements", "frame_shot", "undo_edit", "run_action",
39
+ "import_asset",
119
40
  ]);
120
41
 
121
42
  export class LiveMutationUncertainError extends Error {
@@ -217,8 +138,7 @@ export class LiveHub {
217
138
  }
218
139
 
219
140
  static commandTimeoutMs(name) {
220
- if (name === "load_motion" || name === "prepare_motion_install") return LOAD_MOTION_TIMEOUT_MS;
221
- if (name === "verify_motion_candidate" || name === "repair_motion_candidate") return 60_000;
141
+ if (name === "load_motion") return LOAD_MOTION_TIMEOUT_MS;
222
142
  // A 32 MiB mesh as a data URL will not decode, store and stand in 5 s.
223
143
  if (name === "import_asset") return IMPORT_ASSET_TIMEOUT_MS;
224
144
  // Close two-person shots (OTS) raycast two skinned rigs over a full-frame
@@ -226,6 +146,7 @@ export class LiveHub {
226
146
  if (name === "capture_frame") return CAPTURE_FRAME_TIMEOUT_MS;
227
147
  // A workflow run captures a frame and may generate an image upstream.
228
148
  if (name === "run_workflow") return RUN_WORKFLOW_TIMEOUT_MS;
149
+ if (studioCommands.has(name)) return STUDIO_COMMAND_TIMEOUT_MS;
229
150
  return DEFAULT_COMMAND_TIMEOUT_MS;
230
151
  }
231
152
 
@@ -284,6 +205,7 @@ export class LiveHub {
284
205
  let appliedEmitted = false;
285
206
  let failure = null;
286
207
  let description;
208
+ let studioContext;
287
209
  let mutation;
288
210
  let acknowledgedMutation = false;
289
211
  const emitApplied = () => {
@@ -294,14 +216,30 @@ export class LiveHub {
294
216
  const observer = {
295
217
  hub: this, handle,
296
218
  before(command) {
297
- if (!LiveHub.commandMayMutate(command) || command === "load_motion") return false;
219
+ if (!LiveHub.commandMayMutate(command) || command === "load_motion" || command === "run_action") return false;
298
220
  mutation = { name: command, before: mutationState(command, description), acknowledged: false };
299
221
  description = undefined;
300
222
  return mutation.before === undefined;
301
223
  },
302
224
  baseline(value) { if (mutation) mutation.before = mutationState(mutation.name, value); },
303
225
  receipt(command, value) {
304
- if (command === "describe") {
226
+ if (command === "inspect_studio") {
227
+ studioContext = value?.context;
228
+ } else if (command === "run_action") {
229
+ // The bus attests application itself. No legacy describe diff or
230
+ // post-ack read may turn an admitted refusal into uncertainty.
231
+ if (value?.ok === false) {
232
+ failure = value.mutated === "unknown" || value.code === "UNCERTAIN_APPLY" ? "uncertain" : "failed";
233
+ } else if (value?.ok === true) {
234
+ acknowledgedMutation = true;
235
+ // A journal replay has already reached its after revision; it
236
+ // does not count as another application on this invocation.
237
+ if (studioContext && ((value.authored && value.revision.after > studioContext.revision.scene) ||
238
+ (value.nextHost && ["workspaceId", "documentEpoch", "sceneId", "sceneEpoch"].some(key => value.nextHost[key] !== studioContext.host[key])))) applied = true;
239
+ if (value.output?.rolledBack === true || value.output?.failed?.length > 0) failure = "failed";
240
+ }
241
+ studioContext = undefined;
242
+ } else if (command === "describe") {
305
243
  if (mutation?.acknowledged && !mutation.rolledBack) {
306
244
  const after = mutationState(mutation.name, value);
307
245
  if (mutation.before !== undefined && after !== undefined && !isDeepStrictEqual(mutation.before, after)) applied = true;
@@ -336,6 +274,7 @@ export class LiveHub {
336
274
  emitApplied();
337
275
  // Never retain scene data with an asynchronous motion job.
338
276
  description = undefined;
277
+ studioContext = undefined;
339
278
  mutation = null;
340
279
  });
341
280
  emit("mcp:tool_requested", { request_id: requestId, tool_category: category });
@@ -389,6 +328,8 @@ export class LiveHub {
389
328
  if (!socket || socket.readyState !== WebSocket.OPEN) throw hubError("STALE_HANDLE", `Unknown or stale live workspace handle "${handle}".`);
390
329
 
391
330
  const id = randomUUID();
331
+ // The caller's per-call deadline (a controller frame's timeoutMs, or a
332
+ // command's declared one), capped at the ceiling; else the name's default.
392
333
  const bound = Number.isFinite(timeoutMs) && timeoutMs > 0
393
334
  ? Math.min(timeoutMs, MAX_COMMAND_TIMEOUT_MS)
394
335
  : LiveHub.commandTimeoutMs(name);
@@ -401,7 +342,8 @@ export class LiveHub {
401
342
  : hubError("TIMEOUT", message);
402
343
  reject(error);
403
344
  }, bound);
404
- this.pending.set(id, { name, socket, resolve, reject, timer });
345
+ // Each waiting frame keeps the deadline it runs under.
346
+ this.pending.set(id, { name, socket, resolve, reject, timer, timeoutMs: bound });
405
347
  try {
406
348
  socket.send(JSON.stringify({ type: "cmd", id, name, args }));
407
349
  } catch (error) {