topview-3d-cli 0.1.0__py3-none-any.whl

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 (332) hide show
  1. topview_3d_cli/__init__.py +3 -0
  2. topview_3d_cli/__main__.py +5 -0
  3. topview_3d_cli/_runtime/builtin-assets/LICENSE +396 -0
  4. topview_3d_cli/_runtime/builtin-assets/NOTICE +24 -0
  5. topview_3d_cli/_runtime/builtin-assets/characters/a3d_char_30ec53c93eae4173946b38639691ebe0.glb +0 -0
  6. topview_3d_cli/_runtime/builtin-assets/characters/a3d_char_461b4f4b76ae4b198f439fa4f6f743b6.glb +0 -0
  7. topview_3d_cli/_runtime/builtin-assets/characters/a3d_char_7d220ac359844c80a8faaf0e25478477.glb +0 -0
  8. topview_3d_cli/_runtime/builtin-assets/characters/a3d_char_de37873a79244fbe8a0660ea08d1b4ab.glb +0 -0
  9. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-attack-jab.webp +0 -0
  10. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-attack-lunge.webp +0 -0
  11. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-attack-rear.webp +0 -0
  12. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-crawling-forward-reaching-with-le.webp +0 -0
  13. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-exaggerated-punch-with-right-hand.webp +0 -0
  14. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-examine-fwd.webp +0 -0
  15. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-holding-bow.webp +0 -0
  16. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-jab-with-right-hand.webp +0 -0
  17. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-on-hands-and-toes-right-leg-forwa.webp +0 -0
  18. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-on-right-leg.webp +0 -0
  19. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-push-up.webp +0 -0
  20. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-pushing-backwards.webp +0 -0
  21. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-pushing-with-both-hands.webp +0 -0
  22. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-pushing-with-left-side-of-body.webp +0 -0
  23. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_action-sliding.webp +0 -0
  24. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-arms-spread-looking-upwards.webp +0 -0
  25. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-examine-fwd.webp +0 -0
  26. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-lean-fwd-right-hand-supporting.webp +0 -0
  27. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-leaning-against-object-look-l.webp +0 -0
  28. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-look-back.webp +0 -0
  29. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-look-down-back.webp +0 -0
  30. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-look-fwd-f.webp +0 -0
  31. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-look-fwd-m.webp +0 -0
  32. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-on-knees-arms-up.webp +0 -0
  33. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_crouch-sneaking.webp +0 -0
  34. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-l-toe-top-of-right-foot.webp +0 -0
  35. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-legs-spread-lean-l.webp +0 -0
  36. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-legs-spread-lean-r.webp +0 -0
  37. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-legs-x.webp +0 -0
  38. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-r-foot-arms-extended-backwards.webp +0 -0
  39. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-r-toe-arms-up.webp +0 -0
  40. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-r-toe-l-leg-up.webp +0 -0
  41. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-toes-arch.webp +0 -0
  42. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dance-toes-reach.webp +0 -0
  43. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dyn-floating-bent-forwards.webp +0 -0
  44. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dyn-floating-left-leg-bent-hands-spread.webp +0 -0
  45. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dyn-floating-legs-bent-and-arms-spread.webp +0 -0
  46. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dyn-floating-legs-raised-arms-extended-u.webp +0 -0
  47. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dyn-l-toe-look-l.webp +0 -0
  48. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dyn-leaping-forward-arms-extended-backwa.webp +0 -0
  49. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dynamic-float-arch.webp +0 -0
  50. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_dynamic-float-dive.webp +0 -0
  51. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-back-arched-arms-supp.webp +0 -0
  52. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-legs-to-side-arms-up.webp +0 -0
  53. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-legs-x-arms-supp.webp +0 -0
  54. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-back-left-leg-bent-hands-head.webp +0 -0
  55. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-back-left-leg-bent.webp +0 -0
  56. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-back-legs-x-hands-head.webp +0 -0
  57. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-left-side-left-arm-supporting-hea.webp +0 -0
  58. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-left-side-left-arm-supporting.webp +0 -0
  59. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-right-side-right-arm-supporting.webp +0 -0
  60. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-right-side-right-hand-supporting.webp +0 -0
  61. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-on-stomach-elbows-supporting.webp +0 -0
  62. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-right-arm-supporting-l-arm-up.webp +0 -0
  63. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_lay-right-leg-forward-arms-supp.webp +0 -0
  64. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-run-fwd.webp +0 -0
  65. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-run-reach.webp +0 -0
  66. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-sneaking-forward.webp +0 -0
  67. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-sprinting.webp +0 -0
  68. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-stepping-forward-look-l.webp +0 -0
  69. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-walk-fwd-look-r.webp +0 -0
  70. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-walk-fwd.webp +0 -0
  71. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-walking-arms-on-hips.webp +0 -0
  72. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-walking-right-arm-on-hip.webp +0 -0
  73. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_loco-walking.webp +0 -0
  74. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-arms-holding-left-knee-reclining.webp +0 -0
  75. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-arms-holding-right-knee.webp +0 -0
  76. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-arms-resting-on-knees.webp +0 -0
  77. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-arms-supp.webp +0 -0
  78. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-arms-up.webp +0 -0
  79. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-elbows-on-legs-lean-fwd.webp +0 -0
  80. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-elbows-on-legs-lean-l.webp +0 -0
  81. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-knees-up-hold.webp +0 -0
  82. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-lean-back-arms-supp.webp +0 -0
  83. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-lean-fwd-elbows-on-knees.webp +0 -0
  84. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-lean-fwd-hands-in-front.webp +0 -0
  85. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-legs-x-arms-x.webp +0 -0
  86. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-legs-x-hands-head.webp +0 -0
  87. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-legs-x-hold.webp +0 -0
  88. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-legs-x-reclining.webp +0 -0
  89. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-legs-x-right-arm-over-knee.webp +0 -0
  90. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reaching-hands-towards-toes.webp +0 -0
  91. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reaching-left-hand-towards-right-toe.webp +0 -0
  92. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reclined-facepalm.webp +0 -0
  93. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reclined-hands-head.webp +0 -0
  94. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reclined-left-leg-crossed-hands-head.webp +0 -0
  95. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reclined-left-leg-crossed.webp +0 -0
  96. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reclined-look-down.webp +0 -0
  97. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-reclined-right-leg-crossed-hands-hea.webp +0 -0
  98. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-rev-sit-hands-grasping.webp +0 -0
  99. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_sit-rev-sit-hands-relaxed.webp +0 -0
  100. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-arms-behind-back.webp +0 -0
  101. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-arms-down.webp +0 -0
  102. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-arms-slightly-spread.webp +0 -0
  103. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-bending-forward-arms-x-over-knees.webp +0 -0
  104. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-hands-on-hips-look-back.webp +0 -0
  105. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-l-hip-f.webp +0 -0
  106. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-l-hip-m.webp +0 -0
  107. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-l-leg-r-hip-l-arm-up.webp +0 -0
  108. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-lean-back-arms-behind.webp +0 -0
  109. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-lean-back-l-hip.webp +0 -0
  110. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-left-elbow-resting-obj.webp +0 -0
  111. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-left-leg-obj-left-hand-on-knee-r-h.webp +0 -0
  112. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-left-leg-obj-left-hand-on-knee.webp +0 -0
  113. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-legs-x-arms-up.webp +0 -0
  114. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-legs-x-l-hip.webp +0 -0
  115. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-legs-x-leaning-obj.webp +0 -0
  116. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-legs-x-left-arm-obj-r-hip.webp +0 -0
  117. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-look-down-r.webp +0 -0
  118. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-look-fwd.webp +0 -0
  119. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-look-l.webp +0 -0
  120. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-look-r.webp +0 -0
  121. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-r-arm-up-l-hip.webp +0 -0
  122. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-r-foot-l-leg-up.webp +0 -0
  123. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-r-foot-up.webp +0 -0
  124. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-r-hip-l-arm-up.webp +0 -0
  125. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-r-hip.webp +0 -0
  126. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-right-hand-behind-head.webp +0 -0
  127. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-right-leg-obj-arms-x.webp +0 -0
  128. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_stand-right-leg-obj-l-hip-right-hand-on.webp +0 -0
  129. topview_3d_cli/_runtime/builtin-assets/covers/a3d_pose_t-pose.webp +0 -0
  130. topview_3d_cli/_runtime/builtin-assets/manifest.json +2372 -0
  131. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-attack-jab.json +1 -0
  132. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-attack-lunge.json +1 -0
  133. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-attack-rear.json +1 -0
  134. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-crawling-forward-reaching-with-le.json +1 -0
  135. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-exaggerated-punch-with-right-hand.json +1 -0
  136. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-examine-fwd.json +1 -0
  137. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-holding-bow.json +1 -0
  138. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-jab-with-right-hand.json +1 -0
  139. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-on-hands-and-toes-right-leg-forwa.json +1 -0
  140. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-on-right-leg.json +1 -0
  141. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-push-up.json +1 -0
  142. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-pushing-backwards.json +1 -0
  143. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-pushing-with-both-hands.json +1 -0
  144. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-pushing-with-left-side-of-body.json +1 -0
  145. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_action-sliding.json +1 -0
  146. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-arms-spread-looking-upwards.json +1 -0
  147. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-examine-fwd.json +1 -0
  148. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-lean-fwd-right-hand-supporting.json +1 -0
  149. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-leaning-against-object-look-l.json +1 -0
  150. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-look-back.json +1 -0
  151. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-look-down-back.json +1 -0
  152. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-look-fwd-f.json +1 -0
  153. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-look-fwd-m.json +1 -0
  154. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-on-knees-arms-up.json +1 -0
  155. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_crouch-sneaking.json +1 -0
  156. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-l-toe-top-of-right-foot.json +1 -0
  157. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-legs-spread-lean-l.json +1 -0
  158. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-legs-spread-lean-r.json +1 -0
  159. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-legs-x.json +1 -0
  160. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-r-foot-arms-extended-backwards.json +1 -0
  161. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-r-toe-arms-up.json +1 -0
  162. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-r-toe-l-leg-up.json +1 -0
  163. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-toes-arch.json +1 -0
  164. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dance-toes-reach.json +1 -0
  165. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dyn-floating-bent-forwards.json +1 -0
  166. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dyn-floating-left-leg-bent-hands-spread.json +1 -0
  167. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dyn-floating-legs-bent-and-arms-spread.json +1 -0
  168. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dyn-floating-legs-raised-arms-extended-u.json +1 -0
  169. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dyn-l-toe-look-l.json +1 -0
  170. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dyn-leaping-forward-arms-extended-backwa.json +1 -0
  171. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dynamic-float-arch.json +1 -0
  172. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_dynamic-float-dive.json +1 -0
  173. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-back-arched-arms-supp.json +1 -0
  174. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-legs-to-side-arms-up.json +1 -0
  175. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-legs-x-arms-supp.json +1 -0
  176. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-back-left-leg-bent-hands-head.json +1 -0
  177. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-back-left-leg-bent.json +1 -0
  178. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-back-legs-x-hands-head.json +1 -0
  179. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-left-side-left-arm-supporting-hea.json +1 -0
  180. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-left-side-left-arm-supporting.json +1 -0
  181. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-right-side-right-arm-supporting.json +1 -0
  182. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-right-side-right-hand-supporting.json +1 -0
  183. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-on-stomach-elbows-supporting.json +1 -0
  184. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-right-arm-supporting-l-arm-up.json +1 -0
  185. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_lay-right-leg-forward-arms-supp.json +1 -0
  186. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-run-fwd.json +1 -0
  187. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-run-reach.json +1 -0
  188. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-sneaking-forward.json +1 -0
  189. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-sprinting.json +1 -0
  190. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-stepping-forward-look-l.json +1 -0
  191. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-walk-fwd-look-r.json +1 -0
  192. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-walk-fwd.json +1 -0
  193. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-walking-arms-on-hips.json +1 -0
  194. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-walking-right-arm-on-hip.json +1 -0
  195. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_loco-walking.json +1 -0
  196. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-arms-holding-left-knee-reclining.json +1 -0
  197. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-arms-holding-right-knee.json +1 -0
  198. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-arms-resting-on-knees.json +1 -0
  199. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-arms-supp.json +1 -0
  200. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-arms-up.json +1 -0
  201. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-elbows-on-legs-lean-fwd.json +1 -0
  202. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-elbows-on-legs-lean-l.json +1 -0
  203. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-knees-up-hold.json +1 -0
  204. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-lean-back-arms-supp.json +1 -0
  205. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-lean-fwd-elbows-on-knees.json +1 -0
  206. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-lean-fwd-hands-in-front.json +1 -0
  207. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-legs-x-arms-x.json +1 -0
  208. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-legs-x-hands-head.json +1 -0
  209. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-legs-x-hold.json +1 -0
  210. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-legs-x-reclining.json +1 -0
  211. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-legs-x-right-arm-over-knee.json +1 -0
  212. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reaching-hands-towards-toes.json +1 -0
  213. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reaching-left-hand-towards-right-toe.json +1 -0
  214. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reclined-facepalm.json +1 -0
  215. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reclined-hands-head.json +1 -0
  216. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reclined-left-leg-crossed-hands-head.json +1 -0
  217. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reclined-left-leg-crossed.json +1 -0
  218. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reclined-look-down.json +1 -0
  219. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-reclined-right-leg-crossed-hands-hea.json +1 -0
  220. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-rev-sit-hands-grasping.json +1 -0
  221. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_sit-rev-sit-hands-relaxed.json +1 -0
  222. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-arms-behind-back.json +1 -0
  223. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-arms-down.json +1 -0
  224. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-arms-slightly-spread.json +1 -0
  225. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-bending-forward-arms-x-over-knees.json +1 -0
  226. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-hands-on-hips-look-back.json +1 -0
  227. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-l-hip-f.json +1 -0
  228. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-l-hip-m.json +1 -0
  229. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-l-leg-r-hip-l-arm-up.json +1 -0
  230. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-lean-back-arms-behind.json +1 -0
  231. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-lean-back-l-hip.json +1 -0
  232. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-left-elbow-resting-obj.json +1 -0
  233. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-left-leg-obj-left-hand-on-knee-r-h.json +1 -0
  234. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-left-leg-obj-left-hand-on-knee.json +1 -0
  235. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-legs-x-arms-up.json +1 -0
  236. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-legs-x-l-hip.json +1 -0
  237. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-legs-x-leaning-obj.json +1 -0
  238. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-legs-x-left-arm-obj-r-hip.json +1 -0
  239. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-look-down-r.json +1 -0
  240. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-look-fwd.json +1 -0
  241. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-look-l.json +1 -0
  242. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-look-r.json +1 -0
  243. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-r-arm-up-l-hip.json +1 -0
  244. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-r-foot-l-leg-up.json +1 -0
  245. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-r-foot-up.json +1 -0
  246. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-r-hip-l-arm-up.json +1 -0
  247. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-r-hip.json +1 -0
  248. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-right-hand-behind-head.json +1 -0
  249. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-right-leg-obj-arms-x.json +1 -0
  250. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_stand-right-leg-obj-l-hip-right-hand-on.json +1 -0
  251. topview_3d_cli/_runtime/builtin-assets/poses/a3d_pose_t-pose.json +1 -0
  252. topview_3d_cli/_runtime/director-cli/applyIntent.mjs +35 -0
  253. topview_3d_cli/_runtime/director-cli/browser.mjs +47 -0
  254. topview_3d_cli/_runtime/director-cli/cli.mjs +56 -0
  255. topview_3d_cli/_runtime/director-cli/editSequence.mjs +125 -0
  256. topview_3d_cli/_runtime/director-cli/evaluate.mjs +254 -0
  257. topview_3d_cli/_runtime/director-cli/mediaUrl.mjs +47 -0
  258. topview_3d_cli/_runtime/director-cli/node_modules/@topview/3d-builder/dist/draco/draco_decoder.js +34 -0
  259. topview_3d_cli/_runtime/director-cli/node_modules/@topview/3d-builder/dist/draco/draco_decoder.wasm +0 -0
  260. topview_3d_cli/_runtime/director-cli/node_modules/@topview/3d-builder/dist/draco/draco_wasm_wrapper.js +117 -0
  261. topview_3d_cli/_runtime/director-cli/node_modules/@topview/3d-builder/dist/engine/index.mjs +22219 -0
  262. topview_3d_cli/_runtime/director-cli/node_modules/@topview/3d-builder/dist/evaluate/index.mjs +4229 -0
  263. topview_3d_cli/_runtime/director-cli/node_modules/@topview/3d-builder/dist/headless/index.mjs +22832 -0
  264. topview_3d_cli/_runtime/director-cli/node_modules/@topview/3d-builder/package.json +75 -0
  265. topview_3d_cli/_runtime/director-cli/node_modules/three/LICENSE +21 -0
  266. topview_3d_cli/_runtime/director-cli/node_modules/three/build/three.core.js +59732 -0
  267. topview_3d_cli/_runtime/director-cli/node_modules/three/build/three.module.js +19552 -0
  268. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/controls/OrbitControls.js +1963 -0
  269. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/curves/NURBSCurve.js +155 -0
  270. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/curves/NURBSUtils.js +532 -0
  271. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/libs/draco/draco_decoder.js +34 -0
  272. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/libs/draco/draco_decoder.wasm +0 -0
  273. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/libs/draco/draco_wasm_wrapper.js +117 -0
  274. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/libs/fflate.module.js +2672 -0
  275. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/lines/LineMaterial.js +703 -0
  276. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/lines/LineSegments2.js +426 -0
  277. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/lines/LineSegmentsGeometry.js +298 -0
  278. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/loaders/DRACOLoader.js +739 -0
  279. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/loaders/FBXLoader.js +4580 -0
  280. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/loaders/GLTFLoader.js +4860 -0
  281. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +1434 -0
  282. topview_3d_cli/_runtime/director-cli/node_modules/three/examples/jsm/utils/SkeletonUtils.js +496 -0
  283. topview_3d_cli/_runtime/director-cli/node_modules/three/package.json +123 -0
  284. topview_3d_cli/_runtime/director-cli/node_modules/zod/LICENSE +21 -0
  285. topview_3d_cli/_runtime/director-cli/node_modules/zod/index.js +4 -0
  286. topview_3d_cli/_runtime/director-cli/node_modules/zod/package.json +118 -0
  287. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/ZodError.js +133 -0
  288. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/errors.js +9 -0
  289. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/external.js +6 -0
  290. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/helpers/errorUtil.js +6 -0
  291. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/helpers/parseUtil.js +109 -0
  292. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/helpers/typeAliases.js +1 -0
  293. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/helpers/util.js +133 -0
  294. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/locales/en.js +109 -0
  295. topview_3d_cli/_runtime/director-cli/node_modules/zod/v3/types.js +3693 -0
  296. topview_3d_cli/_runtime/director-cli/package.json +6 -0
  297. topview_3d_cli/_runtime/director-cli/playwright.mjs +26 -0
  298. topview_3d_cli/_runtime/director-cli/render.mjs +336 -0
  299. topview_3d_cli/_runtime/director-cli/static/headless.html +124 -0
  300. topview_3d_cli/_runtime/director-cli/static/measure.mjs +61 -0
  301. topview_3d_cli/_runtime/director-cli/static/pose.mjs +71 -0
  302. topview_3d_cli/_runtime/director-cli/staticIntent.mjs +135 -0
  303. topview_3d_cli/_runtime/runtime.json +6 -0
  304. topview_3d_cli/bom.py +326 -0
  305. topview_3d_cli/contracts/director-v1/schema/director-document.schema.json +1097 -0
  306. topview_3d_cli/contracts/director-v1/schema/fcurves-compact-v1.schema.json +105 -0
  307. topview_3d_cli/director_camera_view.py +54 -0
  308. topview_3d_cli/director_document.py +793 -0
  309. topview_3d_cli/director_geometry.py +66 -0
  310. topview_3d_cli/director_operations.py +679 -0
  311. topview_3d_cli/director_static.py +134 -0
  312. topview_3d_cli/local_assets.py +248 -0
  313. topview_3d_cli/local_bom.py +108 -0
  314. topview_3d_cli/local_catalog.py +156 -0
  315. topview_3d_cli/local_cli.py +493 -0
  316. topview_3d_cli/local_edit.py +350 -0
  317. topview_3d_cli/local_errors.py +104 -0
  318. topview_3d_cli/local_inspect.py +302 -0
  319. topview_3d_cli/local_project.py +280 -0
  320. topview_3d_cli/local_read.py +139 -0
  321. topview_3d_cli/local_render.py +97 -0
  322. topview_3d_cli/node_batch.py +299 -0
  323. topview_3d_cli/renderer.py +75 -0
  324. topview_3d_cli/runtime.py +107 -0
  325. topview_3d_cli-0.1.0.dist-info/METADATA +48 -0
  326. topview_3d_cli-0.1.0.dist-info/RECORD +332 -0
  327. topview_3d_cli-0.1.0.dist-info/WHEEL +5 -0
  328. topview_3d_cli-0.1.0.dist-info/entry_points.txt +2 -0
  329. topview_3d_cli-0.1.0.dist-info/licenses/LICENSE +202 -0
  330. topview_3d_cli-0.1.0.dist-info/licenses/LICENSE-ASSETS +396 -0
  331. topview_3d_cli-0.1.0.dist-info/licenses/NOTICE +18 -0
  332. topview_3d_cli-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,350 @@
