voxflow 1.15.6 → 1.17.0
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 +2 -2
- package/dist/index.js +1 -1
- package/dist/remotion-bundle/bundle.js +0 -1
- package/dist/remotion-bundle/bundle.js.map +1 -1
- package/lib/commands/_registry.js +1 -0
- package/lib/commands/card-render.js +520 -0
- package/lib/commands/card.js +57 -0
- package/lib/commands/skills.js +3 -3
- package/lib/commands/slice-fork.js +4 -4
- package/lib/commands/slice.js +1 -1
- package/lib/core/ffmpeg.js +74 -11
- package/package.json +5 -2
- package/skills/.claude-plugin/marketplace.json +2 -2
- package/skills/.claude-plugin/plugin.json +3 -2
- package/skills/README.md +9 -7
- package/skills/card/SKILL.md +486 -0
- package/skills/card/assets/fonts/MANIFEST.md +29 -0
- package/skills/card/assets/fonts/css/cabinet-grotesk.css +2 -0
- package/skills/card/assets/fonts/css/geist-mono.css +29 -0
- package/skills/card/assets/fonts/css/geist.css +29 -0
- package/skills/card/assets/fonts/css/general-sans.css +2 -0
- package/skills/card/assets/fonts/css/ibm-plex-mono-500.css +49 -0
- package/skills/card/assets/fonts/css/ibm-plex-mono-600.css +49 -0
- package/skills/card/assets/fonts/css/ibm-plex-mono.css +49 -0
- package/skills/card/assets/fonts/css/libre-caslon-display.css +19 -0
- package/skills/card/assets/fonts/css/newsreader.css +29 -0
- package/skills/card/assets/fonts/css/noto-sans-sc.css +1009 -0
- package/skills/card/assets/fonts/css/noto-serif-sc.css +1009 -0
- package/skills/card/assets/fonts/css/satoshi.css +2 -0
- package/skills/card/assets/fonts/css/source-serif-4.css +59 -0
- package/skills/card/assets/fonts/css/space-grotesk.css +29 -0
- package/skills/card/assets/fonts/css/spectral-600.css +49 -0
- package/skills/card/assets/fonts/css/spectral-800.css +49 -0
- package/skills/card/assets/fonts/css/spectral.css +49 -0
- package/skills/card/assets/fonts/fonts.css +25 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-100.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-101.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-102.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-103.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-104.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-105.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-106.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-107.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-108.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-109.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-110.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-111.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-112.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-113.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-114.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-115.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-116.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-117.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-118.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-119.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-21.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-22.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-23.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-24.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-25.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-26.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-27.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-28.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-29.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-30.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-31.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-32.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-33.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-34.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-35.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-36.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-37.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-38.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-39.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-4.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-40.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-41.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-42.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-43.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-44.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-45.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-46.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-47.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-48.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-49.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-5.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-50.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-51.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-52.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-53.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-54.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-55.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-56.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-57.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-58.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-59.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-6.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-60.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-61.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-62.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-63.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-65.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-66.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-67.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-68.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-69.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-70.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-71.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-72.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-73.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-74.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-75.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-76.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-77.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-78.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-79.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-80.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-81.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-82.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-83.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-84.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-85.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-86.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-87.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-88.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-89.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-90.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-91.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-97.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-98.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-bold-subset-99.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-100.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-101.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-102.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-103.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-104.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-105.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-106.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-107.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-108.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-109.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-110.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-111.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-112.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-113.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-114.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-115.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-116.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-117.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-118.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-119.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-21.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-22.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-23.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-24.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-25.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-26.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-27.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-28.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-29.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-30.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-31.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-32.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-33.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-34.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-35.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-36.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-37.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-38.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-39.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-4.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-40.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-41.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-42.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-43.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-44.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-45.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-46.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-47.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-48.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-49.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-5.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-50.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-51.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-52.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-53.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-54.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-55.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-56.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-57.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-58.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-59.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-6.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-60.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-61.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-62.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-63.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-65.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-66.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-67.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-68.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-69.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-70.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-71.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-72.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-73.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-74.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-75.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-76.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-77.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-78.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-79.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-80.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-81.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-82.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-83.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-84.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-85.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-86.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-87.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-88.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-89.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-90.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-91.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-97.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-98.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/files/lxgwwenkailite-regular-subset-99.woff2 +0 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/lxgwwenkailite-bold.css +873 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/lxgwwenkailite-regular.css +873 -0
- package/skills/card/assets/fonts/packages/lxgw-wenkai/style.css +2 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_4e00_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_4fea_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_5268_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_543c_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_5784_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_5b6c_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_5e37_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_60d2_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_6326_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_65b1_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_68a8_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_6cba_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_6fa2_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_73ce_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_77e4_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_7b78_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_7eee_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_81c1_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_8608_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_8aa4_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_8d20_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_8feb_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_94aa_192.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L1_97cd_266.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_3918_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_5081_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_5467_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_55ed_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_57f0_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_5ae4_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_5e15_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_609b_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_63e1_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_66dd_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_696c_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_6c75_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_6e73_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_7114_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_7392_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_7580_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_7769_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_7a71_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_7e21_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_7fcd_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_8203_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_8393_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_85b8_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_87cb_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_8bb5_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_8db6_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_9022_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_91ea_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_9504_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_9655_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_996a_96.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L2_9c95_133.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_101_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_148_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_1d4_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_1e86_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_1edf_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_20_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_2172_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_2495_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_3067_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_30b3_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_30f3_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_3a9_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_421_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_536a_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_60_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_61b8_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_706d_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_7b7c_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_836e_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_9124_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_9795_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_c1_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_fe3a_64.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/L3_ff16_79.woff2 +0 -0
- package/skills/card/assets/fonts/packages/smiley-sans/font.css +80 -0
- package/skills/card/assets/fonts/woff2/fontshare/cabinet-grotesk.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/fontshare/general-sans.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/fontshare/satoshi.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/geist/geist-cyrillic-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/geist/geist-latin-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/geist/geist-latin-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/geist-mono/geist-mono-cyrillic-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/geist-mono/geist-mono-latin-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/geist-mono/geist-mono-latin-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono/ibm-plex-mono-cyrillic-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono/ibm-plex-mono-cyrillic-ext-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono/ibm-plex-mono-vietnamese-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-500/ibm-plex-mono-cyrillic-500-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-500/ibm-plex-mono-cyrillic-ext-500-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-500/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-500/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-500/ibm-plex-mono-vietnamese-500-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-600/ibm-plex-mono-cyrillic-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-600/ibm-plex-mono-cyrillic-ext-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-600/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-600/ibm-plex-mono-latin-ext-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/ibm-plex-mono-600/ibm-plex-mono-vietnamese-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/libre-caslon-display/libre-caslon-display-latin-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/libre-caslon-display/libre-caslon-display-latin-ext-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/newsreader/newsreader-latin-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/newsreader/newsreader-latin-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/newsreader/newsreader-vietnamese-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-100-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-101-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-102-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-103-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-104-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-105-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-106-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-107-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-108-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-109-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-110-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-111-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-112-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-113-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-114-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-115-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-116-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-117-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-118-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-119-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-21-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-22-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-23-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-24-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-25-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-26-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-27-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-28-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-29-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-30-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-31-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-32-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-33-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-34-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-35-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-36-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-37-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-38-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-39-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-4-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-40-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-41-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-42-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-43-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-44-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-45-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-46-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-47-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-48-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-49-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-5-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-50-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-51-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-52-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-53-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-54-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-55-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-56-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-57-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-58-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-59-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-6-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-60-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-61-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-62-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-63-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-64-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-65-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-66-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-67-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-68-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-69-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-70-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-71-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-72-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-73-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-74-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-75-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-76-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-77-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-78-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-79-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-80-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-81-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-82-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-83-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-84-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-85-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-86-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-87-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-88-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-89-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-90-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-91-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-97-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-98-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-99-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-cyrillic-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-latin-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-latin-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-sans-sc/noto-sans-sc-vietnamese-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-100-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-101-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-102-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-103-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-104-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-105-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-106-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-107-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-108-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-109-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-110-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-111-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-112-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-113-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-114-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-115-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-116-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-117-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-118-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-119-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-21-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-22-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-23-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-24-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-25-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-26-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-27-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-28-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-29-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-30-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-31-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-32-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-33-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-34-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-35-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-36-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-37-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-38-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-39-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-4-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-40-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-41-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-42-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-43-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-44-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-45-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-46-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-47-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-48-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-49-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-5-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-50-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-51-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-52-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-53-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-54-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-55-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-56-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-57-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-58-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-59-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-6-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-60-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-61-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-62-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-63-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-64-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-65-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-66-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-67-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-68-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-69-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-70-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-71-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-72-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-73-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-74-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-75-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-76-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-77-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-78-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-79-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-80-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-81-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-82-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-83-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-84-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-85-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-86-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-87-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-88-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-89-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-90-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-91-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-97-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-98-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-99-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-cyrillic-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-latin-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-latin-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/noto-serif-sc/noto-serif-sc-vietnamese-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/source-serif-4/source-serif-4-cyrillic-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/source-serif-4/source-serif-4-cyrillic-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/source-serif-4/source-serif-4-greek-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/source-serif-4/source-serif-4-latin-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/source-serif-4/source-serif-4-latin-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/source-serif-4/source-serif-4-vietnamese-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/space-grotesk/space-grotesk-latin-ext-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/space-grotesk/space-grotesk-latin-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/space-grotesk/space-grotesk-vietnamese-wght-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral/spectral-cyrillic-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral/spectral-cyrillic-ext-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral/spectral-latin-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral/spectral-latin-ext-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral/spectral-vietnamese-400-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-600/spectral-cyrillic-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-600/spectral-cyrillic-ext-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-600/spectral-latin-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-600/spectral-latin-ext-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-600/spectral-vietnamese-600-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-800/spectral-cyrillic-800-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-800/spectral-cyrillic-ext-800-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-800/spectral-latin-800-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-800/spectral-latin-ext-800-normal.woff2 +0 -0
- package/skills/card/assets/fonts/woff2/spectral-800/spectral-vietnamese-800-normal.woff2 +0 -0
- package/skills/card/references/design-languages/cinematic-still.md +57 -0
- package/skills/card/references/design-languages/data-poster.md +57 -0
- package/skills/card/references/design-languages/editorial-artifact.md +58 -0
- package/skills/card/references/design-languages/field-notes.md +58 -0
- package/skills/card/references/design-languages/image-led-magazine.md +57 -0
- package/skills/card/references/design-languages/newsroom-poster.md +58 -0
- package/skills/card/references/design-languages/product-catalog.md +57 -0
- package/skills/card/references/design-languages/swiss-poster.md +60 -0
- package/skills/card/references/design-languages.md +168 -0
- package/skills/card/references/fonts-preview.html +450 -0
- package/skills/card/references/fonts.md +151 -0
- package/skills/card/references/layouts/card-layouts.md +268 -0
- package/skills/card/references/magazine-card-adaptations.md +154 -0
- package/skills/card/references/taste.md +121 -0
- package/skills/card/references/themes/presets.md +314 -0
- package/skills/card/scripts/download-fonts.sh +240 -0
- package/skills/card/scripts/render-cards.mjs +219 -0
- package/skills/voxflow-slice/SKILL.md +0 -415
- package/skills/voxflow-slice/examples/article.md +0 -13
- package/skills/voxflow-slice/examples/expected-deck.json +0 -39
- package/skills/voxflow-slice/examples/validate.mjs +0 -46
- /package/skills/{voxflow-slice → slice}/templates/data-finding/deck.json +0 -0
- /package/skills/{voxflow-slice → slice}/templates/founder-lesson/deck.json +0 -0
- /package/skills/{voxflow-slice → slice}/templates/incident-review/deck.json +0 -0
- /package/skills/{voxflow-slice → slice}/templates/manifest.json +0 -0
- /package/skills/{voxflow-slice → slice}/templates/product-launch/deck.json +0 -0
- /package/skills/{voxflow-slice → slice}/templates/quiet-essay/deck.json +0 -0
|
@@ -25,6 +25,7 @@ module.exports = {
|
|
|
25
25
|
asr: () => require('./asr'),
|
|
26
26
|
'asr-jobs': () => require('./asr-jobs'),
|
|
27
27
|
'auth-cmds': () => require('./auth-cmds'),
|
|
28
|
+
card: () => require('./card'),
|
|
28
29
|
dub: () => require('./dub'),
|
|
29
30
|
explain: () => require('./explain'),
|
|
30
31
|
feedback: () => require('./feedback'),
|
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VoxFlow CLI — card render subcommand
|
|
3
|
+
*
|
|
4
|
+
* Renders a card-skill output directory into a polished narrated MP4:
|
|
5
|
+
* 1. Read deck.json (narration text per card)
|
|
6
|
+
* 2. Ensure PNGs exist
|
|
7
|
+
* 3. Synthesize TTS per card → WAV
|
|
8
|
+
* 4. Render per-card clip: PNG + subtle zoom + subtitle bar + fade
|
|
9
|
+
* 5. Render intro title card + outro branding card
|
|
10
|
+
* 6. Concat all clips (intro + cards + outro)
|
|
11
|
+
* 7. Mix background music (optional)
|
|
12
|
+
*
|
|
13
|
+
* Features:
|
|
14
|
+
* - Subtle center zoom (2%) — content stays readable
|
|
15
|
+
* - Bottom subtitle bar with narration text
|
|
16
|
+
* - Auto intro card (series title) + outro card (branding)
|
|
17
|
+
* - Crossfade via per-clip fade-in/fade-out
|
|
18
|
+
* - Background music loop at low volume
|
|
19
|
+
* - ffmpeg-static fallback (no system FFmpeg required)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
const { parseFlag, runWithRetry } = require('../core/args');
|
|
28
|
+
const { getToken, getTokenInfo } = require('../core/auth');
|
|
29
|
+
const { API_BASE } = require('../core/config');
|
|
30
|
+
const { buildWav, createSilence, PCM_SAMPLE_RATE } = require('../core/audio');
|
|
31
|
+
const { BYTES_PER_MS } = require('../core/timeline');
|
|
32
|
+
const { synthesizeTTS } = require('../core/tts-synthesizer');
|
|
33
|
+
const { runCommand, checkFfmpeg, concatVideos } = require('../core/ffmpeg');
|
|
34
|
+
|
|
35
|
+
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
const RATIO_DIMS = {
|
|
38
|
+
'1:1': { w: 1080, h: 1080 },
|
|
39
|
+
'3:4': { w: 1080, h: 1440 },
|
|
40
|
+
'4:5': { w: 1080, h: 1350 },
|
|
41
|
+
'9:16': { w: 1080, h: 1920 },
|
|
42
|
+
'16:9': { w: 1920, h: 1080 },
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Subtitle styling
|
|
46
|
+
const SUB_FONT_SIZE = 36;
|
|
47
|
+
const SUB_BOX_OPACITY = 0.6;
|
|
48
|
+
const SUB_MARGIN_BOTTOM = 80;
|
|
49
|
+
const SUB_PADDING = 20;
|
|
50
|
+
|
|
51
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
function readDeckJson(dir) {
|
|
54
|
+
const p = path.join(dir, 'deck.json');
|
|
55
|
+
if (!fs.existsSync(p)) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`No deck.json found in ${dir}.\n` +
|
|
58
|
+
` The card SKILL.md workflow must produce a deck.json alongside the HTML files.\n` +
|
|
59
|
+
` See: cli/skills/card/SKILL.md — Step 9.`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resolveCardPng(dir, cardFile) {
|
|
66
|
+
const base = path.basename(cardFile, path.extname(cardFile));
|
|
67
|
+
const candidates = [
|
|
68
|
+
path.join(dir, 'exports', `${base}.png`),
|
|
69
|
+
path.join(dir, `${base}.png`),
|
|
70
|
+
];
|
|
71
|
+
for (const c of candidates) {
|
|
72
|
+
if (fs.existsSync(c)) return c;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function writePcmAsWav(pcmBuffer, dest, trailingSilenceSec = 0) {
|
|
78
|
+
// Append silence to the PCM itself so the WAV's natural duration includes
|
|
79
|
+
// the post-narration "reading time" pause. Using `-shortest` in ffmpeg
|
|
80
|
+
// would otherwise truncate the clip back to the narration-only length.
|
|
81
|
+
const totalPcm = trailingSilenceSec > 0
|
|
82
|
+
? Buffer.concat([pcmBuffer, createSilence(trailingSilenceSec, PCM_SAMPLE_RATE)])
|
|
83
|
+
: pcmBuffer;
|
|
84
|
+
const { wav } = buildWav([totalPcm], { silenceSec: 0 });
|
|
85
|
+
fs.writeFileSync(dest, wav);
|
|
86
|
+
return dest;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function pcmToDurationMs(buf) {
|
|
90
|
+
return Math.round(buf.length / BYTES_PER_MS);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Escape text for an FFmpeg drawtext `text='...'` value.
|
|
95
|
+
*
|
|
96
|
+
* FFmpeg filtergraph parsing has two layers of escaping:
|
|
97
|
+
* 1. The filter argument splitter (`,` and `;` separate filters/chains).
|
|
98
|
+
* 2. The drawtext text= value, single-quoted; `\` and `:` are special.
|
|
99
|
+
*
|
|
100
|
+
* For each special char we therefore emit `\\<char>` \u2014 a single literal
|
|
101
|
+
* backslash plus the char \u2014 so JS source `'\\\\'` (4 chars) = 2-char string `\\`,
|
|
102
|
+
* which ffmpeg parses as one literal backslash.
|
|
103
|
+
*
|
|
104
|
+
* Apostrophes inside a single-quoted text= value cannot be escaped reliably
|
|
105
|
+
* across ffmpeg versions, so we substitute the typographic right single quote
|
|
106
|
+
* (U+2019) which renders identically for human readers.
|
|
107
|
+
*/
|
|
108
|
+
function escapeDrawtext(text) {
|
|
109
|
+
return text
|
|
110
|
+
.replace(/\\/g, '\\\\') // \ \u2192 \\ (one literal backslash)
|
|
111
|
+
.replace(/'/g, '\u2019') // ' \u2192 \u2019 (avoid breaking the surrounding quotes)
|
|
112
|
+
.replace(/;/g, '\\;') // ; \u2192 \; (filter chain separator)
|
|
113
|
+
.replace(/,/g, '\\,') // , \u2192 \, (filter argument separator)
|
|
114
|
+
.replace(/:/g, '\\:') // : \u2192 \: (option separator inside drawtext)
|
|
115
|
+
.replace(/\[/g, '\\[')
|
|
116
|
+
.replace(/\]/g, '\\]')
|
|
117
|
+
.replace(/%/g, '%%') // drawtext format-string escape
|
|
118
|
+
.replace(/\n/g, ' ');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Render functions ──────────────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Render a single card: PNG + optional WAV → MP4 clip with subtitle overlay.
|
|
125
|
+
*/
|
|
126
|
+
async function renderCardClip({ pngPath, wavPath, outPath, durationMs, ratio, subtitle, hasDrawtext = false }) {
|
|
127
|
+
const { w, h } = RATIO_DIMS[ratio] || RATIO_DIMS['9:16'];
|
|
128
|
+
const durationSec = Math.max(3, durationMs / 1000);
|
|
129
|
+
|
|
130
|
+
// No fade between clips — hard cut. Fade-to-black causes visible
|
|
131
|
+
// black frames at transitions since clips are concatenated, not overlaid.
|
|
132
|
+
const vfParts = [
|
|
133
|
+
`scale=${w}:${h}:force_original_aspect_ratio=increase`,
|
|
134
|
+
`crop=${w}:${h}`,
|
|
135
|
+
];
|
|
136
|
+
|
|
137
|
+
// Subtitle bar overlay (only if drawtext is available — checked at pipeline level)
|
|
138
|
+
if (subtitle && hasDrawtext) {
|
|
139
|
+
const escaped = escapeDrawtext(subtitle);
|
|
140
|
+
const fontSize = Math.round(SUB_FONT_SIZE * (w / 1080));
|
|
141
|
+
const boxY = h - SUB_MARGIN_BOTTOM - fontSize - SUB_PADDING * 2;
|
|
142
|
+
vfParts.push(
|
|
143
|
+
`drawtext=text='${escaped}':fontsize=${fontSize}:fontcolor=white:` +
|
|
144
|
+
`x=(w-text_w)/2:y=${boxY + SUB_PADDING}:` +
|
|
145
|
+
`box=1:boxcolor=black@${SUB_BOX_OPACITY}:boxborderw=${SUB_PADDING}`,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
vfParts.push('format=yuv420p');
|
|
150
|
+
|
|
151
|
+
const args = ['-loop', '1', '-t', String(durationSec + 0.1), '-i', path.resolve(pngPath)];
|
|
152
|
+
|
|
153
|
+
if (wavPath) {
|
|
154
|
+
args.push('-i', path.resolve(wavPath));
|
|
155
|
+
args.push('-vf', vfParts.join(','));
|
|
156
|
+
args.push(
|
|
157
|
+
'-c:v', 'libx264', '-preset', 'fast', '-crf', '22', '-bf', '0',
|
|
158
|
+
'-c:a', 'aac', '-b:a', '128k', '-ar', '24000', '-ac', '1',
|
|
159
|
+
'-shortest',
|
|
160
|
+
);
|
|
161
|
+
} else {
|
|
162
|
+
args.push(
|
|
163
|
+
'-f', 'lavfi', '-t', String(durationSec), '-i', 'anullsrc=channel_layout=mono:sample_rate=24000',
|
|
164
|
+
'-vf', vfParts.join(','),
|
|
165
|
+
'-c:v', 'libx264', '-preset', 'fast', '-crf', '22', '-bf', '0',
|
|
166
|
+
'-c:a', 'aac', '-b:a', '128k',
|
|
167
|
+
'-t', String(durationSec),
|
|
168
|
+
'-shortest',
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
args.push('-movflags', '+faststart', '-y', path.resolve(outPath));
|
|
173
|
+
await runCommand('ffmpeg', args);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Generate an intro or outro card via FFmpeg color source (simple solid + no text).
|
|
178
|
+
* Text overlay requires drawtext (libfreetype); if unavailable, renders a plain color card.
|
|
179
|
+
*/
|
|
180
|
+
async function renderTitleCard({ outPath, ratio, title, subtitle, durationSec = 3, bgColor = '1a1520', textColor = 'f4efe6', fadeSeconds = 0.4, isFirst = false, isLast = false, hasDrawtext = false }) {
|
|
181
|
+
const { w, h } = RATIO_DIMS[ratio] || RATIO_DIMS['9:16'];
|
|
182
|
+
const fd = fadeSeconds;
|
|
183
|
+
|
|
184
|
+
const titleSize = Math.round(72 * (w / 1080));
|
|
185
|
+
const subSize = Math.round(32 * (w / 1080));
|
|
186
|
+
const escapedTitle = escapeDrawtext(title || '');
|
|
187
|
+
const escapedSub = escapeDrawtext(subtitle || '');
|
|
188
|
+
|
|
189
|
+
const vfParts = [`color=c=0x${bgColor}:s=${w}x${h}:d=${durationSec}:r=30`];
|
|
190
|
+
|
|
191
|
+
if (hasDrawtext) {
|
|
192
|
+
if (escapedTitle) {
|
|
193
|
+
vfParts.push(
|
|
194
|
+
`drawtext=text='${escapedTitle}':fontsize=${titleSize}:fontcolor=0x${textColor}:` +
|
|
195
|
+
`x=(w-text_w)/2:y=(h-text_h)/2-${Math.round(subSize * 1.5)}`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
if (escapedSub) {
|
|
199
|
+
vfParts.push(
|
|
200
|
+
`drawtext=text='${escapedSub}':fontsize=${subSize}:fontcolor=0x${textColor}@0.6:` +
|
|
201
|
+
`x=(w-text_w)/2:y=(h-text_h)/2+${Math.round(titleSize * 0.8)}`,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (fd > 0) {
|
|
207
|
+
const fadeOutStart = (durationSec - fd).toFixed(3);
|
|
208
|
+
if (!isFirst) vfParts.push(`fade=t=in:st=0:d=${fd}`);
|
|
209
|
+
if (!isLast) vfParts.push(`fade=t=out:st=${fadeOutStart}:d=${fd}`);
|
|
210
|
+
}
|
|
211
|
+
vfParts.push('format=yuv420p');
|
|
212
|
+
|
|
213
|
+
const args = [
|
|
214
|
+
'-f', 'lavfi', '-i', vfParts.join(','),
|
|
215
|
+
'-f', 'lavfi', '-t', String(durationSec), '-i', 'anullsrc=channel_layout=mono:sample_rate=24000',
|
|
216
|
+
'-c:v', 'libx264', '-preset', 'fast', '-crf', '22',
|
|
217
|
+
'-c:a', 'aac', '-b:a', '128k',
|
|
218
|
+
'-t', String(durationSec),
|
|
219
|
+
'-shortest',
|
|
220
|
+
'-movflags', '+faststart', '-y', path.resolve(outPath),
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
await runCommand('ffmpeg', args);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Mix background music into a video at low volume.
|
|
228
|
+
*/
|
|
229
|
+
async function mixBgm(videoPath, bgmPath, outputPath, { volume = 0.08, fadeIn = 1.5 } = {}) {
|
|
230
|
+
await runCommand('ffmpeg', [
|
|
231
|
+
'-i', path.resolve(videoPath),
|
|
232
|
+
'-stream_loop', '-1',
|
|
233
|
+
'-i', path.resolve(bgmPath),
|
|
234
|
+
'-filter_complex',
|
|
235
|
+
`[1:a]volume=${volume},afade=t=in:st=0:d=${fadeIn}[bgm];[0:a][bgm]amix=inputs=2:duration=first:dropout_transition=2[out]`,
|
|
236
|
+
'-map', '0:v', '-map', '[out]',
|
|
237
|
+
'-c:v', 'copy', '-c:a', 'aac', '-b:a', '128k',
|
|
238
|
+
'-movflags', '+faststart', '-y', path.resolve(outputPath),
|
|
239
|
+
]);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// ── Main pipeline ─────────────────────────────────────────────────────────────
|
|
243
|
+
|
|
244
|
+
async function cardRender(opts) {
|
|
245
|
+
const {
|
|
246
|
+
token, api: apiBase, dir,
|
|
247
|
+
noAudio = false,
|
|
248
|
+
noSubtitle = false, noIntro = false, noOutro = false,
|
|
249
|
+
bgm, bgmVolume,
|
|
250
|
+
pause = 2.5, // seconds of silence after narration ends (reading time)
|
|
251
|
+
hold = 5, // seconds to hold each card when --no-audio (no narration)
|
|
252
|
+
introDuration = 2.5,
|
|
253
|
+
outroDuration = 2,
|
|
254
|
+
} = opts;
|
|
255
|
+
const voice = opts.voice || 'female-kefu-xiaoyue';
|
|
256
|
+
const speed = Number(opts.speed) || 1.0;
|
|
257
|
+
|
|
258
|
+
const deck = readDeckJson(dir);
|
|
259
|
+
const cards = deck.cards || [];
|
|
260
|
+
const ratio = deck.meta?.ratio || '9:16';
|
|
261
|
+
const title = deck.meta?.title || '';
|
|
262
|
+
|
|
263
|
+
if (cards.length === 0) throw new Error('deck.json has no cards array entries.');
|
|
264
|
+
|
|
265
|
+
console.log(`\n=== VoxFlow Card Render ===`);
|
|
266
|
+
console.log(`Cards: ${cards.length} | Ratio: ${ratio} | Audio: ${!noAudio}`);
|
|
267
|
+
if (!noAudio) console.log(`Voice: ${voice} | Speed: ${speed}`);
|
|
268
|
+
console.log(`Subtitle: ${!noSubtitle} | Intro: ${!noIntro} | Outro: ${!noOutro}`);
|
|
269
|
+
if (bgm) console.log(`BGM: ${path.basename(bgm)}`);
|
|
270
|
+
|
|
271
|
+
const ffmpegInfo = await checkFfmpeg();
|
|
272
|
+
if (!ffmpegInfo.available) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
'ffmpeg not found. Install: brew install ffmpeg (macOS) / sudo apt install ffmpeg (Linux)\n' +
|
|
275
|
+
' Or: npm install ffmpeg-static',
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
if (ffmpegInfo.source === 'ffmpeg-static') {
|
|
279
|
+
let pkgVersion = '';
|
|
280
|
+
try { pkgVersion = require('ffmpeg-static/package.json').version; } catch { /* unknown */ }
|
|
281
|
+
console.log(` (using ffmpeg-static${pkgVersion ? ` v${pkgVersion}` : ''} — ffmpeg ${ffmpegInfo.version})`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Check drawtext filter availability (needs libfreetype)
|
|
285
|
+
let hasDrawtext = false;
|
|
286
|
+
if (!noSubtitle) {
|
|
287
|
+
try {
|
|
288
|
+
const { stdout } = await runCommand('ffmpeg', ['-hide_banner', '-filters']);
|
|
289
|
+
hasDrawtext = stdout.includes('drawtext');
|
|
290
|
+
} catch { /* unavailable */ }
|
|
291
|
+
if (!hasDrawtext) {
|
|
292
|
+
console.log(` (drawtext unavailable — subtitles disabled)`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Working directory for intermediate files (WAVs, clips).
|
|
297
|
+
// Lives inside the card dir so user can inspect on failure.
|
|
298
|
+
// Cleaned up on success.
|
|
299
|
+
const workDir = path.join(dir, '.card-render-work');
|
|
300
|
+
if (fs.existsSync(workDir)) {
|
|
301
|
+
fs.rmSync(workDir, { recursive: true, force: true });
|
|
302
|
+
}
|
|
303
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
304
|
+
const clipPaths = [];
|
|
305
|
+
let totalQuota = 0;
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
// ── Intro card (only if drawtext available — otherwise it's just a blank dark frame) ──
|
|
309
|
+
if (!noIntro && title && hasDrawtext) {
|
|
310
|
+
console.log(` Rendering intro...`);
|
|
311
|
+
const introPath = path.join(workDir, 'intro.mp4');
|
|
312
|
+
await renderTitleCard({
|
|
313
|
+
outPath: introPath, ratio, title,
|
|
314
|
+
subtitle: deck.meta?.language === 'zh' ? '知识卡片' : 'Card Series',
|
|
315
|
+
durationSec: introDuration, fadeSeconds: 0,
|
|
316
|
+
isFirst: true, isLast: false, hasDrawtext,
|
|
317
|
+
});
|
|
318
|
+
clipPaths.push(introPath);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// ── Per-card clips ──────────────────────────────────────────────────────
|
|
322
|
+
for (let i = 0; i < cards.length; i++) {
|
|
323
|
+
const card = cards[i];
|
|
324
|
+
const pngPath = resolveCardPng(dir, card.file);
|
|
325
|
+
if (!pngPath) {
|
|
326
|
+
throw new Error(
|
|
327
|
+
`PNG for ${card.file} not found. Run render-cards.mjs first:\n` +
|
|
328
|
+
` node cli/skills/card/scripts/render-cards.mjs --input ${dir} --output ${dir}/exports --ratio ${ratio}`,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
let wavPath = null;
|
|
333
|
+
let durationMs = hold * 1000; // silent card hold time
|
|
334
|
+
|
|
335
|
+
if (!noAudio && card.narration) {
|
|
336
|
+
const { audio: pcm, quota } = await synthesizeTTS({
|
|
337
|
+
apiBase, token,
|
|
338
|
+
text: card.narration,
|
|
339
|
+
voiceId: voice, speed,
|
|
340
|
+
format: 'pcm',
|
|
341
|
+
index: i, total: cards.length,
|
|
342
|
+
});
|
|
343
|
+
if (quota?.costDelta) totalQuota += quota.costDelta;
|
|
344
|
+
const wavDest = path.join(workDir, `card-${i}.wav`);
|
|
345
|
+
// Bake the post-narration pause into the WAV itself — otherwise
|
|
346
|
+
// ffmpeg's `-shortest` truncates the clip to the narration length
|
|
347
|
+
// and `--pause` becomes a no-op.
|
|
348
|
+
writePcmAsWav(pcm, wavDest, pause);
|
|
349
|
+
wavPath = wavDest;
|
|
350
|
+
durationMs = pcmToDurationMs(pcm) + Math.round(pause * 1000); // narration + reading time
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const clipOut = path.join(workDir, `clip-${i}.mp4`);
|
|
354
|
+
console.log(` Rendering card ${i + 1}/${cards.length}...`);
|
|
355
|
+
await renderCardClip({
|
|
356
|
+
pngPath, wavPath, outPath: clipOut,
|
|
357
|
+
durationMs, ratio, hasDrawtext,
|
|
358
|
+
subtitle: noSubtitle ? null : (card.narration || card.title || null),
|
|
359
|
+
});
|
|
360
|
+
clipPaths.push(clipOut);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ── Outro card (only if drawtext available) ───────────────────────────
|
|
364
|
+
if (!noOutro && hasDrawtext) {
|
|
365
|
+
console.log(` Rendering outro...`);
|
|
366
|
+
const outroPath = path.join(workDir, 'outro.mp4');
|
|
367
|
+
await renderTitleCard({
|
|
368
|
+
outPath: outroPath, ratio,
|
|
369
|
+
title: 'VoxFlow',
|
|
370
|
+
subtitle: 'voxflow.studio',
|
|
371
|
+
durationSec: outroDuration, fadeSeconds: 0,
|
|
372
|
+
bgColor: '0d0b14',
|
|
373
|
+
isFirst: false, isLast: true, hasDrawtext,
|
|
374
|
+
});
|
|
375
|
+
clipPaths.push(outroPath);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ── Concat ──────────────────────────────────────────────────────────────
|
|
379
|
+
const slug = (title
|
|
380
|
+
? title.replace(/[^a-z0-9一-鿿]/gi, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').toLowerCase()
|
|
381
|
+
: '') || 'cards';
|
|
382
|
+
const outputPath = path.resolve(opts.output || path.join(dir, `${slug}.mp4`));
|
|
383
|
+
|
|
384
|
+
// Ensure output directory exists
|
|
385
|
+
const outputDir = path.dirname(outputPath);
|
|
386
|
+
if (!fs.existsSync(outputDir)) {
|
|
387
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
console.log(`\n Concatenating ${clipPaths.length} clips...`);
|
|
391
|
+
await concatVideos(clipPaths, outputPath, { remux: true });
|
|
392
|
+
|
|
393
|
+
// ── BGM mix ─────────────────────────────────────────────────────────────
|
|
394
|
+
if (bgm && fs.existsSync(bgm)) {
|
|
395
|
+
console.log(` Mixing BGM...`);
|
|
396
|
+
const withBgmPath = outputPath.replace(/\.mp4$/, '-bgm.mp4');
|
|
397
|
+
await mixBgm(outputPath, bgm, withBgmPath, { volume: bgmVolume || 0.08 });
|
|
398
|
+
fs.renameSync(withBgmPath, outputPath);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
console.log(`\n=== Done ===`);
|
|
402
|
+
console.log(`Output: ${outputPath}`);
|
|
403
|
+
if (totalQuota > 0) console.log(`Quota used: ${totalQuota}`);
|
|
404
|
+
|
|
405
|
+
// Success — clean up work directory
|
|
406
|
+
fs.rmSync(workDir, { recursive: true, force: true });
|
|
407
|
+
|
|
408
|
+
return { outputPath, cardCount: cards.length, quotaUsed: totalQuota };
|
|
409
|
+
} catch (err) {
|
|
410
|
+
// Failure — keep work directory for debugging
|
|
411
|
+
if (fs.existsSync(workDir)) {
|
|
412
|
+
console.error(`\n Work directory preserved for debugging: ${workDir}`);
|
|
413
|
+
}
|
|
414
|
+
throw err;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ── CLI handler ───────────────────────────────────────────────────────────────
|
|
419
|
+
|
|
420
|
+
async function handle(args) {
|
|
421
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
422
|
+
console.log(`Usage: voxflow card render <dir> [options]
|
|
423
|
+
|
|
424
|
+
Options:
|
|
425
|
+
<dir> Card output directory (must contain deck.json + exports/*.png)
|
|
426
|
+
|
|
427
|
+
Audio:
|
|
428
|
+
--voice <id> TTS voice ID (default: female-kefu-xiaoyue)
|
|
429
|
+
--speed <n> TTS speed, 0.5-2.0 (default: 1.0)
|
|
430
|
+
--no-audio Silent video — skip TTS synthesis
|
|
431
|
+
|
|
432
|
+
Timing:
|
|
433
|
+
--pause <sec> Silence after narration before next card (default: 2.5)
|
|
434
|
+
--hold <sec> Duration per card in --no-audio mode (default: 5)
|
|
435
|
+
|
|
436
|
+
Structure:
|
|
437
|
+
--no-intro Skip intro title card
|
|
438
|
+
--no-outro Skip outro branding card
|
|
439
|
+
--intro-dur <sec> Intro card duration (default: 2.5)
|
|
440
|
+
--outro-dur <sec> Outro card duration (default: 2)
|
|
441
|
+
|
|
442
|
+
Overlay:
|
|
443
|
+
--no-subtitle Disable subtitle overlay (requires FFmpeg with libfreetype)
|
|
444
|
+
--bgm <path> Background music file (loops at low volume)
|
|
445
|
+
--bgm-volume <n> BGM volume, 0-1 (default: 0.08)
|
|
446
|
+
|
|
447
|
+
Output:
|
|
448
|
+
-o, --output <path> Output MP4 path (default: <dir>/<title>.mp4)
|
|
449
|
+
|
|
450
|
+
Examples:
|
|
451
|
+
voxflow card render cards/fermentation/
|
|
452
|
+
voxflow card render cards/my-set/ --voice v-female-R2s4N9qJ --pause 3
|
|
453
|
+
voxflow card render cards/my-set/ --no-audio --hold 4
|
|
454
|
+
voxflow card render cards/my-set/ --bgm ~/music/ambient.mp3 --bgm-volume 0.1
|
|
455
|
+
voxflow card render cards/my-set/ --no-intro --no-outro`);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// First positional arg = directory
|
|
460
|
+
const valuedFlags = new Set([
|
|
461
|
+
'--voice', '--speed', '--output', '-o',
|
|
462
|
+
'--pause', '--hold', '--intro-dur', '--outro-dur',
|
|
463
|
+
'--bgm', '--bgm-volume', '--token', '--api',
|
|
464
|
+
]);
|
|
465
|
+
let dir;
|
|
466
|
+
for (let i = 0; i < args.length; i++) {
|
|
467
|
+
if (args[i].startsWith('-')) { if (valuedFlags.has(args[i])) i++; continue; }
|
|
468
|
+
dir = args[i]; break;
|
|
469
|
+
}
|
|
470
|
+
if (!dir) { console.error('Error: provide the card output directory'); process.exit(1); }
|
|
471
|
+
|
|
472
|
+
const voice = parseFlag(args, '--voice');
|
|
473
|
+
const speed = parseFlag(args, '--speed');
|
|
474
|
+
const output = parseFlag(args, '--output', '-o');
|
|
475
|
+
const pauseArg = parseFlag(args, '--pause');
|
|
476
|
+
const holdArg = parseFlag(args, '--hold');
|
|
477
|
+
const introDurArg = parseFlag(args, '--intro-dur');
|
|
478
|
+
const outroDurArg = parseFlag(args, '--outro-dur');
|
|
479
|
+
const bgm = parseFlag(args, '--bgm');
|
|
480
|
+
const bgmVolume = parseFlag(args, '--bgm-volume');
|
|
481
|
+
const noAudio = args.includes('--no-audio');
|
|
482
|
+
const noSubtitle = args.includes('--no-subtitle');
|
|
483
|
+
const noIntro = args.includes('--no-intro');
|
|
484
|
+
const noOutro = args.includes('--no-outro');
|
|
485
|
+
const explicitToken = parseFlag(args, '--token');
|
|
486
|
+
const api = parseFlag(args, '--api') || API_BASE;
|
|
487
|
+
|
|
488
|
+
let token = explicitToken;
|
|
489
|
+
if (!noAudio && !token) {
|
|
490
|
+
token = await getToken({ api });
|
|
491
|
+
const info = getTokenInfo();
|
|
492
|
+
if (info) console.log(`\x1b[32mLogged in as ${info.email}\x1b[0m`);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
await runWithRetry(cardRender, {
|
|
496
|
+
token, api,
|
|
497
|
+
dir: path.resolve(dir),
|
|
498
|
+
voice: voice || undefined,
|
|
499
|
+
speed: speed ? Number(speed) : undefined,
|
|
500
|
+
output: output || undefined,
|
|
501
|
+
noAudio, noSubtitle, noIntro, noOutro,
|
|
502
|
+
pause: pauseArg ? Number(pauseArg) : undefined,
|
|
503
|
+
hold: holdArg ? Number(holdArg) : undefined,
|
|
504
|
+
introDuration: introDurArg ? Number(introDurArg) : undefined,
|
|
505
|
+
outroDuration: outroDurArg ? Number(outroDurArg) : undefined,
|
|
506
|
+
bgm: bgm ? path.resolve(bgm) : undefined,
|
|
507
|
+
bgmVolume: bgmVolume ? Number(bgmVolume) : undefined,
|
|
508
|
+
}, api, explicitToken);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
module.exports = {
|
|
512
|
+
cardRender,
|
|
513
|
+
readDeckJson,
|
|
514
|
+
resolveCardPng,
|
|
515
|
+
renderCardClip,
|
|
516
|
+
renderTitleCard,
|
|
517
|
+
escapeDrawtext,
|
|
518
|
+
writePcmAsWav,
|
|
519
|
+
handle,
|
|
520
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VoxFlow CLI — card command
|
|
3
|
+
*
|
|
4
|
+
* Dispatches `voxflow card render <dir>` to card-render.js.
|
|
5
|
+
* The card *generation* workflow lives in cli/skills/card/SKILL.md —
|
|
6
|
+
* Claude Code calls render-cards.mjs directly. This command handles the
|
|
7
|
+
* post-generation video render step which needs API auth (TTS quota).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
async function handle(args) {
|
|
13
|
+
if (args.length > 0 && args[0] === 'render') {
|
|
14
|
+
const cardRender = require('./card-render');
|
|
15
|
+
return cardRender.handle(args.slice(1));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Default: usage
|
|
19
|
+
console.log(`Usage:
|
|
20
|
+
voxflow card render <dir> Render card directory → narrated MP4 video
|
|
21
|
+
|
|
22
|
+
Subcommands:
|
|
23
|
+
render Synthesize TTS narration + render Ken Burns video from card PNGs
|
|
24
|
+
|
|
25
|
+
See: voxflow card render --help`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const meta = {
|
|
29
|
+
card: {
|
|
30
|
+
usage: 'render <dir> [options]',
|
|
31
|
+
description: 'Card video export: narrated MP4 with subtitles, intro/outro, and BGM from a card-skill output directory',
|
|
32
|
+
options: [
|
|
33
|
+
'render <dir> Render deck.json + PNGs → narrated MP4 video',
|
|
34
|
+
'--voice <id> TTS voice ID (default: female-kefu-xiaoyue)',
|
|
35
|
+
'--speed <n> TTS speed, 0.5-2.0 (default: 1.0)',
|
|
36
|
+
'--no-audio Silent video — skip TTS synthesis',
|
|
37
|
+
'--pause <sec> Silence after narration (reading time, default: 2.5)',
|
|
38
|
+
'--hold <sec> Card duration in --no-audio mode (default: 5)',
|
|
39
|
+
'--no-intro Skip intro title card',
|
|
40
|
+
'--no-outro Skip outro branding card',
|
|
41
|
+
'--intro-dur <sec> Intro duration (default: 2.5)',
|
|
42
|
+
'--outro-dur <sec> Outro duration (default: 2)',
|
|
43
|
+
'--no-subtitle Disable subtitle overlay',
|
|
44
|
+
'--bgm <path> Background music (loops at low volume)',
|
|
45
|
+
'--bgm-volume <n> BGM volume, 0-1 (default: 0.08)',
|
|
46
|
+
'-o, --output <path> Output MP4 path (default: <dir>/<title>.mp4)',
|
|
47
|
+
],
|
|
48
|
+
examples: [
|
|
49
|
+
'voxflow card render cards/fermentation/',
|
|
50
|
+
'voxflow card render cards/fermentation/ --voice v-female-R2s4N9qJ -o out.mp4',
|
|
51
|
+
'voxflow card render cards/fermentation/ --bgm ~/music/ambient.mp3',
|
|
52
|
+
'voxflow card render cards/fermentation/ --no-audio --no-subtitle',
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
module.exports = { handle, meta };
|
package/lib/commands/skills.js
CHANGED
|
@@ -23,7 +23,7 @@ const { detectAIAgent } = require('../core/agent-env');
|
|
|
23
23
|
const execFileAsync = promisify(execFile);
|
|
24
24
|
|
|
25
25
|
const SKILLS_NPM_TARGET = 'VoxFlowStudio/skills';
|
|
26
|
-
const SKILL_LIST = ['hub', 'podcast', 'transcribe', 'video', 'slice'];
|
|
26
|
+
const SKILL_LIST = ['hub', 'podcast', 'transcribe', 'video', 'slice', 'card'];
|
|
27
27
|
|
|
28
28
|
// Universal install command — same for every agent. The `skills` npm package
|
|
29
29
|
// detects which AI agents are present on the user's machine and installs the
|
|
@@ -32,8 +32,8 @@ const SKILL_LIST = ['hub', 'podcast', 'transcribe', 'video', 'slice'];
|
|
|
32
32
|
// - `claude skills add voxflow` does NOT exist (was wrong in earlier docs)
|
|
33
33
|
// - `npx skills add VoxFlowStudio/skills --skill voxflow` was wrong too —
|
|
34
34
|
// `--skill voxflow` is interpreted as "find a skill literally named
|
|
35
|
-
// voxflow", but our repo has
|
|
36
|
-
// video / slice), no skill called voxflow.
|
|
35
|
+
// voxflow", but our repo has 6 skills (hub / podcast / transcribe /
|
|
36
|
+
// video / slice / card), no skill called voxflow.
|
|
37
37
|
//
|
|
38
38
|
// Flags:
|
|
39
39
|
// --all install every skill in the target repo (we ship all 5).
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* `voxflow slice fork <template-id>` — copy a curated Slice template's
|
|
5
5
|
* deck.json into the current working directory.
|
|
6
6
|
*
|
|
7
|
-
* Templates live under `cli/skills/
|
|
7
|
+
* Templates live under `cli/skills/slice/templates/<id>/deck.json`
|
|
8
8
|
* with a sibling `manifest.json` describing the gallery. The CLI ships
|
|
9
9
|
* them verbatim (the `files` whitelist in package.json includes `skills/`),
|
|
10
10
|
* so `npm install voxflow` is enough — no separate download.
|
|
@@ -28,11 +28,11 @@ const { validatePaperSlideDeck } = require('../internal/deck-validator');
|
|
|
28
28
|
function resolveTemplatesDir() {
|
|
29
29
|
const candidates = [
|
|
30
30
|
// Source / dev: cli/lib/commands/slice-fork.js → cli/skills/...
|
|
31
|
-
path.resolve(__dirname, '../../skills/
|
|
31
|
+
path.resolve(__dirname, '../../skills/slice/templates'),
|
|
32
32
|
// Published: <pkg>/dist/index.js (bundled) sits beside <pkg>/skills/...
|
|
33
|
-
path.resolve(__dirname, '../skills/
|
|
33
|
+
path.resolve(__dirname, '../skills/slice/templates'),
|
|
34
34
|
// Alt published layout (some build configs flatten skills/ into dist/)
|
|
35
|
-
path.resolve(__dirname, 'skills/
|
|
35
|
+
path.resolve(__dirname, 'skills/slice/templates'),
|
|
36
36
|
];
|
|
37
37
|
for (const c of candidates) {
|
|
38
38
|
try {
|
package/lib/commands/slice.js
CHANGED
|
@@ -216,7 +216,7 @@ async function handle(args) {
|
|
|
216
216
|
}
|
|
217
217
|
// `voxflow slice fork <template-id>` — copy a curated template's
|
|
218
218
|
// deck.json into the user's cwd. No quota / network — assets ship in
|
|
219
|
-
// the published `skills/
|
|
219
|
+
// the published `skills/slice/templates/` directory.
|
|
220
220
|
if (args.length > 0 && args[0] === 'fork') {
|
|
221
221
|
const sliceFork = require('./slice-fork');
|
|
222
222
|
return sliceFork.handle(args.slice(1));
|