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,6 @@
1
+ {
2
+ "name": "@topview/3d-director-cli",
3
+ "private": true,
4
+ "type": "module",
5
+ "license": "Apache-2.0"
6
+ }
@@ -0,0 +1,26 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { createRequire } from 'node:module'
3
+ import path from 'node:path'
4
+ import { fileURLToPath, pathToFileURL } from 'node:url'
5
+
6
+ // TOPVIEW3D_NODE_PREFIX is an npm prefix (it holds node_modules/playwright), used when the
7
+ // renderer ships inside the Python package; otherwise playwright resolves from here.
8
+ export function playwrightDir() {
9
+ const prefix = process.env.TOPVIEW3D_NODE_PREFIX
10
+ try {
11
+ if (prefix) {
12
+ const require = createRequire(path.join(path.resolve(prefix), 'package.json'))
13
+ return path.dirname(require.resolve('playwright/package.json'))
14
+ }
15
+ return path.dirname(fileURLToPath(import.meta.resolve('playwright/package.json')))
16
+ } catch {
17
+ throw new Error('PLAYWRIGHT_NOT_INSTALLED')
18
+ }
19
+ }
20
+
21
+ export async function loadPlaywright() {
22
+ const dir = playwrightDir()
23
+ const manifest = JSON.parse(readFileSync(path.join(dir, 'package.json'), 'utf8'))
24
+ const entry = manifest.exports?.['.']?.import ?? manifest.main ?? 'index.js'
25
+ return import(pathToFileURL(path.join(dir, entry)).href)
26
+ }
@@ -0,0 +1,336 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { createReadStream } from 'node:fs'
3
+ import { mkdir, writeFile } from 'node:fs/promises'
4
+ import http from 'node:http'
5
+ import path from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+ import { loadPlaywright } from './playwright.mjs'
8
+
9
+ const ROOT = path.dirname(fileURLToPath(import.meta.url))
10
+ const RENDERS_DIR_NAME = 'renders'
11
+ const RUN_ID = /^[A-Za-z0-9_-]{1,128}$/
12
+ const THREE_DRACO = path.join(ROOT, 'node_modules/three/examples/jsm/libs/draco')
13
+ const MIME = {
14
+ '.html': 'text/html; charset=utf-8',
15
+ '.js': 'text/javascript; charset=utf-8',
16
+ '.mjs': 'text/javascript; charset=utf-8',
17
+ '.css': 'text/css; charset=utf-8',
18
+ '.json': 'application/json',
19
+ '.wasm': 'application/wasm',
20
+ }
21
+
22
+ function resolveServedFile(relative, localFiles) {
23
+ const local = /^local-assets\/(\d+)\/[^/]+$/.exec(relative)
24
+ if (local) return localFiles[Number(local[1])] ?? null
25
+ if (relative === 'draco' || relative.startsWith('draco/')) {
26
+ const rest = relative === 'draco' ? '' : relative.slice('draco/'.length)
27
+ const file = path.normalize(path.join(THREE_DRACO, rest))
28
+ return file.startsWith(THREE_DRACO) ? file : null
29
+ }
30
+ const file = path.normalize(path.join(ROOT, relative))
31
+ return file.startsWith(ROOT) ? file : null
32
+ }
33
+
34
+ function serveRoot(localFiles = []) {
35
+ return new Promise((resolve) => {
36
+ const server = http.createServer((req, res) => {
37
+ const url = new URL(req.url || '/', 'http://127.0.0.1')
38
+ const relative = decodeURIComponent(url.pathname.replace(/^\/+/, '')) || 'static/headless.html'
39
+ const file = resolveServedFile(relative, localFiles)
40
+ if (!file) {
41
+ res.writeHead(403)
42
+ res.end()
43
+ return
44
+ }
45
+ const stream = createReadStream(file)
46
+ stream.on('error', () => {
47
+ res.writeHead(404)
48
+ res.end()
49
+ })
50
+ stream.on('open', () => {
51
+ res.writeHead(200, { 'Content-Type': MIME[path.extname(file)] || 'application/octet-stream' })
52
+ stream.pipe(res)
53
+ })
54
+ })
55
+ server.listen(0, '127.0.0.1', () => {
56
+ const { port } = server.address()
57
+ resolve({ server, origin: `http://127.0.0.1:${port}` })
58
+ })
59
+ })
60
+ }
61
+
62
+
63
+ // Requests may only reach the local static server and explicitly configured asset
64
+ // origins; anything else is aborted and reported, so offline renders stay offline.
65
+ export function assetOrigins(body) {
66
+ const base = publicAssetBase(body)
67
+ if (!base) return []
68
+ try { return [new URL(base).origin] } catch { return [] }
69
+ }
70
+
71
+ // body.localAssets maps asset keys to absolute files; only those files are served.
72
+ export function localAssetFiles(body) {
73
+ const entries = Object.entries(isPlainObject(body?.localAssets) ? body.localAssets : {})
74
+ for (const [key, file] of entries) {
75
+ if (typeof file !== 'string' || !path.isAbsolute(file)) throw new Error(`LOCAL_ASSET_PATH_INVALID:${key}`)
76
+ }
77
+ return entries
78
+ }
79
+
80
+ function localAssetUrls(entries, origin) {
81
+ return Object.fromEntries(entries.map(([key, file], index) =>
82
+ [key, `${origin}/local-assets/${index}/${encodeURIComponent(path.basename(file))}`]))
83
+ }
84
+
85
+ export async function withPage(work, { allowedOrigins = [], localAssets = [] } = {}) {
86
+ const playwright = await loadPlaywright()
87
+ const { server, origin } = await serveRoot(localAssets.map(([, file]) => path.resolve(file)))
88
+ const network = { blocked: [] }
89
+ let browser
90
+ try {
91
+ browser = await playwright.chromium.launch({
92
+ args: [
93
+ '--use-angle=swiftshader',
94
+ '--enable-unsafe-swiftshader',
95
+ '--ignore-gpu-blocklist',
96
+ '--disable-dev-shm-usage',
97
+ '--disable-web-security',
98
+ ],
99
+ chromiumSandbox: false,
100
+ })
101
+ const page = await browser.newPage()
102
+ const allowed = new Set([origin, ...allowedOrigins])
103
+ await page.route('**/*', (route) => {
104
+ const url = route.request().url()
105
+ let requestOrigin = 'null'
106
+ try { requestOrigin = new URL(url).origin } catch { /* data:, blob: */ }
107
+ if (allowed.has(requestOrigin) || /^(data|blob):/i.test(url)) return route.continue()
108
+ if (network.blocked.length < 50) {
109
+ try { const parsed = new URL(url); network.blocked.push(parsed.origin + parsed.pathname) }
110
+ catch { network.blocked.push('[unparsable URL]') }
111
+ }
112
+ return route.abort('blockedbyclient')
113
+ })
114
+ const warnings = []
115
+ page.on('console', (message) => {
116
+ if (!['warning', 'error'].includes(message.type()) || warnings.length >= 20) return
117
+ // Preserve asset-load diagnostics without returning signed URL credentials.
118
+ warnings.push(message.text().replace(/https?:\/\/[^\s]+/g, (value) => {
119
+ try { const url = new URL(value); return url.origin + url.pathname }
120
+ catch { return '[asset URL]' }
121
+ }))
122
+ })
123
+ page.on('pageerror', (error) => {
124
+ process.stderr.write(`headless pageerror: ${error.message}\n${error.stack || ''}\n`)
125
+ })
126
+ await page.goto(`${origin}/static/headless.html`, { waitUntil: 'load' })
127
+ await page.waitForFunction(() => window.__directorReady === true, null, { timeout: 30_000 })
128
+ return await work(page, origin, warnings, network, localAssetUrls(localAssets, origin))
129
+ } finally {
130
+ if (browser) await browser.close()
131
+ await new Promise((resolve) => server.close(resolve))
132
+ }
133
+ }
134
+
135
+ function digest(buffer) {
136
+ return createHash('sha256').update(buffer).digest('hex')
137
+ }
138
+
139
+ function publicAssetBase(body) {
140
+ return body.publicAssetBase
141
+ || process.env.TOPVIEW3D_DIRECTOR_PUBLIC_ASSET_BASE
142
+ || ''
143
+ }
144
+
145
+ // outputDir is `<absolute>/renders/<runId>`: the caller chooses the root (a project's
146
+ // .topview3d/renders), the renderer writes exactly one run directory below it.
147
+ export function resolveOutputDir(outputDir, pathApi = path) {
148
+ if (typeof outputDir !== 'string' || !outputDir.trim()) {
149
+ throw new Error('RENDER_OUTPUT_DIR_REQUIRED')
150
+ }
151
+ if (!pathApi.isAbsolute(outputDir)) throw new Error('RENDER_OUTPUT_DIR_INVALID')
152
+ if (outputDir.split(/[\\/]+/).some((segment) => segment === '..' || segment === '.')) {
153
+ throw new Error('RENDER_OUTPUT_DIR_INVALID')
154
+ }
155
+ const resolved = pathApi.resolve(outputDir)
156
+ const runId = pathApi.basename(resolved)
157
+ const parent = pathApi.dirname(resolved)
158
+ if (!RUN_ID.test(runId) || pathApi.basename(parent) !== RENDERS_DIR_NAME || parent === resolved) {
159
+ throw new Error('RENDER_OUTPUT_DIR_INVALID')
160
+ }
161
+ return resolved
162
+ }
163
+
164
+ export function resolveRenderSize(body) {
165
+ const requestedWidth = body.width ?? 640
166
+ const requestedHeight = body.height ?? 360
167
+ if (![requestedWidth, requestedHeight].every((value) => Number.isInteger(value) && value >= 64)) {
168
+ throw new Error('render dimensions must be integers >=64')
169
+ }
170
+ const ratio = Math.min(1, 1024 / Math.max(requestedWidth, requestedHeight))
171
+ return {
172
+ width: Math.max(1, Math.round(requestedWidth * ratio)),
173
+ height: Math.max(1, Math.round(requestedHeight * ratio)),
174
+ }
175
+ }
176
+
177
+ export async function renderFrames(body) {
178
+ const frames = body.frames ?? [0]
179
+ if (!frames.length || frames.length > 9) throw new Error('contact sheet requires 1–9 frames')
180
+ const outputDir = resolveOutputDir(body.outputDir)
181
+ const { width, height } = resolveRenderSize(body)
182
+ await mkdir(outputDir, { recursive: true })
183
+ const localAssets = localAssetFiles(body)
184
+ return withPage(async (page, origin, warnings, network, localAssetUrls) => {
185
+ const result = await page.evaluate(async ({
186
+ document, fcurves, frames, width, height, publicAssetBase, dracoDecoderPath, cameraNodeId, sceneSequence,
187
+ localAssetUrls,
188
+ }) => {
189
+ const renderer = await window.createDirectorRenderer({
190
+ document,
191
+ fcurves,
192
+ width,
193
+ height,
194
+ publicAssetBase,
195
+ dracoDecoderPath,
196
+ localAssetUrls,
197
+ })
198
+ try {
199
+ const pngs = []
200
+ for (const frame of frames) {
201
+ const blob = await renderer.renderFrame(frame, cameraNodeId ? { cameraId: cameraNodeId } : undefined)
202
+ const buffer = await blob.arrayBuffer()
203
+ pngs.push({
204
+ frame,
205
+ base64: window.bytesToBase64(buffer),
206
+ bytes: buffer.byteLength,
207
+ })
208
+ }
209
+ const sheet = await window.composeContactSheet(pngs, width, height,
210
+ cameraNodeId ? `${cameraNodeId} · scene ${sceneSequence ?? '?'}` : '')
211
+ return { pngs, sheet }
212
+ } finally {
213
+ renderer.dispose()
214
+ }
215
+ }, {
216
+ document: body.document,
217
+ fcurves: body.fcurves ?? null,
218
+ frames,
219
+ cameraNodeId: body.cameraNodeId,
220
+ sceneSequence: body.sceneSequence,
221
+ width,
222
+ height,
223
+ publicAssetBase: publicAssetBase(body),
224
+ dracoDecoderPath: `${origin}/draco/`,
225
+ localAssetUrls,
226
+ })
227
+ const blank = result.pngs.some((item) => item.bytes < 256)
228
+ const frameEntries = []
229
+ for (const item of result.pngs) {
230
+ const buffer = Buffer.from(item.base64, 'base64')
231
+ const file = path.join(outputDir, `frame-${item.frame}.png`)
232
+ await writeFile(file, buffer)
233
+ frameEntries.push({
234
+ frame: item.frame,
235
+ path: file,
236
+ mimeType: 'image/png',
237
+ sizeBytes: buffer.byteLength,
238
+ sha256: digest(buffer),
239
+ })
240
+ }
241
+ const sheetBuffer = Buffer.from(result.sheet, 'base64')
242
+ const sheetFile = path.join(outputDir, 'contact-sheet.png')
243
+ await writeFile(sheetFile, sheetBuffer)
244
+ const cameraNodeId = body.cameraNodeId ?? body.document?.content?.activeShotCameraNodeId
245
+ const contactSheet = {
246
+ path: sheetFile,
247
+ mimeType: 'image/png',
248
+ sizeBytes: sheetBuffer.byteLength,
249
+ sha256: digest(sheetBuffer),
250
+ }
251
+ const manifestFile = path.join(outputDir, 'render.json')
252
+ await writeFile(manifestFile, `${JSON.stringify({
253
+ version: 1,
254
+ runId: path.basename(outputDir),
255
+ createdAt: new Date().toISOString(),
256
+ width,
257
+ height,
258
+ cameraNodeId,
259
+ sceneSequence: body.sceneSequence,
260
+ frames: frameEntries.map(({ path: file, ...entry }) => ({ ...entry, file: path.basename(file) })),
261
+ contactSheet: { ...contactSheet, path: undefined, file: path.basename(sheetFile) },
262
+ blank,
263
+ blockedRequests: network.blocked,
264
+ ...(isPlainObject(body.metadata) ? { metadata: body.metadata } : {}),
265
+ }, null, 2)}\n`)
266
+ return {
267
+ outputDir,
268
+ manifest: manifestFile,
269
+ cameraNodeId,
270
+ sceneSequence: body.sceneSequence,
271
+ frames: frameEntries,
272
+ contactSheet,
273
+ blank,
274
+ blockedRequests: network.blocked,
275
+ warnings,
276
+ }
277
+ }, { allowedOrigins: assetOrigins(body), localAssets })
278
+ }
279
+
280
+ function isPlainObject(value) {
281
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
282
+ }
283
+
284
+ export async function inspectNodes(body) {
285
+ if (!body || typeof body.document !== 'object' || !Array.isArray(body.nodeIds) || !body.nodeIds.length) {
286
+ throw new Error('document and nodeIds required')
287
+ }
288
+ const localAssets = localAssetFiles(body)
289
+ return withPage(async (page, origin, warnings, network, localAssetUrls) => {
290
+ const nodes = await page.evaluate(async (input) => window.inspectDirectorNodes(input), {
291
+ localAssetUrls,
292
+ document: body.document,
293
+ fcurves: body.fcurves ?? null,
294
+ nodeIds: body.nodeIds,
295
+ frame: body.frames?.[0],
296
+ publicAssetBase: publicAssetBase(body),
297
+ dracoDecoderPath: `${origin}/draco/`,
298
+ })
299
+ return { ok: nodes.every((node) => node.status === 'measured'), nodes, warnings, blockedRequests: network.blocked }
300
+ }, { allowedOrigins: assetOrigins(body), localAssets })
301
+ }
302
+
303
+ export async function applyLibraryPose(body) {
304
+ if (!body || typeof body.document !== 'object') {
305
+ throw new Error('document required')
306
+ }
307
+ const localAssets = localAssetFiles(body)
308
+ return withPage(async (page, origin, warnings, network, localAssetUrls) => page.evaluate(
309
+ (input) => window.compileDirectorPose(input),
310
+ { ...body, localAssets: undefined, localAssetUrls, publicAssetBase: publicAssetBase(body),
311
+ dracoDecoderPath: `${origin}/draco/` },
312
+ ), { allowedOrigins: assetOrigins(body), localAssets })
313
+ }
314
+
315
+ // Compiles several library poses against one loaded page; the document is not modified.
316
+ export async function applyLibraryPoses(body) {
317
+ if (!body || typeof body.document !== 'object' || !Array.isArray(body.items) || !body.items.length) {
318
+ throw new Error('document and items required')
319
+ }
320
+ const localAssets = localAssetFiles(body)
321
+ return withPage(async (page, origin, warnings, network, localAssetUrls) => {
322
+ const results = []
323
+ for (const item of body.items) {
324
+ results.push(await page.evaluate((input) => window.compileDirectorPose(input), {
325
+ document: body.document,
326
+ nodeId: item.nodeId,
327
+ libraryId: item.libraryId,
328
+ pose: item.pose,
329
+ localAssetUrls,
330
+ publicAssetBase: publicAssetBase(body),
331
+ dracoDecoderPath: `${origin}/draco/`,
332
+ }))
333
+ }
334
+ return { results, warnings, blockedRequests: network.blocked }
335
+ }, { allowedOrigins: assetOrigins(body), localAssets })
336
+ }
@@ -0,0 +1,124 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <script type="importmap">
6
+ {
7
+ "imports": {
8
+ "three": "/node_modules/three/build/three.module.js",
9
+ "three/addons/": "/node_modules/three/examples/jsm/",
10
+ "zod": "/node_modules/zod/index.js"
11
+ }
12
+ }
13
+ </script>
14
+ </head>
15
+ <body>
16
+ <canvas id="stage" width="1280" height="720"></canvas>
17
+ <script type="module">
18
+ import { createHeadlessRenderer } from '/node_modules/@topview/3d-builder/dist/headless/index.mjs'
19
+ import { Stage } from '/node_modules/@topview/3d-builder/dist/engine/index.mjs'
20
+ import { Box3, Vector3 } from 'three'
21
+ import { FCurveSet } from '/node_modules/@topview/3d-builder/dist/evaluate/index.mjs'
22
+ import { resolveHeadlessMediaUrl } from '/mediaUrl.mjs'
23
+ import { compileLibraryPose } from './pose.mjs'
24
+ import { supportSurfaces, characterLandmarks } from './measure.mjs'
25
+ window.compileDirectorPose = compileLibraryPose
26
+
27
+ window.createDirectorRenderer = async ({
28
+ document, fcurves, width, height, publicAssetBase, dracoDecoderPath, localAssetUrls,
29
+ }) => {
30
+ const renderer = createHeadlessRenderer({
31
+ width,
32
+ height,
33
+ dracoDecoderPath,
34
+ resolveMediaUrl: (ref) => resolveHeadlessMediaUrl(ref, publicAssetBase || '', localAssetUrls),
35
+ })
36
+ // Evidence renders should not cover faces/contact with Editor name sprites.
37
+ // This copy keeps the saved draft's label settings unchanged.
38
+ const renderDocument = structuredClone(document)
39
+ for (const node of renderDocument.content.nodes) {
40
+ if (node.character) node.character.label = { ...node.character.label, showLabel: false }
41
+ }
42
+ await renderer.load(renderDocument, fcurves)
43
+ return renderer
44
+ }
45
+
46
+ window.inspectDirectorNodes = async ({
47
+ document, fcurves, nodeIds, frame, publicAssetBase, dracoDecoderPath, localAssetUrls,
48
+ }) => {
49
+ const stage = new Stage(ref => resolveHeadlessMediaUrl(ref, publicAssetBase || '', localAssetUrls), { dracoDecoderPath })
50
+ try {
51
+ await stage.load(document)
52
+ if (fcurves) stage.setFcurves(FCurveSet.parse(fcurves))
53
+ stage.seek(frame ?? document.content.timeline.frameStart ?? 0)
54
+ stage.scene.updateMatrixWorld(true)
55
+ return nodeIds.map(nodeId => {
56
+ const node = document.content.nodes.find(n => n.id === nodeId)
57
+ const object = stage.characters.get(nodeId)?.root || stage.props.get(nodeId) || stage.primitives.get(nodeId) || stage.groups.get(nodeId)
58
+ if (!object) return { nodeId, status: 'geometry-unavailable', type: node?.type }
59
+ const bounds = new Box3()
60
+ object.traverse(child => {
61
+ if (!child.isMesh || !child.geometry) return
62
+ // Measure meshes only: character label sprites must not inflate size.
63
+ const box = new Box3().setFromObject(child, true)
64
+ if (!box.isEmpty()) bounds.union(box)
65
+ })
66
+ if (bounds.isEmpty()) return { nodeId, status: 'geometry-unavailable' }
67
+ const point = value => ({ x: value.x, y: value.y, z: value.z })
68
+ return { nodeId, name: node.name, type: node.type, status: 'measured',
69
+ size: point(bounds.getSize(new Vector3())),
70
+ bounds: { min: point(bounds.min), max: point(bounds.max) },
71
+ origin: point(object.getWorldPosition(new Vector3())),
72
+ localForwardAxis: point(new Vector3(0, 0, 1).transformDirection(object.matrixWorld)),
73
+ ...(node.type === 'character' ? { landmarks: characterLandmarks(object) }
74
+ : { supportSurfaces: supportSurfaces(object) }),
75
+ semanticFront: 'unknown; verify in preview', transform: node.transform }
76
+ })
77
+ } finally { stage.dispose() }
78
+ }
79
+
80
+ // Chunked encoder: `String.fromCharCode(...bytes)` spreads every byte as a
81
+ // call argument and overflows the stack for PNGs above ~100 KB, which is
82
+ // any real-resolution frame. Encode in fixed slices instead.
83
+ window.bytesToBase64 = (buffer) => {
84
+ const bytes = new Uint8Array(buffer)
85
+ const chunk = 0x8000
86
+ let binary = ''
87
+ for (let i = 0; i < bytes.length; i += chunk) {
88
+ binary += String.fromCharCode.apply(null, bytes.subarray(i, i + chunk))
89
+ }
90
+ return btoa(binary)
91
+ }
92
+
93
+ window.composeContactSheet = async (pngs, width, height, label = '') => {
94
+ const cols = Math.min(3, pngs.length)
95
+ const rows = Math.ceil(pngs.length / cols)
96
+ const canvas = document.createElement('canvas')
97
+ // Cap the sheet at 1024px on the long edge so the file stays cheap to persist.
98
+ const scale = Math.min(1, 1024 / Math.max(cols * width, rows * height))
99
+ canvas.width = Math.max(1, Math.round(cols * width * scale))
100
+ canvas.height = Math.max(1, Math.round(rows * height * scale))
101
+ const ctx = canvas.getContext('2d')
102
+ ctx.scale(canvas.width / (cols * width), canvas.height / (rows * height))
103
+ for (const [index, item] of pngs.entries()) {
104
+ const image = new Image()
105
+ image.src = `data:image/png;base64,${item.base64}`
106
+ await image.decode()
107
+ const x = (index % cols) * width, y = Math.floor(index / cols) * height
108
+ ctx.drawImage(image, x, y, width, height)
109
+ const fontSize = Math.max(14, Math.round(14 / scale))
110
+ ctx.fillStyle = 'rgba(0,0,0,0.8)'
111
+ ctx.fillRect(x, y, width, fontSize + 10)
112
+ ctx.font = `${fontSize}px sans-serif`
113
+ ctx.fillStyle = '#ffffff'
114
+ ctx.fillText(`${label ? label + ' · ' : ''}frame ${item.frame}`, x + 6, y + fontSize + 2, width - 12)
115
+ }
116
+ const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/png'))
117
+ const buffer = await blob.arrayBuffer()
118
+ return window.bytesToBase64(buffer)
119
+ }
120
+
121
+ window.__directorReady = true
122
+ </script>
123
+ </body>
124
+ </html>
@@ -0,0 +1,61 @@
1
+ import { Box3, Vector3 } from 'three'
2
+
3
+ const point = v => ({ x: v.x, y: v.y, z: v.z })
4
+
5
+ // Geometric candidates only: a chair's seat, armrest and back top can all be
6
+ // horizontal. Consumers must identify the seat from annotations and the image.
7
+ export function supportSurfaces(object) {
8
+ const groups = new Map()
9
+ const a = new Vector3(), b = new Vector3(), c = new Vector3()
10
+ const ab = new Vector3(), ac = new Vector3(), normal = new Vector3()
11
+ object.traverse(mesh => {
12
+ const geometry = mesh.geometry
13
+ if (!mesh.isMesh || mesh.isSkinnedMesh || !geometry?.attributes.position) return
14
+ const indices = geometry.index
15
+ const count = indices?.count ?? geometry.attributes.position.count
16
+ for (let i = 0; i + 2 < count; i += 3) {
17
+ for (const [offset, v] of [[0, a], [1, b], [2, c]]) {
18
+ mesh.getVertexPosition(indices ? indices.getX(i + offset) : i + offset, v)
19
+ v.applyMatrix4(mesh.matrixWorld)
20
+ }
21
+ normal.crossVectors(ab.subVectors(b, a), ac.subVectors(c, a))
22
+ const area = normal.length() / 2
23
+ if (area < 1e-8 || normal.y / (2 * area) < 0.97) continue
24
+ const height = (a.y + b.y + c.y) / 3
25
+ const bucket = Math.round(height / 0.02)
26
+ const group = groups.get(bucket) || { area: 0, weightedHeight: 0, bounds: new Box3() }
27
+ group.area += area
28
+ group.weightedHeight += area * height
29
+ group.bounds.expandByPoint(a).expandByPoint(b).expandByPoint(c)
30
+ groups.set(bucket, group)
31
+ }
32
+ })
33
+ return [...groups.values()].filter(g => g.area > 0.005)
34
+ .sort((a, b) => b.area - a.area).slice(0, 6).map(g => ({
35
+ height: g.weightedHeight / g.area, area: g.area,
36
+ worldWidth: g.bounds.max.x - g.bounds.min.x,
37
+ worldDepth: g.bounds.max.z - g.bounds.min.z,
38
+ bounds: { min: point(g.bounds.min), max: point(g.bounds.max) },
39
+ }))
40
+ }
41
+
42
+ export function characterLandmarks(root) {
43
+ const names = {
44
+ hips: ['mixamorighips', 'hips', 'pelvis'],
45
+ leftKnee: ['mixamorigleftleg', 'leftleg', 'calfl'],
46
+ rightKnee: ['mixamorigrightleg', 'rightleg', 'calfr'],
47
+ leftAnkle: ['mixamorigleftfoot', 'leftfoot', 'footl'],
48
+ rightAnkle: ['mixamorigrightfoot', 'rightfoot', 'footr'],
49
+ leftHip: ['mixamorigleftupleg', 'leftupleg', 'thighl'],
50
+ rightHip: ['mixamorigrightupleg', 'rightupleg', 'thighr'],
51
+ }
52
+ const result = {}
53
+ root.traverse(obj => {
54
+ if (!obj.isBone) return
55
+ const name = obj.name.toLowerCase().replace(/[^a-z0-9]/g, '')
56
+ for (const [key, aliases] of Object.entries(names)) {
57
+ if (aliases.includes(name)) result[key] = point(obj.getWorldPosition(new Vector3()))
58
+ }
59
+ })
60
+ return result
61
+ }
@@ -0,0 +1,71 @@
1
+ import { Stage, poseRootOffsetScale } from '/node_modules/@topview/3d-builder/dist/engine/index.mjs'
2
+ import { Box3, Quaternion, Vector3 } from 'three'
3
+ import { resolveHeadlessMediaUrl } from '/mediaUrl.mjs'
4
+
5
+ const normalize = value => value.toLowerCase().replace(/[^a-z0-9]/g, '')
6
+ const ual = { Hips: 'pelvis', Spine: 'spine_01', Spine1: 'spine_02', Spine2: 'spine_03', Neck: 'neck_01', Head: 'Head' }
7
+ for (const [side, suffix] of [['Left', 'l'], ['Right', 'r']]) {
8
+ for (const [part, target] of Object.entries({ Shoulder: 'clavicle', Arm: 'upperarm', ForeArm: 'lowerarm', Hand: 'hand', UpLeg: 'thigh', Leg: 'calf', Foot: 'foot', ToeBase: 'ball' })) ual[side + part] = `${target}_${suffix}`
9
+ for (const finger of ['Index', 'Middle', 'Ring', 'Pinky', 'Thumb']) {
10
+ for (let i = 1; i <= 3; i++) ual[`${side}Hand${finger}${i}`] = `${finger.toLowerCase()}_0${i}_${suffix}`
11
+ }
12
+ }
13
+
14
+ // The package's evaluate/headless entrypoints do not expose its dynamic pose
15
+ // bank. Materialize the same world-delta retargeting as supported joint controls,
16
+ // so both the Editor and headless renderer can replay the static pose unaided.
17
+ export async function compileLibraryPose({ document, nodeId, pose, libraryId, publicAssetBase, dracoDecoderPath, localAssetUrls }) {
18
+ const doc = structuredClone(document)
19
+ const node = doc.content.nodes.find(n => n.id === nodeId)
20
+ if (!node?.character) throw new Error('DIRECTOR_POSE_REQUIRES_CHARACTER')
21
+ if (node.locked) throw new Error('NODE_LOCKED')
22
+ node.character.animation = { mode: 'pose', controlValues: {} }
23
+ const stage = new Stage(ref => resolveHeadlessMediaUrl(ref, publicAssetBase || '', localAssetUrls), { dracoDecoderPath })
24
+ try {
25
+ await stage.load(doc)
26
+ const character = stage.characters.get(nodeId)
27
+ if (!character) throw new Error('DIRECTOR_POSE_CHARACTER_NOT_LOADED')
28
+ const { root, restPose } = character
29
+ const savedRoot = root.quaternion.clone()
30
+ root.quaternion.identity()
31
+ root.traverse(obj => { if (restPose.has(obj.name)) obj.quaternion.copy(restPose.get(obj.name)) })
32
+ root.updateMatrixWorld(true)
33
+ const byName = new Map(), restWorld = new Map(), assigned = new Map()
34
+ root.traverse(obj => {
35
+ if (obj.isBone) byName.set(normalize(obj.name), obj)
36
+ restWorld.set(obj, obj.getWorldQuaternion(new Quaternion()))
37
+ })
38
+ for (const [name, value] of Object.entries(pose.bones)) {
39
+ const mapped = character.rig === 'ual1' ? ual[name.replace(/^mixamorig:?/i, '')] : null
40
+ const bone = byName.get(normalize(mapped || name))
41
+ if (bone) assigned.set(bone, value)
42
+ }
43
+ if (assigned.size < 10) throw new Error('DIRECTOR_POSE_INCOMPATIBLE_SKELETON')
44
+ const controls = {}
45
+ const apply = obj => {
46
+ const values = assigned.get(obj)
47
+ if (values) {
48
+ const desired = new Quaternion(...values).normalize().multiply(restWorld.get(obj))
49
+ const parent = obj.parent?.getWorldQuaternion(new Quaternion()) || new Quaternion()
50
+ obj.quaternion.copy(parent.invert().multiply(desired))
51
+ obj.updateWorldMatrix(true, false)
52
+ }
53
+ if (obj.isBone) {
54
+ for (const axis of ['x', 'y', 'z']) controls[`joint:${obj.name}:${axis}`] = obj.rotation[axis] * 180 / Math.PI
55
+ }
56
+ for (const child of obj.children) apply(child)
57
+ }
58
+ apply(root)
59
+ const animation = { mode: 'pose', posePresetId: pose.pose_id || libraryId.replace(/^a3d_pose_/, ''),
60
+ controlValues: controls, rootPositionOffset: { x: pose.hips[0], y: pose.hips[1], z: pose.hips[2] } }
61
+ // Return only character pose fields: signed model URLs must not be persisted.
62
+ // Same root drop as applySnapshot: library hips scale with the character's leg length.
63
+ character.inner.position.set(...pose.hips.map(value => value * poseRootOffsetScale(character.legLength)))
64
+ root.quaternion.copy(savedRoot)
65
+ root.updateMatrixWorld(true)
66
+ const bounds = new Box3().setFromObject(character.inner, true)
67
+ const point = value => ({ x: value.x, y: value.y, z: value.z })
68
+ return { animation, pose: { libraryId, matchedBones: assigned.size,
69
+ size: point(bounds.getSize(new Vector3())), bounds: { min: point(bounds.min), max: point(bounds.max) } } }
70
+ } finally { stage.dispose() }
71
+ }