1
+ """``node batch`` and ``pose batch``: staged edits compiled to one atomic operation batch.
2
+
3
+ Every change is staged on a copy of the stored snapshot (static intents run in the Node renderer,
4
+ library poses compile in Chromium). Any rejected change aborts the command before anything is
5
+ written; the compiled batch then goes through the shared operation engine like ``document apply``.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import copy
10
+ import json
11
+ import math
12
+ import sys
13
+ from pathlib import Path
14
+ from typing import Any, Callable
15
+
16
+ from jsonschema import Draft7Validator
17
+
18
+ from topview_3d_cli.director_camera_view import apply_camera_view
19
+ from topview_3d_cli.director_document import new_scene_operation_id, normalize_node
20
+ from topview_3d_cli.director_geometry import check_primitive_geometry, compact_geometry
21
+ from topview_3d_cli.director_static import node_in
22
+ from topview_3d_cli.local_assets import asset_catalog, check_render_assets, find_asset, local_asset_map
23
+ from topview_3d_cli.local_catalog import find_any_asset
24
+ from topview_3d_cli.local_errors import LocalProjectError
25
+ from topview_3d_cli.local_project import apply_operations, base_result, open_project
26
+ from topview_3d_cli.node_batch import (
27
+ BATCH_OPERATION_LIMIT, affected_nodes, batch_schema, compact_node_state, compile_operations, expand_changes,
28
+ node_state, obj, schema_error, stage_delete,
29
+ )
30
+ from topview_3d_cli.renderer import director_cli
31
+
32
+ NODE_BATCH_SCHEMA = batch_schema(require_sequence=False)
33
+ _UPDATE = NODE_BATCH_SCHEMA["properties"]["changes"]["items"]["oneOf"][3]["properties"]
34
+ POSE_BATCH_SCHEMA = obj({
35
+ "expectedSceneSequence": {"type": "integer", "minimum": 0},
36
+ "items": {"type": "array", "minItems": 1, "maxItems": 16, "items": {
37
+ **obj({"nodeId": _UPDATE["nodeId"], "poseId": _UPDATE["nodeId"], "libraryId": _UPDATE["nodeId"],
38
+ **{key: _UPDATE[key] for key in ("position", "rotation", "scale")}}, ("nodeId",)),
39
+ "oneOf": [{"required": ["poseId"]}, {"required": ["libraryId"]}],
40
+ }},
41
+ }, ("items",))
42
+ POSE_FILE_LIMIT = 1024 * 1024
43
+
44
+
45
+ def load_spec(path: str, invalid_code: str) -> dict[str, Any]:
46
+ """Read a JSON object from a file or ``-`` (stdin)."""
47
+ try:
48
+ text = sys.stdin.read() if path == "-" else Path(path).read_text(encoding="utf-8")
49
+ except FileNotFoundError as exc:
50
+ raise LocalProjectError("INPUT_NOT_FOUND", str(path)) from exc
51
+ try:
52
+ value = json.loads(text)
53
+ except json.JSONDecodeError as exc:
54
+ raise LocalProjectError(invalid_code, f"{path}: {exc.msg}") from exc
55
+ if not isinstance(value, dict):
56
+ raise LocalProjectError(invalid_code, f"{path} must contain a JSON object")
57
+ try:
58
+ json.dumps(value, allow_nan=False)
59
+ except ValueError as exc:
60
+ raise LocalProjectError(invalid_code, "NaN and Infinity are not allowed") from exc
61
+ return value
62
+
63
+
64
+ def check_scene_sequence(spec: dict[str, Any], sequence: int) -> None:
65
+ expected = spec.get("expectedSceneSequence")
66
+ if expected is not None and expected != sequence:
67
+ raise LocalProjectError("SCENE_SEQUENCE_CONFLICT",
68
+ f"expectedSceneSequence={expected} but the project is at {sequence}; re-read and re-plan",
69
+ details={"expected": expected, "current": sequence})
70
+
71
+
72
+ # Rejections that name something missing are input errors (exit 2), not scene conflicts.
73
+ _MISSING_REFERENCE = {"NODE_NOT_FOUND:": "DIRECTOR_NODE_NOT_FOUND", "ASSET_NOT_FOUND:": "ASSET_NOT_FOUND"}
74
+
75
+
76
+ def _reject(code: str, index: int, node_id: str, reason: str) -> LocalProjectError:
77
+ return LocalProjectError(code, f"changes[{index}] ({node_id}): {reason}; nothing was written",
78
+ details={"index": index, "nodeId": node_id, "reason": reason})
79
+
80
+
81
+ class _Stager:
82
+ """Runs static intents in the renderer in as few calls as possible, in change order."""
83
+
84
+ def __init__(self, snapshot: dict[str, Any], reject_code: str):
85
+ self.snapshot = snapshot
86
+ self.pending: list[dict[str, Any]] = []
87
+ self.reject_code = reject_code
88
+ self.node_ids: dict[int, str] = {}
89
+
90
+ def intent(self, index: int, node_id: str, intent: dict[str, Any]) -> None:
91
+ self.node_ids[index] = node_id
92
+ self.pending.append({"index": index, "intent": intent})
93
+
94
+ def flush(self) -> None:
95
+ if not self.pending:
96
+ return
97
+ try:
98
+ result = director_cli("apply-intents", {"document": self.snapshot["document"],
99
+ "fcurves": self.snapshot.get("fcurves"),
100
+ "intents": self.pending})
101
+ except LocalProjectError as exc:
102
+ reason = (exc.details or {}).get("reason", "") if isinstance(exc.details, dict) else ""
103
+ if exc.code == "RENDERER_FAILED" and reason.startswith("INTENT_REJECTED:"):
104
+ _, index, message = reason.split(":", 2)
105
+ raise _reject(self.reject_code, int(index), self.node_ids.get(int(index), ""), message) from exc
106
+ raise
107
+ finally:
108
+ self.pending = []
109
+ self.snapshot["document"] = result["document"]
110
+
111
+ def direct(self, work: Callable[[], Any]) -> Any:
112
+ self.flush()
113
+ return work()
114
+
115
+
116
+ def _primitive_size(node: dict[str, Any]) -> dict[str, Any] | None:
117
+ """Parameters and the scaled local size (width/height/depth before rotation) of a primitive."""
118
+ primitive = node.get("primitive") or {}
119
+ parameters = primitive.get("parameters") or {}
120
+ kind = primitive.get("kind")
121
+ if kind == "BoxGeometry":
122
+ size = (parameters.get("width", 0), parameters.get("height", 0), parameters.get("depth", 0))
123
+ elif kind == "SphereGeometry":
124
+ size = (2 * parameters.get("radius", 0),) * 3
125
+ elif kind in ("CylinderGeometry", "ConeGeometry"):
126
+ radius = max(parameters.get("radiusTop", 0), parameters.get("radiusBottom", 0), parameters.get("radius", 0))
127
+ size = (2 * radius, parameters.get("height", 0), 2 * radius)
128
+ else:
129
+ return None
130
+ scale = node["transform"].get("scale") or {}
131
+ return {"kind": kind, "parameters": parameters,
132
+ "size": {axis: round(value * scale.get(axis, 1), 4) for axis, value in zip("xyz", size)}}
133
+
134
+
135
+ def _node_row(node: dict[str, Any], versions: dict[str, Any]) -> dict[str, Any]:
136
+ row = compact_node_state(node_state(node, versions))
137
+ if node.get("type") == "primitive":
138
+ primitive = _primitive_size(node)
139
+ if primitive:
140
+ row["primitive"] = primitive
141
+ return row
142
+
143
+
144
+ def _state(snapshot: dict[str, Any], node_ids: list[str]) -> dict[str, Any]:
145
+ versions = snapshot.get("entityVersions") or {}
146
+ ids = set(affected_nodes(snapshot, node_ids))
147
+ return {
148
+ "sceneSequence": snapshot.get("sceneSequence"),
149
+ "nodes": [_node_row(node, versions)
150
+ for node in snapshot["document"]["content"]["nodes"] if node["id"] in ids],
151
+ "geometry": compact_geometry(check_primitive_geometry(snapshot["document"])),
152
+ }
153
+
154
+
155
+ def _commit(directory: str, before: dict[str, Any], staged: dict[str, Any], deleted_curves: set[str], *,
156
+ stem: str, dry_run: bool) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any], int]:
157
+ try:
158
+ operations, old, new = compile_operations(before, staged, deleted_curves)
159
+ except ValueError as exc:
160
+ raise LocalProjectError("BATCH_TOO_LARGE", str(exc)) from exc
161
+ if operations:
162
+ result = apply_operations(directory, operations, batch_id=new_scene_operation_id(stem), dry_run=dry_run)
163
+ else:
164
+ project = open_project(directory)
165
+ result = {**base_result(project), "dryRun": dry_run, "strictVersions": False, "operationCount": 0,
166
+ "accepted": [], "warnings": [], "entityVersions": project.store.entity_versions()}
167
+ return result, old, new, len(operations)
168
+
169
+
170
+ def _library_entry(catalog: list[dict[str, Any]], kind: str, library_id: str) -> dict[str, Any]:
171
+ return find_any_asset(catalog, library_id, "character" if kind == "characters" else "prop")
172
+
173
+
174
+ def check_node_spec(spec: dict[str, Any], invalid_code: str = "NODE_BATCH_INVALID") -> None:
175
+ error = schema_error(NODE_BATCH_SCHEMA, spec)
176
+ if error:
177
+ raise LocalProjectError(invalid_code, f"{error}; nothing was written")
178
+
179
+
180
+ def stage_node_changes(project: Any, spec: dict[str, Any]):
181
+ """Stage validated ``changes`` on a copy: ``(before, staged, deleted_curves, expanded)``."""
182
+ before = project.store.assemble()
183
+ check_scene_sequence(spec, before["sceneSequence"])
184
+ expanded = expand_changes(spec["changes"])
185
+ if len(expanded) > BATCH_OPERATION_LIMIT:
186
+ raise LocalProjectError("NODE_BATCH_INVALID", f"at most {BATCH_OPERATION_LIMIT} changes after repeat expansion")
187
+ staged = copy.deepcopy(before)
188
+ stager = _Stager(staged, "NODE_BATCH_REJECTED")
189
+ catalog: list[dict[str, Any]] | None = None
190
+ deleted_curves: set[str] = set()
191
+ present = {node["id"] for node in before["document"]["content"]["nodes"]}
192
+ for index, change in enumerate(expanded):
193
+ action, node_id = change["action"], change["nodeId"]
194
+ try:
195
+ if "view" in change and any(key in change for key in ("position", "rotation", "distance", "subjectNodeId")):
196
+ raise ValueError("CAMERA_VIEW_CONFLICT: use view with fov; omit position, rotation, distance and "
197
+ "subjectNodeId")
198
+ if "position" in change and "distance" in change:
199
+ raise ValueError("CAMERA_POSITION_DISTANCE_CONFLICT: use view or distance, not both")
200
+ if action.startswith("add_"):
201
+ if node_id in present:
202
+ raise ValueError(f"NODE_ALREADY_EXISTS:{node_id}")
203
+ present.add(node_id)
204
+ elif node_id not in present:
205
+ raise ValueError(f"NODE_NOT_FOUND:{node_id}")
206
+ else:
207
+ existing = next((node for node in staged["document"]["content"]["nodes"] if node["id"] == node_id), None)
208
+ if existing and existing.get("locked"):
209
+ raise ValueError(f"NODE_LOCKED:{node_id}")
210
+ if action == "delete":
211
+ deleted_curves.update(stager.direct(lambda: stage_delete(staged, node_id)))
212
+ present.discard(node_id)
213
+ continue
214
+ if action == "add_primitive":
215
+ primitive = change["primitive"]
216
+ if primitive["kind"] == "CylinderGeometry" and not any(
217
+ primitive["parameters"][key] > 0 for key in ("radiusTop", "radiusBottom")):
218
+ raise ValueError("CYLINDER_RADIUS_REQUIRED")
219
+ node = normalize_node({"id": node_id, "type": "primitive", "name": change.get("name", node_id),
220
+ "primitive": primitive})
221
+ stager.direct(lambda: staged["document"]["content"]["nodes"].append(node))
222
+ elif action == "add_library":
223
+ if catalog is None:
224
+ catalog = asset_catalog(project.paths)
225
+ try:
226
+ entry = _library_entry(catalog, change["kind"], change["libraryId"])
227
+ except LocalProjectError as exc:
228
+ raise ValueError(f"ASSET_NOT_FOUND:{change['libraryId']}") from exc
229
+ stager.intent(index, node_id, {
230
+ "type": "add-character" if change["kind"] == "characters" else "add-prop",
231
+ "nodeId": node_id, "libraryId": entry["id"],
232
+ "name": change.get("name") or entry.get("name") or node_id, "modelUrl": entry["key"]})
233
+ elif action == "add_camera":
234
+ subject_id = change.get("subjectNodeId") or (change.get("view") or {}).get("subjectNodeId")
235
+ stager.intent(index, node_id, {"type": "add-camera", "nodeId": node_id, "presetId": change["presetId"],
236
+ **({"subjectNodeId": subject_id} if subject_id else {})})
237
+ patch = {key: change[key] for key in ("name", "position", "rotation", "scale") if key in change}
238
+ if patch:
239
+ stager.intent(index, node_id, {"type": "patch-transform", "nodeId": node_id, **patch})
240
+ if "view" in change:
241
+ stager.direct(lambda: apply_camera_view(staged["document"], node_id, change["view"]))
242
+ for field, kind in (("fov", "set-fov"), ("distance", "set-distance")):
243
+ if field in change:
244
+ stager.intent(index, node_id, {"type": kind, "cameraNodeId": node_id, field: change[field]})
245
+ except ValueError as exc:
246
+ reason = str(exc)
247
+ code = next((code for prefix, code in _MISSING_REFERENCE.items() if reason.startswith(prefix)),
248
+ "NODE_BATCH_REJECTED")
249
+ raise _reject(code, index, node_id, reason) from exc
250
+ stager.flush()
251
+ return before, staged, deleted_curves, expanded
252
+
253
+
254
+ def node_batch(directory: str, spec_path: str, *, dry_run: bool = False) -> dict[str, Any]:
255
+ spec = load_spec(spec_path, "NODE_BATCH_INVALID")
256
+ check_node_spec(spec)
257
+ before, staged, deleted_curves, expanded = stage_node_changes(open_project(directory), spec)
258
+ result, old, new, count = _commit(directory, before, staged, deleted_curves, stem="nodes", dry_run=dry_run)
259
+ created = [key for key in new if key not in old]
260
+ updated = [key for key in new if key in old and old[key] != new[key]]
261
+ after = {**staged, "sceneSequence": result["sceneSequence"], "entityVersions": result["entityVersions"]}
262
+ return {**result, "createdIds": created, "updatedIds": updated, "deletedIds": [key for key in old if key not in new],
263
+ "changeCount": len(spec["changes"]), "expandedChangeCount": len(expanded), "operationCount": count,
264
+ "state": _state(after, created + updated)}
265
+
266
+
267
+ def _pose_payload(entry: dict[str, Any]) -> dict[str, Any]:
268
+ path = Path(entry["path"])
269
+ if path.stat().st_size > POSE_FILE_LIMIT:
270
+ raise LocalProjectError("POSE_ASSET_INVALID", f"{entry['id']}: pose file larger than 1 MiB")
271
+ try:
272
+ pose = json.loads(path.read_text(encoding="utf-8"))
273
+ except (UnicodeDecodeError, json.JSONDecodeError) as exc:
274
+ raise LocalProjectError("POSE_ASSET_INVALID", f"{entry['id']}: not JSON") from exc
275
+
276
+ def vector(value, length):
277
+ return isinstance(value, list) and len(value) == length and all(
278
+ type(item) in (int, float) and math.isfinite(item) for item in value)
279
+ bones = pose.get("bones") if isinstance(pose, dict) else None
280
+ if (not isinstance(bones, dict) or not 1 <= len(bones) <= 256
281
+ or not vector(pose.get("hips"), 3)
282
+ or not all(isinstance(name, str) and vector(value, 4) and sum(x * x for x in value) > 0.01
283
+ for name, value in bones.items())):
284
+ raise LocalProjectError("POSE_ASSET_INVALID", f"{entry['id']}: needs hips [x,y,z] and 1-256 bone quaternions")
285
+ return pose
286
+
287
+
288
+ def pose_batch(directory: str, spec: dict[str, Any], *, dry_run: bool = False) -> dict[str, Any]:
289
+ error = next(Draft7Validator(POSE_BATCH_SCHEMA).iter_errors(spec), None)
290
+ if error:
291
+ path = list(error.path)
292
+ index = path[1] if len(path) > 1 and path[0] == "items" and isinstance(path[1], int) else None
293
+ raise LocalProjectError("POSE_BATCH_INVALID", f"{'.'.join(map(str, path))}: {error.message[:450]}; "
294
+ "nothing was written", details={"index": index} if index is not None else None)
295
+ ids = [item["nodeId"] for item in spec["items"]]
296
+ repeated = next((index for index, node_id in enumerate(ids) if node_id in ids[:index]), None)
297
+ if repeated is not None:
298
+ raise LocalProjectError("POSE_BATCH_INVALID", f"items.{repeated}: {ids[repeated]} appears twice; each "
299
+ "character may appear once per batch",
300
+ details={"index": repeated, "nodeId": ids[repeated]})
301
+ project = open_project(directory)
302
+ before = project.store.assemble()
303
+ check_scene_sequence(spec, before["sceneSequence"])
304
+ staged = copy.deepcopy(before)
305
+ document = staged["document"]
306
+ clips = document["content"].get("timeline", {}).get("animation", {}).get("motionClips", [])
307
+ catalog = asset_catalog(project.paths)
308
+ items = []
309
+ for index, item in enumerate(spec["items"]):
310
+ where = {"index": index, "nodeId": item["nodeId"]}
311
+ try:
312
+ node = node_in(document, item["nodeId"])
313
+ except ValueError as exc:
314
+ raise LocalProjectError("DIRECTOR_NODE_NOT_FOUND", f"items.{index}: no node {item['nodeId']}",
315
+ details=where) from exc
316
+ if node.get("type") != "character":
317
+ raise LocalProjectError("POSE_TARGET_INVALID", f"items.{index}: {item['nodeId']} is not a character",
318
+ details=where)
319
+ if node.get("locked"):
320
+ raise _reject("POSE_BATCH_REJECTED", index, item["nodeId"], "NODE_LOCKED")
321
+ if any((clip.get("target") or {}).get("nodeId") == item["nodeId"] for clip in clips):
322
+ raise _reject("POSE_BATCH_REJECTED", index, item["nodeId"],
323
+ "POSE_BLOCKED_BY_MOTION: delete the character's motion clips first")
324
+ try:
325
+ entry = find_asset(catalog, "pose", item.get("poseId") or item["libraryId"])
326
+ except LocalProjectError as exc:
327
+ raise LocalProjectError(exc.code, f"items.{index}: {exc}",
328
+ details={**where, "poseId": item.get("poseId") or item["libraryId"]}) from exc
329
+ items.append({"nodeId": item["nodeId"], "libraryId": entry["id"], "pose": _pose_payload(entry)})
330
+ mapping = local_asset_map(catalog)
331
+ check_render_assets({"content": {"nodes": [node_in(document, node_id) for node_id in ids]}}, mapping)
332
+ compiled = director_cli("apply-library-poses", {"document": document, "items": items,
333
+ "publicAssetBase": "", "localAssets": mapping})
334
+ results = compiled.get("results") or []
335
+ if len(results) != len(items):
336
+ raise LocalProjectError("RENDER_RESULT_INVALID", "apply-library-poses returned the wrong number of results")
337
+ poses = []
338
+ for item, compiled_pose in zip(items, results):
339
+ node_in(document, item["nodeId"])["character"]["animation"] = compiled_pose["animation"]
340
+ poses.append({"nodeId": item["nodeId"], "poseId": item["libraryId"], "pose": compiled_pose.get("pose")})
341
+ stager = _Stager(staged, "POSE_BATCH_REJECTED")
342
+ for index, item in enumerate(spec["items"]):
343
+ patch = {key: item[key] for key in ("position", "rotation", "scale") if key in item}
344
+ if patch:
345
+ stager.intent(index, item["nodeId"], {"type": "patch-transform", "nodeId": item["nodeId"], **patch})
346
+ stager.flush()
347
+ result, old, new, count = _commit(directory, before, staged, set(), stem="poses", dry_run=dry_run)
348
+ after = {**staged, "sceneSequence": result["sceneSequence"], "entityVersions": result["entityVersions"]}
349
+ return {**result, "poses": poses, "updatedIds": [key for key in new if old.get(key) != new[key]],
350
+ "operationCount": count, "state": _state(after, ids)}
@@ -0,0 +1,104 @@
1
+ """Stable error codes and exit codes of the local ``topview-3d-cli`` CLI.
2
+
3
+ Keep this table in sync with ``docs/topview-3d-cli.md``; ``test_local_cli`` enforces it.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ from typing import Any
8
+
9
+ EXIT_OK = 0
10
+ EXIT_FAILED = 1
11
+ EXIT_INVALID_INPUT = 2
12
+
13
+ # code -> (exit code, meaning)
14
+ ERROR_CODES: dict[str, tuple[int, str]] = {
15
+ # Command line and input files
16
+ "USAGE_INVALID": (2, "Unknown command, missing argument or bad option."),
17
+ "PROJECT_NOT_INITIALIZED": (2, "The directory has no .topview3d project; run `project init`."),
18
+ "PROJECT_EXISTS": (2, "`project init` target already contains a project; pass --force to replace it."),
19
+ "OPERATIONS_NOT_FOUND": (2, "The operations file does not exist."),
20
+ "OPERATIONS_JSON_INVALID": (2, "The operations file is not JSON or not an operation batch."),
21
+ "RENDER_PAYLOAD_INVALID": (2, "The render payload is not a JSON object of frames/width/height/cameraNodeId/publicAssetBase."),
22
+ "ASSET_IMPORT_INVALID": (2, "`asset import` got a bad kind, id, file type, cover or pose JSON."),
23
+ "ASSET_NOT_FOUND": (2, "No asset with that id and kind in the local manifests (in a batch, details.index)."),
24
+ "POSE_TARGET_INVALID": (2, "`pose apply` / `pose batch` target is not a character."),
25
+ "INPUT_NOT_FOUND": (2, "A spec, plan, views or checkpoint file does not exist."),
26
+ "NODE_BATCH_INVALID": (2, "`node batch` spec is not JSON or fails the change schema."),
27
+ "POSE_BATCH_INVALID": (2, "`pose batch` spec fails its schema or repeats a character."),
28
+ "BATCH_TOO_LARGE": (2, "The edit compiles to more than 64 operations; split it."),
29
+ "PLAN_INVALID": (2, "`evaluate` plan is not JSON or not exactly one of changes/operations."),
30
+ "VIEWS_INVALID": (2, "`inspect views` spec fails its schema, or the primary camera is not among the views."),
31
+ "CAMERA_REQUIRED": (2, "A --camera / cameraNodeId is not a camera node, or the scene has no camera."),
32
+ "CAMERA_NOT_FOUND": (2, "A --camera / cameraNodeId names no node in the scene."),
33
+ "DANGLING_REFERENCE": (2, "The batch would leave a clip, fcurves or node reference pointing at a missing node."),
34
+ "ENTITY_NOT_FOUND": (2, "Delete targets an entity that never existed."),
35
+ "DIRECTOR_NODE_NOT_FOUND": (2, "A referenced node does not exist (the message names it; batches add details.index)."),
36
+ "DOCUMENT_ENTITY_NOT_FOUND": (2, "`document get --entity` found no node, clip or fcurves shard with that id."),
37
+ "RENDER_NOT_FOUND": (2, "No such render run or frame image in .topview3d/renders."),
38
+ "BOM_CHECKPOINT_INVALID": (2, "`bom checkpoint` patch fails its schema or repeats/conflicts ids."),
39
+ "BOM_TOO_LARGE": (2, "The merged BOM would exceed 64 KiB."),
40
+ # Operation shape (nothing is applied)
41
+ "INVALID_DIRECTOR_BATCH": (2, "Batch must contain 1..64 operations."),
42
+ "INVALID_DIRECTOR_OPERATION": (2, "Operation is not an object or has a bad baseSequence/expectedEntityVersion."),
43
+ "INVALID_OPERATION_ID": (2, "operationId must match [A-Za-z0-9_-]{1,128}."),
44
+ "UNSUPPORTED_DIRECTOR_KIND": (2, "kind is not one of the seven director.* kinds."),
45
+ "INVALID_DIRECTOR_PAYLOAD": (2, "payload is not an object or has missing/extra fields."),
46
+ "INVALID_ENTITY_ID": (2, "entityId is missing, malformed, or not fcurves__<nodeId> for fcurves kinds."),
47
+ "INVALID_DIRECTOR_SCENE": (2, "scene.set payload is invalid (entityId, nodes/clips in content, type/version)."),
48
+ "INVALID_DIRECTOR_NODE": (2, "Node fails normalization/schema or node.id != entityId."),
49
+ "INVALID_DIRECTOR_TRANSFORM": (2, "Node transform is not position/rotation/scale of finite x/y/z."),
50
+ "INVALID_DIRECTOR_CLIP": (2, "Clip kind, id, frame range or camera motion.curves is invalid."),
51
+ "INVALID_DIRECTOR_FCURVES": (2, "fcurves payload is not version 1 compact-v1 or fails its schema."),
52
+ "INVALID_DIRECTOR_DOCUMENT": (2, "The batch would produce a document that fails the director schema."),
53
+ # State conflicts (nothing is applied)
54
+ "ENTITY_VERSION_CONFLICT": (1, "expectedEntityVersion does not match the entity's current version."),
55
+ "ENTITY_DELETED": (1, "Target entity was deleted (strict mode also forbids recreating it)."),
56
+ "ENTITY_TYPE_CONFLICT": (1, "entityId already belongs to another entity type."),
57
+ "SEQUENCE_GAP": (1, "baseSequence is negative or ahead of the project's sceneSequence."),
58
+ "OPERATION_KEY_REUSED": (1, "operationId was already accepted with a different body."),
59
+ "SCENE_SEQUENCE_CONFLICT": (1, "expectedSceneSequence does not match the project; re-read and re-plan."),
60
+ "DIRECTOR_NODE_LOCKED": (1, "`node delete` target is locked."),
61
+ "NODE_BATCH_REJECTED": (1, "One `node batch` change cannot apply to the current scene (details: index, nodeId, reason)."),
62
+ "POSE_BATCH_REJECTED": (1, "A pose target is locked or still has motion clips (details: index, nodeId, reason)."),
63
+ "BOM_REVISION_CONFLICT": (1, "expectedBomRevision does not match the stored BOM."),
64
+ "BOM_REVIEW_EVIDENCE_MISSING": (1, "modelReview needs current `inspect views` evidence with matching image sha256."),
65
+ "DIRECTOR_LAST_CAMERA_REQUIRED": (1, "The last camera cannot be deleted."),
66
+ "DIRECTOR_DELETE_CHILDREN_FIRST": (1, "Delete the node's children first."),
67
+ "DIRECTOR_DELETE_TOO_MANY_DEPENDENCIES": (1, "Cascading delete would exceed one 64-operation batch."),
68
+ # Project state and runtime
69
+ "PROJECT_JSON_INVALID": (1, "A project state file is corrupt."),
70
+ "PROJECT_FORMAT_UNSUPPORTED": (1, "The project was written by a newer CLI (schemaVersion too high)."),
71
+ "DOCUMENT_INVALID": (1, "`document validate` found schema errors or references to missing nodes."),
72
+ "BUILDER_PACKAGE_UNREADABLE": (1, "editor/packages/builder/package.json is missing or has no version."),
73
+ "ASSET_MANIFEST_INVALID": (1, "An asset manifest is corrupt or lists a path outside its root."),
74
+ "POSE_ASSET_INVALID": (1, "A pose file is larger than 1 MiB or lacks hips and 1-256 bone quaternions."),
75
+ "BOM_JSON_INVALID": (1, ".topview3d/bom.json is corrupt; fix or delete it."),
76
+ "RENDER_IMAGE_INVALID": (1, "A render image is not a PNG or no longer matches the sha256 in render.json."),
77
+ "ASSET_FILE_MISSING": (1, "A manifest entry points to a file that does not exist."),
78
+ "ASSET_NOT_AVAILABLE": (1, "A character or prop model in the document has no local asset (see details)."),
79
+ "RUNTIME_MISSING": (1, "The renderer runtime is missing (incomplete install, or an unbuilt checkout)."),
80
+ "NODE_UNAVAILABLE": (1, "`node` is not on PATH."),
81
+ "NPM_UNAVAILABLE": (1, "`browser ensure` needs `npm` (it ships with Node.js)."),
82
+ "PLAYWRIGHT_INSTALL_FAILED": (1, "`browser ensure` could not install the pinned Playwright into the user cache."),
83
+ "BROWSER_INSTALL_FAILED": (1, "`browser ensure` could not install or launch Chromium."),
84
+ "BROWSER_NOT_INSTALLED": (1, "Playwright or Chromium is missing; run `topview-3d-cli browser ensure`."),
85
+ "RENDER_FAILED": (1, "The Node renderer exited with an error."),
86
+ "RENDERER_FAILED": (1, "A non-render Node renderer command (for example pose compilation) failed."),
87
+ "RENDER_RESULT_MISSING": (1, "The Node renderer printed no result."),
88
+ "RENDER_RESULT_INVALID": (1, "The Node renderer printed a non-JSON result."),
89
+ "DOCTOR_FAILED": (1, "Plain `doctor` found a missing or outdated dependency (`doctor --json` always exits 0)."),
90
+ "INTERNAL_ERROR": (1, "Unexpected failure; the message carries the exception."),
91
+ }
92
+
93
+
94
+ def exit_code_for(code: str) -> int:
95
+ return ERROR_CODES.get(code, (EXIT_FAILED, ""))[0]
96
+
97
+
98
+ class LocalProjectError(RuntimeError):
99
+ """A stable, user-facing local project error (codes: ``ERROR_CODES``)."""
100
+
101
+ def __init__(self, code: str, message: str | None = None, *, details: Any = None):
102
+ self.code = code
103
+ self.details = details
104
+ super().__init__(message or code)