voxflow 1.15.0 → 1.15.2

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 (453) hide show
  1. package/README.md +34 -0
  2. package/bin/voxflow.js +27 -0
  3. package/dist/index.js +1 -1
  4. package/dist/remotion-bundle/02a2fb2eb80bc7bf.woff2 +0 -0
  5. package/dist/remotion-bundle/052ca5351e5e06ba.woff2 +0 -0
  6. package/dist/remotion-bundle/05853dd28f4019cb.woff2 +0 -0
  7. package/dist/remotion-bundle/072ead3737f7c0d0.woff2 +0 -0
  8. package/dist/remotion-bundle/07d4248613c86a2e.woff2 +0 -0
  9. package/dist/remotion-bundle/0884a5c2d1d2d99b.woff2 +0 -0
  10. package/dist/remotion-bundle/0b0e185b2752095e.woff2 +0 -0
  11. package/dist/remotion-bundle/0e66c11bde067d91.woff2 +0 -0
  12. package/dist/remotion-bundle/0f7794cfba2c5d21.woff2 +0 -0
  13. package/dist/remotion-bundle/0fdbae5a4365783a.woff2 +0 -0
  14. package/dist/remotion-bundle/112.bundle.js +11 -0
  15. package/dist/remotion-bundle/112.bundle.js.map +1 -0
  16. package/dist/remotion-bundle/113.bundle.js +11 -0
  17. package/dist/remotion-bundle/113.bundle.js.map +1 -0
  18. package/dist/remotion-bundle/119cae0c4c16f7ed.woff2 +0 -0
  19. package/dist/remotion-bundle/14725f649fd1e78c.woff2 +0 -0
  20. package/dist/remotion-bundle/14abe9e3f95f7888.woff2 +0 -0
  21. package/dist/remotion-bundle/163.bundle.js +14678 -0
  22. package/dist/remotion-bundle/163.bundle.js.map +1 -0
  23. package/dist/remotion-bundle/1808c54072bf6d14.woff2 +0 -0
  24. package/dist/remotion-bundle/18948bec3e3012fe.woff2 +0 -0
  25. package/dist/remotion-bundle/1a661c60d0fc84fc.woff2 +0 -0
  26. package/dist/remotion-bundle/1af94941e1bc7e1e.woff2 +0 -0
  27. package/dist/remotion-bundle/1bee0219595f606c.woff2 +0 -0
  28. package/dist/remotion-bundle/1bfd5da7ce9d4ec4.woff2 +0 -0
  29. package/dist/remotion-bundle/1c158d56f1884f3f.woff2 +0 -0
  30. package/dist/remotion-bundle/1cf5e88e667610eb.woff2 +0 -0
  31. package/dist/remotion-bundle/1d431bd10f53c481.woff2 +0 -0
  32. package/dist/remotion-bundle/1d701a81a7670db2.woff2 +0 -0
  33. package/dist/remotion-bundle/1da0fecad4240f16.woff2 +0 -0
  34. package/dist/remotion-bundle/1ed14d3d0c5c63fe.woff2 +0 -0
  35. package/dist/remotion-bundle/1edfecf40e586f53.woff2 +0 -0
  36. package/dist/remotion-bundle/1f479711bc34b054.woff +0 -0
  37. package/dist/remotion-bundle/1f86e54a0ff5fcd1.woff2 +0 -0
  38. package/dist/remotion-bundle/2043ea87d9aabd11.woff2 +0 -0
  39. package/dist/remotion-bundle/20563c39ee8a0e40.woff2 +0 -0
  40. package/dist/remotion-bundle/20c231590fd12c44.woff2 +0 -0
  41. package/dist/remotion-bundle/20ce61713f754c07.woff2 +0 -0
  42. package/dist/remotion-bundle/21eb9306fce24bb1.woff2 +0 -0
  43. package/dist/remotion-bundle/244bf71c0cc851af.woff2 +0 -0
  44. package/dist/remotion-bundle/274d4cfc02bffbcb.woff2 +0 -0
  45. package/dist/remotion-bundle/275.bundle.js +21 -0
  46. package/dist/remotion-bundle/275.bundle.js.map +1 -0
  47. package/dist/remotion-bundle/2958f540b39513dc.woff2 +0 -0
  48. package/dist/remotion-bundle/2a168b98fd97722e.woff2 +0 -0
  49. package/dist/remotion-bundle/2d1f6373937ab55f.woff2 +0 -0
  50. package/dist/remotion-bundle/2d213ae47ff6daa9.woff2 +0 -0
  51. package/dist/remotion-bundle/2e4b1f04fcd05047.woff2 +0 -0
  52. package/dist/remotion-bundle/304170d98f4c4563.woff2 +0 -0
  53. package/dist/remotion-bundle/30d02e136e7a5642.woff2 +0 -0
  54. package/dist/remotion-bundle/3135562b52a714cd.woff2 +0 -0
  55. package/dist/remotion-bundle/313713af2c8144e9.woff2 +0 -0
  56. package/dist/remotion-bundle/325fa4108d2285b9.woff2 +0 -0
  57. package/dist/remotion-bundle/338e927ed3345e0c.woff2 +0 -0
  58. package/dist/remotion-bundle/35fc6b190365bc17.woff2 +0 -0
  59. package/dist/remotion-bundle/37a51f1122d4efc5.woff2 +0 -0
  60. package/dist/remotion-bundle/39a4d63e02736f5e.woff2 +0 -0
  61. package/dist/remotion-bundle/3a00e0d62dfc4171.woff2 +0 -0
  62. package/dist/remotion-bundle/3a6955e6561affe1.woff2 +0 -0
  63. package/dist/remotion-bundle/3c573945aef49b89.woff2 +0 -0
  64. package/dist/remotion-bundle/3cdbfbfa23b516a5.woff2 +0 -0
  65. package/dist/remotion-bundle/3e42f85a9e64ca8a.woff2 +0 -0
  66. package/dist/remotion-bundle/3e83eaf1ec859415.woff2 +0 -0
  67. package/dist/remotion-bundle/3f3c8c90de1250ee.woff2 +0 -0
  68. package/dist/remotion-bundle/434.bundle.js +205 -0
  69. package/dist/remotion-bundle/434.bundle.js.map +1 -0
  70. package/dist/remotion-bundle/44ffc6ca4d781692.woff2 +0 -0
  71. package/dist/remotion-bundle/4670d9c4580b09eb.woff2 +0 -0
  72. package/dist/remotion-bundle/479756881b302824.woff2 +0 -0
  73. package/dist/remotion-bundle/481b82134bfa9c82.woff2 +0 -0
  74. package/dist/remotion-bundle/48d27029626f4328.woff2 +0 -0
  75. package/dist/remotion-bundle/49b7b2a30329c511.woff2 +0 -0
  76. package/dist/remotion-bundle/4c8b25a1a9337045.woff2 +0 -0
  77. package/dist/remotion-bundle/4cba14788ca9259b.woff2 +0 -0
  78. package/dist/remotion-bundle/4cd6c589c004a6a7.woff2 +0 -0
  79. package/dist/remotion-bundle/4cd8d79c1021608d.woff2 +0 -0
  80. package/dist/remotion-bundle/4d8fa99b3f00f9f0.woff2 +0 -0
  81. package/dist/remotion-bundle/4e7805a643f86d53.woff2 +0 -0
  82. package/dist/remotion-bundle/4ff91be454542e3f.woff2 +0 -0
  83. package/dist/remotion-bundle/504cbcba1f63591b.woff2 +0 -0
  84. package/dist/remotion-bundle/5202d792e5791d6c.woff2 +0 -0
  85. package/dist/remotion-bundle/534db5ad4770cc1d.woff2 +0 -0
  86. package/dist/remotion-bundle/53b9568eb85f866b.woff2 +0 -0
  87. package/dist/remotion-bundle/543ad386ca171de9.woff2 +0 -0
  88. package/dist/remotion-bundle/54798e55bbf7976e.woff2 +0 -0
  89. package/dist/remotion-bundle/580.bundle.js +11 -0
  90. package/dist/remotion-bundle/580.bundle.js.map +1 -0
  91. package/dist/remotion-bundle/58d174d1193af6d1.woff2 +0 -0
  92. package/dist/remotion-bundle/591d29ff3ff53c80.woff2 +0 -0
  93. package/dist/remotion-bundle/5c28c4f4824383c6.woff2 +0 -0
  94. package/dist/remotion-bundle/5da9740d2ce894c8.woff2 +0 -0
  95. package/dist/remotion-bundle/6197735364642360.woff2 +0 -0
  96. package/dist/remotion-bundle/6265a4335724080f.woff2 +0 -0
  97. package/dist/remotion-bundle/633f5e4f6394daa7.woff2 +0 -0
  98. package/dist/remotion-bundle/637d95ace6a69c49.woff2 +0 -0
  99. package/dist/remotion-bundle/648e04a04dacff8f.woff2 +0 -0
  100. package/dist/remotion-bundle/64a6e83045a008b2.woff2 +0 -0
  101. package/dist/remotion-bundle/651.bundle.js +11 -0
  102. package/dist/remotion-bundle/651.bundle.js.map +1 -0
  103. package/dist/remotion-bundle/65e2a988c070facc.woff2 +0 -0
  104. package/dist/remotion-bundle/66a2f6ce5cc69105.woff2 +0 -0
  105. package/dist/remotion-bundle/690.bundle.js +3479 -0
  106. package/dist/remotion-bundle/690.bundle.js.map +1 -0
  107. package/dist/remotion-bundle/690ff55252ca715d.woff2 +0 -0
  108. package/dist/remotion-bundle/6a01a1cff49314fc.woff2 +0 -0
  109. package/dist/remotion-bundle/6cbc32670982986c.woff2 +0 -0
  110. package/dist/remotion-bundle/6d3cc42ae547f454.woff2 +0 -0
  111. package/dist/remotion-bundle/6d8f4cfa1ddc0830.woff2 +0 -0
  112. package/dist/remotion-bundle/6e4d7c6ae65e2dc3.woff2 +0 -0
  113. package/dist/remotion-bundle/6e86418bbcefb2e8.woff2 +0 -0
  114. package/dist/remotion-bundle/6ee02884b29cf7fb.woff2 +0 -0
  115. package/dist/remotion-bundle/6f436a74c9e3252c.woff2 +0 -0
  116. package/dist/remotion-bundle/78c8022f1657618b.woff2 +0 -0
  117. package/dist/remotion-bundle/7c5444169792bca4.woff2 +0 -0
  118. package/dist/remotion-bundle/7c86bddd9d997212.woff2 +0 -0
  119. package/dist/remotion-bundle/7e1284684767f584.woff2 +0 -0
  120. package/dist/remotion-bundle/7e81c17522d182b2.woff2 +0 -0
  121. package/dist/remotion-bundle/7eb87be198f7858c.woff2 +0 -0
  122. package/dist/remotion-bundle/8060c928f948aab5.woff2 +0 -0
  123. package/dist/remotion-bundle/80bc9dfbea2b35ae.woff2 +0 -0
  124. package/dist/remotion-bundle/811b83f69963bb48.woff2 +0 -0
  125. package/dist/remotion-bundle/813.bundle.js +117511 -0
  126. package/dist/remotion-bundle/813.bundle.js.map +1 -0
  127. package/dist/remotion-bundle/84df492e349f82e9.woff2 +0 -0
  128. package/dist/remotion-bundle/8501bfd73eb36f2b.woff2 +0 -0
  129. package/dist/remotion-bundle/854236a8376093fe.woff2 +0 -0
  130. package/dist/remotion-bundle/8571d74529082753.woff2 +0 -0
  131. package/dist/remotion-bundle/860bf44f8e6f4b5d.woff2 +0 -0
  132. package/dist/remotion-bundle/879.bundle.js +64 -0
  133. package/dist/remotion-bundle/879.bundle.js.map +1 -0
  134. package/dist/remotion-bundle/887dd482f848d56f.woff2 +0 -0
  135. package/dist/remotion-bundle/89b2132e85fbbb5a.woff2 +0 -0
  136. package/dist/remotion-bundle/8ba60d6c306010c2.woff2 +0 -0
  137. package/dist/remotion-bundle/8c7c4dadea897806.woff2 +0 -0
  138. package/dist/remotion-bundle/8c943f9999706f61.woff2 +0 -0
  139. package/dist/remotion-bundle/8f2a718c90575cc9.woff2 +0 -0
  140. package/dist/remotion-bundle/906b6edb3e1772c9.woff2 +0 -0
  141. package/dist/remotion-bundle/930ff9daccdf14eb.woff2 +0 -0
  142. package/dist/remotion-bundle/934db2f1c403c4d0.woff2 +0 -0
  143. package/dist/remotion-bundle/938.bundle.js +451 -0
  144. package/dist/remotion-bundle/938.bundle.js.map +1 -0
  145. package/dist/remotion-bundle/967.bundle.js +4462 -0
  146. package/dist/remotion-bundle/967.bundle.js.map +1 -0
  147. package/dist/remotion-bundle/9684a1093d3c02ce.woff2 +0 -0
  148. package/dist/remotion-bundle/973dcd0faa6116cc.woff2 +0 -0
  149. package/dist/remotion-bundle/9745400694e76cd8.woff2 +0 -0
  150. package/dist/remotion-bundle/999ef957bed3bdca.woff2 +0 -0
  151. package/dist/remotion-bundle/99a3d67c8b0f43e3.woff2 +0 -0
  152. package/dist/remotion-bundle/a0586c3e03127283.woff2 +0 -0
  153. package/dist/remotion-bundle/a0eb654fdae46269.woff2 +0 -0
  154. package/dist/remotion-bundle/a20e35d3b08f7994.woff2 +0 -0
  155. package/dist/remotion-bundle/a2dcaced7c8c25ab.woff2 +0 -0
  156. package/dist/remotion-bundle/a79255a972a2681a.woff2 +0 -0
  157. package/dist/remotion-bundle/a804b352cb9fec1a.woff2 +0 -0
  158. package/dist/remotion-bundle/aae7117164e1eabc.woff2 +0 -0
  159. package/dist/remotion-bundle/affd121385d0442d.woff2 +0 -0
  160. package/dist/remotion-bundle/b19a6083987ee0d7.woff2 +0 -0
  161. package/dist/remotion-bundle/b1b2bd04d8637981.woff2 +0 -0
  162. package/dist/remotion-bundle/b2c07f341486be87.woff2 +0 -0
  163. package/dist/remotion-bundle/b33d8f82e575c4ce.woff2 +0 -0
  164. package/dist/remotion-bundle/b366c0bed35ef491.woff2 +0 -0
  165. package/dist/remotion-bundle/b41e857ec1b85642.woff2 +0 -0
  166. package/dist/remotion-bundle/b420bb34ccf23e7f.woff2 +0 -0
  167. package/dist/remotion-bundle/b4f7bf4efb0c0ccf.woff2 +0 -0
  168. package/dist/remotion-bundle/b60fe5eca03cff93.woff2 +0 -0
  169. package/dist/remotion-bundle/b6bd31a336e64bce.woff2 +0 -0
  170. package/dist/remotion-bundle/b6d2befba3dfefeb.woff2 +0 -0
  171. package/dist/remotion-bundle/b75f39ab06c43bf4.woff2 +0 -0
  172. package/dist/remotion-bundle/b77880e8c413d4fd.woff2 +0 -0
  173. package/dist/remotion-bundle/b7e38ec441e4a77a.woff2 +0 -0
  174. package/dist/remotion-bundle/b83baa383ff0bf2b.woff2 +0 -0
  175. package/dist/remotion-bundle/b9ad7b6c0a11450a.woff2 +0 -0
  176. package/dist/remotion-bundle/baf84486e8ae3aaf.woff2 +0 -0
  177. package/dist/remotion-bundle/bc047b1f6869cffa.woff2 +0 -0
  178. package/dist/remotion-bundle/bf4f3ac6e93f33aa.woff2 +0 -0
  179. package/dist/remotion-bundle/bf6835ffec5897a2.woff2 +0 -0
  180. package/dist/remotion-bundle/bf8885f581eb1724.woff2 +0 -0
  181. package/dist/remotion-bundle/bundle.js +83376 -0
  182. package/dist/remotion-bundle/bundle.js.map +1 -0
  183. package/dist/remotion-bundle/c03f046bccd789d0.woff2 +0 -0
  184. package/dist/remotion-bundle/c0bb1f8962b73bc3.woff2 +0 -0
  185. package/dist/remotion-bundle/c1003f9a7db6e1cf.woff2 +0 -0
  186. package/dist/remotion-bundle/c15d83fb1e199515.woff2 +0 -0
  187. package/dist/remotion-bundle/c28e7e5d310f73ef.woff2 +0 -0
  188. package/dist/remotion-bundle/c2b840274db78aea.woff2 +0 -0
  189. package/dist/remotion-bundle/c3000e3299d4e45f.woff2 +0 -0
  190. package/dist/remotion-bundle/c83ce886e5288510.woff2 +0 -0
  191. package/dist/remotion-bundle/c87a5a64d4ac0918.woff2 +0 -0
  192. package/dist/remotion-bundle/c8a7e0d049e965fa.woff2 +0 -0
  193. package/dist/remotion-bundle/c949a35d3a3b1faf.woff2 +0 -0
  194. package/dist/remotion-bundle/c9618c9b9ac2bc78.woff2 +0 -0
  195. package/dist/remotion-bundle/ca3add3b84152d5b.woff2 +0 -0
  196. package/dist/remotion-bundle/cad9dd036408d707.woff2 +0 -0
  197. package/dist/remotion-bundle/cbb24916619df439.woff2 +0 -0
  198. package/dist/remotion-bundle/cc054f0b5514e177.woff2 +0 -0
  199. package/dist/remotion-bundle/ccc248ed9312bc71.woff2 +0 -0
  200. package/dist/remotion-bundle/cd9d623aa07af925.woff2 +0 -0
  201. package/dist/remotion-bundle/ce2ba7a321bd1247.woff2 +0 -0
  202. package/dist/remotion-bundle/cf72455f79a29b14.woff2 +0 -0
  203. package/dist/remotion-bundle/d267cbfefab452ac.woff2 +0 -0
  204. package/dist/remotion-bundle/d435cff46a64955f.woff +0 -0
  205. package/dist/remotion-bundle/d494d07f67e363f6.woff2 +0 -0
  206. package/dist/remotion-bundle/d7aa0cc1fa47bf38.woff2 +0 -0
  207. package/dist/remotion-bundle/d7c5ca93d885160a.woff2 +0 -0
  208. package/dist/remotion-bundle/d855d3e252db74e2.woff2 +0 -0
  209. package/dist/remotion-bundle/d8f13d47f02f82c2.woff2 +0 -0
  210. package/dist/remotion-bundle/d9567cce2ee11019.woff2 +0 -0
  211. package/dist/remotion-bundle/db8d4456fc75dd86.woff +0 -0
  212. package/dist/remotion-bundle/dc274628378c47ee.woff2 +0 -0
  213. package/dist/remotion-bundle/dc3e06947bb69903.woff2 +0 -0
  214. package/dist/remotion-bundle/dd67040ac3b6d523.woff2 +0 -0
  215. package/dist/remotion-bundle/e0b04bd488f953f4.woff2 +0 -0
  216. package/dist/remotion-bundle/e2a572ff95089370.woff2 +0 -0
  217. package/dist/remotion-bundle/e2e18a86b1c2b0cc.woff2 +0 -0
  218. package/dist/remotion-bundle/e3a78ee2fc9c6931.woff2 +0 -0
  219. package/dist/remotion-bundle/e654c9d547605a9f.woff2 +0 -0
  220. package/dist/remotion-bundle/e67a3a64c129927c.woff2 +0 -0
  221. package/dist/remotion-bundle/e6be28b4203cd6ce.woff2 +0 -0
  222. package/dist/remotion-bundle/e841907ad9b0a191.woff +0 -0
  223. package/dist/remotion-bundle/e889d1541c69fffa.woff2 +0 -0
  224. package/dist/remotion-bundle/e88ef8c76373a9e2.woff2 +0 -0
  225. package/dist/remotion-bundle/e9c72f4bc37defef.woff2 +0 -0
  226. package/dist/remotion-bundle/e9e35f863403a255.woff2 +0 -0
  227. package/dist/remotion-bundle/eb23b37b009375da.woff2 +0 -0
  228. package/dist/remotion-bundle/ee1342b741625721.woff2 +0 -0
  229. package/dist/remotion-bundle/f07da88543a57ec9.woff2 +0 -0
  230. package/dist/remotion-bundle/f522982115306f8a.woff2 +0 -0
  231. package/dist/remotion-bundle/f8449bd864e6d8bc.woff2 +0 -0
  232. package/dist/remotion-bundle/f906dd5bd95ff9ab.woff2 +0 -0
  233. package/dist/remotion-bundle/f9e9e9413e3c38bb.woff2 +0 -0
  234. package/dist/remotion-bundle/fa5a5b16280994a8.woff2 +0 -0
  235. package/dist/remotion-bundle/favicon.ico +0 -0
  236. package/dist/remotion-bundle/fb19c0517725599b.woff2 +0 -0
  237. package/dist/remotion-bundle/fcaf24232f684b9b.woff2 +0 -0
  238. package/dist/remotion-bundle/fe09e084a3eea8cf.woff2 +0 -0
  239. package/dist/remotion-bundle/ff38d5317df7345a.woff2 +0 -0
  240. package/dist/remotion-bundle/ffe7ea1ea08f455a.woff2 +0 -0
  241. package/dist/remotion-bundle/index.html +49 -0
  242. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/0.mp3 +0 -0
  243. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/1.mp3 +0 -0
  244. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/2.mp3 +0 -0
  245. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/3.mp3 +0 -0
  246. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/0.mp3 +0 -0
  247. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/1.mp3 +0 -0
  248. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/2.mp3 +0 -0
  249. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/3.mp3 +0 -0
  250. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/0.mp3 +0 -0
  251. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/1.mp3 +0 -0
  252. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/2.mp3 +0 -0
  253. package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/3.mp3 +0 -0
  254. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/0.mp3 +0 -0
  255. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/1.mp3 +0 -0
  256. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/2.mp3 +0 -0
  257. package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/3.mp3 +0 -0
  258. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/0.mp3 +0 -0
  259. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/1.mp3 +0 -0
  260. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/2.mp3 +0 -0
  261. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/3.mp3 +0 -0
  262. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/0.mp3 +0 -0
  263. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/1.mp3 +0 -0
  264. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/2.mp3 +0 -0
  265. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/3.mp3 +0 -0
  266. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/0.mp3 +0 -0
  267. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/1.mp3 +0 -0
  268. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/2.mp3 +0 -0
  269. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/3.mp3 +0 -0
  270. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/0.mp3 +0 -0
  271. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/1.mp3 +0 -0
  272. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/2.mp3 +0 -0
  273. package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/3.mp3 +0 -0
  274. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/0.mp3 +0 -0
  275. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/1.mp3 +0 -0
  276. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/2.mp3 +0 -0
  277. package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/3.mp3 +0 -0
  278. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/0.mp3 +0 -0
  279. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/1.mp3 +0 -0
  280. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/2.mp3 +0 -0
  281. package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/3.mp3 +0 -0
  282. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/0.mp3 +0 -0
  283. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/1.mp3 +0 -0
  284. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/2.mp3 +0 -0
  285. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/3.mp3 +0 -0
  286. package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/4.mp3 +0 -0
  287. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/0.mp3 +0 -0
  288. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/1.mp3 +0 -0
  289. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/2.mp3 +0 -0
  290. package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/3.mp3 +0 -0
  291. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/0.mp3 +0 -0
  292. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/1.mp3 +0 -0
  293. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/2.mp3 +0 -0
  294. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/3.mp3 +0 -0
  295. package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/4.mp3 +0 -0
  296. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/0.mp3 +0 -0
  297. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/1.mp3 +0 -0
  298. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/2.mp3 +0 -0
  299. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/3.mp3 +0 -0
  300. package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/4.mp3 +0 -0
  301. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/0.mp3 +0 -0
  302. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/1.mp3 +0 -0
  303. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/2.mp3 +0 -0
  304. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/3.mp3 +0 -0
  305. package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/4.mp3 +0 -0
  306. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/0.mp3 +0 -0
  307. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/1.mp3 +0 -0
  308. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/2.mp3 +0 -0
  309. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/3.mp3 +0 -0
  310. package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/4.mp3 +0 -0
  311. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/0.mp3 +0 -0
  312. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/1.mp3 +0 -0
  313. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/2.mp3 +0 -0
  314. package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/3.mp3 +0 -0
  315. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/0.mp3 +0 -0
  316. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/1.mp3 +0 -0
  317. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/2.mp3 +0 -0
  318. package/dist/remotion-bundle/public/paper-slide-experiments/product-update/3.mp3 +0 -0
  319. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/0.mp3 +0 -0
  320. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/1.mp3 +0 -0
  321. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/2.mp3 +0 -0
  322. package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/3.mp3 +0 -0
  323. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/0.mp3 +0 -0
  324. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/1.mp3 +0 -0
  325. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/2.mp3 +0 -0
  326. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/3.mp3 +0 -0
  327. package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/4.mp3 +0 -0
  328. package/dist/remotion-bundle/public/voiceover/ai-life/card-0.mp3 +0 -0
  329. package/dist/remotion-bundle/public/voiceover/ai-life/card-1.mp3 +0 -0
  330. package/dist/remotion-bundle/public/voiceover/ai-life/card-2.mp3 +0 -0
  331. package/dist/remotion-bundle/public/voiceover/ai-life/card-3.mp3 +0 -0
  332. package/dist/remotion-bundle/public/voiceover/ai-life/card-4.mp3 +0 -0
  333. package/dist/remotion-bundle/public/voiceover/ai-life/card-5.mp3 +0 -0
  334. package/dist/remotion-bundle/public/voiceover/coffee-science/card-0.mp3 +0 -0
  335. package/dist/remotion-bundle/public/voiceover/coffee-science/card-1.mp3 +0 -0
  336. package/dist/remotion-bundle/public/voiceover/coffee-science/card-2.mp3 +0 -0
  337. package/dist/remotion-bundle/public/voiceover/coffee-science/card-3.mp3 +0 -0
  338. package/dist/remotion-bundle/public/voiceover/coffee-science/card-4.mp3 +0 -0
  339. package/dist/remotion-bundle/public/voiceover/coffee-science/card-5.mp3 +0 -0
  340. package/dist/remotion-bundle/public/voiceover/coffee-science/card-6.mp3 +0 -0
  341. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-0.mp3 +0 -0
  342. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-1.mp3 +0 -0
  343. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-2.mp3 +0 -0
  344. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-3.mp3 +0 -0
  345. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-4.mp3 +0 -0
  346. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-5.mp3 +0 -0
  347. package/dist/remotion-bundle/public/voiceover/reading-secrets/card-6.mp3 +0 -0
  348. package/dist/remotion-bundle/public/voiceover/remote-work/card-0.mp3 +0 -0
  349. package/dist/remotion-bundle/public/voiceover/remote-work/card-1.mp3 +0 -0
  350. package/dist/remotion-bundle/public/voiceover/remote-work/card-2.mp3 +0 -0
  351. package/dist/remotion-bundle/public/voiceover/remote-work/card-3.mp3 +0 -0
  352. package/dist/remotion-bundle/public/voiceover/remote-work/card-4.mp3 +0 -0
  353. package/dist/remotion-bundle/public/voiceover/remote-work/card-5.mp3 +0 -0
  354. package/dist/remotion-bundle/source-map-helper.wasm +0 -0
  355. package/lib/cli.js +270 -0
  356. package/lib/commands/_registry.js +48 -0
  357. package/lib/commands/add.js +242 -0
  358. package/lib/commands/asr/azure-transcribe.js +336 -0
  359. package/lib/commands/asr/cloud-transcribe.js +384 -0
  360. package/lib/commands/asr/helpers.js +76 -0
  361. package/lib/commands/asr/index.js +236 -0
  362. package/lib/commands/asr/local-transcribe.js +125 -0
  363. package/lib/commands/asr-jobs.js +257 -0
  364. package/lib/commands/asr.js +11 -0
  365. package/lib/commands/auth-cmds.js +358 -0
  366. package/lib/commands/dub.js +542 -0
  367. package/lib/commands/explain.js +512 -0
  368. package/lib/commands/feedback.js +152 -0
  369. package/lib/commands/image.js +207 -0
  370. package/lib/commands/mcp-key.js +166 -0
  371. package/lib/commands/narrate.js +639 -0
  372. package/lib/commands/picstory-templates.js +276 -0
  373. package/lib/commands/picstory.js +547 -0
  374. package/lib/commands/podcast/dialogue.js +109 -0
  375. package/lib/commands/podcast/generate.js +127 -0
  376. package/lib/commands/podcast/index.js +561 -0
  377. package/lib/commands/podcast/synthesize.js +188 -0
  378. package/lib/commands/podcast.js +11 -0
  379. package/lib/commands/present.js +519 -0
  380. package/lib/commands/publish.js +415 -0
  381. package/lib/commands/skills.js +473 -0
  382. package/lib/commands/slice-render.js +282 -0
  383. package/lib/commands/slice-stage.js +264 -0
  384. package/lib/commands/slice.js +346 -0
  385. package/lib/commands/slides/constants.js +108 -0
  386. package/lib/commands/slides/html-renderer.js +338 -0
  387. package/lib/commands/slides/index.js +345 -0
  388. package/lib/commands/slides.js +11 -0
  389. package/lib/commands/story.js +302 -0
  390. package/lib/commands/summarize.js +532 -0
  391. package/lib/commands/synthesize.js +261 -0
  392. package/lib/commands/translate.js +593 -0
  393. package/lib/commands/upgrade.js +249 -0
  394. package/lib/commands/video-translate.js +577 -0
  395. package/lib/commands/voices.js +292 -0
  396. package/lib/core/agent-env.js +104 -0
  397. package/lib/core/args.js +107 -0
  398. package/lib/core/asr-client.js +448 -0
  399. package/lib/core/asr-jobs-client.js +126 -0
  400. package/lib/core/asr-jobs-store.js +105 -0
  401. package/lib/core/asr-r2-upload.js +181 -0
  402. package/lib/core/asr-upload.js +132 -0
  403. package/lib/core/audio-extract.js +150 -0
  404. package/lib/core/audio.js +219 -0
  405. package/lib/core/auth.js +880 -0
  406. package/lib/core/config.js +197 -0
  407. package/lib/core/feedback.js +64 -0
  408. package/lib/core/ffmpeg.js +476 -0
  409. package/lib/core/http.js +188 -0
  410. package/lib/core/image-client.js +55 -0
  411. package/lib/core/intent-params.js +11 -0
  412. package/lib/core/llm-client.js +76 -0
  413. package/lib/core/logger.js +208 -0
  414. package/lib/core/mic-recorder.js +182 -0
  415. package/lib/core/pause-markers.js +94 -0
  416. package/lib/core/podcast-pacing.js +118 -0
  417. package/lib/core/spinner.js +33 -0
  418. package/lib/core/srt.js +394 -0
  419. package/lib/core/telemetry.js +100 -0
  420. package/lib/core/timeline.js +92 -0
  421. package/lib/core/tts-synthesizer.js +70 -0
  422. package/lib/core/update-check.js +185 -0
  423. package/lib/core/url-download.js +148 -0
  424. package/lib/core/whisper-local.js +279 -0
  425. package/lib/internal/deck-validator.js +488 -0
  426. package/lib/internal/slice-themes.json +370 -0
  427. package/lib/stage-core/cloud-render.js +170 -0
  428. package/lib/stage-core/deck-format.js +133 -0
  429. package/lib/stage-core/edit-prompt.js +104 -0
  430. package/lib/stage-core/event-bus.js +31 -0
  431. package/lib/stage-core/port.js +46 -0
  432. package/lib/stage-core/server.js +352 -0
  433. package/lib/stage-core/snapshot-store.js +198 -0
  434. package/lib/stage-core/watcher.js +106 -0
  435. package/lib/stage-ui/slice/template.js +1672 -0
  436. package/package.json +9 -4
  437. package/skills/.claude-plugin/marketplace.json +22 -0
  438. package/skills/.claude-plugin/plugin.json +25 -0
  439. package/skills/LICENSE +21 -0
  440. package/skills/README.md +120 -0
  441. package/skills/hub/SKILL.md +317 -0
  442. package/skills/podcast/SKILL.md +146 -0
  443. package/skills/slice/SKILL.md +205 -0
  444. package/skills/slice/agents/openai.yaml +4 -0
  445. package/skills/slice/references/deck-schema.md +183 -0
  446. package/skills/slice/references/example-decks.md +108 -0
  447. package/skills/slice/references/themes.md +172 -0
  448. package/skills/transcribe/SKILL.md +473 -0
  449. package/skills/video/SKILL.md +261 -0
  450. package/skills/voxflow-slice/SKILL.md +271 -0
  451. package/skills/voxflow-slice/examples/article.md +13 -0
  452. package/skills/voxflow-slice/examples/expected-deck.json +39 -0
  453. package/skills/voxflow-slice/examples/validate.mjs +46 -0
