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,135 @@
1
+ import { applyStudioIntent } from '@topview/3d-builder/evaluate'
2
+ import { evaluateDocumentFrames } from './evaluate.mjs'
3
+
4
+ const axes = ['x', 'y', 'z']
5
+ function finite(value, label) {
6
+ if (typeof value !== 'number' || !Number.isFinite(value)) throw new Error(`INVALID_${label}`)
7
+ return value
8
+ }
9
+ function vector(value, label, positive = false) {
10
+ if (!value || typeof value !== 'object' || !Object.keys(value).length) throw new Error(`INVALID_${label}`)
11
+ for (const [key, number] of Object.entries(value)) {
12
+ if (!axes.includes(key) || (positive && number <= 0)) throw new Error(`INVALID_${label}`)
13
+ finite(number, label)
14
+ }
15
+ return value
16
+ }
17
+ function length(a, b) { return Math.hypot(...axes.map(axis => a[axis] - b[axis])) }
18
+ function worldToSubject(world, subject, binding) {
19
+ const r = subject.transform.rotation
20
+ const yaw = binding.followRotation ? Math.atan2(Math.sin(r.y * Math.PI / 180), Math.cos(r.x * Math.PI / 180) * Math.cos(r.y * Math.PI / 180)) : 0
21
+ const dx = world.x - subject.transform.position.x, dz = world.z - subject.transform.position.z
22
+ return { x: dx * Math.cos(yaw) - dz * Math.sin(yaw), y: world.y - subject.transform.position.y, z: dx * Math.sin(yaw) + dz * Math.cos(yaw) }
23
+ }
24
+ function subjectToWorld(local, subject, binding) {
25
+ const r = subject.transform.rotation
26
+ const yaw = binding.followRotation ? Math.atan2(Math.sin(r.y * Math.PI / 180), Math.cos(r.x * Math.PI / 180) * Math.cos(r.y * Math.PI / 180)) : 0
27
+ const p = subject.transform.position
28
+ return { x: p.x + local.x * Math.cos(yaw) + local.z * Math.sin(yaw), y: p.y + local.y, z: p.z - local.x * Math.sin(yaw) + local.z * Math.cos(yaw) }
29
+ }
30
+ function resolveBoundCamera(document, node) {
31
+ const binding = node.camera?.subject
32
+ if (binding?.follow) {
33
+ const subject = document.content.nodes.find(n => n.id === binding.nodeId && n.type === 'character')
34
+ if (!subject) throw new Error('CAMERA_SUBJECT_MISSING')
35
+ node.transform.position = subjectToWorld(binding.offset, subject, binding)
36
+ node.camera.lookAt = subjectToWorld(binding.lookAtOffset, subject, binding)
37
+ }
38
+ const target = node.camera?.lookAtTarget
39
+ if (target) {
40
+ const subject = document.content.nodes.find(n => n.id === target.nodeId)
41
+ if (!subject) throw new Error('CAMERA_TARGET_MISSING')
42
+ const offset = target.offset || { x: 0, y: 1.2, z: 0 }
43
+ node.camera.lookAt = Object.fromEntries(axes.map(axis => [axis, subject.transform.position[axis] + offset[axis]]))
44
+ }
45
+ }
46
+ // Same Euler-to-look-at convention used by the Editor camera inspector.
47
+ function aim(position, rotation, distance) {
48
+ const [x, y, z] = axes.map(axis => rotation[axis] * Math.PI / 180)
49
+ const ix = -Math.sin(y) * Math.cos(x), iy = Math.sin(x), iz = -Math.cos(y) * Math.cos(x)
50
+ return { x: position.x + (Math.cos(z) * ix - Math.sin(z) * iy) * distance,
51
+ y: position.y + (Math.sin(z) * ix + Math.cos(z) * iy) * distance,
52
+ z: position.z + iz * distance }
53
+ }
54
+
55
+ export function applyStaticIntent(body) {
56
+ const intent = { ...body.intent }
57
+ const document = structuredClone(body.document)
58
+ const id = intent.nodeId || intent.cameraNodeId
59
+ const node = document.content.nodes.find(n => n.id === id)
60
+ const requireNode = (nodeId, type) => {
61
+ const target = document.content.nodes.find(n => n.id === nodeId)
62
+ if (!target) throw new Error(`NODE_NOT_FOUND:${nodeId}`)
63
+ if (type && target.type !== type) throw new Error(`NODE_TYPE_REQUIRED:${nodeId}:${type}`)
64
+ return target
65
+ }
66
+ // Validate references and role types before passing an intent to the builder.
67
+ if (intent.cameraNodeId) requireNode(intent.cameraNodeId, 'camera')
68
+ if (intent.subjectNodeId) requireNode(intent.subjectNodeId, 'character')
69
+ if (intent.type === 'add-camera' && node) throw new Error(`NODE_ALREADY_EXISTS:${id}`)
70
+ if (['patch-transform', 'move-node', 'set-distance', 'set-fov'].includes(intent.type)) {
71
+ if (!node) throw new Error(`NODE_NOT_FOUND:${id}`)
72
+ if (node.locked) throw new Error(`NODE_LOCKED:${id}`)
73
+ resolveBoundCamera(document, node)
74
+ }
75
+ if (intent.type === 'move-node') {
76
+ if (Boolean(intent.position) === Boolean(intent.offset)) throw new Error('POSITION_OR_OFFSET_REQUIRED')
77
+ if (intent.offset) {
78
+ vector(intent.offset, 'OFFSET')
79
+ intent.position = Object.fromEntries(axes.map(axis => [axis, node.transform.position[axis] + (intent.offset[axis] ?? 0)]))
80
+ }
81
+ intent.type = 'patch-transform'
82
+ }
83
+ if (intent.type === 'set-fov') {
84
+ finite(intent.fov, 'FOV')
85
+ if (intent.fov < 12 || intent.fov > 120) throw new Error('FOV_OUT_OF_RANGE')
86
+ }
87
+ if (intent.type === 'set-distance') {
88
+ finite(intent.distance, 'DISTANCE')
89
+ if (intent.distance < 0.1 || intent.distance > 200) throw new Error('DISTANCE_OUT_OF_RANGE')
90
+ }
91
+ if (intent.type === 'patch-transform') {
92
+ if (!['position', 'rotation', 'scale', 'name'].some(key => intent[key] !== undefined)) throw new Error('EMPTY_NODE_PATCH')
93
+ for (const key of ['position', 'rotation', 'scale']) if (intent[key] !== undefined) vector(intent[key], key.toUpperCase(), key === 'scale')
94
+ if (intent.name !== undefined && (typeof intent.name !== 'string' || !intent.name.trim() || intent.name.length > 128)) throw new Error('INVALID_NODE_NAME')
95
+ }
96
+ const before = node ? structuredClone(node) : null
97
+ const result = applyStudioIntent({ ...body, document, intent })
98
+ if (intent.type === 'patch-transform') {
99
+ const patched = result.document.content.nodes.find(n => n.id === intent.nodeId)
100
+ if (intent.name !== undefined) patched.name = intent.name.trim()
101
+ if (patched.camera && (intent.position || intent.rotation)) {
102
+ const distance = Math.max(0.1, length(before.transform.position, before.camera.lookAt))
103
+ const pinned = before.camera.lookAtTarget || before.camera.subject?.follow
104
+ patched.camera.lookAt = intent.rotation ? aim(patched.transform.position, patched.transform.rotation, distance)
105
+ : pinned ? { ...before.camera.lookAt }
106
+ : Object.fromEntries(axes.map(axis => [axis, before.camera.lookAt[axis] + patched.transform.position[axis] - before.transform.position[axis]]))
107
+ const target = patched.camera.lookAtTarget
108
+ if (target) {
109
+ const subject = result.document.content.nodes.find(n => n.id === target.nodeId)
110
+ target.offset = Object.fromEntries(axes.map(axis => [axis, patched.camera.lookAt[axis] - subject.transform.position[axis]]))
111
+ }
112
+ const binding = patched.camera.subject
113
+ if (binding) {
114
+ const subject = result.document.content.nodes.find(n => n.id === binding.nodeId)
115
+ binding.offset = worldToSubject(patched.transform.position, subject, binding)
116
+ binding.lookAtOffset = worldToSubject(patched.camera.lookAt, subject, binding)
117
+ binding.distance = length(patched.transform.position, patched.camera.lookAt)
118
+ }
119
+ }
120
+ }
121
+ return result
122
+ }
123
+
124
+ export function evaluateStaticPlan(body) {
125
+ let document = structuredClone(body.document)
126
+ if (!Array.isArray(body.changes) || !body.changes.length || body.changes.length > 64) throw new Error('INVALID_PLAN_CHANGES')
127
+ for (const change of body.changes) {
128
+ const patch = Object.fromEntries(['position', 'rotation', 'scale', 'name'].filter(k => change[k] !== undefined).map(k => [k, change[k]]))
129
+ if (!Object.keys(patch).length && change.fov === undefined && change.distance === undefined) throw new Error('EMPTY_PLAN_CHANGE')
130
+ if (Object.keys(patch).length) document = applyStaticIntent({ document, intent: { type: 'patch-transform', nodeId: change.nodeId, ...patch } }).document
131
+ if (change.fov !== undefined) document = applyStaticIntent({ document, intent: { type: 'set-fov', cameraNodeId: change.nodeId, fov: change.fov } }).document
132
+ if (change.distance !== undefined) document = applyStaticIntent({ document, intent: { type: 'set-distance', cameraNodeId: change.nodeId, distance: change.distance } }).document
133
+ }
134
+ return { ...evaluateDocumentFrames({ ...body, document }), dryRun: true }
135
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "builderVersion": "1.0.1-beta.1",
3
+ "threeVersion": "0.184.0",
4
+ "zodVersion": "3.25.76",
5
+ "playwrightVersion": "1.63.0"
6
+ }
topview_3d_cli/bom.py ADDED
@@ -0,0 +1,326 @@
1
+ """Plan / constraint record (BOM): intent, relationships, constraints, camera roles, model review.
2
+
3
+ Pure merge and evidence logic behind the ``topview-3d-cli bom`` and ``inspect views`` commands (stored as
4
+ ``.topview3d/bom.json``). ``checkpoint`` fields are model-owned; the
5
+ runtime owns ``observed`` and ``verification``. Errors are ``ValueError("<CODE>: ...")``.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from typing import Any
11
+
12
+ from jsonschema import Draft7Validator
13
+
14
+ BOM_VERSION = 2
15
+ BOM_MAX_BYTES = 64 * 1024
16
+ CHECKPOINT_FIELDS = ("intent", "relationships", "constraints", "cameras", "notes")
17
+ GUIDES_READ_LIMIT = 32
18
+ OBSERVED_NODE_LIMIT = 200
19
+
20
+ _short = {"type": "string", "maxLength": 2000}
21
+ _entry = {"type": "object", "maxProperties": 24,
22
+ "properties": {"id": {"type": "string", "minLength": 1, "maxLength": 128}},
23
+ "required": ["id"], "additionalProperties": True}
24
+ _review_status = {"enum": ["passed", "failed", "unknown"]}
25
+ CHECKPOINT_SCHEMA = {
26
+ "type": "object",
27
+ "additionalProperties": False,
28
+ "required": ["expectedSceneSequence", "expectedBomRevision"],
29
+ "anyOf": [{"required": [key]} for key in (*CHECKPOINT_FIELDS, "remove", "modelReview")],
30
+ "properties": {
31
+ "expectedSceneSequence": {"type": "integer", "minimum": 0},
32
+ "expectedBomRevision": {"type": "integer", "minimum": 0},
33
+ "intent": {"anyOf": [_short, {"type": "object", "maxProperties": 16}]},
34
+ "relationships": {"type": "array", "maxItems": 128, "items": _entry},
35
+ "constraints": {"type": "array", "maxItems": 128, "items": _entry},
36
+ "cameras": {"type": "array", "maxItems": 32, "items": _entry},
37
+ "notes": {"type": "array", "maxItems": 64, "items": _short},
38
+ "remove": {
39
+ "type": "object", "additionalProperties": False,
40
+ "properties": {key: {"type": "array", "maxItems": 128, "uniqueItems": True,
41
+ "items": {"type": "string", "minLength": 1, "maxLength": 128}}
42
+ for key in ("relationships", "constraints", "cameras")},
43
+ },
44
+ "modelReview": {
45
+ "type": "object", "additionalProperties": False,
46
+ "required": ["views", "constraints"],
47
+ "properties": {
48
+ "views": {"type": "array", "minItems": 1, "maxItems": 24, "items": {
49
+ "type": "object", "additionalProperties": False,
50
+ "required": ["cameraNodeId", "frames", "status", "reason"],
51
+ "properties": {
52
+ "cameraNodeId": {"type": "string", "minLength": 1, "maxLength": 128},
53
+ "frames": {"type": "array", "minItems": 1, "maxItems": 3,
54
+ "items": {"type": "integer", "minimum": 0}},
55
+ "sha256": {"type": "string", "minLength": 1, "maxLength": 128},
56
+ "status": _review_status,
57
+ "reason": {"type": "string", "minLength": 1, "maxLength": 2000},
58
+ },
59
+ }},
60
+ "constraints": {"type": "array", "maxItems": 128, "items": {
61
+ "type": "object", "additionalProperties": False,
62
+ "required": ["id", "status", "reason"],
63
+ "properties": {"id": {"type": "string", "minLength": 1, "maxLength": 128},
64
+ "status": _review_status,
65
+ "reason": {"type": "string", "minLength": 1, "maxLength": 2000}},
66
+ }},
67
+ },
68
+ },
69
+ },
70
+ }
71
+ _CHECKPOINT_VALIDATOR = Draft7Validator(CHECKPOINT_SCHEMA)
72
+
73
+
74
+ def empty_bom(project_id: str) -> dict[str, Any]:
75
+ return {
76
+ "version": BOM_VERSION,
77
+ "projectId": project_id,
78
+ "bomRevision": 0,
79
+ "intent": None,
80
+ "relationships": [],
81
+ "constraints": [],
82
+ "cameras": [],
83
+ "notes": [],
84
+ "guidesRead": [],
85
+ "observed": {"sceneSequence": None, "nodes": []},
86
+ "verification": {"sceneSequence": None, "stale": True},
87
+ "modelReview": None,
88
+ "updatedAt": None,
89
+ }
90
+
91
+
92
+ def normalize_bom(raw: Any, project_id: str) -> dict[str, Any]:
93
+ """Coerce a stored payload into the current shape; unknown / corrupt input falls back to empty."""
94
+ base = empty_bom(project_id)
95
+ if not isinstance(raw, dict):
96
+ return base
97
+ for key in CHECKPOINT_FIELDS:
98
+ if key in raw:
99
+ base[key] = raw[key]
100
+ # Upgrade v1 whole-field records to stable ids without dropping their meaning.
101
+ for key in ("relationships", "constraints", "cameras"):
102
+ upgraded = []
103
+ for index, entry in enumerate(base.get(key) if isinstance(base.get(key), list) else []):
104
+ if isinstance(entry, dict):
105
+ row = dict(entry)
106
+ row.setdefault("id", row.get("nodeId") or f"legacy-{key}-{index + 1}")
107
+ else:
108
+ row = {"id": f"legacy-{key}-{index + 1}", "text": str(entry)}
109
+ upgraded.append(row)
110
+ base[key] = upgraded
111
+ revision = raw.get("bomRevision")
112
+ base["bomRevision"] = revision if isinstance(revision, int) and revision >= 0 else 0
113
+ if isinstance(raw.get("guidesRead"), list):
114
+ base["guidesRead"] = [str(item) for item in raw["guidesRead"] if isinstance(item, str)][:GUIDES_READ_LIMIT]
115
+ if isinstance(raw.get("observed"), dict):
116
+ base["observed"] = {"sceneSequence": raw["observed"].get("sceneSequence"),
117
+ "nodes": list(raw["observed"].get("nodes") or [])[:OBSERVED_NODE_LIMIT]}
118
+ if isinstance(raw.get("verification"), dict):
119
+ base["verification"] = dict(raw["verification"])
120
+ base["verification"]["stale"] = bool(base["verification"].get("stale", True))
121
+ if isinstance(raw.get("modelReview"), dict):
122
+ base["modelReview"] = raw["modelReview"]
123
+ base["updatedAt"] = raw.get("updatedAt")
124
+ return base
125
+
126
+
127
+ def encode_bom(bom: dict[str, Any]) -> bytes:
128
+ data = json.dumps(bom, ensure_ascii=False, indent=2, allow_nan=False).encode("utf-8")
129
+ if len(data) > BOM_MAX_BYTES:
130
+ raise ValueError(f"BOM_TOO_LARGE: {len(data)} bytes > {BOM_MAX_BYTES}")
131
+ return data
132
+
133
+
134
+ def _merge_entries(current: Any, updates: list[dict], removed: set[str], field: str) -> list[dict]:
135
+ entries = list(current) if isinstance(current, list) else []
136
+ if any(not isinstance(entry, dict) or not entry.get("id") for entry in entries):
137
+ raise ValueError(f"BOM_INVALID:{field} entries require stable id")
138
+ update_ids = [entry["id"] for entry in updates]
139
+ if len(update_ids) != len(set(update_ids)) or removed.intersection(update_ids):
140
+ raise ValueError(f"BOM_DUPLICATE_OR_CONFLICTING_IDS:{field}")
141
+ merged = [dict(entry) for entry in entries if entry["id"] not in removed]
142
+ by_id = {entry["id"]: entry for entry in merged}
143
+ for update in updates:
144
+ if update["id"] in by_id:
145
+ by_id[update["id"]].update(update)
146
+ else:
147
+ row = dict(update)
148
+ merged.append(row)
149
+ by_id[row["id"]] = row
150
+ return merged
151
+
152
+
153
+ def apply_checkpoint(bom: dict[str, Any], patch: dict[str, Any]) -> dict[str, Any]:
154
+ """Pure semantic merge; runtime-owned evidence is not writable."""
155
+ error = next(_CHECKPOINT_VALIDATOR.iter_errors(patch), None)
156
+ if error:
157
+ raise ValueError(f"BOM_CHECKPOINT_INVALID:{'.'.join(map(str, error.path))}: {error.message}")
158
+ json.dumps(patch, allow_nan=False)
159
+ merged = dict(bom)
160
+ for key in ("intent", "notes"):
161
+ if key in patch:
162
+ merged[key] = patch[key]
163
+ removals = patch.get("remove") or {}
164
+ for key in ("relationships", "constraints", "cameras"):
165
+ if key in patch or key in removals:
166
+ merged[key] = _merge_entries(merged.get(key), patch.get(key, []),
167
+ set(removals.get(key, [])), key)
168
+ return merged
169
+
170
+
171
+ def merge_checkpoint(current: dict[str, Any], patch: dict[str, Any], sequence: Any) -> dict[str, Any]:
172
+ """Check both CAS versions against ``sequence`` and the stored revision; return the merged BOM."""
173
+ if sequence != patch.get("expectedSceneSequence"):
174
+ raise ValueError("SCENE_SEQUENCE_CONFLICT: read current scene before checkpointing")
175
+ revision = int(current.get("bomRevision") or 0)
176
+ if revision != patch.get("expectedBomRevision"):
177
+ raise ValueError(f"BOM_REVISION_CONFLICT: current bomRevision={revision}; merge against current BOM")
178
+ merged = apply_checkpoint(current, patch)
179
+ semantic_change = any(key in patch for key in (*CHECKPOINT_FIELDS, "remove"))
180
+ if semantic_change and isinstance(merged.get("modelReview"), dict):
181
+ merged["modelReview"] = {**merged["modelReview"], "stale": True}
182
+ if "modelReview" in patch:
183
+ evidence = merged.get("verification") or {}
184
+ if evidence.get("stale") or evidence.get("sceneSequence") != sequence or not evidence.get("views"):
185
+ raise ValueError("BOM_REVIEW_REQUIRES_CURRENT_RUNTIME_EVIDENCE")
186
+ seen = set()
187
+ filled_views = []
188
+ for review in patch["modelReview"]["views"]:
189
+ key = (review["cameraNodeId"], tuple(review["frames"]))
190
+ if key in seen:
191
+ raise ValueError("BOM_REVIEW_DUPLICATE_VIEW")
192
+ seen.add(key)
193
+ filled_views.append(_bind_review_sha(review, evidence.get("views") or []))
194
+ patch = {**patch, "modelReview": {**patch["modelReview"], "views": filled_views}}
195
+ constraint_ids = [row["id"] for row in patch["modelReview"]["constraints"]]
196
+ if len(constraint_ids) != len(set(constraint_ids)):
197
+ raise ValueError("BOM_REVIEW_DUPLICATE_CONSTRAINT")
198
+ required = {row["id"] for row in merged.get("relationships", [])
199
+ if row.get("priority", "hard") == "hard"}
200
+ reviewed_cameras = {row["cameraNodeId"] for row in patch["modelReview"]["views"]}
201
+ cameras = merged.get("cameras") or []
202
+ missing = {
203
+ "constraints": sorted(required - set(constraint_ids)),
204
+ "cameras": sorted({row.get("nodeId") for row in cameras if row.get("nodeId")} - reviewed_cameras),
205
+ "cameraRoles": sorted({"story", "layout_overview"} - {row.get("role") for row in cameras}),
206
+ }
207
+ merged["modelReview"] = {"sceneSequence": sequence, "stale": False,
208
+ **patch["modelReview"], "missingCoverage": missing,
209
+ "coverageComplete": not any(missing.values())}
210
+ merged["bomRevision"] = revision + 1
211
+ encode_bom(merged) # fail before writing when the merged record is oversized
212
+ return merged
213
+
214
+
215
+ def observed_from_snapshot(snapshot: Any) -> dict[str, Any]:
216
+ """Compact node inventory of the authoritative document (ids, types, names, assets)."""
217
+ document = snapshot.get("document") if isinstance(snapshot, dict) else None
218
+ content = document.get("content") if isinstance(document, dict) else None
219
+ nodes = content.get("nodes") if isinstance(content, dict) else None
220
+ rows = []
221
+ for node in (nodes or [])[:OBSERVED_NODE_LIMIT]:
222
+ if not isinstance(node, dict):
223
+ continue
224
+ row = {"id": node.get("id"), "type": node.get("type")}
225
+ if node.get("name"):
226
+ row["name"] = node["name"]
227
+ metadata = node.get("metadata") if isinstance(node.get("metadata"), dict) else {}
228
+ if metadata.get("assetId"):
229
+ row["assetId"] = metadata["assetId"]
230
+ rows.append(row)
231
+ sequence = snapshot.get("sceneSequence") if isinstance(snapshot, dict) else None
232
+ return {"sceneSequence": sequence, "nodes": rows}
233
+
234
+
235
+ def derive_verification(bom: dict[str, Any], observed: dict[str, Any]) -> dict[str, Any]:
236
+ verification = dict(bom.get("verification") or {})
237
+ checked = verification.get("sceneSequence")
238
+ verification["stale"] = checked is None or checked != observed.get("sceneSequence")
239
+ verification.setdefault("sceneSequence", None)
240
+ return verification
241
+
242
+
243
+ def mark_verified(bom: dict[str, Any], scene_sequence: int) -> dict[str, Any]:
244
+ """Record that checks passed against ``scene_sequence``; ``turn_end_sync`` re-derives ``stale``."""
245
+ updated = dict(bom)
246
+ updated["verification"] = {"sceneSequence": scene_sequence, "stale": False}
247
+ return updated
248
+
249
+
250
+ def _evidence_view(views: list, camera_node_id, frames) -> dict[str, Any] | None:
251
+ for row in views:
252
+ if row.get("cameraNodeId") == camera_node_id and row.get("frames") == frames:
253
+ return row
254
+ return None
255
+
256
+
257
+ def _bind_review_sha(review: dict[str, Any], views: list) -> dict[str, Any]:
258
+ """Accept contact-sheet or per-frame hashes; fill sha256 from current evidence when omitted."""
259
+ evidence = _evidence_view(views, review["cameraNodeId"], review["frames"])
260
+ sheet = evidence.get("sha256") if isinstance(evidence, dict) else None
261
+ frame_shas = list((evidence or {}).get("frameSha256s") or [])
262
+ given = review.get("sha256")
263
+ accepted = {value for value in [sheet, *frame_shas] if value}
264
+ if not given:
265
+ if not sheet:
266
+ raise ValueError(
267
+ f"BOM_REVIEW_IMAGE_MISMATCH: {review['cameraNodeId']} frames={review['frames']} "
268
+ "has no current contactSheet sha256"
269
+ )
270
+ return {**review, "sha256": sheet}
271
+ if given in accepted:
272
+ return review
273
+ detail = f"expected sha256={sheet}(contactSheet)" if sheet else "no contactSheet sha256"
274
+ if frame_shas:
275
+ detail += f", frame sha={','.join(frame_shas)}"
276
+ raise ValueError(
277
+ f"BOM_REVIEW_IMAGE_MISMATCH: {review['cameraNodeId']} frames={review['frames']} {detail}"
278
+ )
279
+
280
+
281
+ def _view_evidence(row: dict[str, Any]) -> dict[str, Any]:
282
+ render = row.get("render") if isinstance(row.get("render"), dict) else {}
283
+ sheet = render.get("contactSheet") if isinstance(render.get("contactSheet"), dict) else {}
284
+ frames = render.get("frames") if isinstance(render.get("frames"), list) else []
285
+ frame_shas = list(render.get("frameSha256s") or [])
286
+ if not frame_shas:
287
+ frame_shas = [frame.get("sha256") for frame in frames if isinstance(frame, dict) and frame.get("sha256")]
288
+ return {
289
+ "cameraNodeId": row.get("cameraNodeId"),
290
+ "frames": row.get("frames") or [],
291
+ "numericalOk": row.get("numerical", {}).get("ok") is True,
292
+ "numericalIssues": row.get("numerical", {}).get("issues") or [],
293
+ "renderStatus": row.get("renderStatus"),
294
+ "path": sheet.get("path"),
295
+ "sha256": sheet.get("sha256"),
296
+ "frameSha256s": frame_shas,
297
+ }
298
+
299
+
300
+ def record_runtime_verification(bom: dict[str, Any], result: dict[str, Any]) -> dict[str, Any]:
301
+ """Merge runtime evidence from one inspection; keep same-sequence cameras not re-checked."""
302
+ updated = dict(bom)
303
+ sequence = result.get("sceneSequence")
304
+ previous = dict(bom.get("verification") or {})
305
+ merged: dict[tuple[Any, tuple], dict[str, Any]] = {}
306
+ if previous.get("sceneSequence") == sequence:
307
+ for row in previous.get("views") or []:
308
+ if isinstance(row, dict):
309
+ merged[(row.get("cameraNodeId"), tuple(row.get("frames") or []))] = dict(row)
310
+ for row in result.get("views") or []:
311
+ if not isinstance(row, dict):
312
+ continue
313
+ evidence = _view_evidence(row)
314
+ merged[(evidence.get("cameraNodeId"), tuple(evidence.get("frames") or []))] = evidence
315
+ updated["verification"] = {
316
+ "source": "runtime-v2",
317
+ "sceneSequence": sequence,
318
+ "stale": bool(result.get("stale", True)),
319
+ "checksComplete": bool(result.get("checksComplete")),
320
+ "views": list(merged.values()),
321
+ "geometry": result.get("geometry") or {},
322
+ **({"primaryStoryPreview": result["primaryStoryPreview"]}
323
+ if result.get("primaryStoryPreview") else {}),
324
+ }
325
+ updated["modelReview"] = None
326
+ return updated