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.
- package/README.md +34 -0
- package/bin/voxflow.js +27 -0
- package/dist/index.js +1 -1
- package/dist/remotion-bundle/02a2fb2eb80bc7bf.woff2 +0 -0
- package/dist/remotion-bundle/052ca5351e5e06ba.woff2 +0 -0
- package/dist/remotion-bundle/05853dd28f4019cb.woff2 +0 -0
- package/dist/remotion-bundle/072ead3737f7c0d0.woff2 +0 -0
- package/dist/remotion-bundle/07d4248613c86a2e.woff2 +0 -0
- package/dist/remotion-bundle/0884a5c2d1d2d99b.woff2 +0 -0
- package/dist/remotion-bundle/0b0e185b2752095e.woff2 +0 -0
- package/dist/remotion-bundle/0e66c11bde067d91.woff2 +0 -0
- package/dist/remotion-bundle/0f7794cfba2c5d21.woff2 +0 -0
- package/dist/remotion-bundle/0fdbae5a4365783a.woff2 +0 -0
- package/dist/remotion-bundle/112.bundle.js +11 -0
- package/dist/remotion-bundle/112.bundle.js.map +1 -0
- package/dist/remotion-bundle/113.bundle.js +11 -0
- package/dist/remotion-bundle/113.bundle.js.map +1 -0
- package/dist/remotion-bundle/119cae0c4c16f7ed.woff2 +0 -0
- package/dist/remotion-bundle/14725f649fd1e78c.woff2 +0 -0
- package/dist/remotion-bundle/14abe9e3f95f7888.woff2 +0 -0
- package/dist/remotion-bundle/163.bundle.js +14678 -0
- package/dist/remotion-bundle/163.bundle.js.map +1 -0
- package/dist/remotion-bundle/1808c54072bf6d14.woff2 +0 -0
- package/dist/remotion-bundle/18948bec3e3012fe.woff2 +0 -0
- package/dist/remotion-bundle/1a661c60d0fc84fc.woff2 +0 -0
- package/dist/remotion-bundle/1af94941e1bc7e1e.woff2 +0 -0
- package/dist/remotion-bundle/1bee0219595f606c.woff2 +0 -0
- package/dist/remotion-bundle/1bfd5da7ce9d4ec4.woff2 +0 -0
- package/dist/remotion-bundle/1c158d56f1884f3f.woff2 +0 -0
- package/dist/remotion-bundle/1cf5e88e667610eb.woff2 +0 -0
- package/dist/remotion-bundle/1d431bd10f53c481.woff2 +0 -0
- package/dist/remotion-bundle/1d701a81a7670db2.woff2 +0 -0
- package/dist/remotion-bundle/1da0fecad4240f16.woff2 +0 -0
- package/dist/remotion-bundle/1ed14d3d0c5c63fe.woff2 +0 -0
- package/dist/remotion-bundle/1edfecf40e586f53.woff2 +0 -0
- package/dist/remotion-bundle/1f479711bc34b054.woff +0 -0
- package/dist/remotion-bundle/1f86e54a0ff5fcd1.woff2 +0 -0
- package/dist/remotion-bundle/2043ea87d9aabd11.woff2 +0 -0
- package/dist/remotion-bundle/20563c39ee8a0e40.woff2 +0 -0
- package/dist/remotion-bundle/20c231590fd12c44.woff2 +0 -0
- package/dist/remotion-bundle/20ce61713f754c07.woff2 +0 -0
- package/dist/remotion-bundle/21eb9306fce24bb1.woff2 +0 -0
- package/dist/remotion-bundle/244bf71c0cc851af.woff2 +0 -0
- package/dist/remotion-bundle/274d4cfc02bffbcb.woff2 +0 -0
- package/dist/remotion-bundle/275.bundle.js +21 -0
- package/dist/remotion-bundle/275.bundle.js.map +1 -0
- package/dist/remotion-bundle/2958f540b39513dc.woff2 +0 -0
- package/dist/remotion-bundle/2a168b98fd97722e.woff2 +0 -0
- package/dist/remotion-bundle/2d1f6373937ab55f.woff2 +0 -0
- package/dist/remotion-bundle/2d213ae47ff6daa9.woff2 +0 -0
- package/dist/remotion-bundle/2e4b1f04fcd05047.woff2 +0 -0
- package/dist/remotion-bundle/304170d98f4c4563.woff2 +0 -0
- package/dist/remotion-bundle/30d02e136e7a5642.woff2 +0 -0
- package/dist/remotion-bundle/3135562b52a714cd.woff2 +0 -0
- package/dist/remotion-bundle/313713af2c8144e9.woff2 +0 -0
- package/dist/remotion-bundle/325fa4108d2285b9.woff2 +0 -0
- package/dist/remotion-bundle/338e927ed3345e0c.woff2 +0 -0
- package/dist/remotion-bundle/35fc6b190365bc17.woff2 +0 -0
- package/dist/remotion-bundle/37a51f1122d4efc5.woff2 +0 -0
- package/dist/remotion-bundle/39a4d63e02736f5e.woff2 +0 -0
- package/dist/remotion-bundle/3a00e0d62dfc4171.woff2 +0 -0
- package/dist/remotion-bundle/3a6955e6561affe1.woff2 +0 -0
- package/dist/remotion-bundle/3c573945aef49b89.woff2 +0 -0
- package/dist/remotion-bundle/3cdbfbfa23b516a5.woff2 +0 -0
- package/dist/remotion-bundle/3e42f85a9e64ca8a.woff2 +0 -0
- package/dist/remotion-bundle/3e83eaf1ec859415.woff2 +0 -0
- package/dist/remotion-bundle/3f3c8c90de1250ee.woff2 +0 -0
- package/dist/remotion-bundle/434.bundle.js +205 -0
- package/dist/remotion-bundle/434.bundle.js.map +1 -0
- package/dist/remotion-bundle/44ffc6ca4d781692.woff2 +0 -0
- package/dist/remotion-bundle/4670d9c4580b09eb.woff2 +0 -0
- package/dist/remotion-bundle/479756881b302824.woff2 +0 -0
- package/dist/remotion-bundle/481b82134bfa9c82.woff2 +0 -0
- package/dist/remotion-bundle/48d27029626f4328.woff2 +0 -0
- package/dist/remotion-bundle/49b7b2a30329c511.woff2 +0 -0
- package/dist/remotion-bundle/4c8b25a1a9337045.woff2 +0 -0
- package/dist/remotion-bundle/4cba14788ca9259b.woff2 +0 -0
- package/dist/remotion-bundle/4cd6c589c004a6a7.woff2 +0 -0
- package/dist/remotion-bundle/4cd8d79c1021608d.woff2 +0 -0
- package/dist/remotion-bundle/4d8fa99b3f00f9f0.woff2 +0 -0
- package/dist/remotion-bundle/4e7805a643f86d53.woff2 +0 -0
- package/dist/remotion-bundle/4ff91be454542e3f.woff2 +0 -0
- package/dist/remotion-bundle/504cbcba1f63591b.woff2 +0 -0
- package/dist/remotion-bundle/5202d792e5791d6c.woff2 +0 -0
- package/dist/remotion-bundle/534db5ad4770cc1d.woff2 +0 -0
- package/dist/remotion-bundle/53b9568eb85f866b.woff2 +0 -0
- package/dist/remotion-bundle/543ad386ca171de9.woff2 +0 -0
- package/dist/remotion-bundle/54798e55bbf7976e.woff2 +0 -0
- package/dist/remotion-bundle/580.bundle.js +11 -0
- package/dist/remotion-bundle/580.bundle.js.map +1 -0
- package/dist/remotion-bundle/58d174d1193af6d1.woff2 +0 -0
- package/dist/remotion-bundle/591d29ff3ff53c80.woff2 +0 -0
- package/dist/remotion-bundle/5c28c4f4824383c6.woff2 +0 -0
- package/dist/remotion-bundle/5da9740d2ce894c8.woff2 +0 -0
- package/dist/remotion-bundle/6197735364642360.woff2 +0 -0
- package/dist/remotion-bundle/6265a4335724080f.woff2 +0 -0
- package/dist/remotion-bundle/633f5e4f6394daa7.woff2 +0 -0
- package/dist/remotion-bundle/637d95ace6a69c49.woff2 +0 -0
- package/dist/remotion-bundle/648e04a04dacff8f.woff2 +0 -0
- package/dist/remotion-bundle/64a6e83045a008b2.woff2 +0 -0
- package/dist/remotion-bundle/651.bundle.js +11 -0
- package/dist/remotion-bundle/651.bundle.js.map +1 -0
- package/dist/remotion-bundle/65e2a988c070facc.woff2 +0 -0
- package/dist/remotion-bundle/66a2f6ce5cc69105.woff2 +0 -0
- package/dist/remotion-bundle/690.bundle.js +3479 -0
- package/dist/remotion-bundle/690.bundle.js.map +1 -0
- package/dist/remotion-bundle/690ff55252ca715d.woff2 +0 -0
- package/dist/remotion-bundle/6a01a1cff49314fc.woff2 +0 -0
- package/dist/remotion-bundle/6cbc32670982986c.woff2 +0 -0
- package/dist/remotion-bundle/6d3cc42ae547f454.woff2 +0 -0
- package/dist/remotion-bundle/6d8f4cfa1ddc0830.woff2 +0 -0
- package/dist/remotion-bundle/6e4d7c6ae65e2dc3.woff2 +0 -0
- package/dist/remotion-bundle/6e86418bbcefb2e8.woff2 +0 -0
- package/dist/remotion-bundle/6ee02884b29cf7fb.woff2 +0 -0
- package/dist/remotion-bundle/6f436a74c9e3252c.woff2 +0 -0
- package/dist/remotion-bundle/78c8022f1657618b.woff2 +0 -0
- package/dist/remotion-bundle/7c5444169792bca4.woff2 +0 -0
- package/dist/remotion-bundle/7c86bddd9d997212.woff2 +0 -0
- package/dist/remotion-bundle/7e1284684767f584.woff2 +0 -0
- package/dist/remotion-bundle/7e81c17522d182b2.woff2 +0 -0
- package/dist/remotion-bundle/7eb87be198f7858c.woff2 +0 -0
- package/dist/remotion-bundle/8060c928f948aab5.woff2 +0 -0
- package/dist/remotion-bundle/80bc9dfbea2b35ae.woff2 +0 -0
- package/dist/remotion-bundle/811b83f69963bb48.woff2 +0 -0
- package/dist/remotion-bundle/813.bundle.js +117511 -0
- package/dist/remotion-bundle/813.bundle.js.map +1 -0
- package/dist/remotion-bundle/84df492e349f82e9.woff2 +0 -0
- package/dist/remotion-bundle/8501bfd73eb36f2b.woff2 +0 -0
- package/dist/remotion-bundle/854236a8376093fe.woff2 +0 -0
- package/dist/remotion-bundle/8571d74529082753.woff2 +0 -0
- package/dist/remotion-bundle/860bf44f8e6f4b5d.woff2 +0 -0
- package/dist/remotion-bundle/879.bundle.js +64 -0
- package/dist/remotion-bundle/879.bundle.js.map +1 -0
- package/dist/remotion-bundle/887dd482f848d56f.woff2 +0 -0
- package/dist/remotion-bundle/89b2132e85fbbb5a.woff2 +0 -0
- package/dist/remotion-bundle/8ba60d6c306010c2.woff2 +0 -0
- package/dist/remotion-bundle/8c7c4dadea897806.woff2 +0 -0
- package/dist/remotion-bundle/8c943f9999706f61.woff2 +0 -0
- package/dist/remotion-bundle/8f2a718c90575cc9.woff2 +0 -0
- package/dist/remotion-bundle/906b6edb3e1772c9.woff2 +0 -0
- package/dist/remotion-bundle/930ff9daccdf14eb.woff2 +0 -0
- package/dist/remotion-bundle/934db2f1c403c4d0.woff2 +0 -0
- package/dist/remotion-bundle/938.bundle.js +451 -0
- package/dist/remotion-bundle/938.bundle.js.map +1 -0
- package/dist/remotion-bundle/967.bundle.js +4462 -0
- package/dist/remotion-bundle/967.bundle.js.map +1 -0
- package/dist/remotion-bundle/9684a1093d3c02ce.woff2 +0 -0
- package/dist/remotion-bundle/973dcd0faa6116cc.woff2 +0 -0
- package/dist/remotion-bundle/9745400694e76cd8.woff2 +0 -0
- package/dist/remotion-bundle/999ef957bed3bdca.woff2 +0 -0
- package/dist/remotion-bundle/99a3d67c8b0f43e3.woff2 +0 -0
- package/dist/remotion-bundle/a0586c3e03127283.woff2 +0 -0
- package/dist/remotion-bundle/a0eb654fdae46269.woff2 +0 -0
- package/dist/remotion-bundle/a20e35d3b08f7994.woff2 +0 -0
- package/dist/remotion-bundle/a2dcaced7c8c25ab.woff2 +0 -0
- package/dist/remotion-bundle/a79255a972a2681a.woff2 +0 -0
- package/dist/remotion-bundle/a804b352cb9fec1a.woff2 +0 -0
- package/dist/remotion-bundle/aae7117164e1eabc.woff2 +0 -0
- package/dist/remotion-bundle/affd121385d0442d.woff2 +0 -0
- package/dist/remotion-bundle/b19a6083987ee0d7.woff2 +0 -0
- package/dist/remotion-bundle/b1b2bd04d8637981.woff2 +0 -0
- package/dist/remotion-bundle/b2c07f341486be87.woff2 +0 -0
- package/dist/remotion-bundle/b33d8f82e575c4ce.woff2 +0 -0
- package/dist/remotion-bundle/b366c0bed35ef491.woff2 +0 -0
- package/dist/remotion-bundle/b41e857ec1b85642.woff2 +0 -0
- package/dist/remotion-bundle/b420bb34ccf23e7f.woff2 +0 -0
- package/dist/remotion-bundle/b4f7bf4efb0c0ccf.woff2 +0 -0
- package/dist/remotion-bundle/b60fe5eca03cff93.woff2 +0 -0
- package/dist/remotion-bundle/b6bd31a336e64bce.woff2 +0 -0
- package/dist/remotion-bundle/b6d2befba3dfefeb.woff2 +0 -0
- package/dist/remotion-bundle/b75f39ab06c43bf4.woff2 +0 -0
- package/dist/remotion-bundle/b77880e8c413d4fd.woff2 +0 -0
- package/dist/remotion-bundle/b7e38ec441e4a77a.woff2 +0 -0
- package/dist/remotion-bundle/b83baa383ff0bf2b.woff2 +0 -0
- package/dist/remotion-bundle/b9ad7b6c0a11450a.woff2 +0 -0
- package/dist/remotion-bundle/baf84486e8ae3aaf.woff2 +0 -0
- package/dist/remotion-bundle/bc047b1f6869cffa.woff2 +0 -0
- package/dist/remotion-bundle/bf4f3ac6e93f33aa.woff2 +0 -0
- package/dist/remotion-bundle/bf6835ffec5897a2.woff2 +0 -0
- package/dist/remotion-bundle/bf8885f581eb1724.woff2 +0 -0
- package/dist/remotion-bundle/bundle.js +83376 -0
- package/dist/remotion-bundle/bundle.js.map +1 -0
- package/dist/remotion-bundle/c03f046bccd789d0.woff2 +0 -0
- package/dist/remotion-bundle/c0bb1f8962b73bc3.woff2 +0 -0
- package/dist/remotion-bundle/c1003f9a7db6e1cf.woff2 +0 -0
- package/dist/remotion-bundle/c15d83fb1e199515.woff2 +0 -0
- package/dist/remotion-bundle/c28e7e5d310f73ef.woff2 +0 -0
- package/dist/remotion-bundle/c2b840274db78aea.woff2 +0 -0
- package/dist/remotion-bundle/c3000e3299d4e45f.woff2 +0 -0
- package/dist/remotion-bundle/c83ce886e5288510.woff2 +0 -0
- package/dist/remotion-bundle/c87a5a64d4ac0918.woff2 +0 -0
- package/dist/remotion-bundle/c8a7e0d049e965fa.woff2 +0 -0
- package/dist/remotion-bundle/c949a35d3a3b1faf.woff2 +0 -0
- package/dist/remotion-bundle/c9618c9b9ac2bc78.woff2 +0 -0
- package/dist/remotion-bundle/ca3add3b84152d5b.woff2 +0 -0
- package/dist/remotion-bundle/cad9dd036408d707.woff2 +0 -0
- package/dist/remotion-bundle/cbb24916619df439.woff2 +0 -0
- package/dist/remotion-bundle/cc054f0b5514e177.woff2 +0 -0
- package/dist/remotion-bundle/ccc248ed9312bc71.woff2 +0 -0
- package/dist/remotion-bundle/cd9d623aa07af925.woff2 +0 -0
- package/dist/remotion-bundle/ce2ba7a321bd1247.woff2 +0 -0
- package/dist/remotion-bundle/cf72455f79a29b14.woff2 +0 -0
- package/dist/remotion-bundle/d267cbfefab452ac.woff2 +0 -0
- package/dist/remotion-bundle/d435cff46a64955f.woff +0 -0
- package/dist/remotion-bundle/d494d07f67e363f6.woff2 +0 -0
- package/dist/remotion-bundle/d7aa0cc1fa47bf38.woff2 +0 -0
- package/dist/remotion-bundle/d7c5ca93d885160a.woff2 +0 -0
- package/dist/remotion-bundle/d855d3e252db74e2.woff2 +0 -0
- package/dist/remotion-bundle/d8f13d47f02f82c2.woff2 +0 -0
- package/dist/remotion-bundle/d9567cce2ee11019.woff2 +0 -0
- package/dist/remotion-bundle/db8d4456fc75dd86.woff +0 -0
- package/dist/remotion-bundle/dc274628378c47ee.woff2 +0 -0
- package/dist/remotion-bundle/dc3e06947bb69903.woff2 +0 -0
- package/dist/remotion-bundle/dd67040ac3b6d523.woff2 +0 -0
- package/dist/remotion-bundle/e0b04bd488f953f4.woff2 +0 -0
- package/dist/remotion-bundle/e2a572ff95089370.woff2 +0 -0
- package/dist/remotion-bundle/e2e18a86b1c2b0cc.woff2 +0 -0
- package/dist/remotion-bundle/e3a78ee2fc9c6931.woff2 +0 -0
- package/dist/remotion-bundle/e654c9d547605a9f.woff2 +0 -0
- package/dist/remotion-bundle/e67a3a64c129927c.woff2 +0 -0
- package/dist/remotion-bundle/e6be28b4203cd6ce.woff2 +0 -0
- package/dist/remotion-bundle/e841907ad9b0a191.woff +0 -0
- package/dist/remotion-bundle/e889d1541c69fffa.woff2 +0 -0
- package/dist/remotion-bundle/e88ef8c76373a9e2.woff2 +0 -0
- package/dist/remotion-bundle/e9c72f4bc37defef.woff2 +0 -0
- package/dist/remotion-bundle/e9e35f863403a255.woff2 +0 -0
- package/dist/remotion-bundle/eb23b37b009375da.woff2 +0 -0
- package/dist/remotion-bundle/ee1342b741625721.woff2 +0 -0
- package/dist/remotion-bundle/f07da88543a57ec9.woff2 +0 -0
- package/dist/remotion-bundle/f522982115306f8a.woff2 +0 -0
- package/dist/remotion-bundle/f8449bd864e6d8bc.woff2 +0 -0
- package/dist/remotion-bundle/f906dd5bd95ff9ab.woff2 +0 -0
- package/dist/remotion-bundle/f9e9e9413e3c38bb.woff2 +0 -0
- package/dist/remotion-bundle/fa5a5b16280994a8.woff2 +0 -0
- package/dist/remotion-bundle/favicon.ico +0 -0
- package/dist/remotion-bundle/fb19c0517725599b.woff2 +0 -0
- package/dist/remotion-bundle/fcaf24232f684b9b.woff2 +0 -0
- package/dist/remotion-bundle/fe09e084a3eea8cf.woff2 +0 -0
- package/dist/remotion-bundle/ff38d5317df7345a.woff2 +0 -0
- package/dist/remotion-bundle/ffe7ea1ea08f455a.woff2 +0 -0
- package/dist/remotion-bundle/index.html +49 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaomei/communication/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoxin/career/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/female-kefu-xiaoyue/parenting/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/male-kefu-xiaoxu/time-trap/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/cognition/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/growth/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/parenting/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-A6b7WpG3/soothing/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-female-R2s4N9qJ/cognition/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-Bk7vD3xP/decision/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-W1tH9jVc/manager/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide/v-male-s5NqE0rZ/founder/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/career-advice/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/founder-lesson/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/incident-review/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/learning-loop/4.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/meeting-closure/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/product-update/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/research-reading/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/0.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/1.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/2.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/3.mp3 +0 -0
- package/dist/remotion-bundle/public/paper-slide-experiments/sales-enablement/4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/ai-life/card-5.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-5.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/coffee-science/card-6.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-5.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/reading-secrets/card-6.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-0.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-1.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-2.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-3.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-4.mp3 +0 -0
- package/dist/remotion-bundle/public/voiceover/remote-work/card-5.mp3 +0 -0
- package/dist/remotion-bundle/source-map-helper.wasm +0 -0
- package/lib/cli.js +270 -0
- package/lib/commands/_registry.js +48 -0
- package/lib/commands/add.js +242 -0
- package/lib/commands/asr/azure-transcribe.js +336 -0
- package/lib/commands/asr/cloud-transcribe.js +384 -0
- package/lib/commands/asr/helpers.js +76 -0
- package/lib/commands/asr/index.js +236 -0
- package/lib/commands/asr/local-transcribe.js +125 -0
- package/lib/commands/asr-jobs.js +257 -0
- package/lib/commands/asr.js +11 -0
- package/lib/commands/auth-cmds.js +358 -0
- package/lib/commands/dub.js +542 -0
- package/lib/commands/explain.js +512 -0
- package/lib/commands/feedback.js +152 -0
- package/lib/commands/image.js +207 -0
- package/lib/commands/mcp-key.js +166 -0
- package/lib/commands/narrate.js +639 -0
- package/lib/commands/picstory-templates.js +276 -0
- package/lib/commands/picstory.js +547 -0
- package/lib/commands/podcast/dialogue.js +109 -0
- package/lib/commands/podcast/generate.js +127 -0
- package/lib/commands/podcast/index.js +561 -0
- package/lib/commands/podcast/synthesize.js +188 -0
- package/lib/commands/podcast.js +11 -0
- package/lib/commands/present.js +519 -0
- package/lib/commands/publish.js +415 -0
- package/lib/commands/skills.js +473 -0
- package/lib/commands/slice-render.js +282 -0
- package/lib/commands/slice-stage.js +264 -0
- package/lib/commands/slice.js +346 -0
- package/lib/commands/slides/constants.js +108 -0
- package/lib/commands/slides/html-renderer.js +338 -0
- package/lib/commands/slides/index.js +345 -0
- package/lib/commands/slides.js +11 -0
- package/lib/commands/story.js +302 -0
- package/lib/commands/summarize.js +532 -0
- package/lib/commands/synthesize.js +261 -0
- package/lib/commands/translate.js +593 -0
- package/lib/commands/upgrade.js +249 -0
- package/lib/commands/video-translate.js +577 -0
- package/lib/commands/voices.js +292 -0
- package/lib/core/agent-env.js +104 -0
- package/lib/core/args.js +107 -0
- package/lib/core/asr-client.js +448 -0
- package/lib/core/asr-jobs-client.js +126 -0
- package/lib/core/asr-jobs-store.js +105 -0
- package/lib/core/asr-r2-upload.js +181 -0
- package/lib/core/asr-upload.js +132 -0
- package/lib/core/audio-extract.js +150 -0
- package/lib/core/audio.js +219 -0
- package/lib/core/auth.js +880 -0
- package/lib/core/config.js +197 -0
- package/lib/core/feedback.js +64 -0
- package/lib/core/ffmpeg.js +476 -0
- package/lib/core/http.js +188 -0
- package/lib/core/image-client.js +55 -0
- package/lib/core/intent-params.js +11 -0
- package/lib/core/llm-client.js +76 -0
- package/lib/core/logger.js +208 -0
- package/lib/core/mic-recorder.js +182 -0
- package/lib/core/pause-markers.js +94 -0
- package/lib/core/podcast-pacing.js +118 -0
- package/lib/core/spinner.js +33 -0
- package/lib/core/srt.js +394 -0
- package/lib/core/telemetry.js +100 -0
- package/lib/core/timeline.js +92 -0
- package/lib/core/tts-synthesizer.js +70 -0
- package/lib/core/update-check.js +185 -0
- package/lib/core/url-download.js +148 -0
- package/lib/core/whisper-local.js +279 -0
- package/lib/internal/deck-validator.js +488 -0
- package/lib/internal/slice-themes.json +370 -0
- package/lib/stage-core/cloud-render.js +170 -0
- package/lib/stage-core/deck-format.js +133 -0
- package/lib/stage-core/edit-prompt.js +104 -0
- package/lib/stage-core/event-bus.js +31 -0
- package/lib/stage-core/port.js +46 -0
- package/lib/stage-core/server.js +352 -0
- package/lib/stage-core/snapshot-store.js +198 -0
- package/lib/stage-core/watcher.js +106 -0
- package/lib/stage-ui/slice/template.js +1672 -0
- package/package.json +9 -4
- package/skills/.claude-plugin/marketplace.json +22 -0
- package/skills/.claude-plugin/plugin.json +25 -0
- package/skills/LICENSE +21 -0
- package/skills/README.md +120 -0
- package/skills/hub/SKILL.md +317 -0
- package/skills/podcast/SKILL.md +146 -0
- package/skills/slice/SKILL.md +205 -0
- package/skills/slice/agents/openai.yaml +4 -0
- package/skills/slice/references/deck-schema.md +183 -0
- package/skills/slice/references/example-decks.md +108 -0
- package/skills/slice/references/themes.md +172 -0
- package/skills/transcribe/SKILL.md +473 -0
- package/skills/video/SKILL.md +261 -0
- package/skills/voxflow-slice/SKILL.md +271 -0
- package/skills/voxflow-slice/examples/article.md +13 -0
- package/skills/voxflow-slice/examples/expected-deck.json +39 -0
- package/skills/voxflow-slice/examples/validate.mjs +46 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Single source of truth for Slice visual themes. Consumed by backend (deck-validator / composition-core schemas / render-worker pipeline / slicing prompt), CLI (slice + slice-stage commands), and apps/console (SLICE_THEMES UI metadata). Adding a theme: append an entry here. The Remotion <Composition>/<Still> in video-present/src/Root.tsx + matching CSS blocks in apps/console/app/apps/slice/three-col.css still need authoring, but ID + metadata + dispatch live here. The completeness test (apps/console/lib/slice/__tests__/theme-registry-coverage.test.ts) fails build if you forget either. Optional `variants[]` describes palette swaps within a theme; each variant has its own id/label/accent for UI chips. Default variant = variants[0] or theme-level palette when absent.",
|
|
3
|
+
"default": "paper-slide",
|
|
4
|
+
"themes": [
|
|
5
|
+
{
|
|
6
|
+
"id": "paper-slide",
|
|
7
|
+
"label": "纸面",
|
|
8
|
+
"blurb": "泛黄纸纹 · 衬线红字 · 手绘印章",
|
|
9
|
+
"accent": "#7a1f15",
|
|
10
|
+
"platforms": ["抖音", "视频号", "小红书"],
|
|
11
|
+
"remotion": { "deck": "PaperSlideDeck", "cover": "PaperSlide-Cover" },
|
|
12
|
+
"variants": [
|
|
13
|
+
{ "id": "classic", "label": "经典朱红", "accent": "#7a1f15" },
|
|
14
|
+
{ "id": "forest", "label": "深林墨绿", "accent": "#1e4d33" },
|
|
15
|
+
{ "id": "ocean", "label": "深海靛蓝", "accent": "#1a3a5c" }
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"id": "editorial-mag",
|
|
20
|
+
"label": "编辑刊",
|
|
21
|
+
"blurb": "米白页面 · 衬线斜体 · 杂志感留白",
|
|
22
|
+
"accent": "#6b1a1a",
|
|
23
|
+
"platforms": ["知乎", "公众号", "Linkedin"],
|
|
24
|
+
"remotion": { "deck": "EditorialMagDeck", "cover": "EditorialMag-Cover" },
|
|
25
|
+
"variants": [
|
|
26
|
+
{ "id": "cream", "label": "经典米白", "accent": "#6b1a1a" },
|
|
27
|
+
{ "id": "sepia", "label": "棕褐古典", "accent": "#9a4b1a" },
|
|
28
|
+
{ "id": "cold-grey", "label": "冷调灰蓝", "accent": "#1b4f5c" }
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "bold-poster",
|
|
33
|
+
"label": "大字海报",
|
|
34
|
+
"blurb": "左侧 accent · 黑体粗字 · 数字大块",
|
|
35
|
+
"accent": "#FF3B30",
|
|
36
|
+
"platforms": ["X", "Threads", "Linkedin"],
|
|
37
|
+
"remotion": { "deck": "BoldPosterDeck", "cover": "BoldPoster-Cover" },
|
|
38
|
+
"variants": [
|
|
39
|
+
{ "id": "vermilion", "label": "经典朱红", "accent": "#FF3B30" },
|
|
40
|
+
{ "id": "electric", "label": "电光蓝", "accent": "#0066ff" },
|
|
41
|
+
{ "id": "forest", "label": "深林绿", "accent": "#1f8a3a" }
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "notion-card",
|
|
46
|
+
"label": "Notion 卡",
|
|
47
|
+
"blurb": "纯白底 · 暖灰墨 · 蓝色 accent · 页面图标",
|
|
48
|
+
"accent": "#0066ff",
|
|
49
|
+
"platforms": ["公众号", "飞书", "知识星球"],
|
|
50
|
+
"remotion": { "deck": "NotionCardDeck", "cover": "NotionCard-Cover" },
|
|
51
|
+
"variants": [
|
|
52
|
+
{ "id": "signal", "label": "信号蓝", "accent": "#0066ff" },
|
|
53
|
+
{ "id": "peach", "label": "暖橘桃", "accent": "#ec8854" },
|
|
54
|
+
{ "id": "sage", "label": "宁静鼠尾", "accent": "#5e9b7a" }
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "brutalist",
|
|
59
|
+
"label": "粗野",
|
|
60
|
+
"blurb": "黑白纯色 · 粗边框 · NO.NN 标签 · raw 排版",
|
|
61
|
+
"accent": "#000000",
|
|
62
|
+
"platforms": ["X", "Mastodon", "播客"],
|
|
63
|
+
"remotion": { "deck": "BrutalistDeck", "cover": "Brutalist-Cover" }
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "glass-dark",
|
|
67
|
+
"label": "玻璃夜",
|
|
68
|
+
"blurb": "深色渐变 · 紫色发光 · 玻璃拟态 · 短视频感",
|
|
69
|
+
"accent": "#a855f7",
|
|
70
|
+
"platforms": ["抖音", "视频号", "TikTok"],
|
|
71
|
+
"remotion": { "deck": "GlassDarkDeck", "cover": "GlassDark-Cover" },
|
|
72
|
+
"variants": [
|
|
73
|
+
{ "id": "violet", "label": "电光紫", "accent": "#a855f7" },
|
|
74
|
+
{ "id": "ember", "label": "暖琥珀", "accent": "#ff9844" },
|
|
75
|
+
{ "id": "aqua", "label": "霓虹青", "accent": "#5fd6e0" }
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id": "broadsheet",
|
|
80
|
+
"label": "财经刊",
|
|
81
|
+
"blurb": "FT 三文鱼底 · 重磅衬线 · 首字下沉 · DATELINE 红标",
|
|
82
|
+
"accent": "#0c2e5b",
|
|
83
|
+
"platforms": ["LinkedIn", "知乎", "雪球"],
|
|
84
|
+
"remotion": { "deck": "BroadsheetDeck", "cover": "Broadsheet-Cover" },
|
|
85
|
+
"variants": [
|
|
86
|
+
{ "id": "salmon", "label": "FT 三文鱼", "accent": "#0c2e5b" },
|
|
87
|
+
{ "id": "cream", "label": "周末刊奶白", "accent": "#1e3a5c" },
|
|
88
|
+
{ "id": "editorial-grey", "label": "现代冷灰", "accent": "#0a1428" }
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "blueprint",
|
|
93
|
+
"label": "蓝晒图",
|
|
94
|
+
"blurb": "青底 + 白色网格 · 橙色尺寸标 · 工程图纸感",
|
|
95
|
+
"accent": "#ffb74a",
|
|
96
|
+
"platforms": ["少数派", "知乎", "GitHub"],
|
|
97
|
+
"remotion": { "deck": "BlueprintDeck", "cover": "Blueprint-Cover" },
|
|
98
|
+
"variants": [
|
|
99
|
+
{ "id": "cyanotype", "label": "经典蓝晒", "accent": "#ffb74a" },
|
|
100
|
+
{ "id": "redline", "label": "评审红线", "accent": "#e74c3c" },
|
|
101
|
+
{ "id": "nightshift", "label": "夜班加深", "accent": "#ffd97a" }
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "daisy-pastel",
|
|
106
|
+
"label": "雏菊",
|
|
107
|
+
"blurb": "奶油底 + 手绘雏菊 + 星星 · 粉嫩可爱",
|
|
108
|
+
"accent": "#e58a9c",
|
|
109
|
+
"platforms": ["小红书", "微博", "即刻"],
|
|
110
|
+
"remotion": { "deck": "DaisyPastelDeck", "cover": "DaisyPastel-Cover" },
|
|
111
|
+
"variants": [
|
|
112
|
+
{ "id": "petal", "label": "粉嫩花瓣", "accent": "#e58a9c" },
|
|
113
|
+
{ "id": "meadow", "label": "草地鼠尾草", "accent": "#7ea876" },
|
|
114
|
+
{ "id": "sunset", "label": "夕阳珊瑚", "accent": "#e8957a" }
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "showa-catalog",
|
|
119
|
+
"label": "昭和目录",
|
|
120
|
+
"blurb": "70s city-pop · 彩色圆堆 + 彩虹斜条 + 太阳印章",
|
|
121
|
+
"accent": "#d6437b",
|
|
122
|
+
"platforms": ["小红书", "B 站", "播客"],
|
|
123
|
+
"remotion": { "deck": "ShowaCatalogDeck", "cover": "ShowaCatalog-Cover" },
|
|
124
|
+
"variants": [
|
|
125
|
+
{ "id": "pop", "label": "城市流行", "accent": "#d6437b" },
|
|
126
|
+
{ "id": "pastel", "label": "indie zine 软调", "accent": "#e0a4b8" },
|
|
127
|
+
{ "id": "monochrome", "label": "复古单色", "accent": "#a04030" }
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": "photo-feature",
|
|
132
|
+
"label": "摄影刊",
|
|
133
|
+
"blurb": "全屏摄影 + 渐变压底 + 重磅衬线 · 旅行游记感",
|
|
134
|
+
"accent": "#e8b455",
|
|
135
|
+
"platforms": ["小红书", "知乎", "微博"],
|
|
136
|
+
"remotion": { "deck": "PhotoFeatureDeck", "cover": "PhotoFeature-Cover" },
|
|
137
|
+
"variants": [
|
|
138
|
+
{ "id": "warm-amber", "label": "暖琥珀夕照", "accent": "#e8b455" },
|
|
139
|
+
{ "id": "cool-blue", "label": "冷调暮色", "accent": "#7ecbe8" },
|
|
140
|
+
{ "id": "monochrome", "label": "黑白纪实", "accent": "#cccccc" }
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"id": "atmospheric",
|
|
145
|
+
"label": "深夜刊",
|
|
146
|
+
"blurb": "黑底 + 一束暖光 + 衬线粉红 italic · 深夜散文",
|
|
147
|
+
"accent": "#dd5878",
|
|
148
|
+
"platforms": ["微博", "即刻", "播客"],
|
|
149
|
+
"remotion": { "deck": "AtmosphericDeck", "cover": "Atmospheric-Cover" }
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"id": "art-mag",
|
|
153
|
+
"label": "艺术杂志",
|
|
154
|
+
"blurb": "颗粒感色块 + 大字衬线 · 几何球 · 艺术画廊感",
|
|
155
|
+
"accent": "#dd5e72",
|
|
156
|
+
"platforms": ["小红书", "播客", "即刻"],
|
|
157
|
+
"remotion": { "deck": "ArtMagDeck", "cover": "ArtMag-Cover" },
|
|
158
|
+
"variants": [
|
|
159
|
+
{ "id": "vivid", "label": "高彩编辑", "accent": "#dd5e72" },
|
|
160
|
+
{ "id": "muted", "label": "莫兰迪低饱和", "accent": "#c08488" },
|
|
161
|
+
{ "id": "bauhaus", "label": "包豪斯三原色", "accent": "#c8242c" }
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"id": "tome-noir",
|
|
166
|
+
"label": "夜灯",
|
|
167
|
+
"blurb": "纯黑 + humanist sans · 60/40 非对称 · 暖光晕",
|
|
168
|
+
"accent": "#ffb38a",
|
|
169
|
+
"platforms": ["X", "LinkedIn", "即刻"],
|
|
170
|
+
"remotion": { "deck": "TomeNoirDeck", "cover": "TomeNoir-Cover" },
|
|
171
|
+
"variants": [
|
|
172
|
+
{ "id": "noir", "label": "暖琥珀", "accent": "#ffb38a" },
|
|
173
|
+
{ "id": "bronze", "label": "古铜", "accent": "#c0744a" },
|
|
174
|
+
{ "id": "platinum", "label": "冷银", "accent": "#a8b0bd" }
|
|
175
|
+
]
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"id": "flomo-mute",
|
|
179
|
+
"label": "纯白",
|
|
180
|
+
"blurb": "#fafafa Muji 纸面 · IBM Plex + 苹方 · 绿色细线 · 零装饰",
|
|
181
|
+
"accent": "#4ea870",
|
|
182
|
+
"platforms": ["小红书", "即刻", "微博"],
|
|
183
|
+
"remotion": { "deck": "FlomoMuteDeck", "cover": "FlomoMute-Cover" },
|
|
184
|
+
"variants": [
|
|
185
|
+
{ "id": "muji", "label": "原木绿", "accent": "#4ea870" },
|
|
186
|
+
{ "id": "graphite", "label": "石墨灰", "accent": "#6b7785" },
|
|
187
|
+
{ "id": "linen", "label": "亚麻米", "accent": "#c08a3a" }
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"id": "substack-drop",
|
|
192
|
+
"label": "专栏",
|
|
193
|
+
"blurb": "米色衬线 · 首字下沉 · 章节分隔 · 阅读时间 chip",
|
|
194
|
+
"accent": "#ff6719",
|
|
195
|
+
"platforms": ["公众号", "知乎", "少数派"],
|
|
196
|
+
"remotion": { "deck": "SubstackDropDeck", "cover": "SubstackDrop-Cover" },
|
|
197
|
+
"variants": [
|
|
198
|
+
{ "id": "signal", "label": "信号橙", "accent": "#ff6719" },
|
|
199
|
+
{ "id": "eclipse", "label": "深红夜", "accent": "#8a1f2c" },
|
|
200
|
+
{ "id": "tidewater", "label": "潮汐青", "accent": "#0a5d5f" }
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"id": "ink-scroll",
|
|
205
|
+
"label": "卷轴",
|
|
206
|
+
"blurb": "米黄宣纸 · 楷体竖排 · 印章红 · 水墨边缘",
|
|
207
|
+
"accent": "#c0392b",
|
|
208
|
+
"platforms": ["小红书", "微博", "B 站国创区"],
|
|
209
|
+
"remotion": { "deck": "InkScrollDeck", "cover": "InkScroll-Cover" },
|
|
210
|
+
"variants": [
|
|
211
|
+
{ "id": "seal-red", "label": "朱印红", "accent": "#c0392b" },
|
|
212
|
+
{ "id": "seal-blue", "label": "青衣靛", "accent": "#1f3a6b" },
|
|
213
|
+
{ "id": "seal-jade", "label": "翡翠绿", "accent": "#2a6b4a" }
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"id": "podcast-clip",
|
|
218
|
+
"label": "播客剪辑",
|
|
219
|
+
"blurb": "封面渐变 + 圆形封面 + 大字幕 · 波形 / 时间码底栏",
|
|
220
|
+
"accent": "#ffba78",
|
|
221
|
+
"platforms": ["小宇宙", "即刻", "抖音"],
|
|
222
|
+
"remotion": { "deck": "PodcastClipDeck", "cover": "PodcastClip-Cover" }
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"id": "ink-wash",
|
|
226
|
+
"label": "新中式",
|
|
227
|
+
"blurb": "宣纸 + 思源宋体 · 横排单字 · 笔触 · 朱印 · 留白",
|
|
228
|
+
"accent": "#b3261d",
|
|
229
|
+
"platforms": ["知乎长文", "小红书", "公众号"],
|
|
230
|
+
"remotion": { "deck": "InkWashDeck", "cover": "InkWash-Cover" },
|
|
231
|
+
"variants": [
|
|
232
|
+
{ "id": "vermilion", "label": "朱印红", "accent": "#b3261d" },
|
|
233
|
+
{ "id": "azure", "label": "青花蓝", "accent": "#1d4a7a" },
|
|
234
|
+
{ "id": "bronze", "label": "古铜褐", "accent": "#8a5a26" }
|
|
235
|
+
]
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"id": "morandi-calm",
|
|
239
|
+
"label": "莫兰迪",
|
|
240
|
+
"blurb": "低饱和粉褐 + 苹方 Light · 色块分区 · 零阴影零渐变",
|
|
241
|
+
"accent": "#9c5a4a",
|
|
242
|
+
"platforms": ["小红书", "公众号", "即刻"],
|
|
243
|
+
"remotion": { "deck": "MorandiCalmDeck", "cover": "MorandiCalm-Cover" }
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"id": "douyin-data",
|
|
247
|
+
"label": "数据卡",
|
|
248
|
+
"blurb": "纯黑底 + 抖音品红 + 湖蓝 · RGB 色差 · 大数字 60%",
|
|
249
|
+
"accent": "#FE2C55",
|
|
250
|
+
"platforms": ["抖音", "视频号", "小红书"],
|
|
251
|
+
"remotion": { "deck": "DouyinDataDeck", "cover": "DouyinData-Cover" }
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"id": "highlighter-note",
|
|
255
|
+
"label": "学习笔记",
|
|
256
|
+
"blurb": "奶油格纸 + 印刷体黑字 + Caveat 手写 · 黄色荧光笔 + 红色批注",
|
|
257
|
+
"accent": "#FFE63B",
|
|
258
|
+
"platforms": ["小红书", "B 站", "知乎"],
|
|
259
|
+
"remotion": { "deck": "HighlighterNoteDeck", "cover": "HighlighterNote-Cover" },
|
|
260
|
+
"variants": [
|
|
261
|
+
{ "id": "yellow", "label": "经典荧光黄", "accent": "#FFE63B" },
|
|
262
|
+
{ "id": "pink", "label": "粉色荧光", "accent": "#ff6ba0" },
|
|
263
|
+
{ "id": "mint", "label": "薄荷蓝笔", "accent": "#5fc88a" }
|
|
264
|
+
]
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"id": "memphis-design",
|
|
268
|
+
"label": "Memphis 设计",
|
|
269
|
+
"blurb": "奶油 + 原色块 · 波浪线 + 锯齿 + 实心圆 · 1986 后现代",
|
|
270
|
+
"accent": "#ff4d6d",
|
|
271
|
+
"platforms": ["即刻", "小红书", "播客"],
|
|
272
|
+
"remotion": { "deck": "MemphisDesignDeck", "cover": "MemphisDesign-Cover" }
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"id": "bauhaus-grid",
|
|
276
|
+
"label": "Bauhaus 包豪斯",
|
|
277
|
+
"blurb": "奶油纸 + 红黄蓝原色 + 圆方三角 · 1923 包豪斯几何构图",
|
|
278
|
+
"accent": "#d62828",
|
|
279
|
+
"platforms": ["LinkedIn", "设计博客", "工业设计", "知乎"],
|
|
280
|
+
"remotion": { "deck": "BauhausGridDeck", "cover": "BauhausGrid-Cover" }
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"id": "riso-print",
|
|
284
|
+
"label": "双色印刷",
|
|
285
|
+
"blurb": "荧光粉 + 钴蓝错版 · 网点 + 噪点 · Risograph 独立印刷",
|
|
286
|
+
"accent": "#ff48a7",
|
|
287
|
+
"platforms": ["独立开发", "设计 newsletter", "音乐厂牌"],
|
|
288
|
+
"remotion": { "deck": "RisoPrintDeck", "cover": "RisoPrint-Cover" }
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"id": "chrome-y2k",
|
|
292
|
+
"label": "千禧液态金属",
|
|
293
|
+
"blurb": "镀铬全息 + 像素栅 + 双径向辉光 · Y2K Bratz/iPod 质感",
|
|
294
|
+
"accent": "#8e6dff",
|
|
295
|
+
"platforms": ["小红书 girlie", "抖音 Z 世代", "TikTok"],
|
|
296
|
+
"remotion": { "deck": "ChromeY2kDeck", "cover": "ChromeY2k-Cover" }
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"id": "botanical-press",
|
|
300
|
+
"label": "植物图谱",
|
|
301
|
+
"blurb": "羊皮纸 + Cormorant 斜体 + 拉丁学名 · 18 世纪植物标本页",
|
|
302
|
+
"accent": "#5a6d2c",
|
|
303
|
+
"platforms": ["茶道", "园艺", "慢生活"],
|
|
304
|
+
"remotion": { "deck": "BotanicalPressDeck", "cover": "BotanicalPress-Cover" },
|
|
305
|
+
"variants": [
|
|
306
|
+
{ "id": "sage", "label": "鼠尾草绿", "accent": "#5a6d2c" },
|
|
307
|
+
{ "id": "copper", "label": "铜版褐", "accent": "#a06340" },
|
|
308
|
+
{ "id": "indigo", "label": "古典靛蓝", "accent": "#2c5078" }
|
|
309
|
+
]
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
"id": "art-nouveau",
|
|
313
|
+
"label": "新艺术",
|
|
314
|
+
"blurb": "Mucha 曲线 + 烫金 + 装饰边框 · 1900 巴黎沙龙海报",
|
|
315
|
+
"accent": "#b07d2d",
|
|
316
|
+
"platforms": ["艺术评论", "美术志", "插画家"],
|
|
317
|
+
"remotion": { "deck": "ArtNouveauDeck", "cover": "ArtNouveau-Cover" }
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"id": "tabloid-print",
|
|
321
|
+
"label": "小报头条",
|
|
322
|
+
"blurb": "红色 BREAKING + Anton 巨字 + 半调 + 双栏 · 八卦小报封面",
|
|
323
|
+
"accent": "#d6261a",
|
|
324
|
+
"platforms": ["行业八卦", "争议事件", "独立专栏"],
|
|
325
|
+
"remotion": { "deck": "TabloidPrintDeck", "cover": "TabloidPrint-Cover" }
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"id": "arcade-pixel",
|
|
329
|
+
"label": "街机像素",
|
|
330
|
+
"blurb": "CRT 扫描线 + 8-bit 像素 + RGB 色差 · 80s 街机标题屏",
|
|
331
|
+
"accent": "#c5f54c",
|
|
332
|
+
"platforms": ["独立游戏", "像素艺术", "90s 复古"],
|
|
333
|
+
"remotion": { "deck": "ArcadePixelDeck", "cover": "ArcadePixel-Cover" }
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"id": "hand-lettered",
|
|
337
|
+
"label": "黑板手写",
|
|
338
|
+
"blurb": "黑板绿底 + 粉笔白字 + Caveat 手写 · 咖啡馆菜单板",
|
|
339
|
+
"accent": "#f7d34a",
|
|
340
|
+
"platforms": ["咖啡馆菜单", "教师 notebook", "生活感"],
|
|
341
|
+
"remotion": { "deck": "HandLetteredDeck", "cover": "HandLettered-Cover" },
|
|
342
|
+
"variants": [
|
|
343
|
+
{ "id": "chalkboard", "label": "黑板绿", "accent": "#f7d34a" },
|
|
344
|
+
{ "id": "slate", "label": "石板灰", "accent": "#f0c84a" },
|
|
345
|
+
{ "id": "kraft", "label": "牛皮纸棕", "accent": "#f5c060" }
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"id": "stamp-collector",
|
|
350
|
+
"label": "邮票集",
|
|
351
|
+
"blurb": "齿孔 + 邮戳 + 面额 · 复古集邮册标本页",
|
|
352
|
+
"accent": "#1f4e6b",
|
|
353
|
+
"platforms": ["旅行游记", "收藏品", "怀旧专栏"],
|
|
354
|
+
"remotion": { "deck": "StampCollectorDeck", "cover": "StampCollector-Cover" },
|
|
355
|
+
"variants": [
|
|
356
|
+
{ "id": "navy", "label": "邮政蓝", "accent": "#1f4e6b" },
|
|
357
|
+
{ "id": "sepia", "label": "棕褐版", "accent": "#7a4a26" },
|
|
358
|
+
{ "id": "forest", "label": "森林绿", "accent": "#2a5a40" }
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"id": "tropical-postcard",
|
|
363
|
+
"label": "热带明信片",
|
|
364
|
+
"blurb": "落日渐变 + 椰影 + 浪潮线 · 60s 旅游海报明信片",
|
|
365
|
+
"accent": "#f04e9a",
|
|
366
|
+
"platforms": ["旅行游记", "夏日散文", "小红书 vlog"],
|
|
367
|
+
"remotion": { "deck": "TropicalPostcardDeck", "cover": "TropicalPostcard-Cover" }
|
|
368
|
+
}
|
|
369
|
+
]
|
|
370
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stage → backend bridge for the cloud Slice renderer.
|
|
5
|
+
*
|
|
6
|
+
* Background: stage runs on localhost with no auth. The backend cloud-render
|
|
7
|
+
* endpoint (`POST /api/paper-slide/render`) requires a JWT and costs 500
|
|
8
|
+
* quota per call. To let users go from "deck I'm happy with" → "mp4 in my
|
|
9
|
+
* hands" without leaving stage, we proxy three calls through the local stage
|
|
10
|
+
* server:
|
|
11
|
+
*
|
|
12
|
+
* submit(deck) → POST /api/paper-slide/render { jobId }
|
|
13
|
+
* status(jobId) → GET /api/render/:jobId { status, video_url? }
|
|
14
|
+
* quota() → GET /api/user/quota { remaining, monthly }
|
|
15
|
+
*
|
|
16
|
+
* Auth: we read the same `~/.config/voxflow/token.json` cache the CLI uses.
|
|
17
|
+
* No interactive refresh — if the token is missing or expired, callers get a
|
|
18
|
+
* machine-readable `not_logged_in` code and the UI tells the user to run
|
|
19
|
+
* `voxflow login`. Auto-refresh would mean potentially launching a browser,
|
|
20
|
+
* which is the wrong move when the user already has stage open.
|
|
21
|
+
*
|
|
22
|
+
* Design choice — proxy everything: never expose the JWT to the page. The
|
|
23
|
+
* UI talks to localhost:5180/api/render-mp4 etc.; this module is the only
|
|
24
|
+
* thing that ever sees the access token. Same posture as the rest of the
|
|
25
|
+
* stage server (no third-party tabs can read it via the Origin allowlist).
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const http = require('http');
|
|
29
|
+
const https = require('https');
|
|
30
|
+
|
|
31
|
+
const { API_BASE } = require('../core/config');
|
|
32
|
+
const { readCachedToken } = require('../core/auth');
|
|
33
|
+
|
|
34
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
35
|
+
|
|
36
|
+
function requestJson(targetUrl, opts = {}, body = null, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const u = new URL(targetUrl);
|
|
39
|
+
const mod = u.protocol === 'https:' ? https : http;
|
|
40
|
+
const headers = Object.assign({}, opts.headers || {});
|
|
41
|
+
let payload = null;
|
|
42
|
+
if (body !== null && body !== undefined) {
|
|
43
|
+
payload = Buffer.from(JSON.stringify(body), 'utf8');
|
|
44
|
+
headers['Content-Type'] = 'application/json';
|
|
45
|
+
headers['Content-Length'] = payload.length;
|
|
46
|
+
}
|
|
47
|
+
const req = mod.request({
|
|
48
|
+
hostname: u.hostname,
|
|
49
|
+
port: u.port || (u.protocol === 'https:' ? 443 : 80),
|
|
50
|
+
path: u.pathname + u.search,
|
|
51
|
+
method: opts.method || 'GET',
|
|
52
|
+
headers,
|
|
53
|
+
}, (res) => {
|
|
54
|
+
const chunks = [];
|
|
55
|
+
res.on('data', (c) => chunks.push(c));
|
|
56
|
+
res.on('end', () => {
|
|
57
|
+
const raw = Buffer.concat(chunks).toString('utf8');
|
|
58
|
+
let parsed = null;
|
|
59
|
+
try { parsed = JSON.parse(raw); } catch { /* keep as null on non-JSON */ }
|
|
60
|
+
resolve({ status: res.statusCode, data: parsed, raw });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
req.on('error', reject);
|
|
64
|
+
req.setTimeout(timeoutMs, () => { req.destroy(new Error(`upstream timeout after ${timeoutMs}ms`)); });
|
|
65
|
+
if (payload) req.write(payload);
|
|
66
|
+
req.end();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {object} [opts]
|
|
72
|
+
* @param {string} [opts.apiBase=API_BASE]
|
|
73
|
+
* @param {() => ({access_token:string}|null)} [opts.tokenLoader] For tests.
|
|
74
|
+
* @returns {{
|
|
75
|
+
* submit: (deck:object) => Promise<{code:string, jobId?:string, message?:string, ...}>,
|
|
76
|
+
* status: (jobId:string) => Promise<{code:string, status?:string, videoUrl?:string|null, ...}>,
|
|
77
|
+
* quota: () => Promise<{code:string, remaining?:number, monthly?:number, ...}>,
|
|
78
|
+
* }}
|
|
79
|
+
*/
|
|
80
|
+
function createCloudRenderClient(opts = {}) {
|
|
81
|
+
const apiBase = (opts.apiBase || API_BASE).replace(/\/$/, '');
|
|
82
|
+
const tokenLoader = typeof opts.tokenLoader === 'function' ? opts.tokenLoader : readCachedToken;
|
|
83
|
+
|
|
84
|
+
function authHeaders() {
|
|
85
|
+
const cached = tokenLoader();
|
|
86
|
+
if (!cached || !cached.access_token) return null;
|
|
87
|
+
return { Authorization: 'Bearer ' + cached.access_token };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function submit(deck) {
|
|
91
|
+
if (!deck || !Array.isArray(deck.cards)) {
|
|
92
|
+
return { code: 'invalid_deck', message: 'deck.cards must be an array' };
|
|
93
|
+
}
|
|
94
|
+
const headers = authHeaders();
|
|
95
|
+
if (!headers) return { code: 'not_logged_in', message: 'Run `voxflow login` first.' };
|
|
96
|
+
let r;
|
|
97
|
+
try {
|
|
98
|
+
r = await requestJson(`${apiBase}/api/paper-slide/render`, { method: 'POST', headers }, { deck });
|
|
99
|
+
} catch (err) {
|
|
100
|
+
return { code: 'network_error', message: err.message || String(err) };
|
|
101
|
+
}
|
|
102
|
+
if (r.status === 401) return { code: 'not_logged_in', message: 'Token expired — run `voxflow login`.' };
|
|
103
|
+
if (r.status === 402 || r.status === 429) {
|
|
104
|
+
return { code: 'quota_exceeded', message: r.data?.message || 'Insufficient quota' };
|
|
105
|
+
}
|
|
106
|
+
if (r.status >= 400 || !r.data) {
|
|
107
|
+
return { code: r.data?.code || 'render_submit_failed', message: r.data?.message || `HTTP ${r.status}` };
|
|
108
|
+
}
|
|
109
|
+
const jobId = r.data.data?.jobId || r.data.jobId;
|
|
110
|
+
if (!jobId) return { code: 'render_submit_failed', message: 'no jobId in response' };
|
|
111
|
+
return { code: 'success', jobId };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function status(jobId) {
|
|
115
|
+
if (typeof jobId !== 'string' || jobId.length === 0) {
|
|
116
|
+
return { code: 'invalid_id', message: 'jobId required' };
|
|
117
|
+
}
|
|
118
|
+
const headers = authHeaders();
|
|
119
|
+
if (!headers) return { code: 'not_logged_in', message: 'Run `voxflow login` first.' };
|
|
120
|
+
let r;
|
|
121
|
+
try {
|
|
122
|
+
r = await requestJson(`${apiBase}/api/render/${encodeURIComponent(jobId)}`, { method: 'GET', headers });
|
|
123
|
+
} catch (err) {
|
|
124
|
+
return { code: 'network_error', message: err.message || String(err) };
|
|
125
|
+
}
|
|
126
|
+
if (r.status === 401) return { code: 'not_logged_in' };
|
|
127
|
+
if (r.status === 404) return { code: 'job_not_found' };
|
|
128
|
+
if (r.status >= 400 || !r.data) {
|
|
129
|
+
return { code: r.data?.code || 'status_failed', message: r.data?.message || `HTTP ${r.status}` };
|
|
130
|
+
}
|
|
131
|
+
const job = r.data.data || r.data;
|
|
132
|
+
return {
|
|
133
|
+
code: 'success',
|
|
134
|
+
status: job.status,
|
|
135
|
+
videoUrl: job.video_url || job.videoUrl || null,
|
|
136
|
+
progress: job.progress,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function quota() {
|
|
141
|
+
const headers = authHeaders();
|
|
142
|
+
if (!headers) return { code: 'not_logged_in' };
|
|
143
|
+
let r;
|
|
144
|
+
try {
|
|
145
|
+
r = await requestJson(`${apiBase}/api/user/quota`, { method: 'GET', headers });
|
|
146
|
+
} catch (err) {
|
|
147
|
+
return { code: 'network_error', message: err.message };
|
|
148
|
+
}
|
|
149
|
+
if (r.status === 401) return { code: 'not_logged_in' };
|
|
150
|
+
if (r.status >= 400 || !r.data) {
|
|
151
|
+
return { code: 'quota_lookup_failed', message: `HTTP ${r.status}` };
|
|
152
|
+
}
|
|
153
|
+
const q = r.data.data || r.data;
|
|
154
|
+
return {
|
|
155
|
+
code: 'success',
|
|
156
|
+
remaining: typeof q.remaining === 'number' ? q.remaining : null,
|
|
157
|
+
monthly: typeof q.monthly === 'number' ? q.monthly : null,
|
|
158
|
+
bonus: typeof q.bonus === 'number' ? q.bonus : null,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { submit, status, quota };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// The render quota cost is hardcoded backend-side (500 per cloud-render).
|
|
166
|
+
// We expose it here so the UI can show "this costs N quota" without an
|
|
167
|
+
// extra round-trip — keep this in sync if the backend ladder changes.
|
|
168
|
+
const CLOUD_RENDER_COST = 500;
|
|
169
|
+
|
|
170
|
+
module.exports = { createCloudRenderClient, CLOUD_RENDER_COST };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure deck formatters used by the Stage UI (browser-side via stringification)
|
|
5
|
+
* AND by node:test units. Keep self-contained — no closures, no requires —
|
|
6
|
+
* because `Function.prototype.toString()` ships the source verbatim into the
|
|
7
|
+
* UI HTML and the browser then `eval`s the body inside an IIFE.
|
|
8
|
+
*
|
|
9
|
+
* Inputs are deliberately defensive about unknown card shapes (slice deck
|
|
10
|
+
* cards have varied kinds: title / body / outro; not every card has every
|
|
11
|
+
* field). Outputs are plain strings — clipboard-ready, no HTML escaping
|
|
12
|
+
* (browsers handle that on paste).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Convert a single Slice card to a plain-text snippet — the kind a user
|
|
17
|
+
* would paste into X / Twitter / 即刻 / 公众号 caption / 微博:
|
|
18
|
+
*
|
|
19
|
+
* {title}
|
|
20
|
+
* {caption (if distinct from title)}
|
|
21
|
+
*
|
|
22
|
+
* {narration}
|
|
23
|
+
*
|
|
24
|
+
* Empty fields are skipped. Returns '' if the card has nothing useful.
|
|
25
|
+
*
|
|
26
|
+
* @param {object} card Slice deck card (any shape)
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
function formatCardAsText(card) {
|
|
30
|
+
if (!card || typeof card !== 'object') return '';
|
|
31
|
+
const lines = [];
|
|
32
|
+
let title = null;
|
|
33
|
+
if (Array.isArray(card.title)) title = card.title.join(' · ');
|
|
34
|
+
else if (typeof card.title === 'string') title = card.title;
|
|
35
|
+
if (title && title.trim()) lines.push(title.trim());
|
|
36
|
+
|
|
37
|
+
if (typeof card.caption === 'string'
|
|
38
|
+
&& card.caption.trim()
|
|
39
|
+
&& card.caption.trim() !== title) {
|
|
40
|
+
lines.push(card.caption.trim());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof card.narration === 'string' && card.narration.trim()) {
|
|
44
|
+
if (lines.length > 0) lines.push('');
|
|
45
|
+
lines.push(card.narration.trim());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return lines.join('\n').trim();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Convert a whole Slice deck to a clean Markdown document. Useful for pasting
|
|
53
|
+
* into Notion / blog editors / 飞书 docs / hand-formatting elsewhere:
|
|
54
|
+
*
|
|
55
|
+
* # {seriesTitle || header || 'Deck'}
|
|
56
|
+
*
|
|
57
|
+
* ## 1. {card title}
|
|
58
|
+
*
|
|
59
|
+
* {caption if distinct}
|
|
60
|
+
*
|
|
61
|
+
* > {narration, multi-line preserved as blockquote}
|
|
62
|
+
*
|
|
63
|
+
* Returns '' if the deck shape is unusable.
|
|
64
|
+
*
|
|
65
|
+
* @param {object} deck
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
function formatDeckAsMarkdown(deck) {
|
|
69
|
+
if (!deck || typeof deck !== 'object') return '';
|
|
70
|
+
const out = [];
|
|
71
|
+
const top = (typeof deck.seriesTitle === 'string' && deck.seriesTitle.trim())
|
|
72
|
+
|| (typeof deck.header === 'string' && deck.header.trim())
|
|
73
|
+
|| 'Deck';
|
|
74
|
+
out.push('# ' + top);
|
|
75
|
+
out.push('');
|
|
76
|
+
|
|
77
|
+
const cards = Array.isArray(deck.cards) ? deck.cards : [];
|
|
78
|
+
for (let i = 0; i < cards.length; i++) {
|
|
79
|
+
const c = cards[i] || {};
|
|
80
|
+
let title = null;
|
|
81
|
+
if (Array.isArray(c.title)) title = c.title.join(' · ');
|
|
82
|
+
else if (typeof c.title === 'string') title = c.title;
|
|
83
|
+
if (!title || !title.trim()) {
|
|
84
|
+
title = (typeof c.caption === 'string' && c.caption.trim())
|
|
85
|
+
? c.caption.trim()
|
|
86
|
+
: 'Card ' + (i + 1);
|
|
87
|
+
}
|
|
88
|
+
out.push('## ' + (i + 1) + '. ' + title);
|
|
89
|
+
out.push('');
|
|
90
|
+
|
|
91
|
+
if (typeof c.caption === 'string'
|
|
92
|
+
&& c.caption.trim()
|
|
93
|
+
&& c.caption.trim() !== title) {
|
|
94
|
+
out.push(c.caption.trim());
|
|
95
|
+
out.push('');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (typeof c.narration === 'string' && c.narration.trim()) {
|
|
99
|
+
// Multi-line narration → each line gets the blockquote prefix.
|
|
100
|
+
const quoted = c.narration.trim().split('\n').map((ln) => '> ' + ln).join('\n');
|
|
101
|
+
out.push(quoted);
|
|
102
|
+
out.push('');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return out.join('\n').trim() + '\n';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Suggest a friendly filename for the deck JSON download. Sanitises the
|
|
111
|
+
* deck title to filesystem-safe ASCII and tacks on `.json`.
|
|
112
|
+
*
|
|
113
|
+
* @param {object} deck
|
|
114
|
+
* @returns {string}
|
|
115
|
+
*/
|
|
116
|
+
function suggestDeckFilename(deck) {
|
|
117
|
+
const top = (deck && typeof deck.seriesTitle === 'string' && deck.seriesTitle.trim())
|
|
118
|
+
|| (deck && typeof deck.header === 'string' && deck.header.trim())
|
|
119
|
+
|| 'deck';
|
|
120
|
+
const safe = top
|
|
121
|
+
.replace(/[<>:"/\\|?*]+/g, '-')
|
|
122
|
+
.replace(/\s+/g, '-')
|
|
123
|
+
.replace(/-+/g, '-')
|
|
124
|
+
.replace(/^-+|-+$/g, '')
|
|
125
|
+
.slice(0, 60);
|
|
126
|
+
return (safe || 'deck') + '.json';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = {
|
|
130
|
+
formatCardAsText,
|
|
131
|
+
formatDeckAsMarkdown,
|
|
132
|
+
suggestDeckFilename,
|
|
133
|
+
};
|