@@ -0,0 +1,488 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * PaperSlideDeck shape validator — vendored copy for the CLI's offline route.
5
+ *
6
+ * Source of truth lives at backend/services/paper-slide/deck-validator.js;
7
+ * this file is a verbatim copy except for the slice-themes.json require path.
8
+ * The copy keeps the published `voxflow` tarball self-contained — users who
9
+ * `npm install voxflow` get the validator without needing the monorepo.
10
+ *
11
+ * To re-sync after upstream changes:
12
+ * cp backend/services/paper-slide/deck-validator.js cli/lib/internal/deck-validator.js
13
+ * cp slice-themes.json cli/lib/internal/slice-themes.json
14
+ * # then re-apply the require-path tweak below.
15
+ */
16
+
17
+ const SLICE_THEME_REGISTRY = require('./slice-themes.json');
18
+ const VALID_THEMES = new Set(SLICE_THEME_REGISTRY.themes.map((t) => t.id));
19
+
20
+ // Theme id -> Set of valid variant ids, derived from the canonical registry.
21
+ // Themes without a `variants[]` entry get an empty set; the validator then
22
+ // rejects any non-null variantId so an unexpected value can't slip through.
23
+ const THEME_VARIANTS = new Map(
24
+ SLICE_THEME_REGISTRY.themes.map((t) => [
25
+ t.id,
26
+ new Set((t.variants || []).map((v) => v.id)),
27
+ ])
28
+ );
29
+
30
+ // Rich card kinds (P6). title/body/outro are the original three. quote/data/list
31
+ // are content-shape variants the LLM may emit when the article has a quotable
32
+ // line / a stand-out number / a 3-point structure. The render-worker pipeline
33
+ // downgrades the new kinds to body shape per-theme (paper-slide + editorial-mag
34
+ // get real visual treatments in a follow-up; other 4 themes always fall back).
35
+ const VALID_KINDS = new Set(['title', 'body', 'quote', 'data', 'list', 'outro']);
36
+
37
+ // Caps mirrored from the prompt — kept here so the validator rejects an LLM
38
+ // over-shoot rather than letting an unrenderable card slip through to the
39
+ // renderer's text-box.
40
+ const QUOTE_TEXT_MAX = 60;
41
+ const QUOTE_ATTRIBUTION_MAX = 30;
42
+ const DATA_VALUE_MAX = 12;
43
+ const DATA_UNIT_MAX = 8;
44
+ const DATA_LABEL_MAX = 30;
45
+ const LIST_ITEM_MAX_LEN = 30;
46
+ const LIST_ITEM_MIN_COUNT = 2;
47
+ const LIST_ITEM_MAX_COUNT = 4;
48
+
49
+ function nonEmptyString(value) {
50
+ return typeof value === 'string' && value.trim().length > 0;
51
+ }
52
+
53
+ function validateQuotePayload(quote, i) {
54
+ if (!quote || typeof quote !== 'object') {
55
+ throw new Error(`cards[${i}].quote must be an object`);
56
+ }
57
+ if (!nonEmptyString(quote.text)) {
58
+ throw new Error(`cards[${i}].quote.text empty`);
59
+ }
60
+ if (quote.text.length > QUOTE_TEXT_MAX) {
61
+ throw new Error(`cards[${i}].quote.text too long (${quote.text.length} > ${QUOTE_TEXT_MAX})`);
62
+ }
63
+ if (quote.attribution != null) {
64
+ if (typeof quote.attribution !== 'string') {
65
+ throw new Error(`cards[${i}].quote.attribution must be string or null`);
66
+ }
67
+ if (quote.attribution.length > QUOTE_ATTRIBUTION_MAX) {
68
+ throw new Error(
69
+ `cards[${i}].quote.attribution too long (${quote.attribution.length} > ${QUOTE_ATTRIBUTION_MAX})`
70
+ );
71
+ }
72
+ }
73
+ }
74
+
75
+ function validateDataPayload(data, i) {
76
+ if (!data || typeof data !== 'object') {
77
+ throw new Error(`cards[${i}].data must be an object`);
78
+ }
79
+ if (!nonEmptyString(data.value)) {
80
+ throw new Error(`cards[${i}].data.value empty`);
81
+ }
82
+ if (data.value.length > DATA_VALUE_MAX) {
83
+ throw new Error(`cards[${i}].data.value too long (${data.value.length} > ${DATA_VALUE_MAX})`);
84
+ }
85
+ if (!nonEmptyString(data.label)) {
86
+ throw new Error(`cards[${i}].data.label empty`);
87
+ }
88
+ if (data.label.length > DATA_LABEL_MAX) {
89
+ throw new Error(`cards[${i}].data.label too long (${data.label.length} > ${DATA_LABEL_MAX})`);
90
+ }
91
+ if (data.unit != null) {
92
+ if (typeof data.unit !== 'string') {
93
+ throw new Error(`cards[${i}].data.unit must be string or null`);
94
+ }
95
+ if (data.unit.length > DATA_UNIT_MAX) {
96
+ throw new Error(`cards[${i}].data.unit too long (${data.unit.length} > ${DATA_UNIT_MAX})`);
97
+ }
98
+ }
99
+ }
100
+
101
+ function validateListPayload(list, i) {
102
+ if (!list || typeof list !== 'object') {
103
+ throw new Error(`cards[${i}].list must be an object`);
104
+ }
105
+ if (!Array.isArray(list.items)) {
106
+ throw new Error(`cards[${i}].list.items must be array`);
107
+ }
108
+ if (list.items.length < LIST_ITEM_MIN_COUNT || list.items.length > LIST_ITEM_MAX_COUNT) {
109
+ throw new Error(
110
+ `cards[${i}].list.items must be ${LIST_ITEM_MIN_COUNT}–${LIST_ITEM_MAX_COUNT} entries (got ${list.items.length})`
111
+ );
112
+ }
113
+ list.items.forEach((item, j) => {
114
+ if (!item || typeof item !== 'object') {
115
+ throw new Error(`cards[${i}].list.items[${j}] must be object`);
116
+ }
117
+ if (!nonEmptyString(item.text)) {
118
+ throw new Error(`cards[${i}].list.items[${j}].text empty`);
119
+ }
120
+ if (item.text.length > LIST_ITEM_MAX_LEN) {
121
+ throw new Error(
122
+ `cards[${i}].list.items[${j}].text too long (${item.text.length} > ${LIST_ITEM_MAX_LEN})`
123
+ );
124
+ }
125
+ if (item.glyph != null && typeof item.glyph !== 'string') {
126
+ throw new Error(`cards[${i}].list.items[${j}].glyph must be string or null`);
127
+ }
128
+ });
129
+ }
130
+
131
+ function validatePaperSlideDeck(deck) {
132
+ if (!deck || typeof deck !== 'object') throw new Error('deck missing');
133
+ for (const f of ['header', 'seriesTitle', 'seriesTagline']) {
134
+ if (typeof deck[f] !== 'string' || !deck[f].trim()) {
135
+ throw new Error(`deck.${f} missing or empty`);
136
+ }
137
+ }
138
+ // Optional cover hints — ignored if absent (null/undefined OK);
139
+ // hard fail only if present and wrong type (non-string).
140
+ // Cover always has a deterministic fallback from card data.
141
+ for (const f of ['coverHookCaption', 'coverFigureKeyword']) {
142
+ if (deck[f] != null && typeof deck[f] !== 'string') {
143
+ throw new Error(`deck.${f} must be string or null`);
144
+ }
145
+ }
146
+ // Optional theme — defaults to 'paper-slide' downstream when absent.
147
+ // Reject unknown values explicitly so a typo'd theme never silently
148
+ // routes to the default composition (would mask real bugs).
149
+ if (deck.theme != null && !VALID_THEMES.has(deck.theme)) {
150
+ throw new Error(
151
+ `deck.theme invalid: ${deck.theme} (valid: ${[...VALID_THEMES].join(', ')})`
152
+ );
153
+ }
154
+ // Optional variantId — palette swap within the current theme (e.g.
155
+ // editorial-mag has cream/sepia/cold-grey). Validated against the
156
+ // registry's `variants[]` for the selected (or default) theme. Themes
157
+ // that don't declare variants reject any non-null variantId — a typo'd
158
+ // variant should never silently fall back to the default palette.
159
+ if (deck.variantId != null) {
160
+ if (typeof deck.variantId !== 'string' || !deck.variantId.trim()) {
161
+ throw new Error('deck.variantId must be a non-empty string when present');
162
+ }
163
+ const themeId = deck.theme || SLICE_THEME_REGISTRY.default;
164
+ const validVariants = THEME_VARIANTS.get(themeId) || new Set();
165
+ if (validVariants.size === 0) {
166
+ throw new Error(
167
+ `deck.variantId set but theme "${themeId}" declares no variants`
168
+ );
169
+ }
170
+ if (!validVariants.has(deck.variantId)) {
171
+ throw new Error(
172
+ `deck.variantId invalid for theme "${themeId}": ${deck.variantId} (valid: ${[...validVariants].join(', ')})`
173
+ );
174
+ }
175
+ }
176
+ // Optional aiCoverUrl — public Supabase Storage URL of an AI-generated
177
+ // cover the user kept across edits. Persisted in cards_data.deck so a
178
+ // second-pass render of the same project doesn't lose the candidate
179
+ // (Phase 7 — AiCoverPanel wiring lands the read path). Validated as a
180
+ // public-assets URL only; rejecting other origins keeps the field from
181
+ // becoming an arbitrary-URL injection vector via the deck shape.
182
+ if (deck.aiCoverUrl != null) {
183
+ if (typeof deck.aiCoverUrl !== 'string' || !deck.aiCoverUrl.trim()) {
184
+ throw new Error('deck.aiCoverUrl must be a non-empty string when present');
185
+ }
186
+ const allowedPrefix =
187
+ 'https://iwkonytsjysszmafqchh.supabase.co/storage/v1/object/public/public-assets/';
188
+ if (!deck.aiCoverUrl.startsWith(allowedPrefix)) {
189
+ throw new Error('deck.aiCoverUrl must be a public-assets bucket URL');
190
+ }
191
+ }
192
+ // Card-count cap widened from 8 → 9 because BrandKit auto-appends an
193
+ // outro card on top of the LLM's max-6-card output (5 narrative + 1
194
+ // title still fits well below 9). Outro is appended server-side after
195
+ // slicing, so the LLM still targets 4–6 narrative cards.
196
+ if (!Array.isArray(deck.cards) || deck.cards.length < 2 || deck.cards.length > 9) {
197
+ throw new Error(`deck.cards must be 2–9 entries (got ${deck.cards?.length})`);
198
+ }
199
+ if (deck.cards[0].kind !== 'title') {
200
+ throw new Error('first card must be kind=title');
201
+ }
202
+ // Outro card invariant: at most one, and only as the LAST card. Multiple
203
+ // outros or a mid-deck outro is always a wiring bug worth surfacing
204
+ // (e.g. double-injection on retry) — fail loud rather than render twice.
205
+ const outroCount = deck.cards.filter((c) => c.kind === 'outro').length;
206
+ if (outroCount > 1) throw new Error(`deck has ${outroCount} outro cards (max 1)`);
207
+ if (outroCount === 1 && deck.cards[deck.cards.length - 1].kind !== 'outro') {
208
+ throw new Error('outro card must be last');
209
+ }
210
+ deck.cards.forEach((card, i) => {
211
+ if (!VALID_KINDS.has(card.kind)) {
212
+ throw new Error(`cards[${i}].kind invalid: ${card.kind}`);
213
+ }
214
+ if (typeof card.narration !== 'string' || !card.narration.trim()) {
215
+ throw new Error(`cards[${i}].narration empty`);
216
+ }
217
+ if (card.kind === 'title' && (!Array.isArray(card.title) || card.title.length === 0)) {
218
+ throw new Error(`cards[${i}].title must be non-empty array for kind=title`);
219
+ }
220
+ if (card.kind === 'body' && (!card.caption || !String(card.caption).trim())) {
221
+ throw new Error(`cards[${i}].caption empty for kind=body`);
222
+ }
223
+ if (card.kind === 'quote') validateQuotePayload(card.quote, i);
224
+ if (card.kind === 'data') validateDataPayload(card.data, i);
225
+ if (card.kind === 'list') validateListPayload(card.list, i);
226
+ // Optional per-card voice override (#3220). Absent ⇒ render-worker
227
+ // uses the job-level voiceId. Shape check only — the voice library is
228
+ // the source of truth for valid IDs, and the TTS request will surface
229
+ // a clean 404 if the voiceId is unknown / not owned by the user.
230
+ if (card.voiceId != null) {
231
+ if (typeof card.voiceId !== 'string' || !card.voiceId.trim()) {
232
+ throw new Error(`cards[${i}].voiceId must be a non-empty string when present`);
233
+ }
234
+ if (card.voiceId.length > 128) {
235
+ throw new Error(`cards[${i}].voiceId too long (${card.voiceId.length} > 128)`);
236
+ }
237
+ }
238
+ // Optional per-card image URL — photo-feature / atmospheric themes
239
+ // composite it as a full-bleed background; other themes ignore it.
240
+ // Shape-check only (string, length cap, http(s) prefix); reachability
241
+ // is handled at render time by the composition's onError fallback.
242
+ if (card.imageUrl != null) {
243
+ if (typeof card.imageUrl !== 'string') {
244
+ throw new Error(`cards[${i}].imageUrl must be string or null`);
245
+ }
246
+ if (card.imageUrl.length > 2048) {
247
+ throw new Error(
248
+ `cards[${i}].imageUrl too long (${card.imageUrl.length} > 2048)`
249
+ );
250
+ }
251
+ if (!/^https?:\/\//.test(card.imageUrl)) {
252
+ throw new Error(`cards[${i}].imageUrl must start with http(s)://`);
253
+ }
254
+ }
255
+ if (card.kind === 'outro') {
256
+ if (!card.outro || typeof card.outro !== 'object') {
257
+ throw new Error(`cards[${i}].outro must be an object`);
258
+ }
259
+ if (typeof card.outro.cta !== 'string' || !card.outro.cta.trim()) {
260
+ throw new Error(`cards[${i}].outro.cta empty`);
261
+ }
262
+ if (card.outro.handle != null && typeof card.outro.handle !== 'string') {
263
+ throw new Error(`cards[${i}].outro.handle must be string or null`);
264
+ }
265
+ }
266
+ });
267
+ // Optional brandKit snapshot — pure shape check, identity is server-
268
+ // populated so we can be strict about types (catches client-side
269
+ // tampering / version skew).
270
+ if (deck.brandKit != null) {
271
+ if (typeof deck.brandKit !== 'object') throw new Error('deck.brandKit must be object');
272
+ const bk = deck.brandKit;
273
+ for (const f of ['displayName', 'orgName', 'handle', 'brandColor']) {
274
+ if (bk[f] != null && typeof bk[f] !== 'string') {
275
+ throw new Error(`deck.brandKit.${f} must be string or null`);
276
+ }
277
+ }
278
+ if (bk.footerPosition != null && !['bottom-left', 'bottom-right', 'none'].includes(bk.footerPosition)) {
279
+ throw new Error('deck.brandKit.footerPosition invalid');
280
+ }
281
+ }
282
+ }
283
+
284
+ // ── V2 LayoutTree-shaped deck validation (#3434) ─────────────────────────────
285
+ //
286
+ // Slice v2 cards are LayoutTrees instead of kind-tagged fields. v1 ships
287
+ // for theme=paper-slide only; other themes keep V1. The element set is
288
+ // deliberately restricted vs ai-clips' 17-element schema — paper-slide's
289
+ // renderer only knows how to style these 6 (heading / body / paper-figure
290
+ // / quote / stat / steps). Anything else is rejected so a renderer that
291
+ // silently no-ops on unknown elements doesn't ship a broken video.
292
+
293
+ const V2_ALLOWED_ELEMENTS = new Set(['heading', 'body', 'paper-figure', 'quote', 'stat', 'steps']);
294
+ const V2_HEADING_MAX = 22;
295
+ const V2_BODY_TEXT_MAX = 30;
296
+ const V2_STAT_LABEL_MAX = 30;
297
+
298
+ function validateV2Children(children, cardIdx, allowedElements, opts = {}) {
299
+ if (!Array.isArray(children) || children.length === 0) {
300
+ throw new Error(`cards[${cardIdx}].children must be non-empty array`);
301
+ }
302
+ if (opts.maxChildren && children.length > opts.maxChildren) {
303
+ throw new Error(`cards[${cardIdx}].children too many (${children.length} > ${opts.maxChildren})`);
304
+ }
305
+ const elements = [];
306
+ children.forEach((el, j) => {
307
+ if (!el || typeof el !== 'object') {
308
+ throw new Error(`cards[${cardIdx}].children[${j}] must be object`);
309
+ }
310
+ if (!allowedElements.has(el.el)) {
311
+ throw new Error(
312
+ `cards[${cardIdx}].children[${j}].el invalid: ${el.el} ` +
313
+ `(allowed for this kind: ${[...allowedElements].join(', ')})`
314
+ );
315
+ }
316
+ elements.push(el);
317
+ if (el.el === 'heading') {
318
+ if (!nonEmptyString(el.text)) throw new Error(`cards[${cardIdx}].children[${j}].text empty`);
319
+ if (el.text.length > V2_HEADING_MAX) {
320
+ throw new Error(`cards[${cardIdx}].children[${j}].text too long (${el.text.length} > ${V2_HEADING_MAX})`);
321
+ }
322
+ // Trailing punctuation guard — prompt rule, mirrored in validator
323
+ // so LLM drift can't slip a trailing 。!? through to subtitles.
324
+ if (/[。!?.!?…]$/.test(el.text.trim())) {
325
+ throw new Error(`cards[${cardIdx}].children[${j}].text must not end with punctuation`);
326
+ }
327
+ } else if (el.el === 'body') {
328
+ if (!nonEmptyString(el.text)) throw new Error(`cards[${cardIdx}].children[${j}].text empty`);
329
+ if (el.text.length > V2_BODY_TEXT_MAX) {
330
+ throw new Error(`cards[${cardIdx}].children[${j}].text too long (${el.text.length} > ${V2_BODY_TEXT_MAX})`);
331
+ }
332
+ } else if (el.el === 'paper-figure') {
333
+ if (!nonEmptyString(el.figureKeyword)) {
334
+ throw new Error(`cards[${cardIdx}].children[${j}].figureKeyword empty`);
335
+ }
336
+ } else if (el.el === 'quote') {
337
+ validateQuotePayload({ text: el.text, attribution: el.attribution }, cardIdx);
338
+ } else if (el.el === 'stat') {
339
+ // stat.value may be number or numeric string ("3x" / "240万+")
340
+ if (el.value == null || (typeof el.value !== 'number' && !nonEmptyString(el.value))) {
341
+ throw new Error(`cards[${cardIdx}].children[${j}].value missing`);
342
+ }
343
+ const valueStr = String(el.value);
344
+ if (valueStr.length > DATA_VALUE_MAX) {
345
+ throw new Error(`cards[${cardIdx}].children[${j}].value too long (${valueStr.length} > ${DATA_VALUE_MAX})`);
346
+ }
347
+ if (el.unit != null) {
348
+ if (typeof el.unit !== 'string') throw new Error(`cards[${cardIdx}].children[${j}].unit must be string`);
349
+ if (el.unit.length > DATA_UNIT_MAX) {
350
+ throw new Error(`cards[${cardIdx}].children[${j}].unit too long (${el.unit.length} > ${DATA_UNIT_MAX})`);
351
+ }
352
+ }
353
+ if (el.label != null) {
354
+ if (typeof el.label !== 'string') throw new Error(`cards[${cardIdx}].children[${j}].label must be string`);
355
+ if (el.label.length > V2_STAT_LABEL_MAX) {
356
+ throw new Error(`cards[${cardIdx}].children[${j}].label too long (${el.label.length} > ${V2_STAT_LABEL_MAX})`);
357
+ }
358
+ }
359
+ } else if (el.el === 'steps') {
360
+ if (!Array.isArray(el.items) || el.items.length < LIST_ITEM_MIN_COUNT || el.items.length > LIST_ITEM_MAX_COUNT) {
361
+ throw new Error(
362
+ `cards[${cardIdx}].children[${j}].items must be ${LIST_ITEM_MIN_COUNT}–${LIST_ITEM_MAX_COUNT} entries`
363
+ );
364
+ }
365
+ el.items.forEach((item, k) => {
366
+ if (!item || typeof item !== 'object') {
367
+ throw new Error(`cards[${cardIdx}].children[${j}].items[${k}] must be object`);
368
+ }
369
+ if (!nonEmptyString(item.label)) {
370
+ throw new Error(`cards[${cardIdx}].children[${j}].items[${k}].label empty`);
371
+ }
372
+ if (item.label.length > LIST_ITEM_MAX_LEN) {
373
+ throw new Error(
374
+ `cards[${cardIdx}].children[${j}].items[${k}].label too long (${item.label.length} > ${LIST_ITEM_MAX_LEN})`
375
+ );
376
+ }
377
+ });
378
+ }
379
+ });
380
+ return elements;
381
+ }
382
+
383
+ function validatePaperSlideDeckV2(deck) {
384
+ if (!deck || typeof deck !== 'object') throw new Error('deck missing');
385
+ for (const f of ['header', 'seriesTitle', 'seriesTagline']) {
386
+ if (!nonEmptyString(deck[f])) {
387
+ throw new Error(`deck.${f} missing or empty`);
388
+ }
389
+ }
390
+ for (const f of ['coverHookCaption', 'coverFigureKeyword']) {
391
+ if (deck[f] != null && typeof deck[f] !== 'string') {
392
+ throw new Error(`deck.${f} must be string or null`);
393
+ }
394
+ }
395
+ if (deck.theme != null && !VALID_THEMES.has(deck.theme)) {
396
+ throw new Error(`deck.theme invalid: ${deck.theme}`);
397
+ }
398
+ // V2 only ships for paper-slide in v1. Reject other themes loudly so a
399
+ // wrong-theme deck never hits the V2 renderer (which doesn't know how to
400
+ // style for editorial-mag / bold-poster / etc.).
401
+ if (deck.theme != null && deck.theme !== 'paper-slide') {
402
+ throw new Error(`v2 LayoutTree decks only supported for paper-slide theme (got ${deck.theme})`);
403
+ }
404
+ if (!Array.isArray(deck.cards) || deck.cards.length < 3 || deck.cards.length > 6) {
405
+ throw new Error(`deck.cards must be 3–6 entries (got ${deck.cards?.length})`);
406
+ }
407
+ if (deck.cards[0].kind !== 'title') {
408
+ throw new Error('first card must be kind=title');
409
+ }
410
+ // Cap on rich-kind cards to keep variety up
411
+ const richCounts = { quote: 0, data: 0, list: 0 };
412
+ deck.cards.forEach((card, i) => {
413
+ if (!card || typeof card !== 'object') throw new Error(`cards[${i}] missing`);
414
+ if (!['title', 'body', 'quote', 'data', 'list'].includes(card.kind)) {
415
+ throw new Error(`cards[${i}].kind invalid: ${card.kind} (v2 supports title/body/quote/data/list)`);
416
+ }
417
+ if (!nonEmptyString(card.narration)) throw new Error(`cards[${i}].narration empty`);
418
+
419
+ if (card.kind === 'title') {
420
+ const els = validateV2Children(card.children, i, new Set(['heading']), { maxChildren: 3 });
421
+ if (els.length === 0) throw new Error(`cards[${i}] title must have at least one heading`);
422
+ } else if (card.kind === 'body') {
423
+ const els = validateV2Children(card.children, i, new Set(['heading', 'body', 'paper-figure']), { maxChildren: 4 });
424
+ const figs = els.filter((e) => e.el === 'paper-figure');
425
+ if (figs.length !== 1) throw new Error(`cards[${i}] body must contain exactly one paper-figure (got ${figs.length})`);
426
+ const heads = els.filter((e) => e.el === 'heading');
427
+ if (heads.length === 0) throw new Error(`cards[${i}] body must contain at least one heading`);
428
+ } else if (card.kind === 'quote') {
429
+ // LLM frequently prepends a heading and/or body descriptor to rich
430
+ // cards — allow them (the PaperSlide renderer reads quote.text /
431
+ // stat / steps directly and ignores any non-discriminator elements
432
+ // on these kinds). Discriminator element must still be present
433
+ // exactly once. Cap at 3 children to keep output bounded.
434
+ const els = validateV2Children(card.children, i, new Set(['heading', 'body', 'quote']), { maxChildren: 3 });
435
+ const quoteEls = els.filter((e) => e.el === 'quote');
436
+ if (quoteEls.length !== 1) throw new Error(`cards[${i}] quote card must contain exactly one quote element (got ${quoteEls.length})`);
437
+ richCounts.quote += 1;
438
+ } else if (card.kind === 'data') {
439
+ const els = validateV2Children(card.children, i, new Set(['heading', 'body', 'stat']), { maxChildren: 3 });
440
+ const statEls = els.filter((e) => e.el === 'stat');
441
+ if (statEls.length !== 1) throw new Error(`cards[${i}] data card must contain exactly one stat element (got ${statEls.length})`);
442
+ richCounts.data += 1;
443
+ } else if (card.kind === 'list') {
444
+ const els = validateV2Children(card.children, i, new Set(['heading', 'body', 'steps']), { maxChildren: 3 });
445
+ const stepsEls = els.filter((e) => e.el === 'steps');
446
+ if (stepsEls.length !== 1) throw new Error(`cards[${i}] list card must contain exactly one steps element (got ${stepsEls.length})`);
447
+ richCounts.list += 1;
448
+ }
449
+ });
450
+ // Cap on rich-kind variety — at most 1 of each (same as V1 prompt rule)
451
+ for (const k of Object.keys(richCounts)) {
452
+ if (richCounts[k] > 1) {
453
+ throw new Error(`deck has ${richCounts[k]} ${k} cards (max 1 per deck)`);
454
+ }
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Detect whether a deck is V2 LayoutTree-shaped. The discriminator is the
460
+ * presence of `children` on the first card — V1 cards never have it. Falls
461
+ * back to V1 detection so callers can use this as a switch point.
462
+ */
463
+ function isV2LayoutTreeDeck(deck) {
464
+ return !!(deck && Array.isArray(deck.cards) && deck.cards[0] && Array.isArray(deck.cards[0].children));
465
+ }
466
+
467
+ module.exports = {
468
+ validatePaperSlideDeck,
469
+ validatePaperSlideDeckV2,
470
+ isV2LayoutTreeDeck,
471
+ V2_ALLOWED_ELEMENTS,
472
+ VALID_THEMES,
473
+ THEME_VARIANTS,
474
+ VALID_KINDS,
475
+ // Caps + payload helpers — exported for unit tests and so the slice
476
+ // validator in slice.js can mirror the same shape rules without drift.
477
+ validateQuotePayload,
478
+ validateDataPayload,
479
+ validateListPayload,
480
+ QUOTE_TEXT_MAX,
481
+ QUOTE_ATTRIBUTION_MAX,
482
+ DATA_VALUE_MAX,
483
+ DATA_UNIT_MAX,
484
+ DATA_LABEL_MAX,
485
+ LIST_ITEM_MAX_LEN,
486
+ LIST_ITEM_MIN_COUNT,
487
+ LIST_ITEM_MAX_COUNT,
488
+ };